public CastRoutine SpellSavingThrow(SpellAttackEffector failure,SpellAttackEffector success,AbilityType abilityType)
    {
        return((AT.Battle.Actor caster,AT.Battle.Action cast,List <AT.ATTile> targets) => {
            AT.Battle.Cast c = cast as AT.Battle.Cast;
            foreach (AT.ATTile target in targets)
            {
                SaveSituation sit = new SaveSituation(target.FirstOccupant.ActorComponent.CharSheet,
                                                      cast.actor.CharSheet,
                                                      abilityType,
                                                      SaveContext.SPELL,
                                                      c.Spell);
                List <AT.Character.Effect.GenericEffect> resultingEffects = null;

                ResultType result = sit.GetResult();
                switch (result)
                {
                case ResultType.SUCCESS:
                    resultingEffects = success.Invoke(cast,target);
                    break;

                case ResultType.FAILURE:
                    resultingEffects = failure.Invoke(cast,target);
                    break;
                }


                CharacterCastingAnimation castingAnims = caster.GetComponent <CharacterCastingAnimation>();
                if (castingAnims != null)
                {
                    castingAnims.SetupAndDoCastAnimation(cast);
                    castingAnims.OneShotSpellRelease((animationInst) => {
                        if (resultingEffects != null)
                        {
                            foreach (AT.Character.Effect.GenericEffect effect in resultingEffects)
                            {
                                effect.ApplyTo(target.FirstOccupant.CharSheet,cast);
                            }
                        }
                    });

                    castingAnims.OneShotAnimEnded((animationInst) => {
                        cast.CallOnFinished();
                    });
                }
                else
                {
                    if (resultingEffects != null)
                    {
                        foreach (AT.Character.Effect.GenericEffect effect in resultingEffects)
                        {
                            effect.ApplyTo(target.FirstOccupant.CharSheet,cast);
                        }
                    }
                    cast.CallOnFinished();
                }
            }
        });
    }
    public CastRoutine SpellTouchAttack(SpellAttackEffector hit,SpellAttackEffector crit = null,SpellAttackEffector miss = null)
    {
        return((AT.Battle.Actor caster,AT.Battle.Action cast,List <AT.ATTile> targets) => {
            foreach (AT.ATTile target in targets)
            {
                AttackSituation sit = new AttackSituation(caster.CharSheet,target.FirstOccupant.CharSheet,cast);

                List <AT.Character.Effect.GenericEffect> resultingEffects = null;

                ResultType result = sit.GetResult();
                switch (result)
                {
                case ResultType.HIT:
                    resultingEffects = hit.Invoke(cast,target);
                    break;

                case ResultType.CRITICAL_HIT:
                    if (crit != null)
                    {
                        resultingEffects = crit.Invoke(cast,target);
                    }
                    break;

                case ResultType.MISS:
                    if (miss != null)
                    {
                        resultingEffects = miss.Invoke(cast,target);
                    }
                    break;

                case ResultType.CRITICAL_MISS:
                    //nothing
                    break;
                }


                CharacterCastingAnimation castingAnims = caster.GetComponent <CharacterCastingAnimation>();
                if (castingAnims != null)
                {
                    castingAnims.SetupAndDoCastAnimation(cast);
                    castingAnims.OneShotSpellRelease((animationInst) => {
                        if (resultingEffects != null)
                        {
                            foreach (AT.Character.Effect.GenericEffect effect in resultingEffects)
                            {
                                if (target.FirstOccupant != null)
                                {
                                    effect.ApplyTo(target.FirstOccupant.CharSheet,cast);
                                }
                            }
                        }
                    });

                    castingAnims.OneShotAnimEnded((animationInst) => {
                        cast.CallOnFinished();
                    });
                }
                else
                {
                    if (resultingEffects != null)
                    {
                        foreach (AT.Character.Effect.GenericEffect effect in resultingEffects)
                        {
                            effect.ApplyTo(target.FirstOccupant.CharSheet,cast);
                        }
                    }
                    cast.CallOnFinished();
                }
            }
        });
    }