Example #1
0
        // Find where the PC should come to cast the spell, and the best target there (todo : optimize if needed)
        public SpellTarget FindBestTarget(PlayedFighter pc, IEnumerable <Cell> sourceCells, IEnumerable <Fighter> actors, Spell.SpellCategory category)
        {
            if (LevelTemplate.statesForbidden != null)
            {
                if (LevelTemplate.statesForbidden.Any(state => pc.HasState(state)))
                {
                    logger.Debug("Spell {0} skipped : statesForbidden {1}", this, string.Join(",", LevelTemplate.statesForbidden));
                    pc.Character.SendWarning("Spell {0} skipped : statesForbidden {1}", this, string.Join(",", LevelTemplate.statesForbidden));
                    return(null); // Can't cast this : all the required states are not on the caster
                }
            }
            if (LevelTemplate.statesRequired != null)
            {
                if (!LevelTemplate.statesRequired.All(state => pc.HasState(state)))
                {
                    logger.Debug("Spell {0} skipped : statesRequired {1}", this, string.Join(",", LevelTemplate.statesForbidden));
                    pc.Character.SendWarning("Spell {0} skipped : statesRequired {1}", this, string.Join(",", LevelTemplate.statesForbidden));
                    return(null); // Can't cast this : at least one required state is not on the caster
                }
            }
            if (IsMaitrise(null)) // If the spell is a maitrise, then ignore it if not of the proper type for equipped weapon.
            {
                Weapon weapon = pc.Character.Inventory.GetEquippedWeapon();
                if (weapon == null)
                {
                    return(null);
                }
                if (!IsMaitrise(weapon.typeId))
                {
                    return(null);
                }
            }
            _losMap = new LOSMap(pc.Fight);
            SpellTarget bestResult = null;

            #region optimisations
            IEnumerable <Fighter> enemies = pc.GetOpposedTeam().FightersAlive;
            IEnumerable <Fighter> friends = pc.Team.FightersAlive;

            bool goodSpell = (Categories & (SpellCategory.Buff | SpellCategory.Healing)) != 0;
            bool badSpell  = (Categories & (SpellCategory.Damages | SpellCategory.Curse)) != 0;
            IEnumerable <Fighter> targets = null;
            int targetsCount = 0;
            if (goodSpell && badSpell)
            {
                goodSpell = badSpell = false;
            }
            else
            {
                targets      = goodSpell ? friends : enemies;
                targetsCount = targets.Count();
            }
            uint surface = this.GetArea(category);
            efficiencyCache = null;
            if (!areaDependsOnDirection)
            {
                efficiencyCache = new Dictionary <short, int>();
            }
            #endregion
            if (surface == 1 && LevelTemplate.range == 0) // Hack fast Cure and protect self
            {
                var res = GetSpellDamages(pc, pc);
                if (res.Damage > 0)
                {
                    bestResult = new SpellTarget(res.Damage, pc.Cell, pc.Cell, this);
                }
            }
            else
            {
                foreach (Cell source in sourceCells)
                {
                    IEnumerable <Cell> destCells = GetCellsAtSpellRange(pc, source, actors);
                    if (goodSpell || badSpell)
                    {
                        if (surface <= 1 && LevelTemplate.range > 0)
                        {
                            destCells = destCells.Intersect(targets.Select(fighter => fighter.Cell)); // for spells that have an area of effect of 1, just find enemies or friends as targets. No need to scan all the range.
                        }
                    }
                    if (surface >= 560 && destCells.Count() > 1) // For spells that cover the full map, use only the first cell
                    {
                        destCells = destCells.Take(1);
                    }
                    SpellTarget newResult = FindBestTarget(pc, source, destCells, actors, category);
                    if (newResult == null || newResult.Efficiency <= 0)
                    {
                        continue;
                    }
                    if (bestResult == null || bestResult.Efficiency < newResult.Efficiency)
                    {
                        bestResult = newResult;
                        if (surface >= 560)
                        {
                            break;                 // if spell covers all map, and we have some hit, then no need to continue (first source cells are nearest)
                        }
                        if (targetsCount == 1 && surface == 1)
                        {
                            break;                                    // only one target and 1 cell area spell => no need to loop further
                        }
                    }
                }
            }
            if (bestResult != null)
            {
                bestResult.Efficiency *= (pc.Stats.CurrentAP / LevelTemplate.apCost);
                bestResult.cast        = false;
            }

            return(bestResult);
        }
        /// <summary>
        /// Warning : this method says if this affect may affect this target. But NOT if the target can be the target of the spell
        /// (cf épée divine, where you cast it on yourself despite it effects only enemies around you)
        /// </summary>
        /// <param name="spellEffect"></param>
        /// <param name="spell"></param>
        /// <param name="caster"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        public static bool canAffectTarget(EffectDice spellEffect, Spell spell, PlayedFighter caster, Fighter target)
        {
            if (spell.LevelTemplate.spellBreed == (uint)BreedEnum.Eniripsa && spell.Categories == Spell.SpellCategory.Healing && caster.HasState(76))
            {
                return(false);
            }
            //if (!spell.IsAvailable(target == null ? null : (int?)target.Id)) return false;
            //BiM.Behaviors.Game.Spells.Spell.SpellCategory categories = 0;
            uint surface = spellEffect.Surface;

            //categories = BiM.Behaviors.Game.Spells.Spell.GetEffectCategories((uint)spellEffect.Id, spell.LevelTemplate.id);
            if (spellEffect.Targets == SpellTargetType.NONE)
            {
                spellEffect.Targets = SpellTargetType.ALL;
            }
            //if (target == null) return !spell.LevelTemplate.needTakenCell;

            if (caster == target) // Self
            {
                return((spellEffect.Targets & (SpellTargetType.ONLY_SELF | SpellTargetType.SELF)) != 0);
            }


            if (caster.Team == target.Team) // Ally
            {
                if (target.Summoned)
                {
                    return((spellEffect.Targets & SpellTargetType.ALLIES_SUMMON) != 0);
                }
                else
                {
                    return((spellEffect.Targets & SpellTargetType.ALLIES_NON_SUMMON) != 0);
                }
            }

            if (target.Summoned) // Enemies
            {
                return((spellEffect.Targets & SpellTargetType.ENEMIES_SUMMON) != 0);
            }
            else
            {
                return((spellEffect.Targets & SpellTargetType.ENEMIES_NON_SUMMON) != 0);
            }
        }