public virtual IEnumerable <Wait> RoutineStart() { CalculateDamage(); CalculateArmor(); yield return(Attacker.OnStartAttack(this)); yield return(Defender.OnStartDefend(this)); List <Wait> waits = new List <Wait>(); foreach (var effect in ExtraEffects) { waits.Add(effect.Start(this)); } yield return(new WaitAll(waits)); FinalDamage = Elements.ToDictionary(pair => pair.Key, pair => CalculateSplitElement(pair.Key, pair.Value * Damage)); if (!Unblockable) { var blockChance = Defender.GetStat(Stat.BlockChance); var critBlockChance = Defender.GetStat(Stat.CritBlockChance); CheckBlock(blockChance, critBlockChance, ref Blocked, ref CritBlocked); } if (Blocked || CritBlocked) { var blockValue = Defender.GetStat(Stat.BlockValue); var blockRate = Defender.GetStat(Stat.BlockRate); BlockDamage(blockValue, blockRate); PopupHelper.Add(new MessageText(Defender, "Blocked!")); } foreach (var damage in FinalDamage) { if (damage.Value >= 0) { Defender.TakeDamage(damage.Value, damage.Key, PopupHelper); } else { Defender.Heal(-damage.Value, PopupHelper); } } foreach (var statusEffect in StatusEffects) { Defender.AddStatusEffect(statusEffect); } double total = FinalDamage.Sum(x => Math.Abs(x.Value)); Effect.Apply(new EffectLastHit(Defender, Attacker, total)); if (Defender is Creature creature) { if (HitEffects.Empty() && !NoStandardEffect) { GenerateHitEffects(creature); } Scheduler.Instance.Run(RoutineHitEffects(creature)); } waits.Clear(); foreach (var effect in ExtraEffects) { waits.Add(effect.End(this)); } yield return(new WaitAll(waits)); yield return(Attacker.OnAttack(this)); yield return(Defender.OnDefend(this)); yield return(new WaitAll(Waits)); if (CheckDeath && Defender is Creature targetCreature) { targetCreature.CheckDead(HitDirection); } }