public static void ProcessUseSkill(ClientConnection client, UseSkill message)
        {
            var avatar = client.Avatar as MobileAvatar;
            if (avatar == null)
            {
                client.LogMessage("Requested a skill, but doesn't have an avatar.");
                return;
            }
            Schema.EnumSkillRow esr = Global.ModelSchema.EnumSkill.FindByEnumSkillID(message.SkillId);
            if (esr == null)
            {
                client.LogMessage("Requested an invalid skill " + message.SkillId);
                return;
            }

            // If already performing a skill invocation, just queue the request for later.
            if (avatar.ActivatingSkill != null)
            {
                avatar.SkillQueue.Enqueue(message);
                return;
            }

            if (esr.LeadTime <= 0)
            {
                // process it now
                UseSkillNow(avatar, message);
            }
            else
            {
                // process it later, after lead-time has elapsed
                avatar.ActivatingSkill = message;
                avatar.ActivatingSkillTimestamp = Global.Now;
                avatar.ActivatingSkillLeadTime = TimeSpan.FromSeconds(esr.LeadTime);
            }
        }
        public static void ProcessUseSkill(this World world, ClientConnection client, UseSkill message)
        {
            var source = client.Avatar as CombatantModel;
            if (source == null)
            {
                client.LogMessage("Requested a skill without an avatar.");
                return;
            }

            Schema.EnumSkillRow esr = Global.Schema.EnumSkill.FindByEnumSkillID((int)message.Skill);
            if (esr == null)
            {
                client.LogMessage("Requested an invalid skill " + message.Skill);
                return;
            }

            EntityModel target;
            switch ((EnumTargetType)esr.EnumTargetTypeID)
            {
                case EnumTargetType.TargetSelf:
                    target = source;
                    break;
                case EnumTargetType.TargetMobile:
                    if (message.TargetPhysicalObjectIDs.Length == 0)
                    {
                        world.LogMessage(source, "No target specified, this skill may only be used on Mobiles.");
                        return;
                    }
                    target = world.History.Head.Entities.ValueOrDefault(message.TargetPhysicalObjectIDs[0]);
                    if (target == null)
                    {
                        world.LogMessage(source, "Target " + message.TargetPhysicalObjectIDs[0] + " not found.");
                        return;
                    }
                    break;
                default:
                    world.LogMessage(source, "That skill has an unsupported target type " + esr.EnumTargetTypeID);
                    Log.Error("Unhandled target type " + esr.EnumTargetTypeID + " for skill " + esr.EnumSkillID + " " + esr.EnumSkillName);
                    return;
            }


            if (source.ActivatingSkill != EnumSkill.None)         // queue the request for later.
                world.Apply(new EntityUpdateEvent(
                    source.EnqueueSkill(message.Skill, target),
                    "Enqueuing Skill " + message.Skill));
            else if (esr.LeadTime <= 0)                 // process it now
                world.UseSkillNow(source, esr, target);
            else                                        // process it later, after lead-time has elapsed
                world.Apply(new EntityUpdateEvent(
                    source.StartSkill(message.Skill, target, Global.Now, TimeSpan.FromSeconds(esr.LeadTime)),
                    "Activating Skill " + message.Skill));
        }
        public static void UseSkillNow(MobileAvatar caster, UseSkill message)
        {
            Schema.EnumSkillRow esr = Global.ModelSchema.EnumSkill.FindByEnumSkillID(message.SkillId);
            if (esr == null)
            {
                caster.SendLog("Requested an invalid skill " + message.SkillId);
                return;
            }

            if (esr.EnergyCost > caster.Energy)
            {
                caster.SendLog("Not enough energy to use " + esr.EnumSkillName + ", require " + esr.EnergyCost + ".");
                return;
            }

            // TODO: make this work
            /*
            if ( esr.EnumMobileState > caster.MobileState ) {
                caster.SendLog( "Not while " + caster.MobileState.Name );
            }
            */

            MobileAvatar target;
            switch ((EnumTargetType)esr.EnumTargetTypeID)
            {
                case EnumTargetType.TargetSelf:
                    target = caster;
                    break;
                case EnumTargetType.TargetMobile:
                    if (message.TargetPhysicalObjectIDs.Length == 0)
                    {
                        caster.SendLog("No target specified, this skill may only be used on Mobiles.");
                        return;
                    }
                    target = (MobileAvatar)Global.World.PhysicalObjects[message.TargetPhysicalObjectIDs[0]];
                    if (target == null)
                    {
                        caster.SendLog("Target " + message.TargetPhysicalObjectIDs[0] + " not found.");
                        return;
                    }
                    if ((caster.Position - target.Position).Length > esr.Range)
                    {
                        // target is out of range
                        caster.SendLog(target.TemplateObjectName + " is out of range");
                        return;
                    }
                    break;
                default:
                    caster.SendLog("That skill does not work yet, contact admin.");
                    Log.Error("Unhandled target type " + esr.EnumTargetTypeID + " for skill " + esr.EnumSkillID);
                    return;
            }

            if (TargetSkill(caster, target, esr))
            {
                // successful casting affects affinity with the elements
                caster.AffinityAir += esr.AirAffinity / 1000f;
                caster.AffinityEarth += esr.EarthAffinity / 1000f;
                caster.AffinityFire += esr.FireAffinity / 1000f;
                caster.AffinityLife += esr.LifeAffinity / 1000f;
                caster.AffinityWater += esr.WaterAffinity / 1000f;
            }

            // deduct energy regardless
            caster.Energy -= esr.EnergyCost;
        }
 void ProcessMessage(ClientConnection client, UseSkill message)
 {
     World.ProcessUseSkill(client, message);
 }