public SpellTarget FindBestUsage(PlayedFighter pc, Spell.SpellCategory category, bool withWeapon, IEnumerable<Cell> possiblePlacement = null) { SpellTarget spellTarget = new SpellTarget(); if (pc.PCStats.CurrentAP <= 0) return spellTarget; Stopwatch timer = new Stopwatch(); timer.Start(); PathFinder pathFinder = new PathFinder(pc.Fight, true); IEnumerable<Cell> sourceCells = possiblePlacement == null ? pc.GetPossibleMoves(true, true, pathFinder) : possiblePlacement; IEnumerable<Fighter> actorsWithoutPC = pc.Fight.AliveActors.Where(actor => actor != pc); List<Spell> spells = m_spells.ToList(); if (withWeapon && ((category & (Spell.SpellCategory.Damages | Spell.SpellCategory.Healing)) != 0)) spells.Add(WeaponSpellLike()); //logger.Debug("***FindBestUsage {0}, {1} spells in book. {2} PA. {3}/{4} HP ***", category, spells.Count, pc.PCStats.CurrentAP, pc.PCStats.Health, pc.PCStats.MaxHealth); Object thisLock = new Object(); //foreach(Spell spell in spells) int NbSpellsChecked = 0; Parallel.ForEach(spells, spell => { NbSpellsChecked++; if (spell != null && !IgnoredSpells.Contains(spell.Template.id)) { int spellId = spell.Template.id; if (spell.IsAvailable(null) && ((spellId != 0 && pc.CanCastSpells) || (spellId == 0 && pc.CanFight)) && spell.LevelTemplate.apCost <= pc.Stats.CurrentAP && pc.CanCastSpell(spellId)) { if ((spell.Categories & category) > 0) { SpellTarget lastSpellTarget = spell.FindBestTarget(pc, sourceCells, actorsWithoutPC, category); if (lastSpellTarget != null && lastSpellTarget.Efficiency > spellTarget.Efficiency) //lock (thisLock) spellTarget = lastSpellTarget; //if (lastSpellTarget != null) // logger.Debug("efficiency {0} = {1} ({2})", lastSpellTarget.Spell, lastSpellTarget.Efficiency, lastSpellTarget.Comment); //lock (thisLock) // logger.Debug("efficiency {0} = ???", spell); // else //lock (thisLock) // logger.Debug("efficiency {0} = {1} ({2})", lastSpellTarget.Spell, lastSpellTarget.Efficiency, lastSpellTarget.Comment); } } else { // lock (thisLock) // logger.Info("{0} skipped : available={1} ({6}), canUse={2}, ApCost={3}, CanCast({4})={5}", spell, spell.IsAvailable(null), ((spellId != 0 && pc.CanCastSpells) || (spellId == 0 && pc.CanFight)), spell.LevelTemplate.apCost <= pc.Stats.CurrentAP, spellId, pc.CanCastSpell(spellId), spell.AvailabilityExplainString(null)); } } } ); //Debug.Assert(NbSpellsChecked == spells.Count); timer.Stop(); spellTarget.TimeSpan = timer.Elapsed; //pc.Character.SendInformation("Spell {0} selected - efficientcy : {1} - comment = {2}", spellTarget.Spell, spellTarget.Efficiency, spellTarget.Comment); return spellTarget; }
/*public bool IsProperTarget(PlayedFighter caster, Fighter target, Spell spell) { // SpellTargetType if (target == null) return spell.LevelTemplate.needFreeCell && spell.IsAvailable(null, null); foreach (var spellEffect in spell.GetEffects()) if (EffectBase.canAffectTarget(spellEffect, spell, caster, target)) return true; return false; }*/ #endregion Availability management #region Spell selection /*public IEnumerable<Spell> GetOrderListOfSimpleBoostSpells(PlayedFighter caster, Fighter target, Spell.SpellCategory category) { return m_spells.Where(spell => (caster.Stats.CurrentAP >= spell.LevelTemplate.apCost) && spell.IsAvailable(caster.Id, category) && IsProperTarget(caster, target, spell)).OrderByDescending(spell => spell.Level).ThenByDescending(spell => spell.LevelTemplate.minPlayerLevel); } public IEnumerable<Spell> GetOrderedAttackSpells(PlayedFighter caster, Fighter target, Spell.SpellCategory category = Spell.SpellCategory.Damages) { Debug.Assert(((category & Spell.SpellCategory.Damages) > 0), "category do not include Damage effects"); return m_spells.Where(spell => (caster.Stats.CurrentAP >= spell.LevelTemplate.apCost) && spell.IsAvailable(target.Id, category) && IsProperTarget(caster, target, spell)) .OrderByDescending(spell => (int)(spell.GetSpellDamages(caster, target, Spell.SpellCategory.Damages).Damage) * (caster.Stats.CurrentAP / (int)spell.LevelTemplate.apCost)); }*/ public SpellTarget FindBestUsage(PlayedFighter pc, List<int> spellIds, IEnumerable<Cell> possiblePlacement = null) { Stopwatch timer = new Stopwatch(); timer.Start(); PathFinder pathFinder = new PathFinder(pc.Fight, true); IEnumerable<Cell> sourceCells = possiblePlacement == null ? pc.GetPossibleMoves(true, true, pathFinder) : possiblePlacement; IEnumerable<Fighter> actorsWithoutPC = pc.Fight.AliveActors.Where(actor => actor != pc); SpellTarget spellTarget = new SpellTarget(); foreach (int spellId in spellIds) { Spell spell = m_spells.FirstOrDefault(sp => sp.Template.id == spellId); if (spell == null && spellId == 0) spell = WeaponSpellLike(); if (spell != null) { if (spell.IsAvailable(null) && ((spellId != 0 && pc.CanCastSpells) || (spellId == 0 && pc.CanFight)) && spell.LevelTemplate.apCost <= pc.Stats.CurrentAP && pc.CanCastSpell(spellId)) if (spell != null && spell.IsAvailable(null) && spell.LevelTemplate.apCost <= pc.Stats.CurrentAP) { SpellTarget lastSpellTarget = spell.FindBestTarget(pc, sourceCells, actorsWithoutPC, Spell.SpellCategory.All); if (lastSpellTarget != null && lastSpellTarget.Efficiency > spellTarget.Efficiency) { spellTarget = lastSpellTarget; break; // Stop on the first spell with positive efficiency } } } } timer.Stop(); spellTarget.TimeSpan = timer.Elapsed; return spellTarget; }