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); }