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 SpellRangedAttack(SpellAttackEffector hit,
                                         MissileScript.MissileAnimationName missileName,
                                         SpellAttackEffector crit = null,
                                         SpellAttackEffector miss = null)
    {
        return((AT.Battle.Actor caster,AT.Battle.Action cast,List <AT.ATTile> targets) => {
            GameObject prefab = MissileAnimationPrefabDispenser.instance.GetAnimationPrefabByName(missileName);

            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) => {
                        GameObject copy = Instantiate(prefab);
                        copy.transform.position = caster.transform.position;
                        MissileScript missile = copy.GetComponent <MissileScript>();

                        missile.LaunchAt(target,true);
                        //Safe to not worry about unsubbing, thanks to garbage cleanup
                        missile.OnConnectedWithTarget += (MissileScript self) => {
                            if (resultingEffects != null)
                            {
                                foreach (AT.Character.Effect.GenericEffect effect in resultingEffects)
                                {
                                    if (target.FirstOccupant != null)
                                    {
                                        effect.ApplyTo(target.FirstOccupant.CharSheet,cast);
                                    }
                                }
                            }
                            //This assumes only one missile.   Needs a "Checkin of sorts, to conditionally check on finished"
                            cast.CallOnFinished();
                        };
                    });                     //ToBe ATOCIJL
                }
                else
                {
                    GameObject copy = Instantiate(prefab);
                    copy.transform.position = caster.transform.position;
                    MissileScript missile = copy.GetComponent <MissileScript>();
                    missile.LaunchAt(target.transform);
                    //Safe to not worry about unsubbing, thanks to garbage cleanup
                    missile.OnConnectedWithTarget += (MissileScript self) => {
                        if (resultingEffects != null)
                        {
                            foreach (AT.Character.Effect.GenericEffect effect in resultingEffects)
                            {
                                effect.ApplyTo(target.FirstOccupant.CharSheet,cast);
                            }
                        }
                        //This assumes only one missile.   Needs a "Checkin of sorts, to conditionally check on finished"
                        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();
                }
            }
        });
    }