public static void UseSkillNow(this World world, CombatantModel source, Schema.EnumSkillRow skill, EntityModel target)
        {
            if (source.MobileState == EnumMobileState.Dead || source.MobileState == EnumMobileState.Incapacitated)
            {
                world.LogMessage(source, "Unable to use " + skill.EnumSkillName + " while " + source.MobileState);
                return;
            }

            /* TODO: skill specific states
            if ( skill.EnumMobileState > caster.MobileState ) {
                caster.SendLog( "Not while " + caster.MobileState.Name );
            }
             */

            if ((source.Position - target.Position).Length > skill.Range)
            {
                world.LogMessage(source, target.Name + " is out of range");
                return;
            }

            if (skill.EnergyCost > source.Energy)
            {
                world.LogMessage(source, "Not enough energy to use " + skill.EnumSkillName + ", requires " + skill.EnergyCost);
                return;
            }
            
            // deduct energy regardless
            // TODO: can remove the explicit cast here by using generics
            source = (CombatantModel)source.WithEnergyChange(-skill.EnergyCost);

            bool succeeds = source.Succeeds(skill);

            bool hits = source.Hits(target, skill);

            bool avoids = target.Avoids(source, skill);

            // successful casting affects affinity with the elements
            if (succeeds && hits && !avoids)
            {
                // TODO: can remove the explicit cast here by using generics
                source = (CombatantModel)source.WithAffinityChange(
                    skill.AirAffinity / 1000f,
                    skill.EarthAffinity / 1000f,
                    skill.FireAffinity / 1000f,
                    skill.LifeAffinity / 1000f,
                    skill.WaterAffinity / 1000f);

                // TODO: just get the damage number instead??

                switch ((EnumActivationType)skill.EnumActivationTypeID)
                {
                    case EnumActivationType.AttackSpell:
                        target = target.MagicallyDamagedBy(source, skill);
                        break;
                    case EnumActivationType.Enchantment:
                        target = target.EnchantedBy(source, skill);
                        break;
                    case EnumActivationType.Glamour:
                        source.Activates(skill, target);
                        break;
                    case EnumActivationType.HealingSpell:
                        target = target.HealedBy(source, skill);
                        break;
                    case EnumActivationType.Skill:
                        target = target.DamagedBy(source, skill);
                        target = target.AffectedBy(source, skill);
                        source.Activates(skill, target);
                        break;
                    case EnumActivationType.Sorcery:
                        break;
                    default:
                        world.LogMessage(source, "That skill does not work yet, contact admin.");
                        Log.Error("Unhandled activation type " + (EnumActivationType)skill.EnumActivationTypeID + " for skill " + skill.EnumSkillName);
                        break;
                }
            }

            source = source.FinishSkill();
            string description = avoids ? "Avoided" : !hits ? "Missed" : !succeeds ? "Failed" : "Success";
            world.Apply(new SkillEvent(source, (EnumSkill)skill.EnumSkillID, target, succeeds, hits, avoids, description));
        }