public SpellTarget ComputeSpellImpact(Spell spell, Cell targetCell, Cell castCell) { SpellTarget damages = null; var cast = SpellManager.Instance.GetSpellCastHandler(Fighter, spell, targetCell, false); cast.CastCell = castCell; if (!cast.Initialize()) { return(null); } foreach (var handler in cast.GetEffectHandlers()) { if (!handler.CanApply()) { return(null); } handler.CastCell = castCell; foreach (var target in handler.GetAffectedActors()) { if (target != Fighter || handler.AffectedCells.Contains(castCell)) // we take in account the movement of the caster before the spell cast { CumulEffects(handler, ref damages, target, spell); } } } if (damages != null) { damages.AffectedCells = cast.GetEffectHandlers().SelectMany(x => x.AffectedCells).Distinct().ToArray(); } return(damages); }
public SpellTarget ComputeSpellImpact(Spell spell, FightActor target) { SpellTarget result = null; foreach (EffectDice current in spell.CurrentSpellLevel.Effects) { this.CumulEffects(current, ref result, target, spell); } return(result); }
public void Add(SpellTarget dmg) { MinFire += dmg.MinFire; MaxFire += dmg.MaxFire; MinWater += dmg.MinWater; MaxWater += dmg.MaxWater; MinEarth += dmg.MinEarth; MaxEarth += dmg.MaxEarth; MinAir += dmg.MinAir; MaxAir += dmg.MaxAir; MinNeutral += dmg.MinNeutral; MaxNeutral += dmg.MaxNeutral; MinHeal += dmg.MinHeal; MaxHeal += dmg.MaxHeal; Curse += dmg.Curse; Boost += dmg.Boost; }
public AISpellCastPossibility(Spell spell, SpellTarget target) { Target = target; Spell = spell; MaxConsecutiveCast = MAX_CONSECUTIVE_CAST; }
private static void AdjustDamage(SpellTarget damages, uint damage1, uint damage2, SpellCategory category, double chanceToHappen, int addDamage, int addDamagePercent, int reduceDamage, int reduceDamagePercent, bool negativ) { double minDamage = damage1; double maxDamage = damage1 >= damage2 ? damage1 : damage2; if (reduceDamagePercent >= 100) { return; // No damage } minDamage = ((minDamage * (1 + (addDamagePercent / 100.0)) + addDamage) - reduceDamage) * (1 - (reduceDamagePercent / 100.0)) * chanceToHappen; maxDamage = ((maxDamage * (1 + (addDamagePercent / 100.0)) + addDamage) - reduceDamage) * (1 - (reduceDamagePercent / 100.0)) * chanceToHappen; if (minDamage < 0) { minDamage = 0; } if (maxDamage < 0) { maxDamage = 0; } if (negativ) // or IsFriend { minDamage *= -0.3; // High penalty for firing on friends maxDamage *= -0.3; // High penalty for firing on friends } switch (category) { case SpellCategory.DamagesNeutral: damages.MinNeutral += minDamage; damages.MaxNeutral += maxDamage; break; case SpellCategory.DamagesFire: damages.MinFire += minDamage; damages.MaxAir += maxDamage; break; case SpellCategory.DamagesAir: damages.MinAir += minDamage; damages.MaxAir += maxDamage; break; case SpellCategory.DamagesWater: damages.MinWater += minDamage; damages.MaxWater += maxDamage; break; case SpellCategory.DamagesEarth: damages.MinEarth += minDamage; damages.MaxEarth += maxDamage; break; case SpellCategory.Healing: damages.MinHeal += minDamage; damages.MaxHeal += maxDamage; break; } }
// todo : do something more general (ghost actors) private void CumulEffects(SpellEffectHandler handler, ref SpellTarget spellImpact, FightActor target, Spell spell) { var effect = handler.Dice; var isFriend = Fighter.Team.Id == target.Team.Id; var result = new SpellTarget(); var category = SpellIdentifier.GetEffectCategories(effect.EffectId); if (category == 0) { return; } if (Fighter is SummonedTurret) { isFriend = category == SpellCategory.Healing; } var chanceToHappen = 1.0; // // When chances to happen is under 100%, then we reduce spellImpact accordingly, for simplicity, but after having apply damage bonus & reduction. // So average damage should remain exact even if Min and Max are not. if (effect.Random > 0) { chanceToHappen = effect.Random / 100.0; } if ((target is SummonedFighter)) { chanceToHappen /= 2; // It's much better to hit non-summoned foes => effect on summons (except allies summon for Osa) is divided by 2. } uint min; uint max; if (handler is DamagePerHPLost) { min = max = (uint)Math.Round(((Fighter.Stats.Health.DamageTaken * effect.DiceNum) / 100d)); } else if (handler is Kill && target != Fighter) // doesn't take sacrifice in account { min = max = (uint)target.LifePoints; } else { min = (uint)Math.Min(effect.DiceNum, effect.DiceFace); max = (uint)Math.Max(effect.DiceNum, effect.DiceFace); } if ((category & SpellCategory.DamagesNeutral) > 0) { AdjustDamage(result, min, max, SpellCategory.DamagesNeutral, chanceToHappen, Fighter.Stats.GetTotal(PlayerFields.NeutralDamageBonus) + Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + Fighter.Stats.GetTotal(PlayerFields.PhysicalDamage), Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + Fighter.Stats.GetTotal(PlayerFields.Strength), target.Stats.GetTotal(PlayerFields.NeutralElementReduction), target.Stats.GetTotal(PlayerFields.NeutralResistPercent), isFriend); } if ((category & SpellCategory.DamagesFire) > 0) { AdjustDamage(result, min, max, SpellCategory.DamagesNeutral, chanceToHappen, Fighter.Stats.GetTotal(PlayerFields.FireDamageBonus) + Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + Fighter.Stats.GetTotal(PlayerFields.MagicDamage), Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + Fighter.Stats.GetTotal(PlayerFields.Intelligence), target.Stats.GetTotal(PlayerFields.FireElementReduction), target.Stats.GetTotal(PlayerFields.FireResistPercent), isFriend); } if ((category & SpellCategory.DamagesAir) > 0) { AdjustDamage(result, min, max, SpellCategory.DamagesNeutral, chanceToHappen, Fighter.Stats.GetTotal(PlayerFields.AirDamageBonus) + Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + Fighter.Stats.GetTotal(PlayerFields.MagicDamage), Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + Fighter.Stats.GetTotal(PlayerFields.Agility), target.Stats.GetTotal(PlayerFields.AirElementReduction), target.Stats.GetTotal(PlayerFields.AirResistPercent), isFriend); } if ((category & SpellCategory.DamagesWater) > 0) { AdjustDamage(result, min, max, SpellCategory.DamagesNeutral, chanceToHappen, Fighter.Stats.GetTotal(PlayerFields.WaterDamageBonus) + Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + Fighter.Stats.GetTotal(PlayerFields.MagicDamage), Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + Fighter.Stats.GetTotal(PlayerFields.Chance), target.Stats.GetTotal(PlayerFields.WaterElementReduction), target.Stats.GetTotal(PlayerFields.WaterResistPercent), isFriend); } if ((category & SpellCategory.DamagesEarth) > 0) { AdjustDamage(result, min, max, SpellCategory.DamagesNeutral, chanceToHappen, Fighter.Stats.GetTotal(PlayerFields.EarthDamageBonus) + Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + Fighter.Stats.GetTotal(PlayerFields.PhysicalDamage), Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + Fighter.Stats.GetTotal(PlayerFields.Strength), target.Stats.GetTotal(PlayerFields.EarthElementReduction), target.Stats.GetTotal(PlayerFields.EarthResistPercent), isFriend); } if ((category & SpellCategory.Healing) > 0) { var steal = (category & SpellCategory.Damages) > 0; if (steal) { target = Fighter; // Probably hp steal } var hptoHeal = (uint)(Math.Max(0, target.MaxLifePoints - target.LifePoints)); // Can't heal over max if (steal) { result.MinHeal = Math.Min(hptoHeal, Math.Abs(result.MinDamage)); result.MaxHeal = Math.Min(hptoHeal, Math.Abs(result.MaxDamage)); } else { if (hptoHeal > 0) { AdjustDamage(result, (uint)Math.Min(effect.DiceNum, hptoHeal), (uint)Math.Min(effect.DiceFace, hptoHeal), SpellCategory.Healing, chanceToHappen, Fighter.Stats.GetTotal(PlayerFields.HealBonus), Fighter.Stats.GetTotal(PlayerFields.Intelligence), 0, 0, !isFriend); if (result.Heal > hptoHeal) { if (isFriend) { result.MinHeal = result.MaxHeal = +hptoHeal; } else { result.MinHeal = result.MaxHeal = -hptoHeal; } } } } } if ((category & SpellCategory.Buff) > 0) { if (isFriend) { result.Boost += spell.CurrentLevel * chanceToHappen; } else { result.Boost -= spell.CurrentLevel * chanceToHappen; } } if ((category & SpellCategory.Curse) > 0) { var ratio = spell.CurrentLevel * chanceToHappen; if (effect.EffectId == EffectsEnum.Effect_SkipTurn) // Let say this effect counts as 2 damage per level of the target { ratio = target.Level * 2 * chanceToHappen; } if (isFriend) { result.Curse -= 2 * ratio; } else { result.Curse += ratio; } } if (isFriend) { result.Add(result); // amplify (double) effects on friends. } if (!isFriend && ((category & SpellCategory.Damages) > 0) && result.MinDamage > target.LifePoints) // Enough damage to kill the target => affect an arbitrary 50% of max heal (with at least current health), so strong spells are not favored anymore. { double ratio = Math.Max(target.MaxLifePoints / 2d, target.LifePoints) / result.MinDamage; result.Multiply(ratio); } if (spellImpact != null) { spellImpact.Add(result); } else { spellImpact = result; } }
public AISpellCastPossibility FindFirstSpellCast() { var casts = new List <AISpellCastPossibility>(); var minUsedAP = 0; var minUsedPM = 0; foreach (var priority in Priorities.OrderByDescending(x => x.Value)) { // find best spell var impactComparer = new SpellImpactComparer(this, priority.Key); foreach (var possibleCast in Possibilities.OrderByDescending(x => x, new SpellCastComparer(this, priority.Key))) { var category = SpellIdentifier.GetSpellCategories(possibleCast.Spell); var dummy = possibleCast; if ((category & priority.Key) == 0 || casts.Any(x => x.Spell == dummy.Spell)) // spell already used { continue; } if (Fighter.AP - minUsedAP < possibleCast.Spell.CurrentSpellLevel.ApCost) { continue; } if (possibleCast.IsSummoningSpell) { var target = new SpellTarget() { Target = new TargetCell(possibleCast.SummonCell), CastCell = Fighter.Cell, AffectedCells = new [] { possibleCast.SummonCell } }; casts.Add(new AISpellCastPossibility(possibleCast.Spell, target)); minUsedAP += (int)possibleCast.Spell.CurrentSpellLevel.ApCost; continue; } // find best target foreach (var impact in possibleCast.Impacts.OrderByDescending(x => x, impactComparer)) { if (impactComparer.GetScore(impact) <= 0) { continue; } Cell castSpell = impact.CastCell; var cast = new AISpellCastPossibility(possibleCast.Spell, impact); if (castSpell == Fighter.Cell) { casts.Add(cast); minUsedAP += (int)possibleCast.Spell.CurrentSpellLevel.ApCost; continue; } var pathfinder = new Pathfinder(m_environment.CellInformationProvider); var path = pathfinder.FindPath(Fighter.Position.Cell.Id, castSpell.Id, false); if (path.IsEmpty() || path.MPCost > Fighter.MP) { continue; } cast.MoveBefore = path; casts.Add(cast); minUsedAP += (int)possibleCast.Spell.CurrentSpellLevel.ApCost; minUsedPM += path.MPCost; break; } } } if (casts.Count > 1) { // check if the second spell can be casted before var max = MaxConsecutiveSpellCast(casts[0].Spell, Fighter.AP); if (casts[1].Spell.CurrentSpellLevel.ApCost <= Fighter.AP - max * casts[0].Spell.CurrentSpellLevel.ApCost && casts[0].MoveBefore != null) { if (casts[1].MoveBefore == null) { return(casts[1]); } var pathfinder = new Pathfinder(m_environment.CellInformationProvider); var path = pathfinder.FindPath(casts[1].MoveBefore.EndCell.Id, casts[0].MoveBefore != null ? casts[0].MoveBefore.EndCell.Id : Fighter.Cell.Id, false); if (!path.IsEmpty() && path.MPCost + casts[1].MPCost <= Fighter.MP) { return(casts[1]); } } } return(casts.FirstOrDefault()); }
private static void AdjustDamage(SpellTarget damages, uint damage1, uint damage2, SpellCategory category, double chanceToHappen, int addDamage, int addDamagePercent, int reduceDamage, int reduceDamagePercent, bool negativ) { double num = damage1; double num2 = (damage1 >= damage2) ? damage1 : damage2; if (reduceDamagePercent < 100) { num = (num * (1.0 + (double)addDamagePercent / 100.0) + (double)addDamage - (double)reduceDamage) * (1.0 - (double)reduceDamagePercent / 100.0) * chanceToHappen; num2 = (num2 * (1.0 + (double)addDamagePercent / 100.0) + (double)addDamage - (double)reduceDamage) * (1.0 - (double)reduceDamagePercent / 100.0) * chanceToHappen; if (num < 0.0) { num = 0.0; } if (num2 < 0.0) { num2 = 0.0; } if (negativ) { num *= -1.5; num2 *= -1.5; } if (category <= SpellCategory.DamagesEarth) { if (category != SpellCategory.Healing) { if (category != SpellCategory.DamagesWater) { if (category == SpellCategory.DamagesEarth) { damages.MinEarth += num; damages.MaxEarth += num2; } } else { damages.MinWater += num; damages.MaxWater += num2; } } else { damages.MinHeal += num; damages.MaxHeal += num2; } } else { if (category != SpellCategory.DamagesAir) { if (category != SpellCategory.DamagesFire) { if (category == SpellCategory.DamagesNeutral) { damages.MinNeutral += num; damages.MaxNeutral += num2; } } else { damages.MinFire += num; damages.MaxAir += num2; } } else { damages.MinAir += num; damages.MaxAir += num2; } } } }
private void CumulEffects(EffectDice effect, ref SpellTarget spellImpact, FightActor target, Spell spell) { bool flag = this.Fighter.Team.Id == target.Team.Id; SpellTarget spellTarget = new SpellTarget(); SpellTargetType arg_2A_0 = effect.Targets; SpellCategory effectCategories = SpellIdentifier.GetEffectCategories(effect.EffectId); if (effectCategories != SpellCategory.None) { double num = 1.0; if (effect.Random > 0) { num = (double)effect.Random / 100.0; } if (target is SummonedFighter) { num /= 2.0; } uint damage = (uint)System.Math.Min(effect.DiceNum, effect.DiceFace); uint damage2 = (uint)System.Math.Max(effect.DiceNum, effect.DiceFace); if ((effectCategories & SpellCategory.DamagesNeutral) > SpellCategory.None) { SpellSelector.AdjustDamage(spellTarget, damage, damage2, SpellCategory.DamagesNeutral, num, this.Fighter.Stats.GetTotal(PlayerFields.NeutralDamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.PhysicalDamage), this.Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + this.Fighter.Stats.GetTotal(PlayerFields.Strength), target.Stats.GetTotal(PlayerFields.NeutralElementReduction), target.Stats.GetTotal(PlayerFields.NeutralResistPercent), flag); } if ((effectCategories & SpellCategory.DamagesFire) > SpellCategory.None) { SpellSelector.AdjustDamage(spellTarget, damage, damage2, SpellCategory.DamagesNeutral, num, this.Fighter.Stats.GetTotal(PlayerFields.FireDamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.MagicDamage), this.Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + this.Fighter.Stats.GetTotal(PlayerFields.Intelligence), target.Stats.GetTotal(PlayerFields.FireElementReduction), target.Stats.GetTotal(PlayerFields.FireResistPercent), flag); } if ((effectCategories & SpellCategory.DamagesAir) > SpellCategory.None) { SpellSelector.AdjustDamage(spellTarget, damage, damage2, SpellCategory.DamagesNeutral, num, this.Fighter.Stats.GetTotal(PlayerFields.AirDamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.MagicDamage), this.Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + this.Fighter.Stats.GetTotal(PlayerFields.Agility), target.Stats.GetTotal(PlayerFields.AirElementReduction), target.Stats.GetTotal(PlayerFields.AirResistPercent), flag); } if ((effectCategories & SpellCategory.DamagesWater) > SpellCategory.None) { SpellSelector.AdjustDamage(spellTarget, damage, damage2, SpellCategory.DamagesNeutral, num, this.Fighter.Stats.GetTotal(PlayerFields.WaterDamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.MagicDamage), this.Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + this.Fighter.Stats.GetTotal(PlayerFields.Chance), target.Stats.GetTotal(PlayerFields.WaterElementReduction), target.Stats.GetTotal(PlayerFields.WaterResistPercent), flag); } if ((effectCategories & SpellCategory.DamagesEarth) > SpellCategory.None) { SpellSelector.AdjustDamage(spellTarget, damage, damage2, SpellCategory.DamagesNeutral, num, this.Fighter.Stats.GetTotal(PlayerFields.EarthDamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.DamageBonus) + this.Fighter.Stats.GetTotal(PlayerFields.PhysicalDamage), this.Fighter.Stats.GetTotal(PlayerFields.DamageBonusPercent) + this.Fighter.Stats.GetTotal(PlayerFields.Strength), target.Stats.GetTotal(PlayerFields.EarthElementReduction), target.Stats.GetTotal(PlayerFields.EarthResistPercent), flag); } if ((effectCategories & SpellCategory.Healing) > SpellCategory.None) { bool flag2; if (flag2 = ((effectCategories & SpellCategory.Damages) > SpellCategory.None)) { target = this.Fighter; } uint num2 = (uint)System.Math.Max(0, target.MaxLifePoints - target.LifePoints); if (flag2) { spellTarget.MinHeal = System.Math.Min(num2, System.Math.Abs(spellTarget.MinDamage)); spellTarget.MaxHeal = System.Math.Min(num2, System.Math.Abs(spellTarget.MaxDamage)); } else { if (num2 > 0u) { SpellSelector.AdjustDamage(spellTarget, (uint)System.Math.Min((long)effect.DiceNum, (long)((ulong)num2)), (uint)System.Math.Min((long)effect.DiceFace, (long)((ulong)num2)), SpellCategory.Healing, num, this.Fighter.Stats.GetTotal(PlayerFields.HealBonus), this.Fighter.Stats.GetTotal(PlayerFields.Intelligence), 0, 0, !flag); if (spellTarget.Heal > num2) { if (flag) { spellTarget.MinHeal = (spellTarget.MaxHeal = num2); } else { spellTarget.MinHeal = (spellTarget.MaxHeal = (double)(-(double)((ulong)num2))); } } } } } if ((effectCategories & SpellCategory.Buff) > SpellCategory.None) { if (flag) { spellTarget.Boost += (double)spell.CurrentLevel * num; } else { spellTarget.Boost -= (double)spell.CurrentLevel * num; } } if ((effectCategories & SpellCategory.Curse) > SpellCategory.None) { double num3 = (double)spell.CurrentLevel * num; if (effect.EffectId == EffectsEnum.Effect_SkipTurn) { num3 = (double)(target.Level * 2) * num; } if (flag) { spellTarget.Curse -= 2.0 * num3; } else { spellTarget.Curse += num3; } } if (flag) { spellTarget.Add(spellTarget); } if (!flag && (effectCategories & SpellCategory.Damages) > SpellCategory.None && spellTarget.MinDamage > (double)target.LifePoints) { double num3 = System.Math.Max((double)target.MaxLifePoints / 2.0, (double)target.LifePoints) / spellTarget.MinDamage; spellTarget.Multiply(num3); } if (spellImpact != null) { spellImpact.Add(spellTarget); } else { spellImpact = spellTarget; } } }
public void AnalysePossibilities() { this.Possibilities = new System.Collections.Generic.List <SpellCastInformations>(); foreach (Spell current in this.Fighter.Spells.Values) { SpellCategory spellCategories = SpellIdentifier.GetSpellCategories(current); SpellLevelTemplate currentSpellLevel = current.CurrentSpellLevel; SpellCastInformations spellCastInformations = new SpellCastInformations(current); if ((long)this.Fighter.AP >= (long)((ulong)currentSpellLevel.ApCost) && !currentSpellLevel.StatesForbidden.Any(new Func <int, bool>(this.Fighter.HasState))) { if (!currentSpellLevel.StatesRequired.Any((int state) => !this.Fighter.HasState(state)) && this.Fighter.SpellHistory.CanCastSpell(current.CurrentSpellLevel)) { if ((spellCategories & SpellCategory.Summoning) != SpellCategory.None && this.Fighter.CanSummon()) { Cell freeAdjacentCell = this.m_environment.GetFreeAdjacentCell(); if (freeAdjacentCell == null) { continue; } spellCastInformations.IsSummoningSpell = true; spellCastInformations.SummonCell = freeAdjacentCell; } else { foreach (FightActor current2 in from fighter in this.Fighter.Fight.Fighters where fighter.IsAlive() && fighter.IsVisibleFor(this.Fighter) select fighter) { int mPToUse; if (this.CanReach(current2, current, out mPToUse) && this.Fighter.SpellHistory.CanCastSpell(current.CurrentSpellLevel, current2.Cell)) { spellCastInformations.MPToUse = mPToUse; SpellTarget spellTarget = this.ComputeSpellImpact(current, current2); if (spellTarget != null) { spellTarget.Target = current2; if (spellTarget.Damage >= 0.0) { spellCastInformations.Impacts.Add(spellTarget); } } } } } this.Possibilities.Add(spellCastInformations); } } } if (Brain.Brain.DebugMode) { Debug.WriteLine(this.Fighter.Name); using (System.Collections.Generic.Dictionary <int, Spell> .ValueCollection.Enumerator enumerator = this.Fighter.Spells.Values.GetEnumerator()) { while (enumerator.MoveNext()) { Spell spell = enumerator.Current; Debug.WriteLine("Spell {0} ({1}) :: {2}", new object[] { spell.Template.Name, spell.Id, SpellIdentifier.GetSpellCategories(spell) }); System.Collections.Generic.IEnumerable <SpellCastInformations> arg_2C4_0 = this.Possibilities; Func <SpellCastInformations, bool> predicate = (SpellCastInformations x) => x.Spell == spell; SpellCastInformations spellCastInformations2 = arg_2C4_0.FirstOrDefault(predicate); if (spellCastInformations2 != null) { if (spellCastInformations2.IsSummoningSpell) { Debug.WriteLine("\tSummon Spell"); } else { ObjectDumper objectDumper = new ObjectDumper(8); objectDumper.MemberPredicate = ((System.Reflection.MemberInfo member) => !member.Name.Contains("Target")); ObjectDumper objectDumper2 = objectDumper; Debug.WriteLine("\t{0} Targets", new object[] { spellCastInformations2.Impacts.Count }); foreach (SpellTarget spellTarget in spellCastInformations2.Impacts) { Debug.Write(objectDumper2.DumpElement(spellTarget)); if (spellTarget.Target != null) { Debug.WriteLine("\t\tTarget = " + spellTarget.Target + spellTarget.Target.Id.ToString()); } } } } } } Debug.WriteLine(""); } }