예제 #1
0
        /// <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);
        }
예제 #2
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;
        }