using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Drawing;

using HISP.Player;
using HISP.Game;
using HISP.Security;
using HISP.Game.Chat;
using HISP.Player.Equips;
using HISP.Game.Services;
using HISP.Game.Inventory;
using HISP.Game.SwfModules;
using HISP.Game.Horse;
using HISP.Game.Items;

namespace HISP.Server
{
    public class GameServer
    {

        public static Socket ServerSocket;

        public static GameClient[] ConnectedClients // Done to prevent Enumerator Changed errors.
        {
            get {
                return connectedClients.ToArray();
            }
        }

        public static int IdleTimeout;
        public static int IdleWarning;

        public static Random RandomNumberGenerator = new Random();

        /*
         *  Private stuff 
         */
        private static int gameTickSpeed = 4320; // Changing this to ANYTHING else will cause desync with the client.
        private static int totalMinutesElapsed = 0;
        private static int oneMinute = 1000 * 60;
        private static List<GameClient> connectedClients = new List<GameClient>();
        private static Timer gameTimer; // Controls in-game time.
        private static Timer minuteTimer; // ticks every real world minute.
        private static void onGameTick(object state)
        {
            World.TickWorldClock();
            
            gameTimer.Change(gameTickSpeed, gameTickSpeed);
        }
        private static void onMinuteTick(object state)
        {
            totalMinutesElapsed++;

            if (totalMinutesElapsed % 8 == 0)
            {
                Database.IncAllUsersFreeTime(1);
            }

            if(totalMinutesElapsed % 24 == 0)
                Database.DoIntrestPayments(ConfigReader.IntrestRate);

            foreach (World.Town town in World.Towns)
            {
                if (RandomNumberGenerator.Next(0, 100) < 25)
                {
                    town.Weather = town.SelectRandomWeather();
                    Logger.DebugPrint("Changing the weather in " + town.Name + " to " + town.Weather);
                }
            }

            foreach (World.Isle isle in World.Isles)
            {
                if(RandomNumberGenerator.Next(0,100) < 25)
                {
                    isle.Weather = isle.SelectRandomWeather();
                    Logger.DebugPrint("Changing the weather in " + isle.Name + " to " + isle.Weather);
                }
            }


            Database.IncPlayerTirednessForOfflineUsers();
            DroppedItems.Update();
            WildHorse.Update();
            minuteTimer.Change(oneMinute, oneMinute);
        }

        /*
         * This section is where all the event handlers live, 
         * eg: OnMovementPacket is whenever the server receies a movement request from the client.
         */
        public static void OnCrossdomainPolicyRequest(GameClient sender)
        {
            Logger.DebugPrint("Cross-Domain-Policy request received from: " + sender.RemoteIp);

            byte[] crossDomainPolicyResponse = CrossDomainPolicy.GetPolicy();

            sender.SendPacket(crossDomainPolicyResponse);
        }


        public static void OnHorseInteraction(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent horse interaction when not logged in.");
                return;
            }

            if(packet.Length < 3)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid sized horse interaction packet: " + BitConverter.ToString(packet).Replace("-", " "));
                return;
            }

            byte method = packet[1];
            switch(method)
            {
                case PacketBuilder.HORSE_LIST:
                    sender.LoggedinUser.MetaPriority = true;
                    byte[] metaTags = PacketBuilder.CreateMetaPacket(Meta.BuildHorseInventory(sender.LoggedinUser));
                    sender.SendPacket(metaTags);
                    break;
                case PacketBuilder.HORSE_PROFILE:
                    byte methodProfileEdit = packet[2]; 
                    if(methodProfileEdit == PacketBuilder.HORSE_PROFILE_EDIT)
                    {
                        if (sender.LoggedinUser.LastViewedHorse != null)
                        {
                            sender.LoggedinUser.MetaPriority = true;
                            byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseDescriptionEditMeta(sender.LoggedinUser.LastViewedHorse));
                            sender.SendPacket(metaPacket);
                        }
                        else
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + "Trying to edit description of no horse");
                        }
                    }
                    else
                    {
                        Logger.InfoPrint(BitConverter.ToString(packet).Replace("-", " "));
                    }
                    break;
                case PacketBuilder.HORSE_FEED:
                    int randomId = 0;
                    string packetStr = Encoding.UTF8.GetString(packet);
                    string randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if (sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        HorseInstance horseInst = sender.LoggedinUser.HorseInventory.GetHorseById(randomId);

                        sender.LoggedinUser.LastViewedHorse = horseInst;
                        sender.LoggedinUser.MetaPriority = true;
                        byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseFeedMenu(horseInst, sender.LoggedinUser));
                        sender.SendPacket(metaPacket);
                        break;
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to feed at a non existant horse.");
                        break;
                    }
                case PacketBuilder.HORSE_PET:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if (sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        HorseInstance horseInst = sender.LoggedinUser.HorseInventory.GetHorseById(randomId);
                        sender.LoggedinUser.LastViewedHorse = horseInst;
                        int randMoodAddition = RandomNumberGenerator.Next(1, 20);
                        int randTiredMinus = RandomNumberGenerator.Next(1, 10);



                        string message = "";
                        if(horseInst.BasicStats.Mood + randMoodAddition > 1000)
                            message = Messages.FormatHorsePetMessage(randMoodAddition, randTiredMinus);
                        else 
                            message = Messages.FormatHorsePetTooHappyMessage(randMoodAddition, randTiredMinus);


                        
                        horseInst.BasicStats.Tiredness -= randTiredMinus;
                        horseInst.BasicStats.Mood += randMoodAddition;

                        byte[] petMessagePacket = PacketBuilder.CreateChat(message, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(petMessagePacket);

                        break;
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to feed at a non existant horse.");
                        break;
                    }
                case PacketBuilder.HORSE_VET_SERVICE_ALL:

                    if (World.InSpecialTile(sender.LoggedinUser.X, sender.LoggedinUser.Y))
                    {
                        World.SpecialTile tile = World.GetSpecialTile(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                        if (tile.Code.StartsWith("VET-"))
                        {
                            string[] vetInfo = tile.Code.Split('-');
                            int vetId = int.Parse(vetInfo[1]);
                            Vet vet = Vet.GetVetById(vetId);
                            int price = 0;

                            foreach (HorseInstance horse in sender.LoggedinUser.HorseInventory.HorseList)
                                price += vet.CalculatePrice(horse.BasicStats.Health);
                            if(price == 0)
                            {
                                byte[] notNeededMessagePacket = PacketBuilder.CreateChat(Messages.VetServicesNotNeededAll, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(notNeededMessagePacket);
                                break;
                            }
                            else if (sender.LoggedinUser.Money >= price)
                            {
                                foreach (HorseInstance horse in sender.LoggedinUser.HorseInventory.HorseList)
                                    horse.BasicStats.Health = 1000;

                                byte[] healedMessagePacket = PacketBuilder.CreateChat(Messages.VetAllFullHealthRecoveredMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(healedMessagePacket);

                                sender.LoggedinUser.Money -= price;

                            }
                            else
                            {
                                byte[] cannotAffordMessagePacket = PacketBuilder.CreateChat(Messages.VetCannotAffordMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(cannotAffordMessagePacket);
                                break;
                            }
                            UpdateArea(sender);
                        }
                    }
                    break;
                case PacketBuilder.HORSE_VET_SERVICE:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);

                    if (randomIdStr == "NaN")
                        break;
                        
                    try
                    {
                        randomId = int.Parse(randomIdStr);
                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if (sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        HorseInstance horseInst = sender.LoggedinUser.HorseInventory.GetHorseById(randomId);
                        sender.LoggedinUser.LastViewedHorse = horseInst;

                        if(World.InSpecialTile(sender.LoggedinUser.X, sender.LoggedinUser.Y))
                        {
                            World.SpecialTile tile = World.GetSpecialTile(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                            if(tile.Code.StartsWith("VET-"))
                            {
                                string[] vetInfo = tile.Code.Split('-');
                                int vetId = int.Parse(vetInfo[1]);

                                Vet vet = Vet.GetVetById(vetId);
                                int price = vet.CalculatePrice(horseInst.BasicStats.Health);
                                if(sender.LoggedinUser.Money >= price)
                                {
                                    horseInst.BasicStats.Health = 1000;
                                    sender.LoggedinUser.Money -= price;

                                    byte[] messagePacket = PacketBuilder.CreateChat(Messages.FormatVetHorseAtFullHealthMessage(horseInst.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(messagePacket);
                                }
                                else
                                {
                                    byte[] cantAffordMessage = PacketBuilder.CreateChat(Messages.VetCannotAffordMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(cantAffordMessage);
                                }
                                UpdateArea(sender);
                            }
                        }
                        break;
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to use vet services on a non existant horse.");
                        break;
                    }
                case PacketBuilder.HORSE_GIVE_FEED:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if(sender.LoggedinUser.LastViewedHorse == null)
                    {
                        Logger.InfoPrint(sender.LoggedinUser.Username + " Tried to feed a non existant horse.");
                        break;
                    }
                    if (sender.LoggedinUser.Inventory.HasItem(randomId))
                    {
                        InventoryItem item = sender.LoggedinUser.Inventory.GetItemByRandomid(randomId);
                        Item.ItemInformation itemInfo = item.ItemInstances[0].GetItemInfo();
                        HorseInstance horseInstance = sender.LoggedinUser.LastViewedHorse;
                        bool tooMuch = false;
                        if (itemInfo.Type == "HORSEFOOD")
                        {
                            foreach(Item.Effects effect in itemInfo.Effects)
                            {
                                switch(effect.EffectsWhat)
                                {
                                    case "HEALTH":
                                        if (horseInstance.BasicStats.Health + effect.EffectAmount > 1000)
                                            tooMuch = true;
                                        horseInstance.BasicStats.Health += effect.EffectAmount;
                                        break;
                                    case "HUNGER":
                                        if (horseInstance.BasicStats.Hunger + effect.EffectAmount > 1000)
                                            tooMuch = true;
                                        horseInstance.BasicStats.Hunger += effect.EffectAmount;
                                        break;
                                    case "MOOD":
                                        if (horseInstance.BasicStats.Mood + effect.EffectAmount > 1000)
                                            tooMuch = true;
                                        horseInstance.BasicStats.Mood += effect.EffectAmount;
                                        break;
                                    case "GROOM":
                                        if (horseInstance.BasicStats.Groom + effect.EffectAmount > 1000)
                                            tooMuch = true;
                                        horseInstance.BasicStats.Groom += effect.EffectAmount;
                                        break;
                                    case "SHOES":
                                        if (horseInstance.BasicStats.Shoes + effect.EffectAmount > 1000)
                                            tooMuch = true;
                                        horseInstance.BasicStats.Shoes += effect.EffectAmount;
                                        break;
                                    case "THIRST":
                                        if (horseInstance.BasicStats.Thirst + effect.EffectAmount > 1000)
                                            tooMuch = true;
                                        horseInstance.BasicStats.Thirst += effect.EffectAmount;
                                        break;
                                    case "TIREDNESS":
                                        if (horseInstance.BasicStats.Tiredness + effect.EffectAmount > 1000)
                                            tooMuch = true;
                                        horseInstance.BasicStats.Tiredness += effect.EffectAmount;
                                        break;

                                    case "INTELLIGENCEOFFSET":
                                        horseInstance.AdvancedStats.Inteligence += effect.EffectAmount;
                                        horseInstance.MagicUsed++;
                                        break;
                                    case "PERSONALITYOFFSET":
                                        horseInstance.AdvancedStats.Personality += effect.EffectAmount;
                                        horseInstance.MagicUsed++;
                                        break;
                                    case "SPOILED":
                                        horseInstance.Spoiled += effect.EffectAmount;
                                        break;
                                }
                            }
                            sender.LoggedinUser.Inventory.Remove(item.ItemInstances[0]);

                            byte[] horseNeighThanksPacket = PacketBuilder.CreateChat(Messages.HorseNeighsThanks, PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(horseNeighThanksPacket);

                            if (tooMuch)
                            {
                                byte[] horseCouldntFinishItAll = PacketBuilder.CreateChat(Messages.HorseCouldNotFinish, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(horseCouldntFinishItAll);
                            }

                            sender.LoggedinUser.MetaPriority = true;
                            byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseFeedMenu(sender.LoggedinUser.LastViewedHorse, sender.LoggedinUser));
                            sender.SendPacket(metaPacket);
                            break;
                        }
                        else
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + "Tried to feed a horse a non-HORSEFOOD item.");
                        }
                        break;
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to feed a non existant item to a horse.");
                        break;
                    }
                case PacketBuilder.HORSE_RELEASE:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if (sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        if(World.InTown(sender.LoggedinUser.X, sender.LoggedinUser.Y))
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to reelease a horse while inside a town....");
                            break;
                        }


                        HorseInstance horseInst = sender.LoggedinUser.HorseInventory.GetHorseById(randomId);
                        if(sender.LoggedinUser.CurrentlyRidingHorse != null)
                        {
                            if(horseInst.RandomId == sender.LoggedinUser.CurrentlyRidingHorse.RandomId) 
                            {
                                byte[] errorChatPacket = PacketBuilder.CreateChat(Messages.HorseCantReleaseTheHorseYourRidingOn, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(errorChatPacket);
                                break;
                            }

                        }

                        if (horseInst.Description == "")
                            horseInst.Description += Messages.FormatHorseReleasedBy(sender.LoggedinUser.Username);

                        Logger.InfoPrint(sender.LoggedinUser.Username + " RELEASED HORSE: " + horseInst.Name + " (a " + horseInst.Breed.Name + ").");

                        sender.LoggedinUser.HorseInventory.DeleteHorse(horseInst);
                        new WildHorse(horseInst, sender.LoggedinUser.X, sender.LoggedinUser.Y, 60, true);
                        
                        sender.LoggedinUser.LastViewedHorse = horseInst;
                        sender.LoggedinUser.MetaPriority = true;
                        byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseReleased());
                        sender.SendPacket(metaPacket);
                        break;
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to tack at a non existant horse.");
                        break;
                    }
                case PacketBuilder.HORSE_TACK:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if (sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        HorseInstance horseInst = sender.LoggedinUser.HorseInventory.GetHorseById(randomId);
                        
                        sender.LoggedinUser.LastViewedHorse = horseInst;
                        sender.LoggedinUser.MetaPriority = true;
                        byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildTackMenu(horseInst, sender.LoggedinUser));
                        sender.SendPacket(metaPacket);
                        break;
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to tack at a non existant horse.");
                        break;
                    }
                case PacketBuilder.HORSE_DRINK:
                    if(World.InSpecialTile(sender.LoggedinUser.X, sender.LoggedinUser.Y))
                    {
                        World.SpecialTile tile = World.GetSpecialTile(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                        if(tile.Code != "POND")
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to drink from a pond when not on one.");
                            break;
                        }
                    }

                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if (sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        HorseInstance horseInst = sender.LoggedinUser.HorseInventory.GetHorseById(randomId);

                        if(horseInst.BasicStats.Health < 200)
                        {
                            byte[] hpToLow = PacketBuilder.CreateChat(Messages.FormatPondHpLowMessage(horseInst.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(hpToLow);
                            break;
                        }

                        if(horseInst.BasicStats.Thirst < 1000)
                        {
                            horseInst.BasicStats.Thirst = 1000;
                            byte[] drinkFull = PacketBuilder.CreateChat(Messages.FormatPondDrinkFull(horseInst.Name),PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(drinkFull);

                            if(RandomNumberGenerator.Next(0, 100) < 25)
                            {
                                horseInst.BasicStats.Health -= 200;
                                byte[] ohNoes = PacketBuilder.CreateChat(Messages.FormatPondDrinkOhNoes(horseInst.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(ohNoes);
                            }

                            UpdateArea(sender);
                        }
                        else
                        {
                            byte[] notThirsty = PacketBuilder.CreateChat(Messages.FormatPondNotThirsty(horseInst.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(notThirsty);
                            break;
                        }
                        break;
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to tack at a non existant horse.");
                        break;
                    }
                case PacketBuilder.HORSE_TACK_EQUIP:

                    int itemId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    string itemIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        itemId = int.Parse(itemIdStr);
                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if(Item.ItemIdExist(itemId))
                    {
                        if(sender.LoggedinUser.LastViewedHorse != null)
                        {
                            if(sender.LoggedinUser.LastViewedHorse.AutoSell > 0)
                            {
                                byte[] failMessagePacket = PacketBuilder.CreateChat(Messages.HorseTackFailAutoSell, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(failMessagePacket);
                                break;
                            }

                            if(sender.LoggedinUser.Inventory.HasItemId(itemId))
                            {
                                Item.ItemInformation itemInfo = Item.GetItemById(itemId);
                                if (itemInfo.Type == "TACK")
                                {
                                    switch (itemInfo.GetMiscFlag(0))
                                    {
                                        case 1: // Saddle
                                            if(sender.LoggedinUser.LastViewedHorse.Equipment.Saddle != null)
                                                sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(sender.LoggedinUser.LastViewedHorse.Equipment.Saddle.Id));
                                            Database.SetSaddle(sender.LoggedinUser.LastViewedHorse.RandomId, itemInfo.Id);
                                            sender.LoggedinUser.LastViewedHorse.Equipment.Saddle = itemInfo;
                                            break;
                                        case 2: // Saddle Pad
                                            if (sender.LoggedinUser.LastViewedHorse.Equipment.SaddlePad != null)
                                                sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(sender.LoggedinUser.LastViewedHorse.Equipment.SaddlePad.Id));
                                            Database.SetSaddlePad(sender.LoggedinUser.LastViewedHorse.RandomId, itemInfo.Id);
                                            sender.LoggedinUser.LastViewedHorse.Equipment.SaddlePad = itemInfo;
                                            break;
                                        case 3: // Bridle
                                            if (sender.LoggedinUser.LastViewedHorse.Equipment.Bridle != null)
                                                sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(sender.LoggedinUser.LastViewedHorse.Equipment.Bridle.Id));
                                            Database.SetBridle(sender.LoggedinUser.LastViewedHorse.RandomId, itemInfo.Id);
                                            sender.LoggedinUser.LastViewedHorse.Equipment.Bridle = itemInfo;
                                            break;
                                    }


                                    sender.LoggedinUser.Inventory.Remove(sender.LoggedinUser.Inventory.GetItemByItemId(itemId).ItemInstances[0]); // Remove item from inventory.

                                    sender.LoggedinUser.MetaPriority = true;
                                    byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildTackMenu(sender.LoggedinUser.LastViewedHorse, sender.LoggedinUser));
                                    sender.SendPacket(metaPacket);

                                    byte[] equipMsgPacket = PacketBuilder.CreateChat(Messages.FormatEquipTackMessage(itemInfo.Name, sender.LoggedinUser.LastViewedHorse.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(equipMsgPacket);

                                }
                                else if(itemInfo.Type == "COMPANION")
                                {
                                    if (sender.LoggedinUser.LastViewedHorse.Equipment.Companion != null)
                                        sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(sender.LoggedinUser.LastViewedHorse.Equipment.Companion.Id));
                                    Database.SetCompanion(sender.LoggedinUser.LastViewedHorse.RandomId, itemInfo.Id);
                                    sender.LoggedinUser.LastViewedHorse.Equipment.Companion = itemInfo;

                                    sender.LoggedinUser.Inventory.Remove(sender.LoggedinUser.Inventory.GetItemByItemId(itemId).ItemInstances[0]); // Remove item from inventory.

                                    sender.LoggedinUser.MetaPriority = true;
                                    byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseCompanionEquipMenu(sender.LoggedinUser.LastViewedHorse, sender.LoggedinUser));
                                    sender.SendPacket(metaPacket);

                                    byte[] equipMsgPacket = PacketBuilder.CreateChat(Messages.FormatHorseCompanionEquipMessage(sender.LoggedinUser.LastViewedHorse.Name, itemInfo.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(equipMsgPacket);
                                }
                                else
                                {
                                    Logger.ErrorPrint(sender.LoggedinUser.Username + " tried to equip a tack item to a hrose but that item was not of type \"TACK\".");
                                }
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " tried to equip tack he doesnt have");
                                break;
                            }
                        }
                        else
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " tried to equip tack to a horse when not viewing one.");
                            break;
                        }
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " tried to equip tack he doesnt exist");
                        break;
                    }

                    break;
                case PacketBuilder.HORSE_TACK_UNEQUIP:
                    if (sender.LoggedinUser.LastViewedHorse != null)
                    {
                        byte equipSlot = packet[2];
                        switch(equipSlot)
                        {
                            case 0x31: // Saddle
                                if (sender.LoggedinUser.LastViewedHorse.Equipment.Saddle != null)
                                    sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(sender.LoggedinUser.LastViewedHorse.Equipment.Saddle.Id));
                                Database.ClearSaddle(sender.LoggedinUser.LastViewedHorse.RandomId);
                                sender.LoggedinUser.LastViewedHorse.Equipment.Saddle = null;
                                break;
                            case 0x32: // Saddle Pad
                                if (sender.LoggedinUser.LastViewedHorse.Equipment.SaddlePad != null)
                                    sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(sender.LoggedinUser.LastViewedHorse.Equipment.SaddlePad.Id));
                                Database.ClearSaddlePad(sender.LoggedinUser.LastViewedHorse.RandomId);
                                sender.LoggedinUser.LastViewedHorse.Equipment.SaddlePad = null;
                                break;
                            case 0x33: // Bridle
                                if (sender.LoggedinUser.LastViewedHorse.Equipment.Bridle != null)
                                    sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(sender.LoggedinUser.LastViewedHorse.Equipment.Bridle.Id));
                                Database.ClearBridle(sender.LoggedinUser.LastViewedHorse.RandomId);
                                sender.LoggedinUser.LastViewedHorse.Equipment.Bridle = null;
                                break;
                            case 0x34: // Companion
                                if (sender.LoggedinUser.LastViewedHorse.Equipment.Companion != null)
                                    sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(sender.LoggedinUser.LastViewedHorse.Equipment.Companion.Id));
                                Database.ClearCompanion(sender.LoggedinUser.LastViewedHorse.RandomId);
                                sender.LoggedinUser.LastViewedHorse.Equipment.Companion = null;
                                goto companionRemove;
                            default:
                                Logger.ErrorPrint("Unknown equip slot: " + equipSlot.ToString("X"));
                                break;
                        }
                        byte[] itemUnequipedMessage = PacketBuilder.CreateChat(Messages.FormatUnEquipTackMessage(sender.LoggedinUser.LastViewedHorse.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(itemUnequipedMessage);

                        sender.LoggedinUser.MetaPriority = true;
                        byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildTackMenu(sender.LoggedinUser.LastViewedHorse, sender.LoggedinUser));
                        sender.SendPacket(metaPacket);
                        break;
                    companionRemove:;
                        itemUnequipedMessage = PacketBuilder.CreateChat(Messages.FormatHorseCompanionRemoveMessage(sender.LoggedinUser.LastViewedHorse.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(itemUnequipedMessage);

                        sender.LoggedinUser.MetaPriority = true;
                        metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseCompanionEquipMenu(sender.LoggedinUser.LastViewedHorse, sender.LoggedinUser));
                        sender.SendPacket(metaPacket);
                        break;

                    }
                    else
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to unequip items from non existnat horse");
                    }
                    break;
                case PacketBuilder.HORSE_DISMOUNT:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if (sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        sender.LoggedinUser.CurrentlyRidingHorse = null;

                        byte[] stopRidingHorseMessagePacket = PacketBuilder.CreateChat(Messages.HorseStopRidingMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(stopRidingHorseMessagePacket);


                        sender.LoggedinUser.Facing %= 5;
                        byte[] rideHorsePacket = PacketBuilder.CreateHorseRidePacket(sender.LoggedinUser.X, sender.LoggedinUser.Y, sender.LoggedinUser.CharacterId, sender.LoggedinUser.Facing, 10, true);
                        sender.SendPacket(rideHorsePacket);

                        UpdateUserInfo(sender.LoggedinUser);
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to dismount at a non existant horse.");
                        break;
                    }
                    break;
                case PacketBuilder.HORSE_MOUNT:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        break;
                    }
                    if (sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        HorseInstance horseInst = sender.LoggedinUser.HorseInventory.GetHorseById(randomId);
                        
                        if(horseInst.Equipment.Saddle == null || horseInst.Equipment.SaddlePad == null || horseInst.Equipment.Bridle == null)
                        {
                            byte[] horseNotTackedMessage = PacketBuilder.CreateChat(Messages.HorseCannotMountUntilTackedMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(horseNotTackedMessage);
                            break;
                        }

                        string ridingHorseMessage = Messages.FormatHorseRidingMessage(horseInst.Name);
                        byte[] ridingHorseMessagePacket = PacketBuilder.CreateChat(ridingHorseMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(ridingHorseMessagePacket);

                        sender.LoggedinUser.CurrentlyRidingHorse = horseInst;

                        // Determine what sprite to use;
                        int incBy = 0;
                        switch(horseInst.Color)
                        {
                            case "brown":
                                incBy = 1;
                                break;
                            case "cremello":
                            case "white":
                                incBy = 2;
                                break;
                            case "black":
                                incBy = 3;
                                break;
                            case "chestnut":
                                incBy = 4;
                                break;
                            case "bay":
                                incBy = 5;
                                break;
                            case "grey":
                                incBy = 6;
                                break;
                            case "dun":
                                incBy = 7;
                                break;
                            case "palomino":
                                incBy = 8;
                                break;
                            case "roan":
                                incBy = 9;
                                break;
                            case "pinto":
                                incBy = 10;
                                break;
                        }


                        if(horseInst.Breed.Type == "zebra")
                        {
                            incBy = 11;
                        }
                        if(horseInst.Breed.Id == 5) // Appaloosa
                        {
                            if(horseInst.Color == "brown")
                                incBy = 12;
                        }
                        if (horseInst.Breed.Type == "camel")
                        {
                            if (horseInst.Color == "brown")
                                incBy = 13;
                            if (horseInst.Color == "white")
                                incBy = 14;

                        }
                        if (horseInst.Breed.Type == "unicorn")
                        {
                            incBy = 15;
                        }
                        if (horseInst.Breed.Type == "pegasus")
                        {
                            incBy = 16;
                        }
                        if(horseInst.Breed.Id == 170) // Unipeg
                        {
                            incBy = 17;
                        }

                        incBy *= 5;
                        sender.LoggedinUser.Facing %= 5;
                        sender.LoggedinUser.Facing += incBy;


                        byte[] rideHorsePacket = PacketBuilder.CreateHorseRidePacket(sender.LoggedinUser.X, sender.LoggedinUser.Y, sender.LoggedinUser.CharacterId, sender.LoggedinUser.Facing, 10, true);
                        sender.SendPacket(rideHorsePacket);

                        UpdateUserInfo(sender.LoggedinUser);
                        break;
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to mount at a non existant horse.");
                        break;
                    }
                case PacketBuilder.HORSE_LOOK:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);

                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        return;
                    }
                    if(sender.LoggedinUser.HorseInventory.HorseIdExist(randomId))
                    {
                        HorseInstance horseInst = sender.LoggedinUser.HorseInventory.GetHorseById(randomId);
                        UpdateHorseMenu(sender, horseInst);
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to look at a non existant horse.");
                        break;
                    }

                    break;
                case PacketBuilder.HORSE_ESCAPE:
                    if(WildHorse.DoesHorseExist(sender.LoggedinUser.CapturingHorseId))
                    {
                        WildHorse capturing = WildHorse.GetHorseById(sender.LoggedinUser.CapturingHorseId);
                        sender.LoggedinUser.CapturingHorseId = 0;

                        capturing.Escape();
                        Logger.InfoPrint(sender.LoggedinUser.Username + " Failed to capture: " + capturing.Instance.Breed.Name + " new location: " + capturing.X + ", " + capturing.Y);

                        sender.LoggedinUser.MetaPriority = true;
                        byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseEscapedMessage());
                        sender.SendPacket(metaPacket);

                        UpdateAreaForAll(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                    }

                    break;
                case PacketBuilder.HORSE_CAUGHT:
                    if (WildHorse.DoesHorseExist(sender.LoggedinUser.CapturingHorseId))
                    {
                        WildHorse capturing = WildHorse.GetHorseById(sender.LoggedinUser.CapturingHorseId);
                        sender.LoggedinUser.CapturingHorseId = 0;

                        try
                        {
                            capturing.Capture(sender.LoggedinUser);
                        }
                        catch(InventoryFullException)
                        {
                            byte[] chatMsg = PacketBuilder.CreateChat(Messages.TooManyHorses, PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(chatMsg);
                            break;
                        }

                        sender.LoggedinUser.TrackedItems.GetTrackedItem(Tracking.TrackableItem.HorseCapture).Count++;
                        Logger.InfoPrint(sender.LoggedinUser.Username + " Captured a: " + capturing.Instance.Breed.Name + " new location: " + capturing.X + ", " + capturing.Y);

                        sender.LoggedinUser.MetaPriority = true;
                        byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseCaughtMessage());
                        sender.SendPacket(metaPacket);

                        UpdateAreaForAll(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                    }

                    break;
                case PacketBuilder.HORSE_TRY_CAPTURE:
                    randomId = 0;
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packetStr.Length - 4);
                    try
                    {
                        randomId = int.Parse(randomIdStr);
                        
                    }
                    catch (Exception)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid randomid to horse interaction packet ");
                        return;
                    }
                    if (!WildHorse.DoesHorseExist(randomId))
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to catch a horse that doesnt exist.");
                        return;
                    }
                    sender.LoggedinUser.CapturingHorseId = randomId;
                    byte[] chatPacket = PacketBuilder.CreateChat(Messages.HorseCaptureTimer, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(chatPacket);
                    byte[] swfModulePacket = PacketBuilder.CreateSwfModulePacket("catchhorse", PacketBuilder.PACKET_SWF_MODULE_FORCE);
                    sender.SendPacket(swfModulePacket);

                    break;
                default:
                    Logger.DebugPrint("Unknown horse packet: " + BitConverter.ToString(packet).Replace("-", " "));
                    break;
            }
        }

        public static void OnDynamicInputReceived(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent dyamic input when not logged in.");
                return;
            }
            string packetStr = Encoding.UTF8.GetString(packet);
            string dynamicInputStr = packetStr.Substring(1, packetStr.Length - 3);
            if(dynamicInputStr.Contains("|"))
            {
                string[] dynamicInput = dynamicInputStr.Split('|');
                if(dynamicInput.Length >= 1)
                {
                    int inputId = 0;
                    try
                    {
                        inputId = int.Parse(dynamicInput[0]);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid dynamic input ");
                        return;
                    }

                    switch(inputId) 
                    {
                        case 1: // Bank
                            if (dynamicInput.Length >= 2)
                            {
                                int moneyDeposited = 0;
                                int moneyWithdrawn = 0;
                                try
                                {
                                    moneyDeposited = int.Parse(dynamicInput[1]);
                                    moneyWithdrawn = int.Parse(dynamicInput[2]);
                                }
                                catch (FormatException)
                                {
                                    Logger.ErrorPrint(sender.LoggedinUser.Username + " tried to deposit/witthdraw NaN money....");
                                    break;
                                }

                                if((moneyDeposited <= sender.LoggedinUser.Money) && moneyDeposited != 0)
                                {
                                    sender.LoggedinUser.Money -= moneyDeposited;
                                    sender.LoggedinUser.BankMoney += Convert.ToUInt64(moneyDeposited);

                                    byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatDepositedMoneyMessage(moneyDeposited), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(chatPacket);
                                }

                                if ((Convert.ToUInt64(moneyWithdrawn) <= sender.LoggedinUser.BankMoney) && moneyWithdrawn != 0)
                                {
                                    sender.LoggedinUser.BankMoney -= Convert.ToUInt64(moneyWithdrawn);
                                    sender.LoggedinUser.Money += moneyWithdrawn;

                                    byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatWithdrawMoneyMessage(moneyWithdrawn), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(chatPacket);
                                }

                                UpdateArea(sender);
                                break;
                            }
                            else
                            {
                                Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid dynamic input (private notes, wrong size)");
                                break;
                            }
                        case 5: // Horse Description
                            if (dynamicInput.Length >= 3)
                            {
                                if(sender.LoggedinUser.LastViewedHorse != null)
                                {
                                    sender.LoggedinUser.MetaPriority = true;
                                    sender.LoggedinUser.LastViewedHorse.Name = dynamicInput[1];
                                    sender.LoggedinUser.LastViewedHorse.Description = dynamicInput[2];
                                    byte[] horseNameSavedPacket = PacketBuilder.CreateChat(Messages.FormatHorseSavedProfileMessage(sender.LoggedinUser.LastViewedHorse.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(horseNameSavedPacket);
                                    UpdateHorseMenu(sender, sender.LoggedinUser.LastViewedHorse);
                                }
                                break;
                            }
                            else
                            {
                                Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid dynamic input (NPC Search, wrong size)");
                                break;
                            }
                        case 4: // NPC Search
                            if(dynamicInput.Length >= 2)
                            {
                                sender.LoggedinUser.MetaPriority = true;
                                string metaWindow = Meta.BuildNpcSearch(dynamicInput[1]);
                                byte[] metaPacket = PacketBuilder.CreateMetaPacket(metaWindow);
                                sender.SendPacket(metaPacket);
                                break;
                            }
                            else
                            {
                                Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid dynamic input (NPC Search, wrong size)");
                                break;
                            }
                        case 7: // Private Notes
                            if (dynamicInput.Length >= 2)
                            {
                                sender.LoggedinUser.PrivateNotes = dynamicInput[1];
                                UpdateStats(sender);
                                byte[] chatPacket = PacketBuilder.CreateChat(Messages.PrivateNotesSavedMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(chatPacket);
                                break;
                            }
                            else
                            {
                                Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid dynamic input (private notes, wrong size)");
                                break;
                            }
                        case 10: // Change auto sell price
                            if (dynamicInput.Length >= 2)
                            {
                                if (sender.LoggedinUser.LastViewedHorse != null)
                                {
                                    sender.LoggedinUser.MetaPriority = true;
                                    HorseInstance horseInstance = sender.LoggedinUser.LastViewedHorse;
                                    int newSellPrice = 0;
                                    try
                                    {
                                        newSellPrice = int.Parse(dynamicInput[1]);
                                    }
                                    catch (FormatException)
                                    {
                                        Logger.ErrorPrint(sender.LoggedinUser.Username + " tried to set sell price to non int value.");
                                        break;
                                    }

                                    byte[] sellPricePacket;
                                    if (newSellPrice > 0)
                                        sellPricePacket = PacketBuilder.CreateChat(Messages.FormatAutoSellConfirmedMessage(newSellPrice), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    else
                                        sellPricePacket = PacketBuilder.CreateChat(Messages.HorseAutoSellRemoved, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(sellPricePacket);
                                    horseInstance.AutoSell = newSellPrice;

                                    UpdateHorseMenu(sender, sender.LoggedinUser.LastViewedHorse);
                                }
                            }
                            else
                            {
                                Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid dynamic input (autosell, wrong size)");
                                break;
                            }
                            break;

                        case 12: // Abuse Report
                            if (dynamicInput.Length >= 2)
                            {
                                string userName = dynamicInput[1];
                                string reason = dynamicInput[2];
                                if(Database.CheckUserExist(userName))
                                {
                                    if(reason == "")
                                    {
                                        byte[] validReasonPlz = PacketBuilder.CreateChat(Messages.AbuseReportProvideValidReason, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                        sender.SendPacket(validReasonPlz);
                                        break;
                                    }

                                    Database.AddReport(sender.LoggedinUser.Username, userName, reason);
                                    byte[] chatPacket = PacketBuilder.CreateChat(Messages.AbuseReportFiled, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(chatPacket);
                                    UpdateArea(sender);
                                    break;
                                }
                                else
                                {
                                    byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatAbuseReportPlayerNotFound(userName), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(chatPacket);
                                    break;
                                }
                            }
                            else
                            {
                                Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid dynamic input (private notes, wrong size)");
                                break;
                            }
                        case 14:
                            if(dynamicInput.Length >= 1)
                            {
                                string password = dynamicInput[1];
                                // Get current tile
                                if(World.InSpecialTile(sender.LoggedinUser.X, sender.LoggedinUser.Y))
                                {
                                    World.SpecialTile tile = World.GetSpecialTile(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                                    if(tile.Code.StartsWith("PASSWORD-"))
                                    {
                                        string[] args = tile.Code.Replace("!","-").Split('-');
                                        if(args.Length >= 3)
                                        {
                                            string expectedPassword = args[1];
                                            int questId = int.Parse(args[2]);
                                            if(password.ToLower() == expectedPassword.ToLower())
                                            {
                                                Quest.CompleteQuest(sender.LoggedinUser, Quest.GetQuestById(questId), false);
                                            }
                                            else
                                            {
                                                Quest.FailQuest(sender.LoggedinUser, Quest.GetQuestById(questId), false);
                                            }
                                        }
                                        else
                                        {
                                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Send invalid password input request. (Too few arguments!)");
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Send password input request. (Not on password tile!)");
                                        break;
                                    }
                                }
                                else
                                {
                                    Logger.HackerPrint(sender.LoggedinUser.Username + " Sent a password while not in a special tile.");
                                    break;
                                }
                            }
                            else
                            {
                                Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid password request, (wrong size)");
                                break;
                            }

                            break;
                        default:
                            Logger.ErrorPrint("Unknown dynamic input: " + inputId.ToString() + " packet dump: " + BitConverter.ToString(packet).Replace("-", " "));
                            break;
                    }


                }
                else
                {
                    Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to send a invalid dynamic input (wrong size)");
                    return;
                }
            }
            

        }

        public static void OnPlayerInfoPacket(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Requests player info when not logged in.");
                return;
            }
            if(packet.Length < 3)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent playerinfo packet of wrong size");
            }

            byte method = packet[1];
            switch(method)
            {
                case PacketBuilder.PLAYERINFO_PLAYER_LIST:
                    sender.LoggedinUser.MetaPriority = true;
                    byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildPlayerList(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
            }

        }
        public static void OnDynamicButtonPressed(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Clicked dyamic button when not logged in.");
                return;
            }
            string packetStr = Encoding.UTF8.GetString(packet);
            string buttonIdStr = packetStr.Substring(1, packetStr.Length - 3);

            switch(buttonIdStr)
            {
                case "3": // Quest Log
                    sender.LoggedinUser.MetaPriority = true;
                    byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildQuestLog(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "4": // View Horse Breeds
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseList());
                    sender.SendPacket(metaPacket);
                    break;
                case "5": // Back to horse
                    if (sender.LoggedinUser.LastViewedHorse != null)
                        UpdateHorseMenu(sender, sender.LoggedinUser.LastViewedHorse);
                    break;
                case "6": // Equip companion
                    if (sender.LoggedinUser.LastViewedHorse != null)
                    {
                        sender.LoggedinUser.MetaPriority = true;
                        HorseInstance horseInstance = sender.LoggedinUser.LastViewedHorse;
                        metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseCompanionEquipMenu(horseInstance,sender.LoggedinUser));
                        sender.SendPacket(metaPacket);
                    }
                    break;
                case "8":
                    if(sender.LoggedinUser.LastViewedHorse != null)
                    {
                        sender.LoggedinUser.MetaPriority = true;
                        HorseInstance horseInstance = sender.LoggedinUser.LastViewedHorse;
                        metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseReleaseConfirmationMessage(horseInstance));
                        sender.SendPacket(metaPacket);
                    }
                    break;
                case "9": // View Tack (Libary)
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildTackLibary());
                    sender.SendPacket(metaPacket);
                    break;
                case "10": // View Companions (Libary)
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildCompanionLibary());
                    sender.SendPacket(metaPacket);
                    break;
                case "11": // Randomize horse name
                    if (sender.LoggedinUser.LastViewedHorse != null)
                    {
                        sender.LoggedinUser.MetaPriority = true;
                        HorseInstance horseInstance = sender.LoggedinUser.LastViewedHorse;
                        horseInstance.ChangeNameWithoutUpdatingDatabase(HorseInfo.GenerateHorseName());
                        metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseDescriptionEditMeta(horseInstance));
                        sender.SendPacket(metaPacket);
                    }
                    break;
                case "12": // View Minigames (Libary)
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildMinigamesLibary());
                    sender.SendPacket(metaPacket);
                    break;
                case "20": // Minigame Rankings
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildMinigameRankingsForUser(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "21": // Private Notes
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildPrivateNotes(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "22": // View Locations (Libary)
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildLocationsLibary());
                    sender.SendPacket(metaPacket);
                    break;
                case "23": // View Awards (Libary)
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildAwardsLibary());
                    sender.SendPacket(metaPacket);
                    break;
                case "24": // Award List
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildAwardList(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "35": // Buddy List
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildBuddyList(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "36":
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildNearbyList(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "37": // All Players List
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildPlayerList());
                    sender.SendPacket(metaPacket);
                    break;
                case "40": // All Players Alphabetical
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildPlayerListAlphabetical());
                    sender.SendPacket(metaPacket);
                    break;
                case "30": // Find NPC
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildFindNpcMenu());
                    sender.SendPacket(metaPacket);
                    break;
                case "25": // Set auto sell price
                    if (sender.LoggedinUser.LastViewedHorse != null)
                    {
                        sender.LoggedinUser.MetaPriority = true;
                        HorseInstance horseInstance = sender.LoggedinUser.LastViewedHorse;
                        metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildAutoSellMenu(horseInstance));
                        sender.SendPacket(metaPacket);
                    }
                    break;
                case "33":
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildAllBasicStats(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "34":
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildAllStats(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "38":
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildBooksLibary());
                    sender.SendPacket(metaPacket);
                    break;
                case "53": // Misc Stats / Tracked Items
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildMiscStats(sender.LoggedinUser));
                    sender.SendPacket(metaPacket);
                    break;
                case "28c1": // Abuse Report
                    sender.LoggedinUser.MetaPriority = true;
                    metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildAbuseReportPage());
                    sender.SendPacket(metaPacket);
                    break;
                case "52c1": // Horse set to KEEPER
                    string category = "KEEPER";
                    goto setCategory;
                case "52c2": // Horse set to TRAINING
                    category = "TRAINING";
                    goto setCategory;
                case "52c3": // Horse set to TRADING
                    category = "TRADING";
                    goto setCategory;
                case "52c4": // Horse set to RETIRED
                    category = "RETIRED";
                    goto setCategory;
                setCategory:;
                    if (sender.LoggedinUser.LastViewedHorse != null)
                    {
                        sender.LoggedinUser.LastViewedHorse.Category = category;
                        byte[] categoryChangedPacket = PacketBuilder.CreateChat(Messages.FormatHorseSetToNewCategory(category), PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(categoryChangedPacket);

                        sender.LoggedinUser.MetaPriority = true;
                        UpdateHorseMenu(sender, sender.LoggedinUser.LastViewedHorse);
                    }
                    break;

                default:
                    if(buttonIdStr.StartsWith("39c")) // Book Read
                    {
                        string idStr = buttonIdStr.Substring(3);
                        int bookId = -1;
                        try
                        {
                            bookId = int.Parse(idStr);
                        }
                        catch (FormatException)
                        {
                            Logger.DebugPrint(sender.LoggedinUser.Username + " Tried to read a book of id NaN");
                            break;
                        };

                        if(Book.BookExists(bookId))
                        {
                            Book book = Book.GetBookById(bookId);
                            sender.LoggedinUser.MetaPriority = true;
                            metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildBookReadLibary(book));
                            sender.SendPacket(metaPacket);
                        }
                        else
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + "Tried to read a book that doesnt exist.");
                        }
                        break;
                    }
                    if(buttonIdStr.StartsWith("32c")) // Horse Whisperer
                    {
                        string idStr = buttonIdStr.Substring(3);
                        int breedId = -1;
                        try
                        {
                            breedId = int.Parse(idStr);
                        }
                        catch (FormatException) {
                            Logger.DebugPrint(sender.LoggedinUser.Username + " Tried to whisper a horse with BreedId NaN.");
                            break; 
                        };
                        
                        if(sender.LoggedinUser.Money < 50000)
                        {
                            byte[] cannotAffordMessage = PacketBuilder.CreateChat(Messages.WhispererServiceCannotAfford, PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(cannotAffordMessage);
                            break;
                        }

                        List<WildHorse> horsesFound = new List<WildHorse>();
                        foreach(WildHorse horse in WildHorse.WildHorses)
                        {
                            if(horse.Instance.Breed.Id == breedId)
                            {
                                horsesFound.Add(horse);
                            }
                        }
                        int cost = 0;
                        if(horsesFound.Count >= 1)
                        {
                            cost = 50000;
                        }
                        else
                        {
                            cost = 10000;
                        }

                        byte[] pricingMessage = PacketBuilder.CreateChat(Messages.FormatWhispererPrice(cost), PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(pricingMessage);

                        byte[] serachResultMeta = PacketBuilder.CreateMetaPacket(Meta.BuildWhisperSearchResults(horsesFound.ToArray()));
                        sender.SendPacket(serachResultMeta);
                        
                        sender.LoggedinUser.Money -= cost;
                        break;
                    }
                    else if(buttonIdStr.StartsWith("4c")) // Libary Breed Search
                    {
                        string idStr = buttonIdStr.Substring(2);
                        int breedId = -1;
                        HorseInfo.Breed horseBreed;
                        try
                        {
                            breedId = int.Parse(idStr);
                            horseBreed = HorseInfo.GetBreedById(breedId);
                        }
                        catch (Exception) {
                            Logger.DebugPrint(sender.LoggedinUser.Username + " Sent invalid libary breed viewer request.");
                            break; 
                        };
                        string metaTag = Meta.BuildBreedViewerLibary(horseBreed);
                        metaPacket = PacketBuilder.CreateMetaPacket(metaTag);
                        sender.SendPacket(metaPacket);

                        string swf = "breedviewer.swf?terrain=book&breed=" + horseBreed.Swf + "&j=";
                        byte[] loadSwf = PacketBuilder.CreateSwfModulePacket(swf, PacketBuilder.PACKET_SWF_MODULE_FORCE);
                        sender.SendPacket(loadSwf);

                        break;
                        
                    }
                    if(AbuseReport.DoesReasonExist(buttonIdStr))
                    {
                        sender.LoggedinUser.MetaPriority = true;
                        metaPacket = PacketBuilder.CreateMetaPacket(AbuseReport.GetReasonById(buttonIdStr).Meta);
                        sender.SendPacket(metaPacket);
                        break;
                    }

                    Logger.ErrorPrint("Dynamic button #" + buttonIdStr + " unknown... Packet Dump: "+BitConverter.ToString(packet).Replace("-", " "));
                    break;
            }
        }
        public static void OnUserInfoRequest(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Requested user information when not logged in.");
                return;
            }
            Database.AddOnlineUser(sender.LoggedinUser.Id, sender.LoggedinUser.Administrator, sender.LoggedinUser.Moderator, sender.LoggedinUser.Subscribed);
            
            Logger.DebugPrint(sender.LoggedinUser.Username + " Requested user information.");

            User user = sender.LoggedinUser;

            byte[] MovementPacket = PacketBuilder.CreateMovementPacket(user.X, user.Y, user.CharacterId, user.Facing, PacketBuilder.DIRECTION_TELEPORT, true);
            sender.SendPacket(MovementPacket);

            byte[] WelcomeMessage = PacketBuilder.CreateWelcomeMessage(user.Username);
            sender.SendPacket(WelcomeMessage);

            
            byte[] WorldData = PacketBuilder.CreateWorldData(World.ServerTime.Minutes, World.ServerTime.Days, World.ServerTime.Years, sender.LoggedinUser.GetWeatherSeen());
            sender.SendPacket(WorldData);

            // Send first time message;
            if (sender.LoggedinUser.NewPlayer)
            {
                byte[] NewUserMessage = PacketBuilder.CreateChat(Messages.NewUserMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                sender.SendPacket(NewUserMessage);
            }


            byte[] SecCodePacket = PacketBuilder.CreateSecCode(user.SecCodeSeeds, user.SecCodeInc, user.Administrator, user.Moderator);
            sender.SendPacket(SecCodePacket);

            byte[] BaseStatsPacketData = PacketBuilder.CreatePlayerData(user.Money, GameServer.GetNumberOfPlayers(), user.MailBox.MailCount);
            sender.SendPacket(BaseStatsPacketData);

            UpdateArea(sender);

            foreach (GameClient client in ConnectedClients)
            {
                if (client.LoggedIn)
                {
                    if (client.LoggedinUser.Id != user.Id)
                    {
                        byte[] PlayerInfo = PacketBuilder.CreatePlayerInfoUpdateOrCreate(client.LoggedinUser.X, client.LoggedinUser.Y, client.LoggedinUser.Facing, client.LoggedinUser.CharacterId, client.LoggedinUser.Username);
                        sender.SendPacket(PlayerInfo);
                    }
                }
            }

            foreach (User nearbyUser in GameServer.GetNearbyUsers(sender.LoggedinUser.X, sender.LoggedinUser.Y, false, false))
                if (nearbyUser.Id != sender.LoggedinUser.Id)
                    UpdateArea(nearbyUser.LoggedinClient);

            byte[] IsleData = PacketBuilder.CreatePlaceData(World.Isles.ToArray(), World.Towns.ToArray(), World.Areas.ToArray());
            sender.SendPacket(IsleData);

            byte[] TileFlags = PacketBuilder.CreateTileOverlayFlags(Map.OverlayTileDepth);
            sender.SendPacket(TileFlags);

            byte[] MotdData = PacketBuilder.CreateMotd();
            sender.SendPacket(MotdData);

        }

        public static void OnSwfModuleCommunication(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " tried to send swf communication when not logged in.");
                return;
            }
            if (packet.Length < 4)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid swf commmunication Packet");
                return;
            }


            byte module = packet[1];
            switch(module)
            {
                case PacketBuilder.SWFMODULE_BRICKPOET:
                    if(packet.Length < 5)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent invalid BRICKPOET packet (swf communication, WRONG SIZE)");
                        break;
                    }
                    if(packet[2] == PacketBuilder.BRICKPOET_LIST_ALL)
                    {
                        if (packet.Length < 6)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent invalid BRICKPOET LIST ALL packet (swf communication, WRONG SIZE)");
                            break;
                        }

                        int roomId = packet[3] - 40;
                        Brickpoet.PoetryPeice[] room;
                        try
                        {
                            room = Brickpoet.GetPoetryRoom(roomId);
                        }
                        catch(KeyNotFoundException)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " tried to load an invalid brickpoet room: " + roomId);
                            break;
                        }

                        byte[] poetPacket = PacketBuilder.CreateBrickPoetListPacket(room);
                        sender.SendPacket(poetPacket);
                    }
                    else if(packet[3] == PacketBuilder.BRICKPOET_MOVE)
                    {
                        if (packet.Length < 0xB)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent invalid BRICKPOET MOVE packet (swf communication, WRONG SIZE)");
                            break;
                        }
                        string packetStr = Encoding.UTF8.GetString(packet);
                        if(!packetStr.Contains('|'))
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent invalid BRICKPOET MOVE packet (swf communication, NO | SEPERATOR)");
                            break;
                        }
                        string[] args = packetStr.Split('|');
                        if(args.Length < 5)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent invalid BRICKPOET MOVE Packet (swf communication, NOT ENOUGH | SEPERATORS.");
                            break;
                        }

                        int roomId = packet[2] - 40;
                        int peiceId;
                        int x;
                        int y;
                        Brickpoet.PoetryPeice[] room;
                        Brickpoet.PoetryPeice peice;

                        try
                        {
                            peiceId = int.Parse(args[1]);
                            x = int.Parse(args[2]);
                            y = int.Parse(args[3]);


                            room = Brickpoet.GetPoetryRoom(roomId);
                            peice = Brickpoet.GetPoetryPeice(room, peiceId);
                            
                        }
                        catch (Exception)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " tried to move a peice in an invalid brickpoet room: " + roomId);
                            break;
                        }

                        peice.X = x;
                        peice.Y = y;

                        foreach(User user in GetUsersOnSpecialTileCode("MULTIROOM-" + "P" + roomId.ToString()))
                        {
                            if (user.Id == sender.LoggedinUser.Id)
                                continue;

                            byte[] updatePoetRoomPacket = PacketBuilder.CreateBrickPoetMovePacket(peice);
                            user.LoggedinClient.SendPacket(updatePoetRoomPacket);
                            
                        }

                        if (Database.GetLastPlayer("P" + roomId) != sender.LoggedinUser.Id)
                        {
                            Database.SetLastPlayer("P" + roomId, sender.LoggedinUser.Id);
                            UpdateAreaForAll(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                        }

                        break;
                    }
                    else
                    {
                        Logger.DebugPrint(" packet dump: " + BitConverter.ToString(packet).Replace("-", " "));
                        break;
                    }

                    break;
                default:
                    Logger.DebugPrint("Unknown moduleid : " + module + " packet dump: " + BitConverter.ToString(packet).Replace("-"," "));
                    break;

            }

        }

        public static void OnWish(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " tried to wish when not logged in.");
                return;
            }

            if(packet.Length < 4)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid wish Packet");
                return;
            }

            if (!sender.LoggedinUser.Inventory.HasItemId(Item.WishingCoin))
            {
                Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to use a wishing well while having 0 coins.");
                return;
            }

            InventoryItem wishingCoinInvItems = sender.LoggedinUser.Inventory.GetItemByItemId(Item.WishingCoin);
            byte wishType = packet[1];
            string message = "";

            byte[] chatMsg = PacketBuilder.CreateChat(Messages.TossedCoin, PacketBuilder.CHAT_BOTTOM_RIGHT);
            sender.SendPacket(chatMsg);

            switch(wishType)
            {
                case PacketBuilder.WISH_MONEY:
                    int gainMoney = RandomNumberGenerator.Next(500, 1000);
                    sender.LoggedinUser.Money += gainMoney;
                    message = Messages.FormatWishMoneyMessage(gainMoney);
                    break;
                case PacketBuilder.WISH_ITEMS:
                    Item.ItemInformation[] wishableItmes = Item.GetAllWishableItems();
                    int item = RandomNumberGenerator.Next(0, wishableItmes.Length);
                    Item.ItemInformation itm = wishableItmes[item];
                    item = RandomNumberGenerator.Next(0, wishableItmes.Length);
                    Item.ItemInformation itm2 = wishableItmes[item];

                    sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(itm.Id));
                    sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(itm2.Id));

                    message = Messages.FormatWishThingsMessage(itm.Name, itm2.Name);
                    break;
                case PacketBuilder.WISH_WORLDPEACE:
                    byte[] tooDeep = PacketBuilder.CreateChat(Messages.WorldPeaceOnlySoDeep, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(tooDeep);

                    wishableItmes = Item.GetAllWishableItems();
                    item = RandomNumberGenerator.Next(0, wishableItmes.Length);
                    int earnMoney = RandomNumberGenerator.Next(0, 500);
                    itm = wishableItmes[item];


                    sender.LoggedinUser.Money += earnMoney;
                    sender.LoggedinUser.Inventory.AddIgnoringFull(new ItemInstance(itm.Id));

                    message = Messages.FormatWishWorldPeaceMessage(earnMoney, itm.Name);
                    break;
                default:
                    Logger.ErrorPrint("Unknnown Wish type: " + wishType.ToString("X"));
                    break;
            }
            sender.LoggedinUser.TrackedItems.GetTrackedItem(Tracking.TrackableItem.WishingWell).Count++;
            byte[] msg = PacketBuilder.CreateChat(message, PacketBuilder.CHAT_BOTTOM_RIGHT);
            sender.SendPacket(msg);

            sender.LoggedinUser.Inventory.Remove(wishingCoinInvItems.ItemInstances[0]);
            UpdateArea(sender);
        }
        public static void OnKeepAlive(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Requested update when not logged in.");
                return;
            }
            if (packet.Length < 2)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid update Packet");
                return;
            }

            if (packet[1] == PacketBuilder.PACKET_CLIENT_TERMINATOR)
            {
                Logger.DebugPrint("Sending " + sender.LoggedinUser.Username + " updated info...");
                UpdatePlayer(sender);
            }
        }
        public static void OnStatsPacket(GameClient sender, byte[] packet)
        {
            if(!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Requested stats when not logged in.");
                return;
            }
            if(packet.Length < 3)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + "Sent an invalid Stats Packet");
                return;
            }


        }
        public static void OnProfilePacket(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Requested to change profile page when not logged in.");
                return;
            }
            if (packet.Length < 2)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid Profile Packet");
                return;
            }

            byte method = packet[1];
            if (method == PacketBuilder.PACKET_CLIENT_TERMINATOR)
            {
                UpdateStats(sender);
            }
            if (method == PacketBuilder.VIEW_PROFILE)
            {
                sender.LoggedinUser.MetaPriority = true;
                string profilePage = sender.LoggedinUser.ProfilePage;
                profilePage = profilePage.Replace("<", "[");
                profilePage = profilePage.Replace(">", "]");
                byte[] profilePacket = PacketBuilder.CreateProfilePacket(profilePage);
                sender.SendPacket(profilePacket);
            }
            else if (method == PacketBuilder.SAVE_PROFILE)
            {

                string packetStr = Encoding.UTF8.GetString(packet);
                if (packet.Length < 3 || !packetStr.Contains('|'))
                {
                    Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid Profile SAVE Packet");
                    return;
                }

                int characterId = (packet[2] - 20) * 64 + (packet[3] - 20);

                string profilePage = packetStr.Split('|')[1];
                profilePage = profilePage.Substring(0, profilePage.Length - 2);
                profilePage = profilePage.Replace("[", "<");
                profilePage = profilePage.Replace("]", ">");
                sender.LoggedinUser.CharacterId = characterId;
                sender.LoggedinUser.ProfilePage = profilePage;

                Logger.DebugPrint(sender.LoggedinUser.Username + " Changed to character id: " + characterId + " and set there Profile Description to '" + profilePage + "'");

                byte[] chatPacket = PacketBuilder.CreateChat(Messages.ProfileSavedMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                sender.SendPacket(chatPacket);

                UpdateArea(sender);
                UpdateUserInfo(sender.LoggedinUser);
            }
            else if (method == PacketBuilder.SECCODE_AWARD)
            {
                byte[] ExpectedSecCode = sender.LoggedinUser.GenerateSecCode();
                byte[] GotSecCode = new byte[4];
                Array.ConstrainedCopy(packet, 2, GotSecCode, 0, GotSecCode.Length);
                Logger.DebugPrint(sender.LoggedinUser.Username + " Sent sec code: " + BitConverter.ToString(GotSecCode).Replace("-", " "));
                if (ExpectedSecCode.SequenceEqual(GotSecCode))
                {
                    if (packet.Length < 6)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a seccode AWARD request with invalid size");
                        return;
                    }

                    string packetStr = Encoding.UTF8.GetString(packet);
                    string awardIdStr = packetStr.Substring(6, packetStr.Length - 6 - 2);

                    int value = -1;
                    try
                    {
                        value = int.Parse(awardIdStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent correct sec code, but invalid awardid value");
                        return;
                    }

                    sender.LoggedinUser.Awards.AddAward(Award.GetAwardById(value));
                    return;
                }
                else
                {
                    byte[] errorMessage = PacketBuilder.CreateChat(Messages.InvalidSecCodeError, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(errorMessage);
                    Logger.HackerPrint(sender.LoggedinUser.Username + " Sent invalid sec code");
                    return;
                }
            }
            else if (method == PacketBuilder.SECCODE_SCORE || method == PacketBuilder.SECCODE_TIME)
            {
                bool time = (method == PacketBuilder.SECCODE_TIME);

                byte[] ExpectedSecCode = sender.LoggedinUser.GenerateSecCode();
                byte[] GotSecCode = new byte[4];
                Array.ConstrainedCopy(packet, 2, GotSecCode, 0, GotSecCode.Length);
                Logger.DebugPrint(sender.LoggedinUser.Username + " Sent sec code: " + BitConverter.ToString(GotSecCode).Replace("-", " "));
                if (ExpectedSecCode.SequenceEqual(GotSecCode))
                {
                    if (packet.Length < 6)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a seccode score request with invalid size");
                        return;
                    }

                    string packetStr = Encoding.UTF8.GetString(packet);
                    string gameInfoStr = packetStr.Substring(6, packetStr.Length - 6 - 2);
                    if (gameInfoStr.Contains("|"))
                    {
                        string[] gameInfo = gameInfoStr.Split('|');
                        if (gameInfo.Length < 2)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a invalid seccode score request");
                            return;
                        }

                        string gameTitle = gameInfo[0];
                        string gameScoreStr = gameInfo[1];

                        int value = -1;
                        try
                        {
                            value = int.Parse(gameScoreStr);
                        }
                        catch (FormatException)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent correct sec code, but invalid score value");
                            return;
                        }

                        bool newHighscore = sender.LoggedinUser.Highscores.UpdateHighscore(gameTitle, value, time);
                        if (newHighscore && !time)
                        {
                            byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatHighscoreBeatenMessage(value), PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(chatPacket);
                        }
                        else
                        {
                            byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatTimeBeatenMessage(value), PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(chatPacket);
                        }
                    }
                    else
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " didnt send a game name AND a score.");
                        return;
                    }

                }
                else
                {
                    byte[] errorMessage = PacketBuilder.CreateChat(Messages.InvalidSecCodeError, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(errorMessage);
                    Logger.HackerPrint(sender.LoggedinUser.Username + " Sent invalid sec code");
                    return;
                }
            }
            else if (method == PacketBuilder.SECCODE_MONEY)
            {

                byte[] ExpectedSecCode = sender.LoggedinUser.GenerateSecCode();
                byte[] GotSecCode = new byte[4];
                Array.ConstrainedCopy(packet, 2, GotSecCode, 0, GotSecCode.Length);
                Logger.DebugPrint(sender.LoggedinUser.Username + " Sent sec code: " + BitConverter.ToString(GotSecCode).Replace("-", " "));
                if (ExpectedSecCode.SequenceEqual(GotSecCode))
                {
                    if (packet.Length < 6)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a seccode money request with invalid size");
                        return;
                    }

                    string packetStr = Encoding.UTF8.GetString(packet);
                    string gameInfoStr = packetStr.Substring(6, packetStr.Length - 6 - 2);
                    if (gameInfoStr.Contains("|"))
                    {
                        string[] moneyInfo = gameInfoStr.Split('|');
                        if (moneyInfo.Length < 2)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a invalid money score request");
                            return;
                        }

                        string id = moneyInfo[0]; // not sure what this is for?

                        string moneyStr = moneyInfo[1];
                        int value = -1;
                        try
                        {
                            value = int.Parse(moneyStr);
                        }
                        catch (FormatException)
                        {
                            Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent correct sec code, but invalid money value");
                            return;
                        }

                        int moneyEarned = value * 10;
                        Logger.InfoPrint(sender.LoggedinUser.Username + " Earned $" + moneyEarned + " In: " + id);

                        sender.LoggedinUser.Money += moneyEarned;
                        byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatMoneyEarnedMessage(moneyEarned), PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(chatPacket);

                    }
                    else
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " didnt send a game name AND a score.");
                        return;
                    }

                }
            }
            else if (method == PacketBuilder.SECCODE_GIVE_ITEM)
            {
                byte[] ExpectedSecCode = sender.LoggedinUser.GenerateSecCode();
                byte[] GotSecCode = new byte[4];
                Array.ConstrainedCopy(packet, 2, GotSecCode, 0, GotSecCode.Length);
                Logger.DebugPrint(sender.LoggedinUser.Username + " Sent sec code: " + BitConverter.ToString(GotSecCode).Replace("-", " "));
                if (ExpectedSecCode.SequenceEqual(GotSecCode))
                {
                    if (packet.Length < 6)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a seccode item request with invalid size");
                        return;
                    }
                    string packetStr = Encoding.UTF8.GetString(packet);
                    string intStr = packetStr.Substring(6, packetStr.Length - 6 - 2);
                    int value = -1;
                    try
                    {
                        value = int.Parse(intStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent correct sec code, but invalid value");
                        return;
                    }


                    if (Item.ItemIdExist(value))
                    {
                        ItemInstance itm = new ItemInstance(value);
                        sender.LoggedinUser.Inventory.Add(itm);
                        Item.ItemInformation itemInfo = Item.GetItemById(value);
                        byte[] earnedItemMessage = PacketBuilder.CreateChat(Messages.FormatYouEarnedAnItemMessage(itemInfo.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(earnedItemMessage);
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Sent correct sec code, but tried to give an non existant item");
                        return;
                    }

                }
                else
                {
                    byte[] errorMessage = PacketBuilder.CreateChat(Messages.InvalidSecCodeError, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(errorMessage);
                    Logger.HackerPrint(sender.LoggedinUser.Username + " Sent invalid sec code");
                    return;
                }
            }
            else if (method == PacketBuilder.SECCODE_DELETE_ITEM)
            {
                byte[] ExpectedSecCode = sender.LoggedinUser.GenerateSecCode();
                byte[] GotSecCode = new byte[4];
                Array.ConstrainedCopy(packet, 2, GotSecCode, 0, GotSecCode.Length);
                Logger.DebugPrint(sender.LoggedinUser.Username + " Sent sec code: " + BitConverter.ToString(GotSecCode).Replace("-", " "));
                if (ExpectedSecCode.SequenceEqual(GotSecCode))
                {
                    if (packet.Length < 6)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a seccode item request with invalid size");
                        return;
                    }
                    string packetStr = Encoding.UTF8.GetString(packet);
                    string intStr = packetStr.Substring(6, packetStr.Length - 6 - 2);
                    int value = -1;
                    try
                    {
                        value = int.Parse(intStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent correct sec code, but invalid value");
                        return;
                    }


                    if (sender.LoggedinUser.Inventory.HasItemId(value))
                    {
                        InventoryItem item = sender.LoggedinUser.Inventory.GetItemByItemId(value);
                        sender.LoggedinUser.Inventory.Remove(item.ItemInstances[0]);

                        Item.ItemInformation itemInfo = Item.GetItemById(value);
                        byte[] lostItemMessage = PacketBuilder.CreateChat(Messages.FormatYouLostAnItemMessage(itemInfo.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(lostItemMessage);

                        UpdateArea(sender);
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Sent correct sec code, but tried to delete an non existant item");
                        return;
                    }

                }
                else
                {
                    byte[] errorMessage = PacketBuilder.CreateChat(Messages.InvalidSecCodeError, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(errorMessage);
                    Logger.HackerPrint(sender.LoggedinUser.Username + " Sent invalid sec code");
                    return;
                }
            }
            else if (method == PacketBuilder.SECCODE_QUEST)
            {
                byte[] ExpectedSecCode = sender.LoggedinUser.GenerateSecCode();
                byte[] GotSecCode = new byte[4];
                Array.ConstrainedCopy(packet, 2, GotSecCode, 0, GotSecCode.Length);
                Logger.DebugPrint(sender.LoggedinUser.Username + " Sent sec code: " + BitConverter.ToString(GotSecCode).Replace("-", " "));
                if (ExpectedSecCode.SequenceEqual(GotSecCode))
                {
                    if (packet.Length < 6)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a seccode quest request with invalid size");
                        return;
                    }
                    string packetStr = Encoding.UTF8.GetString(packet);
                    string intStr = packetStr.Substring(6, packetStr.Length - 6 - 2);
                    int value = -1;
                    try
                    {
                        value = int.Parse(intStr);
                    }
                    catch (FormatException)
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Sent correct sec code, but invalid value");
                        return;
                    }


                    if (Quest.DoesQuestExist(value))
                    {
                        Quest.QuestEntry questEntry = Quest.GetQuestById(value);
                        Quest.ActivateQuest(sender.LoggedinUser, questEntry);
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Sent correct sec code, but tried to activate a non existant quest");
                        return;
                    }


                }
                else
                {
                    byte[] errorMessage = PacketBuilder.CreateChat(Messages.InvalidSecCodeError, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(errorMessage);
                    Logger.HackerPrint(sender.LoggedinUser.Username + " Sent invalid sec code");
                    return;
                }
            }
            else if (method == PacketBuilder.PROFILE_HIGHSCORES_LIST)
            {
                sender.LoggedinUser.MetaPriority = true;
                string packetStr = Encoding.UTF8.GetString(packet);
                string gameName = packetStr.Substring(2, packetStr.Length - 4);
                byte[] metaTag = PacketBuilder.CreateMetaPacket(Meta.BuildTopHighscores(gameName));
                sender.SendPacket(metaTag);
            }
            else if (method == PacketBuilder.PROFILE_BESTTIMES_LIST)
            {
                sender.LoggedinUser.MetaPriority = true;
                string packetStr = Encoding.UTF8.GetString(packet);
                string gameName = packetStr.Substring(2, packetStr.Length - 4);
                byte[] metaTag = PacketBuilder.CreateMetaPacket(Meta.BuildTopTimes(gameName));
                sender.SendPacket(metaTag);
            }

        }
        public static void OnMovementPacket(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent movement packet when not logged in.");
                return;
            }

            User loggedInUser = sender.LoggedinUser;
            byte movementDirection = packet[1];

            if (loggedInUser.Thirst <= 0 || loggedInUser.Hunger <= 0 || loggedInUser.Tiredness <= 0)
            {
                if (RandomNumberGenerator.Next(0, 10) == 7 || sender.LoggedinUser.Username.ToLower() == "dream")
                {
                    byte[] possibleDirections = new byte[] { PacketBuilder.MOVE_UP, PacketBuilder.MOVE_DOWN, PacketBuilder.MOVE_RIGHT, PacketBuilder.MOVE_LEFT };

                    if (possibleDirections.Contains(movementDirection))
                    {
                        byte newDirection = possibleDirections[RandomNumberGenerator.Next(0, possibleDirections.Length)];
                        if (newDirection != movementDirection)
                        {
                            movementDirection = newDirection;
                            if (loggedInUser.Thirst <= 0)
                            {
                                byte[] chatMessage = PacketBuilder.CreateChat(Messages.FormatRandomMovementMessage(Messages.StatThirst.ToUpper()), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(chatMessage);
                            }
                            else if (loggedInUser.Hunger <= 0)
                            {
                                byte[] chatMessage = PacketBuilder.CreateChat(Messages.FormatRandomMovementMessage(Messages.StatHunger.ToUpper()), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(chatMessage);
                            }
                            else if (loggedInUser.Tiredness <= 0)
                            {
                                byte[] chatMessage = PacketBuilder.CreateChat(Messages.FormatRandomMovementMessage(Messages.StatTired.ToUpper()), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(chatMessage);
                            }

                        }
                    }
                }
            }



            int onHorse = 0;
            int facing = sender.LoggedinUser.Facing;
            while (facing >= 5)
            {
                facing = facing - 5;
                onHorse++;
            }
            byte direction = 0;
            int newX = loggedInUser.X;
            int newY = loggedInUser.Y;
            bool moveTwo = false;

            if (movementDirection == PacketBuilder.MOVE_ESCAPE)
            {

                byte Direction;
                if (World.InSpecialTile(loggedInUser.X, loggedInUser.Y))
                {

                    World.SpecialTile tile = World.GetSpecialTile(loggedInUser.X, loggedInUser.Y);
                    if (tile.ExitX != 0)
                        newX = tile.ExitX;
                    if (tile.ExitY != 0)
                        newY = tile.ExitY;
                    else
                        if (Map.CheckPassable(loggedInUser.X, loggedInUser.Y + 1) || loggedInUser.NoClip)
                            newY += 1;



                    if (loggedInUser.X + 1 == newX && loggedInUser.Y == newY)
                        Direction = PacketBuilder.DIRECTION_RIGHT;
                    else if (loggedInUser.X - 1 == newX && loggedInUser.Y == newY)
                        Direction = PacketBuilder.DIRECTION_LEFT;
                    else if (loggedInUser.Y + 1 == newY && loggedInUser.X == newX)
                        Direction = PacketBuilder.DIRECTION_DOWN;
                    else if (loggedInUser.Y - 1 == newY && loggedInUser.X == newX)
                        Direction = PacketBuilder.DIRECTION_UP;
                    else
                        Direction = PacketBuilder.DIRECTION_TELEPORT;

                    loggedInUser.X = newX;
                    loggedInUser.Y = newY;


                }
                else
                {
                    if (Map.CheckPassable(loggedInUser.X, loggedInUser.Y + 1) || loggedInUser.NoClip)
                        loggedInUser.Y += 1;

                    Direction = PacketBuilder.DIRECTION_DOWN;
                }


                loggedInUser.Facing = Direction + (onHorse * 5);
                Logger.DebugPrint("Exiting player: " + loggedInUser.Username + " to: " + loggedInUser.X + "," + loggedInUser.Y);
                byte[] moveResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, Direction, true);
                sender.SendPacket(moveResponse);
                Update(sender);
                return;
            }

            if (movementDirection == PacketBuilder.MOVE_UP)
            {
                direction = PacketBuilder.DIRECTION_UP;
                if (Map.CheckPassable(newX, newY - 1) || loggedInUser.NoClip)
                    newY -= 1;
                

                if (loggedInUser.Facing == (direction + (onHorse * 5))&& onHorse != 0) // Double move
                    if (Map.CheckPassable(newX, newY - 1) || loggedInUser.NoClip)
                    {
                        newY -= 1;
                        moveTwo = true;
                    }
            }
            else if (movementDirection == PacketBuilder.MOVE_LEFT)
            {
                direction = PacketBuilder.DIRECTION_LEFT;
                if (Map.CheckPassable(newX - 1, newY) || loggedInUser.NoClip)
                    newX -= 1;


                if (loggedInUser.Facing == (direction + (onHorse * 5)) && onHorse != 0) // Double move
                    if (Map.CheckPassable(newX - 1, newY) || loggedInUser.NoClip)
                    {
                        newX -= 1;
                        moveTwo = true;
                    }
            }
            else if (movementDirection == PacketBuilder.MOVE_RIGHT)
            {
                direction = PacketBuilder.DIRECTION_RIGHT;
                if (Map.CheckPassable(newX + 1, newY) || loggedInUser.NoClip)
                    newX += 1;


                if (loggedInUser.Facing == (direction + (onHorse * 5)) && onHorse != 0) // Double move
                    if (Map.CheckPassable(newX + 1, newY) || loggedInUser.NoClip)
                    {
                        newX += 1;
                        moveTwo = true;
                    }
            }
            else if (movementDirection == PacketBuilder.MOVE_DOWN)
            {
                direction = PacketBuilder.DIRECTION_DOWN;
                if (Map.CheckPassable(newX, newY + 1) || loggedInUser.NoClip)
                    newY += 1;


                if (loggedInUser.Facing == (direction + (onHorse * 5)) && onHorse != 0) // Double move
                    if (Map.CheckPassable(newX, newY + 1) || loggedInUser.NoClip)
                    {
                        newY += 1;
                        moveTwo = true;
                    }
            }
            else if(movementDirection == PacketBuilder.MOVE_UPDATE)
            {
                UpdateArea(sender);
                return;
            }

            if(loggedInUser.Y != newY || loggedInUser.X != newX)
            {
                loggedInUser.Facing = direction + (onHorse * 5);
                if (moveTwo)
                    direction += 20;
                loggedInUser.Y = newY;
                loggedInUser.X = newX;
                byte[] moveResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, direction, true);
                sender.SendPacket(moveResponse);
            }
            else
            {
                byte[] moveResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, PacketBuilder.DIRECTION_NONE, false);
                sender.SendPacket(moveResponse);
            }


            Update(sender);
        }
        public static void OnQuitPacket(GameClient sender, byte[] packet)
        {
            if(!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent quit packet when not logged in.");
                return;    
            }
            Logger.InfoPrint(sender.LoggedinUser.Username + " Clicked \"Quit Game\".. Disconnecting");
            sender.Disconnect();
        }
        public static void OnNpcInteraction(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent npc interaction packet when not logged in.");
                return;
            }
            if (packet.Length < 3)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent an invalid npc interaction packet.");
                return;
            }
            byte action = packet[1];
            if (action == PacketBuilder.NPC_START_CHAT)
            {

                string packetStr = Encoding.UTF8.GetString(packet);
                string number = packetStr.Substring(2, packetStr.Length - 4);
                int chatId = 0;
                try
                {
                    chatId = int.Parse(number);
                }
                catch (FormatException)
                {
                    Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to start talking to an NPC with id that is NaN.");
                    return;
                }
                sender.LoggedinUser.MetaPriority = true;
                Npc.NpcEntry entry = Npc.GetNpcById(chatId);
                
                int defaultChatpointId = Npc.GetDefaultChatpoint(sender.LoggedinUser, entry);
                Npc.NpcChat startingChatpoint = Npc.GetNpcChatpoint(entry, defaultChatpointId);

                string metaInfo = Meta.BuildChatpoint(sender.LoggedinUser, entry, startingChatpoint);
                byte[] metaPacket = PacketBuilder.CreateMetaPacket(metaInfo);
                sender.SendPacket(metaPacket);

                sender.LoggedinUser.LastTalkedToNpc = entry;
            }
            else if (action == PacketBuilder.NPC_CONTINUE_CHAT)
            {
                string packetStr = Encoding.UTF8.GetString(packet);
                string number = packetStr.Substring(2, packetStr.Length - 4);
                int replyId = 0;
                try
                {
                    replyId = int.Parse(number);
                }
                catch (FormatException)
                {
                    Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to reply to an NPC with replyid that is NaN.");
                    return;
                }

                Npc.NpcEntry lastNpc = sender.LoggedinUser.LastTalkedToNpc;
                Npc.NpcReply reply;
                try
                {
                    reply = Npc.GetNpcReply(lastNpc, replyId);
                }
                catch(KeyNotFoundException)
                {
                    Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to reply with replyid that does not exist.");
                    return;
                }

                if (reply.GotoChatpoint == -1)
                {
                    UpdateArea(sender);
                    return;
                }
                sender.LoggedinUser.MetaPriority = true;
                string metaInfo = Meta.BuildChatpoint(sender.LoggedinUser, lastNpc, Npc.GetNpcChatpoint(lastNpc, reply.GotoChatpoint));
                byte[] metaPacket = PacketBuilder.CreateMetaPacket(metaInfo);
                sender.SendPacket(metaPacket);
                return;
            }
        }
        public static void OnTransportUsed(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent transport packet when not logged in.");
                return;
            }
            if (packet.Length < 3)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent an invalid transport packet.");
                return;
            }


            string packetStr = Encoding.UTF8.GetString(packet);
            string number = packetStr.Substring(1, packetStr.Length - 3);

            int transportid;
            try
            {
                transportid =  Int32.Parse(number);
            }
            catch(FormatException)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Tried to use a transport with id that is NaN.");
                return;
            }
            try
            {
                Transport.TransportPoint transportPoint = Transport.GetTransportPoint(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                if (transportPoint.X != sender.LoggedinUser.X && transportPoint.Y != sender.LoggedinUser.Y)
                {
                    Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to use transport id: " + transportid.ToString() + " while not the correct transport point!");
                    return;
                }

                Transport.TransportLocation transportLocation = Transport.GetTransportLocation(transportid);


                if (sender.LoggedinUser.Money >= transportLocation.Cost)
                {
                    

                    string swfToLoad = Messages.BoatCutscene;
                    if (transportLocation.Type == "WAGON")
                        swfToLoad = Messages.WagonCutscene;

                    if (transportLocation.Type != "ROWBOAT")
                    {
                        byte[] swfModulePacket = PacketBuilder.CreateSwfModulePacket(swfToLoad, PacketBuilder.PACKET_SWF_CUTSCENE);
                        sender.SendPacket(swfModulePacket);
                    }

                    sender.LoggedinUser.Teleport(transportLocation.GotoX, transportLocation.GotoY);
                    sender.LoggedinUser.TrackedItems.GetTrackedItem(Tracking.TrackableItem.Transport).Count++;

                    byte[] welcomeToIslePacket = PacketBuilder.CreateChat(Messages.FormatWelcomeToAreaMessage(transportLocation.LocationTitle), PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(welcomeToIslePacket);

                    sender.LoggedinUser.Money -= transportLocation.Cost;
                }
                else
                {
                    byte[] cantAfford = PacketBuilder.CreateChat(Messages.CantAffordTransport, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(cantAfford);
                }
            }
            catch (KeyNotFoundException)
            {
                Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to use transport id: " + transportid.ToString() + " while not on a transport point!");
            }

         
        }
        public static void OnChatPacket(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent chat packet when not logged in.");
                return;
            }

            if (packet.Length < 4)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent an invalid chat packet.");
                return;
            }


            string packetStr = Encoding.UTF8.GetString(packet);

            Chat.ChatChannel channel = (Chat.ChatChannel)packet[1];
            string message = packetStr.Substring(2, packetStr.Length - 4);

            if (Chat.ProcessCommand(sender.LoggedinUser, message))
            {
                Logger.DebugPrint(sender.LoggedinUser.Username + " Attempting to run command '" + message + "' in channel: " + channel.ToString());
                return;
            }
           

            Logger.DebugPrint(sender.LoggedinUser.Username + " Attempting to say '" + message + "' in channel: " + channel.ToString());

            string nameTo = null;
            if (channel == Chat.ChatChannel.Dm)
            {
                nameTo = Chat.GetDmRecipiant(message);
                message = Chat.GetDmMessage(message);
            }

            if (message == "")
                return;

            Object violationReason = Chat.FilterMessage(message);
            if (violationReason != null)
            {
                sender.LoggedinUser.ChatViolations += 1;
                string chatViolationMessage = Messages.FormatGlobalChatViolationMessage((Chat.Reason)violationReason);
                byte[] chatViolationPacket = PacketBuilder.CreateChat(chatViolationMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                sender.SendPacket(chatViolationPacket);
                return;
            }

            byte chatSide = Chat.GetSide(channel);
            message = Chat.DoCorrections(message);
            message = Chat.EscapeMessage(message);


            string failedReason = Chat.NonViolationChecks(sender.LoggedinUser, message);
            if (failedReason != null)
            {
                byte[] failedMessage = PacketBuilder.CreateChat(failedReason, PacketBuilder.CHAT_BOTTOM_RIGHT);
                sender.SendPacket(failedMessage);
                return;
            }

            GameClient[] recipiants = Chat.GetRecipiants(sender.LoggedinUser, channel, nameTo);

            // Finally send chat message.
            string formattedMessage = Chat.FormatChatForOthers(sender.LoggedinUser, channel, message);
            string formattedMessageSender = Chat.FormatChatForSender(sender.LoggedinUser, channel, message, nameTo);
            byte[] chatPacketOthers = PacketBuilder.CreateChat(formattedMessage, chatSide);
            byte[] chatPacketSender = PacketBuilder.CreateChat(formattedMessageSender, chatSide);
            byte[] playDmSound = PacketBuilder.CreatePlaysoundPacket(Chat.PrivateMessageSound);
            // Send to clients ...
            foreach (GameClient recipiant in recipiants)
            {
                recipiant.SendPacket(chatPacketOthers);
                if (channel == Chat.ChatChannel.Dm)
                    recipiant.SendPacket(playDmSound);
            }

            // Send to sender
            sender.SendPacket(chatPacketSender);
        }
        public static void OnClickPacket(GameClient sender, byte[] packet)
        {

            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Send click packet when not logged in.");
                return;
            }
            if (packet.Length < 6)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid Click Packet");
                return;
            }
            
            string packetStr = Encoding.UTF8.GetString(packet);
            if(packetStr.Contains("|"))
            {
                string packetContents = packetStr.Substring(1, packetStr.Length - 3);
                string[] xy = packetContents.Split('|');
                int x = 0;
                int y = 0;

                try
                {
                    x = int.Parse(xy[0])+4;
                    y = int.Parse(xy[1])+1;
                }
                catch(FormatException)
                {
                    Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent a click packet with non-string xy value.");
                    return;
                }

                // Get description of tile 
                string returnedMsg = Messages.NothingInterestingHere;
                if(World.InSpecialTile(x, y))
                {
                    World.SpecialTile tile = World.GetSpecialTile(x, y);
                    if (tile.Title != null)
                        returnedMsg = tile.Title;
                }

                byte[] tileInfoPacket = PacketBuilder.CreateClickTileInfoPacket(returnedMsg);
                sender.SendPacket(tileInfoPacket);
            }
        }
        public static void OnItemInteraction(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent object interaction packet when not logged in.");
                return;
            }
            if (packet.Length < 3)
            {
                Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object interaction packet.");
                return;
            }

            byte action = packet[1];
            switch(action)
            {
                case PacketBuilder.ITEM_PICKUP_ALL:
                    string chatMsg = Messages.GrabAllItemsMessage;
                    DroppedItems.DroppedItem[] droppedItems = DroppedItems.GetItemsAt(sender.LoggedinUser.X, sender.LoggedinUser.Y);

                    try
                    {
                        foreach (DroppedItems.DroppedItem item in droppedItems)
                        {
                            sender.LoggedinUser.Inventory.Add(item.instance);
                            DroppedItems.RemoveDroppedItem(item);
                        }
                    }
                    catch (InventoryException)
                    {
                        chatMsg = Messages.GrabbedAllItemsButInventoryFull;
                        break;
                    }

                    UpdateAreaForAll(sender.LoggedinUser.X, sender.LoggedinUser.Y);

                    byte[] chatMessage = PacketBuilder.CreateChat(chatMsg, PacketBuilder.CHAT_BOTTOM_RIGHT);
                    sender.SendPacket(chatMessage);

                    break;
                case PacketBuilder.ITEM_PICKUP:
                    string packetStr = Encoding.UTF8.GetString(packet);
                    string randomIdStr = packetStr.Substring(2, packet.Length - 4);
                    int randomId = 0;

                    try
                    {
                        randomId = Int32.Parse(randomIdStr);
                    }
                    catch(FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object interaction packet.");
                        return;
                    }

                    try
                    {
                        DroppedItems.DroppedItem item = DroppedItems.GetDroppedItemById(randomId);
                        try
                        {
                            sender.LoggedinUser.Inventory.Add(item.instance);
                        }
                        catch (InventoryException)
                        {
                            byte[] inventoryFullMessage = PacketBuilder.CreateChat(Messages.GrabbedItemButInventoryFull, PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(inventoryFullMessage);
                            break;
                        }

                        
                        DroppedItems.RemoveDroppedItem(item);

                        UpdateAreaForAll(sender.LoggedinUser.X, sender.LoggedinUser.Y);

                        chatMessage = PacketBuilder.CreateChat(Messages.GrabbedItemMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(chatMessage);
                    }
                    catch(KeyNotFoundException)
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to grab a non existing object.");
                        return;
                    }

                    break;
                case PacketBuilder.ITEM_REMOVE:
                    char toRemove = (char)packet[2];
                    switch(toRemove)
                    {
                        case '1':
                            if(sender.LoggedinUser.EquipedCompetitionGear.Head != null)
                            {
                                ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedCompetitionGear.Head.Id);
                                sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                sender.LoggedinUser.EquipedCompetitionGear.Head = null;
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Attempted to remove competition gear when none was equipped.");
                            }
                            break;
                        case '2':
                            if (sender.LoggedinUser.EquipedCompetitionGear.Body != null)
                            {
                                ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedCompetitionGear.Body.Id);
                                sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                sender.LoggedinUser.EquipedCompetitionGear.Body = null;
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Attempted to remove competition gear when none was equipped.");
                            }
                            break;
                        case '3':
                            if (sender.LoggedinUser.EquipedCompetitionGear.Legs != null)
                            {
                                ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedCompetitionGear.Legs.Id);
                                sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                sender.LoggedinUser.EquipedCompetitionGear.Legs = null;
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Attempted to remove competition gear when none was equipped.");
                            }
                            break;
                        case '4':
                            if (sender.LoggedinUser.EquipedCompetitionGear.Feet != null)
                            {
                                ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedCompetitionGear.Feet.Id);
                                sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                sender.LoggedinUser.EquipedCompetitionGear.Feet = null;
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Attempted to remove competition gear when none was equipped.");
                            }
                            break;
                        case '5':
                            if (sender.LoggedinUser.EquipedJewelry.Slot1 != null)
                            {
                                ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedJewelry.Slot1.Id);
                                sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                sender.LoggedinUser.EquipedJewelry.Slot1 = null;
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Attempted to remove jewery when none was equipped.");
                            }
                            break;
                        case '6':
                            if (sender.LoggedinUser.EquipedJewelry.Slot2 != null)
                            {
                                ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedJewelry.Slot2.Id);
                                sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                sender.LoggedinUser.EquipedJewelry.Slot2 = null;
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Attempted to remove jewery when none was equipped.");
                            }
                            break;
                        case '7':
                            if (sender.LoggedinUser.EquipedJewelry.Slot3 != null)
                            {
                                ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedJewelry.Slot3.Id);
                                sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                sender.LoggedinUser.EquipedJewelry.Slot3 = null;
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Attempted to remove jewery when none was equipped.");
                            }
                            break;
                        case '8':
                            if (sender.LoggedinUser.EquipedJewelry.Slot4 != null)
                            {
                                ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedJewelry.Slot4.Id);
                                sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                sender.LoggedinUser.EquipedJewelry.Slot4 = null;
                            }
                            else
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Attempted to remove jewery when none was equipped.");
                            }
                            break;
                        default:
                            Logger.InfoPrint(sender.LoggedinUser.Username + "Unimplemented  \"remove worn item\" ItemInteraction packet: " + BitConverter.ToString(packet).Replace("-", " "));
                            break;
                    }

                    UpdateStats(sender);
                    if(toRemove >= '1' && toRemove <= '4')
                    {
                        byte[] itemRemovedMessage = PacketBuilder.CreateChat(Messages.RemoveCompetitionGear, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(itemRemovedMessage);
                    }
                    else if (toRemove >= '5' && toRemove <= '8')
                    {
                        byte[] itemRemovedMessage = PacketBuilder.CreateChat(Messages.RemoveJewelry, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(itemRemovedMessage);
                    }
                    
                    break;
                case PacketBuilder.ITEM_WEAR:
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packet.Length - 2);
                    randomId = 0;

                    try
                    {
                        randomId = Int32.Parse(randomIdStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object interaction packet.");
                        return;
                    }
                    if (sender.LoggedinUser.Inventory.HasItem(randomId))
                    {
                        InventoryItem itm = sender.LoggedinUser.Inventory.GetItemByRandomid(randomId);
                        ItemInstance instance = itm.ItemInstances[0];
                     
                        Item.ItemInformation itemInf = instance.GetItemInfo();
                        if(itemInf.Type == "CLOTHES")
                        {
                            switch (itemInf.GetMiscFlag(0))
                            {
                                case CompetitionGear.MISC_FLAG_HEAD:
                                    if (sender.LoggedinUser.EquipedCompetitionGear.Head == null)
                                        sender.LoggedinUser.EquipedCompetitionGear.Head = itemInf;
                                    else
                                    {
                                        ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedCompetitionGear.Head.Id);
                                        sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                        sender.LoggedinUser.EquipedCompetitionGear.Head = itemInf;
                                    }
                                    break;
                                case CompetitionGear.MISC_FLAG_BODY:
                                    if (sender.LoggedinUser.EquipedCompetitionGear.Body == null)
                                        sender.LoggedinUser.EquipedCompetitionGear.Body = itemInf;
                                    else
                                    {
                                        ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedCompetitionGear.Body.Id);
                                        sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                        sender.LoggedinUser.EquipedCompetitionGear.Body = itemInf;
                                    }
                                    break;
                                case CompetitionGear.MISC_FLAG_LEGS:
                                    if (sender.LoggedinUser.EquipedCompetitionGear.Legs == null)
                                        sender.LoggedinUser.EquipedCompetitionGear.Legs = itemInf;
                                    else
                                    {
                                        ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedCompetitionGear.Legs.Id);
                                        sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                        sender.LoggedinUser.EquipedCompetitionGear.Legs = itemInf;
                                    }
                                    break;
                                case CompetitionGear.MISC_FLAG_FEET:
                                    if (sender.LoggedinUser.EquipedCompetitionGear.Feet == null)
                                        sender.LoggedinUser.EquipedCompetitionGear.Feet = itemInf;
                                    else
                                    {
                                        ItemInstance itemInstance = new ItemInstance(sender.LoggedinUser.EquipedCompetitionGear.Feet.Id);
                                        sender.LoggedinUser.Inventory.AddIgnoringFull(itemInstance);
                                        sender.LoggedinUser.EquipedCompetitionGear.Feet = itemInf;
                                    }
                                    break;
                                default: 
                                    Logger.ErrorPrint(itemInf.Name + " Has unknown misc flags.");
                                    return;
                            }
                            sender.LoggedinUser.Inventory.Remove(instance);
                            byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatEquipCompetitionGearMessage(itemInf.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(chatPacket);
                        }
                        else if(itemInf.Type == "JEWELRY")
                        {
                            bool addedJewelry = false;
                            if (sender.LoggedinUser.EquipedJewelry.Slot1 == null)
                            {
                                sender.LoggedinUser.EquipedJewelry.Slot1 = itemInf;
                                addedJewelry = true;
                            }
                            else if (sender.LoggedinUser.EquipedJewelry.Slot2 == null)
                            {
                                sender.LoggedinUser.EquipedJewelry.Slot2 = itemInf;
                                addedJewelry = true;
                            }
                            else if (sender.LoggedinUser.EquipedJewelry.Slot3 == null)
                            {
                                sender.LoggedinUser.EquipedJewelry.Slot3 = itemInf;
                                addedJewelry = true;
                            }
                            else if (sender.LoggedinUser.EquipedJewelry.Slot4 == null)
                            {
                                sender.LoggedinUser.EquipedJewelry.Slot4 = itemInf;
                                addedJewelry = true;
                            }

                            if(addedJewelry)
                            {
                                sender.LoggedinUser.Inventory.Remove(instance);
                                byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatJewerlyEquipMessage(itemInf.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(chatPacket);
                            }
                            else
                            {
                                byte[] chatPacket = PacketBuilder.CreateChat(Messages.MaxJewelryMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(chatPacket);
                            }
                        }

                        UpdateInventory(sender);
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to wear an item they did not have.");
                    }
                    break;
                case PacketBuilder.ITEM_DRINK:
                    packetStr = Encoding.UTF8.GetString(packet);
                    string idStr = packetStr.Substring(2, packet.Length - 4);
                    if(idStr == "NaN") // Fountain
                    {
                        string msg = Messages.FountainDrankYourFull;
                        bool looseMoney = RandomNumberGenerator.Next(0, 20) == 18;
                        if(looseMoney)
                        {
                            int looseAmount = RandomNumberGenerator.Next(0, 100);
                            if (looseAmount > sender.LoggedinUser.Money)
                                looseAmount = sender.LoggedinUser.Money;
                            sender.LoggedinUser.Money -= looseAmount;
                            msg = Messages.FormatDroppedMoneyMessage(looseAmount);
                        }

                        sender.LoggedinUser.Thirst = 1000;
                        byte[] drankFromFountainMessage = PacketBuilder.CreateChat(msg, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(drankFromFountainMessage);
                    }
                    else
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + "Sent unknown ITEM_DRINK command id: " + idStr);
                    }
                    break;
                case PacketBuilder.ITEM_CONSUME:
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packet.Length - 3);
                    randomId = 0;

                    try
                    {
                        randomId = Int32.Parse(randomIdStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object interaction packet.");
                        return;
                    }

                    if (sender.LoggedinUser.Inventory.HasItem(randomId))
                    {
                        InventoryItem itm = sender.LoggedinUser.Inventory.GetItemByRandomid(randomId);
                        ItemInstance instance = itm.ItemInstances[0];
                        sender.LoggedinUser.Inventory.Remove(instance);
                        Item.ItemInformation itmInfo = instance.GetItemInfo();
                        bool toMuch = Item.ConsumeItem(sender.LoggedinUser, itmInfo);

                        byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatConsumeItemMessaege(itmInfo.Name), PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(chatPacket);
                        if (toMuch)
                        {
                            chatPacket = PacketBuilder.CreateChat(Messages.ConsumedButMaxReached, PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(chatPacket);
                        }

                        UpdateInventory(sender);
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to consume an item they did not have.");
                    }
                    break;
                case PacketBuilder.ITEM_DROP:
                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packet.Length - 2);
                    randomId = 0;

                    try
                    {
                        randomId = Int32.Parse(randomIdStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object interaction packet.");
                        return;
                    }

                    if(sender.LoggedinUser.Inventory.HasItem(randomId))
                    {
                        InventoryItem itm = sender.LoggedinUser.Inventory.GetItemByRandomid(randomId);
                        ItemInstance instance = itm.ItemInstances[0];
                        DroppedItems.AddItem(instance, sender.LoggedinUser.X, sender.LoggedinUser.Y);
                        sender.LoggedinUser.Inventory.Remove(instance);
                        byte[] chatPacket = PacketBuilder.CreateChat(Messages.DroppedAnItemMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(chatPacket);
                        UpdateInventory(sender);
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to drop an item they did not have.");
                    }
                    break;
                case PacketBuilder.ITEM_SHOVEL:
                    if (packet[2] != 0x14)
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Used ITEM_SHOVEL with 3rd byte not 0x14.");
                    if (!Quest.UseTool(sender.LoggedinUser, Quest.Shovel, sender.LoggedinUser.X, sender.LoggedinUser.Y))
                    {
                        byte[] ChatPacket = PacketBuilder.CreateChat(Messages.ShovelNothing, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(ChatPacket);
                    }
                    break;
                case PacketBuilder.ITEM_RAKE:
                    if (packet[2] != 0x14)
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Used ITEM_RAKE with 3rd byte not 0x14.");
                    if (!Quest.UseTool(sender.LoggedinUser, Quest.Rake, sender.LoggedinUser.X, sender.LoggedinUser.Y))
                    {
                        byte[] ChatPacket = PacketBuilder.CreateChat(Messages.RakeNothing, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(ChatPacket);
                    }
                    break;
                case PacketBuilder.ITEM_MAGNIFYING:
                    if (packet[2] != 0x14)
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Used ITEM_MAGNIFYING with 3rd byte not 0x14.");
                    if (!Quest.UseTool(sender.LoggedinUser, Quest.MagnifyingGlass, sender.LoggedinUser.X, sender.LoggedinUser.Y))
                    {
                        byte[] ChatPacket = PacketBuilder.CreateChat(Messages.MagnifyNothing, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(ChatPacket);
                    }
                    break;
                case PacketBuilder.ITEM_BINOCULARS:
                    if (packet[2] != 0x14)
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Used ITEM_BINOCULARS with 3rd byte not 0x14.");
                    if(!Quest.UseTool(sender.LoggedinUser, Quest.Binoculars, sender.LoggedinUser.X, sender.LoggedinUser.Y))
                    {
                        byte[] ChatPacket = PacketBuilder.CreateChat(Messages.BinocularsNothing, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(ChatPacket);
                    }
                    break;
                case PacketBuilder.ITEM_SELL: // Handles selling an item.
                    int totalSold = 1;
                    int message = 1;

                    packetStr = Encoding.UTF8.GetString(packet);
                    randomIdStr = packetStr.Substring(2, packet.Length - 2);
                    randomId = 0;
                    // Prevent crashing on non-int string.
                    try
                    {
                        randomId = Int32.Parse(randomIdStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object sell packet.");
                        return;
                    }

                    if (!sender.LoggedinUser.Inventory.HasItem(randomId))
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to sell a item that they doesnt have in there inventory");
                        return;
                    }

                    InventoryItem invItem = sender.LoggedinUser.Inventory.GetItemByRandomid(randomId);
                    int itemId = invItem.ItemId;
                    goto doSell;
                case PacketBuilder.ITEM_SELL_ALL:
                    packetStr = Encoding.UTF8.GetString(packet);
                    string itemIdStr = packetStr.Substring(2, packet.Length - 2);
                    itemId = 0;
                    // Prevent crashing on non-int string.
                    try
                    {
                        itemId = Int32.Parse(itemIdStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object sell packet.");
                        return;
                    }

                    if (!sender.LoggedinUser.Inventory.HasItemId(itemId))
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to sell a item that they doesnt have in there inventory");
                        return;
                    }
                    invItem = sender.LoggedinUser.Inventory.GetItemByItemId(itemId);

                    totalSold = invItem.ItemInstances.Count;
                    message = 2;
                    goto doSell;
                doSell:;

                    Item.ItemInformation itemInfo = Item.GetItemById(itemId);
                    Shop shop = sender.LoggedinUser.LastShoppedAt;
                    if (shop != null)
                    {
                        int sellPrice = shop.CalculateSellCost(itemInfo) * totalSold;
                        if (shop.CanSell(itemInfo))
                        {
                            for(int i = 0; i < totalSold; i++)
                            {
                                ItemInstance itemInstance = invItem.ItemInstances[0];
                                sender.LoggedinUser.Inventory.Remove(itemInstance);
                                shop.Inventory.Add(itemInstance);
                            }

                            sender.LoggedinUser.Money += sellPrice;

                            UpdateAreaForAll(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                            if(message == 1)
                            {
                                byte[] soldItemMessage = PacketBuilder.CreateChat(Messages.FormatSellMessage(itemInfo.Name, sellPrice), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(soldItemMessage);
                            }
                            if(message == 2)
                            {
                                string name = itemInfo.Name;
                                if (totalSold > 1)
                                    name = itemInfo.PluralName;

                                byte[] soldItemMessage = PacketBuilder.CreateChat(Messages.FormatSellAllMessage(name, sellPrice,totalSold), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(soldItemMessage);
                            }

                        }
                        else
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to sell a item that was not avalible to be sold.");
                        }
                    }
                    break;

                case PacketBuilder.ITEM_BUY_AND_CONSUME:
                    packetStr = Encoding.UTF8.GetString(packet);
                    itemIdStr = packetStr.Substring(2, packet.Length - 3);
                    itemId = 0;
                    // Prevent crashing on non-int string.
                    try
                    {
                        itemId = Int32.Parse(itemIdStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object buy and consume packet.");
                        return;
                    }
                    if (!Item.ItemIdExist(itemId))
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to buy an itemid that doesnt even exist.");
                        break;
                    }

                    Inn lastInn = sender.LoggedinUser.LastVisitedInn;
                    if (lastInn != null)
                    {
                        try
                        {
                            itemInfo = lastInn.GetStockedItem(itemId);
                            int price = lastInn.CalculateBuyCost(itemInfo);
                            if(sender.LoggedinUser.Money >= price)
                            {
                                sender.LoggedinUser.Money -= price;
                                bool toMuch = Item.ConsumeItem(sender.LoggedinUser, itemInfo);

                                string tooMuchMessage = Messages.ConsumedButMaxReached;
                                if (itemInfo.Effects.Length > 0)
                                    if (itemInfo.Effects[0].EffectsWhat == "TIREDNESS")
                                        tooMuchMessage = Messages.InnFullyRested;
                                if (itemInfo.Effects.Length > 1)
                                    if (itemInfo.Effects[1].EffectsWhat == "TIREDNESS")
                                        tooMuchMessage = Messages.InnFullyRested;

                                byte[] enjoyedServiceMessage = PacketBuilder.CreateChat(Messages.FormatInnEnjoyedServiceMessage(itemInfo.Name, price), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(enjoyedServiceMessage);

                                if(toMuch)
                                {
                                    byte[] toMuchMessage = PacketBuilder.CreateChat(tooMuchMessage, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                    sender.SendPacket(toMuchMessage);
                                }

                                UpdateArea(sender);
                            }
                            else
                            {
                                byte[] cantAffordMessage = PacketBuilder.CreateChat(Messages.InnCannotAffordService, PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(cantAffordMessage);
                            }
                        }
                        catch(KeyNotFoundException)
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to buy and consume an item not stocked by the inn there standing on.");
                        }
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to buy and consume item while not in a inn.");
                    }
                    break;

                case PacketBuilder.ITEM_BUY: // Handles buying an item.
                    message = 1;
                    int count = 1;
                    goto doPurchase;
                case PacketBuilder.ITEM_BUY_5:
                    message = 2;
                    count = 5;
                    goto doPurchase;
                case PacketBuilder.ITEM_BUY_25:
                    message = 3;
                    count = 25;
                doPurchase:;
                    packetStr = Encoding.UTF8.GetString(packet);
                    itemIdStr = packetStr.Substring(2, packet.Length - 3);
                    itemId = 0;
                    // Prevent crashing on non-int string.
                    try
                    {
                        itemId = Int32.Parse(itemIdStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object buy packet.");
                        return;
                    }

                    if(!Item.ItemIdExist(itemId))
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to buy an itemid that doesnt even exist.");
                        break;
                    }

                    itemInfo = Item.GetItemById(itemId);
                    shop = sender.LoggedinUser.LastShoppedAt;
                    if (shop != null)
                    {
                        int buyCost = shop.CalculateBuyCost(itemInfo) * count;
                        if (sender.LoggedinUser.Money < buyCost)
                        {
                            byte[] cantAffordMessage = PacketBuilder.CreateChat(Messages.CantAfford1, PacketBuilder.CHAT_BOTTOM_RIGHT);
                            sender.SendPacket(cantAffordMessage);
                            return;
                        }
                        if (shop.Inventory.HasItemId(itemId))
                        {
                            if (shop.Inventory.GetItemByItemId(itemId).ItemInstances.Count < count)
                            {
                                Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to buy more of an item than is in stock.");
                                break;
                            }


                            // Check we wont overflow the inventory
                            if (sender.LoggedinUser.Inventory.HasItemId(itemId)) 
                            {
                                InventoryItem items = sender.LoggedinUser.Inventory.GetItemByItemId(itemId);
                                if (items.ItemInstances.Count + count > ConfigReader.MAX_STACK)
                                {
                                    goto showError;
                                }

                            }
                            else if(sender.LoggedinUser.Inventory.Count + 1 > Messages.DefaultInventoryMax)
                            {
                                goto showError;
                            }

                            for (int i = 0; i < count; i++)
                            {
                                ItemInstance itemInstance = shop.Inventory.GetItemByItemId(itemId).ItemInstances[0];
                                try
                                {
                                    sender.LoggedinUser.Inventory.Add(itemInstance);
                                }
                                catch (InventoryException)
                                {
                                    Logger.ErrorPrint("Failed to add: " + itemInfo.Name + " to " + sender.LoggedinUser.Username + " inventory.");
                                    break;
                                }
                                shop.Inventory.Remove(itemInstance);
                            }

                            sender.LoggedinUser.Money -= buyCost;


                            // Send chat message to client.
                            UpdateAreaForAll(sender.LoggedinUser.X, sender.LoggedinUser.Y);
                            if (message == 1)
                            {
                                byte[] broughtItemMessage = PacketBuilder.CreateChat(Messages.FormatBuyMessage(itemInfo.Name, buyCost), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(broughtItemMessage);
                            }
                            else if (message == 2)
                            {
                                byte[] broughtItemMessage = PacketBuilder.CreateChat(Messages.FormatBuy5Message(itemInfo.PluralName, buyCost), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(broughtItemMessage);
                            }
                            else if (message == 3)
                            {
                                byte[] broughtItemMessage = PacketBuilder.CreateChat(Messages.FormatBuy25Message(itemInfo.PluralName, buyCost), PacketBuilder.CHAT_BOTTOM_RIGHT);
                                sender.SendPacket(broughtItemMessage);
                            }
                        }
                        else
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to buy a item that was not for sale.");
                        }
                    }
                    else
                    {
                        Logger.HackerPrint(sender.LoggedinUser.Username + " Tried to buy an item while not in a store.");
                    }


                    break;

                showError:;
                    if (message == 1)
                    {
                        byte[] inventoryFullMessage = PacketBuilder.CreateChat(Messages.Brought1ButInventoryFull, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(inventoryFullMessage);
                    }
                    else if (message == 2)
                    {

                        byte[] inventoryFullMessage = PacketBuilder.CreateChat(Messages.Brought5ButInventoryFull, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(inventoryFullMessage);
                    }
                    else if (message == 3)
                    {

                        byte[] inventoryFullMessage = PacketBuilder.CreateChat(Messages.Brought25ButInventoryFull, PacketBuilder.CHAT_BOTTOM_RIGHT);
                        sender.SendPacket(inventoryFullMessage);
                    }
                    break;

                case PacketBuilder.PACKET_INFORMATION:
                    packetStr = Encoding.UTF8.GetString(packet);
                    string valueStr = packetStr.Substring(3, packet.Length - 3);
                    int value = 0;
                    try
                    {
                        value = Int32.Parse(valueStr);
                    }
                    catch (FormatException)
                    {
                        Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid object interaction packet.");
                        return;
                    }
                    if (packet[2] == PacketBuilder.ITEM_INFORMATON)
                    {
                        itemId = -1;
                        if (sender.LoggedinUser.Inventory.HasItem(value))
                            itemId = sender.LoggedinUser.Inventory.GetItemByRandomid(value).ItemId;
                        else if (DroppedItems.IsDroppedItemExist(value))
                            itemId = DroppedItems.GetDroppedItemById(value).instance.ItemId;
                        if (itemId == -1)
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + " asked for details of non existiant item.");
                            return;
                        }
                        sender.LoggedinUser.MetaPriority = true;
                        Item.ItemInformation info = Item.GetItemById(itemId);
                        string infoMessage = Meta.BuildItemInfo(info);
                        byte[] metaPacket = PacketBuilder.CreateMetaPacket(infoMessage);
                        sender.SendPacket(metaPacket);
                    }
                    if (packet[2] == PacketBuilder.ITEM_INFORMATON_ID)
                    {
                        sender.LoggedinUser.MetaPriority = true;
                        if (!Item.ItemIdExist(value))
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + " asked for details of non existiant item.");
                            return;
                        }

                        Item.ItemInformation info = Item.GetItemById(value);
                        string infoMessage = Meta.BuildItemInfo(info);
                        byte[] metaPacket = PacketBuilder.CreateMetaPacket(infoMessage);
                        sender.SendPacket(metaPacket);
                    }
                    else if(packet[2] == PacketBuilder.NPC_INFORMATION)
                    {
                        if(Npc.NpcExists(value))
                        {
                            sender.LoggedinUser.MetaPriority = true;
                            Npc.NpcEntry npc = Npc.GetNpcById(value);
                            string infoMessage = Meta.BuildNpcInfo(npc);
                            byte[] metaPacket = PacketBuilder.CreateMetaPacket(infoMessage);
                            sender.SendPacket(metaPacket);
                        }
                        else
                        {
                            Logger.HackerPrint(sender.LoggedinUser.Username + " asked for details of non existiant npc.");
                            return;
                        }
                    }

                    break;
                default:
                    Logger.WarnPrint(sender.LoggedinUser.Username + " Sent an unknown Item Interaction Packet type: " + action.ToString() + ", Packet Dump: " + BitConverter.ToString(packet).Replace('-', ' '));
                    break;
            }

        }
        public static void OnInventoryRequested(GameClient sender, byte[] packet)
        {
            if (!sender.LoggedIn)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent chat packet when not logged in.");
                return;
            }

            if (packet.Length < 2)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent an invalid inventory request packet.");
                return;
            }

            UpdateInventory(sender);
        }
        public static void OnLoginRequest(GameClient sender, byte[] packet)
        {
            Logger.DebugPrint("Login request received from: " + sender.RemoteIp);

            string loginRequestString = Encoding.UTF8.GetString(packet).Substring(1);

            if (!loginRequestString.Contains('|') || packet.Length < 3)
            {
                Logger.ErrorPrint(sender.RemoteIp + " Sent an invalid login request");
                return;
            }

            if (packet[1] != PacketBuilder.PACKET_CLIENT_TERMINATOR)
            {
                string[] loginParts = loginRequestString.Split('|');
                if (loginParts.Length < 3)
                {
                    Logger.ErrorPrint(sender.RemoteIp + " Sent a login request of invalid length. " + loginRequestString);
                    return;
                }

                int version = int.Parse(loginParts[0]);
                string encryptedUsername = loginParts[1];
                string encryptedPassword = loginParts[2];
                string username = Authentication.DecryptLogin(encryptedUsername);
                string password = Authentication.DecryptLogin(encryptedPassword);

                if (Authentication.CheckPassword(username, password))
                {
                    // Obtain user information
                    int userId = Database.GetUserid(username);

                    if(Database.IsUserBanned(userId))
                    {
                        Logger.DebugPrint(sender.RemoteIp + " Tried to login to : " + username + " but, the account was banned.");
                        byte[] userBannedPacket = PacketBuilder.CreateLoginPacket(false, Messages.LoginFailedReasonBanned);
                        sender.SendPacket(userBannedPacket);
                        return;
                    }

                    if(Database.IsIpBanned(sender.RemoteIp))
                    {
                        Logger.DebugPrint(sender.RemoteIp + " Tried to login to : " + username + " but, the IP was banned.");
                        byte[] ipBannedPacket = PacketBuilder.CreateLoginPacket(false, Messages.FormatIpBannedMessage(sender.RemoteIp));
                        sender.SendPacket(ipBannedPacket);
                        return;
                    }


                    sender.Login(userId);
                    sender.LoggedinUser.Password = password;

                    byte[] ResponsePacket = PacketBuilder.CreateLoginPacket(true);
                    sender.SendPacket(ResponsePacket);

                    Logger.DebugPrint(sender.RemoteIp + " Logged into : " + sender.LoggedinUser.Username + " (ADMIN: " + sender.LoggedinUser.Administrator + " MOD: " + sender.LoggedinUser.Moderator + ")");

                    // Send login message
                    byte[] loginMessageBytes = PacketBuilder.CreateChat(Messages.FormatLoginMessage(sender.LoggedinUser.Username), PacketBuilder.CHAT_BOTTOM_LEFT);
                    foreach (GameClient client in ConnectedClients)
                        if (client.LoggedIn)
                            if (!client.LoggedinUser.MuteLogins && !client.LoggedinUser.MuteAll)
                                if (client.LoggedinUser.Id != userId)
                                        client.SendPacket(loginMessageBytes);

                    UpdateUserInfo(sender.LoggedinUser);

                }
                else
                {
                    Logger.WarnPrint(sender.RemoteIp + " Attempted to login to: " + username + " with incorrect password " + password);
                    byte[] ResponsePacket = PacketBuilder.CreateLoginPacket(false);
                    sender.SendPacket(ResponsePacket);
                }
            }

        }

        public static void OnDisconnect(GameClient sender)
        {
            connectedClients.Remove(sender);
            if (sender.LoggedIn)
            {
                Database.SetPlayerLastLogin(Convert.ToInt32(new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds()), sender.LoggedinUser.Id); // Set last login date

                Database.RemoveOnlineUser(sender.LoggedinUser.Id);
                // Send disconnect message
                byte[] logoutMessageBytes = PacketBuilder.CreateChat(Messages.FormatLogoutMessage(sender.LoggedinUser.Username), PacketBuilder.CHAT_BOTTOM_LEFT);
                foreach (GameClient client in ConnectedClients)
                    if (client.LoggedIn)
                        if (!client.LoggedinUser.MuteLogins && !client.LoggedinUser.MuteAll)
                            if (client.LoggedinUser.Id != sender.LoggedinUser.Id)
                                client.SendPacket(logoutMessageBytes);
                // Tell clients of diconnect (remove from chat)
                byte[] playerRemovePacket = PacketBuilder.CreatePlayerLeavePacket(sender.LoggedinUser.Username);
                foreach (GameClient client in ConnectedClients)
                    if (client.LoggedIn)
                        if (client.LoggedinUser.Id != sender.LoggedinUser.Id)
                            client.SendPacket(playerRemovePacket);
            }

        }

        /*
         *  Get(Some Information)
         */


        public static bool IsUserOnline(int id)
        {
            try
            {
                GetUserById(id);
                return true;
            }
            catch (KeyNotFoundException)
            {
                return false;
            }
        }

        public static User[] GetUsersInTown(World.Town town, bool includeStealth = false, bool includeMuted = false)
        {
            List<User> usersInTown = new List<User>();
            foreach (GameClient client in ConnectedClients)
                if (client.LoggedIn)
                {
                    if (!includeStealth && client.LoggedinUser.Stealth)
                        continue;
                    if (!includeMuted && client.LoggedinUser.MuteIsland)
                        continue;
                    if (World.InTown(client.LoggedinUser.X, client.LoggedinUser.Y))
                        if (World.GetIsle(client.LoggedinUser.X, client.LoggedinUser.Y).Name == town.Name)
                            usersInTown.Add(client.LoggedinUser);
                }

            return usersInTown.ToArray();
        }
        public static User[] GetUsersInIsle(World.Isle isle, bool includeStealth = false, bool includeMuted = false)
        {
            List<User> usersInIsle = new List<User>();
            foreach (GameClient client in ConnectedClients)
                if (client.LoggedIn)
                {
                    if (!includeStealth && client.LoggedinUser.Stealth)
                        continue;
                    if (!includeMuted && client.LoggedinUser.MuteIsland)
                        continue;
                    if (World.InIsle(client.LoggedinUser.X, client.LoggedinUser.Y))
                        if (World.GetIsle(client.LoggedinUser.X, client.LoggedinUser.Y).Name == isle.Name)
                            usersInIsle.Add(client.LoggedinUser);
                }

            return usersInIsle.ToArray();
        }

        public static User[] GetUsersOnSpecialTileCode(string code)
        {
            List<User> userList = new List<User>();

            foreach (GameClient client in connectedClients)
            {
                if (client.LoggedIn)
                {

                    if (World.InSpecialTile(client.LoggedinUser.X, client.LoggedinUser.Y))
                    {
                        World.SpecialTile tile = World.GetSpecialTile(client.LoggedinUser.X, client.LoggedinUser.Y);

                        if (tile.Code == code)
                        {
                            userList.Add(client.LoggedinUser);
                        }
                    }
                }
            }
            return userList.ToArray();
        }
        public static User[] GetUsersAt(int x, int y, bool includeStealth = false, bool includeMuted = false)
        {
            List<User> usersHere = new List<User>();
            foreach(GameClient client in ConnectedClients)
            {
                if(client.LoggedIn)
                {
                    if (!includeStealth && client.LoggedinUser.Stealth)
                        continue;
                    if (!includeMuted && client.LoggedinUser.MuteNear)
                        continue;
                    if (client.LoggedinUser.X == x && client.LoggedinUser.Y == y)
                        usersHere.Add(client.LoggedinUser);
                }
            }
            return usersHere.ToArray();
        }
        public static User GetUserByName(string username)
        {
            foreach(GameClient client in ConnectedClients)
            {
                if(client.LoggedIn)
                {
                    if (client.LoggedinUser.Username == username)
                        return client.LoggedinUser;
                }
            }
            throw new KeyNotFoundException("User was not found.");
        }

        public static User GetUserById(int id)
        {
            foreach(GameClient client in ConnectedClients)
            {
                if (client.LoggedIn)
                    if (client.LoggedinUser.Id == id)
                        return client.LoggedinUser;
            }

            throw new KeyNotFoundException("User not found (not online?)");
        }
        public static User[] GetNearbyUsers(int x, int y, bool includeStealth=false, bool includeMuted=false)
        {
            int startX = x - 15;
            int endX = x + 15;
            int startY = y - 19;
            int endY = y + 19;
            List<User> usersNearby = new List<User>();

            foreach (GameClient client in ConnectedClients)
                if (client.LoggedIn)
                {
                    if (!includeStealth && client.LoggedinUser.Stealth)
                        continue;
                    if (!includeMuted && client.LoggedinUser.MuteNear)
                        continue;
                    if (startX <= client.LoggedinUser.X && endX >= client.LoggedinUser.X && startY <= client.LoggedinUser.Y && endY >= client.LoggedinUser.Y)
                        usersNearby.Add(client.LoggedinUser);
                }

            return usersNearby.ToArray();
        }
        public static int GetNumberOfPlayers(bool includeStealth=false)
        {
            int count = 0;
            foreach(GameClient client in ConnectedClients)
                if (client.LoggedIn)
                {
                    if (!includeStealth && client.LoggedinUser.Stealth)
                        continue;
                    if (!client.LoggedinUser.Stealth)
                        count++;
                }
            
            return count;
        }

        public static Point[] GetAllBuddyLocations(User caller)
        {
            List<Point> allLocations = new List<Point>();

            foreach (GameClient client in ConnectedClients)
            {
                if (client.LoggedIn)
                {

                    if (!caller.Friends.List.Contains(client.LoggedinUser.Id))
                        continue;
                    

                    if (!client.LoggedinUser.Stealth)
                        allLocations.Add(new Point(client.LoggedinUser.X, client.LoggedinUser.Y));

                }
            }

            return allLocations.ToArray();
        }

        public static Point[] GetAllPlayerLocations(User caller)
        {
            List<Point> allLocations = new List<Point>();
            
            foreach (GameClient client in ConnectedClients)
            {
                if (client.LoggedIn)
                {

                    if (client.LoggedinUser.Id == caller.Id) 
                        continue;
                    
                    if (!client.LoggedinUser.Stealth)
                        allLocations.Add(new Point(client.LoggedinUser.X, client.LoggedinUser.Y));
                    
                }

                        
            }
            return allLocations.ToArray();
        }
        public static int GetNumberOfPlayersListeningToAdsChat()
        {
            int count = 0;
            foreach (GameClient client in ConnectedClients)
            {
                if (client.LoggedIn)
                    if (!client.LoggedinUser.MuteAds)
                        count++;
            }
            return count;
        }

        public static int GetNumberOfModsOnline()
        {
            int count = 0;
            foreach (GameClient client in ConnectedClients)
            {
                if (client.LoggedIn)
                    if(client.LoggedinUser.Moderator)
                        count++;
            }
            return count;
        }
        public static int GetNumberOfAdminsOnline()
        {
            int count = 0;
            foreach (GameClient client in ConnectedClients)
            {
                if (client.LoggedIn)
                    if (client.LoggedinUser.Administrator)
                        count++;
            }
            return count;
        }

        /*
         *  Update game state functions.
         */

        public static void Update(GameClient client)
        {
            UpdateArea(client);
            foreach (User nearbyUser in GameServer.GetNearbyUsers(client.LoggedinUser.X, client.LoggedinUser.Y, false, false))
                if (nearbyUser.Id != client.LoggedinUser.Id)
                    if(!nearbyUser.MetaPriority)
                        UpdateArea(nearbyUser.LoggedinClient);


            UpdateUserInfo(client.LoggedinUser);
        }

        public static void UpdateHorseMenu(GameClient forClient, HorseInstance horseInst)
        {
            int TileID = Map.GetTileId(forClient.LoggedinUser.X, forClient.LoggedinUser.Y, false);
            string type = Map.TerrainTiles[TileID - 1].Type;
            forClient.LoggedinUser.LastViewedHorse = horseInst;
            forClient.LoggedinUser.MetaPriority = true;
            byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildHorseInformation(horseInst, forClient.LoggedinUser));
            forClient.SendPacket(metaPacket);

            string loadSwf = HorseInfo.BreedViewerSwf(horseInst, type);
            byte[] swfPacket = PacketBuilder.CreateSwfModulePacket(loadSwf, PacketBuilder.PACKET_SWF_MODULE_FORCE);
            forClient.SendPacket(swfPacket);
        }
        public static void UpdateInventory(GameClient forClient)
        {
            if (!forClient.LoggedIn)
                return;
            forClient.LoggedinUser.MetaPriority = true;
            byte[] metaPacket = PacketBuilder.CreateMetaPacket(Meta.BuildInventoryInfo(forClient.LoggedinUser.Inventory));
            forClient.SendPacket(metaPacket);
        }

        public static void UpdateWeather(GameClient forClient)
        {
            if (!forClient.LoggedIn)
            {
                Logger.ErrorPrint(forClient.RemoteIp + "tried to update weather information when not logged in.");
                return;
            }

            byte[] WeatherUpdate = PacketBuilder.CreateWeatherUpdatePacket(forClient.LoggedinUser.GetWeatherSeen());
            forClient.SendPacket(WeatherUpdate);
        }
        public static void UpdateWorld(GameClient forClient)
        {
            if (!forClient.LoggedIn)
            {
                Logger.ErrorPrint(forClient.RemoteIp + "tried to update world information when not logged in.");
                return;
            }

            byte[] WorldData = PacketBuilder.CreateWorldData(World.ServerTime.Minutes, World.ServerTime.Days, World.ServerTime.Years, forClient.LoggedinUser.GetWeatherSeen());
            forClient.SendPacket(WorldData);
        }
        public static void UpdatePlayer(GameClient forClient)
        {
            if (!forClient.LoggedIn)
            {
                Logger.ErrorPrint(forClient.RemoteIp + "tried to update player information when not logged in.");
                return;
            }
            byte[] PlayerData = PacketBuilder.CreatePlayerData(forClient.LoggedinUser.Money, GameServer.GetNumberOfPlayers(), forClient.LoggedinUser.MailBox.MailCount);
            forClient.SendPacket(PlayerData);
        }
        public static void UpdateUserInfo(User user)
        {
            byte[] playerInfoBytes = PacketBuilder.CreatePlayerInfoUpdateOrCreate(user.X, user.Y, user.Facing, user.CharacterId, user.Username);



            List<User> users = new List<User>();
            foreach (GameClient client in ConnectedClients)
                if (client.LoggedIn)
                {
                    if (client.LoggedinUser.Id != user.Id)
                        client.SendPacket(playerInfoBytes);
                }


        }
        public static void UpdateAreaForAll(int x, int y)
        {
            foreach(GameClient client in ConnectedClients)
            {
                if (client.LoggedIn)
                    if (client.LoggedinUser.X == x && client.LoggedinUser.Y == y)
                        if(!client.LoggedinUser.MetaPriority)
                            UpdateArea(client);
            }
        }
        public static void UpdateArea(GameClient forClient)
        {
            if (!forClient.LoggedIn)
            {
                Logger.ErrorPrint(forClient.RemoteIp + "tried to update tile information when not logged in.");
                return;
            }

            string LocationStr = "";
            if (!World.InSpecialTile(forClient.LoggedinUser.X, forClient.LoggedinUser.Y))
            {
                LocationStr = Meta.BuildMetaInfo(forClient.LoggedinUser, forClient.LoggedinUser.X, forClient.LoggedinUser.Y);
            }
            else
            {
                World.SpecialTile specialTile = World.GetSpecialTile(forClient.LoggedinUser.X, forClient.LoggedinUser.Y);
                if (specialTile.AutoplaySwf != null && specialTile.AutoplaySwf != "")
                {
                    byte[] swfModulePacket = PacketBuilder.CreateSwfModulePacket(specialTile.AutoplaySwf,PacketBuilder.PACKET_SWF_MODULE_GENTLE);
                    forClient.SendPacket(swfModulePacket);
                }
                if (specialTile.Code != null)
                    if (!ProcessMapCodeWithArg(forClient, specialTile))
                        return;
                LocationStr = Meta.BuildSpecialTileInfo(forClient.LoggedinUser, specialTile);
            }

            string lastWeather = forClient.LoggedinUser.LastSeenWeather;
            string weather = forClient.LoggedinUser.GetWeatherSeen();
            if(lastWeather != weather)
            {
                byte[] WeatherUpdate = PacketBuilder.CreateWeatherUpdatePacket(weather);
                forClient.SendPacket(WeatherUpdate);
            }

            byte[] AreaMessage = PacketBuilder.CreateMetaPacket(LocationStr);
            forClient.SendPacket(AreaMessage);
            forClient.LoggedinUser.MetaPriority = false;

        }
        public static void UpdateStats(GameClient client)
        {
            if (!client.LoggedIn)
                return;

            client.LoggedinUser.MetaPriority = true;
            string metaWind = Meta.BuildStatsMenu(client.LoggedinUser);
            byte[] statsPacket = PacketBuilder.CreateMetaPacket(metaWind);
            client.SendPacket(statsPacket);

        }

        /*
         *   Other...
         */
        public static bool ProcessMapCodeWithArg(GameClient forClient, World.SpecialTile tile)
        {
            string mapCode = tile.Code;
            if(mapCode.Contains('-'))
            {
                string[] codeInfo = mapCode.Split('-');
                string command = codeInfo[0];
                string paramaters = codeInfo[1];

                if(command == "JUMP")
                {
                    if(paramaters.Contains(','))
                    {
                        string[] args = paramaters.Split(',');
                        try
                        {
                            int newX = int.Parse(args[0]);
                            int newY = int.Parse(args[1]);
                            forClient.LoggedinUser.Teleport(newX, newY);
                            if (World.InIsle(tile.X, tile.Y))
                            {
                                World.Isle isle = World.GetIsle(tile.X, tile.Y);
                                int tileset = isle.Tileset;
                                int overlay = Map.GetTileId(tile.X, tile.Y, true);
                                if (tileset == 6 && overlay == 249) // warp point
                                {
                                    byte[] swfPacket = PacketBuilder.CreateSwfModulePacket("warpcutscene", PacketBuilder.PACKET_SWF_CUTSCENE);
                                    forClient.SendPacket(swfPacket);
                                }
                            }
                            return false;
                        }
                        catch(Exception)
                        {
                            return true;
                        }
                    }
                }
            }
            return true;
        }
        public static void StartServer()
        {
            ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress hostIP = IPAddress.Parse(ConfigReader.BindIP);
            IPEndPoint ep = new IPEndPoint(hostIP, ConfigReader.Port);
            ServerSocket.Bind(ep);
            Logger.InfoPrint("Binding to ip: " + ConfigReader.BindIP + " On port: " + ConfigReader.Port.ToString());
            ServerSocket.Listen(10000);
            gameTimer = new Timer(new TimerCallback(onGameTick), null, gameTickSpeed, gameTickSpeed);
            minuteTimer = new Timer(new TimerCallback(onMinuteTick), null, oneMinute, oneMinute);
            while (true)
            {
                Logger.InfoPrint("Waiting for new connections...");

                Socket cientSocket = ServerSocket.Accept();
                GameClient client = new GameClient(cientSocket);
                connectedClients.Add(client);
            }
        }

        
        

    }
}
