private int UpdateKillsCount(int currentCount, FightResult result, SimulationType type) { int count = currentCount; switch (type) { case SimulationType.MinimalDamage: count -= result.KilledMin; break; case SimulationType.MaximalDamage: count -= result.KilledMax; break; case SimulationType.AverageDamage: count -= result.KilledAvg; break; default: break; } if (count < 0) { count = 0; } return(count); }
private void MergeFightResult(FightResult f1, FightResult f2) { f1.DamageAvg += f2.DamageAvg; f1.DamageMax += f2.DamageMax; f1.DamageMin += f2.DamageMin; f1.KilledAvg += f2.KilledAvg; f1.KilledMax += f2.KilledMax; f1.KilledMin += f2.KilledMin; }
private int GetLeftDamage(FightResult result, SimulationType type) { switch (type) { case SimulationType.MinimalDamage: return(result.DamageLeftMin); case SimulationType.MaximalDamage: return(result.DamageLeftMax); case SimulationType.AverageDamage: return(result.DamageLeftAvg); default: return(0); } }
private FightResult CreatureFight(Fight fight, Hero attackerHero, Hero defenderHero, CreatureRef attackerRef, CreatureRef defenderRef, int attackerCount, int defenderCount, TextWriter log, AttackType attackType, int damageLeft = 0) { log.WriteLine("{0} ({1}) attacks {2} ({3})", attackerRef.Name, attackerCount, defenderRef.Name, defenderCount); decimal I1 = 0, R1 = 0; decimal I2 = 0, I3 = 0, I4 = 0, I5 = 0, R2 = 0, R3 = 0, R4 = 0, R5 = 0, R6 = 0, R7 = 0, R8 = 0; int DMGbmin = 0; int DMGbmax = 0; // TODO: check for spells modification for DMGb Creature attacker = World.Creatures[attackerRef.Name]; Creature defender = World.Creatures[defenderRef.Name]; if (attackType == AttackType.Ranged && !System.Array.Exists(attacker.AttackType, element => element == AttackType.Ranged)) { log.WriteLine("{0} cannot attack ranged. Attack type changed to Melee", attackerRef.Name); attackType = AttackType.Melee; } Dictionary <FactorType, List <FactorInfo> > attackerFactors = new Dictionary <FactorType, List <FactorInfo> >(); Dictionary <FactorType, List <FactorInfo> > defenderFactors = new Dictionary <FactorType, List <FactorInfo> >(); // Loading heroes factors AddHeroFactors(attackerFactors, attackerHero, fight, attacker, defender, attackType, attackerRef, defenderRef); AddHeroFactors(defenderFactors, defenderHero, fight, attacker, defender, attackType, attackerRef, defenderRef); // Loading creature factors AddCreatureFactors(attackerFactors, attackerRef, fight, attacker, defender, attackType, attackerRef, defenderRef); AddCreatureFactors(defenderFactors, defenderRef, fight, attacker, defender, attackType, attackerRef, defenderRef); // I1 & R1 // basic I1 & R1 int attack = attackerHero.Attack + attacker.Attack; int defense = defenderHero.Defense + defender.Defense; if (attacker.Terrain[0] == fight.Terrain[0]) { attack += 1; log.WriteLine("+1 added to atack to {0} for terrain bonus", attacker.Name); } if (defender.Terrain[0] == fight.Terrain[0]) { defense += 1; log.WriteLine("+1 added to defense to {0} for terrain bonus", defender.Name); } DMGbmin = attacker.MinDamage; DMGbmax = attacker.MaxDamage; int dmg = System.Convert.ToInt32(ExecuteFactor(FactorType.I0, attackerFactors, defenderFactors, attackerHero, attacker, log)); if (dmg > 0) { DMGbmax += dmg; log.WriteLine("{0} added to DMGMax.", DMGbmax); } DMGbmin = DMGbmin * attackerCount; DMGbmax = DMGbmax * attackerCount; attack += System.Convert.ToInt32(ExecuteFactor(FactorType.I1, attackerFactors, defenderFactors, attackerHero, attacker, log)); defense += System.Convert.ToInt32(ExecuteFactor(FactorType.R1, defenderFactors, defenderFactors, defenderHero, defender, log)); attack = System.Convert.ToInt32(attack * (1 - ExecuteFactor(FactorType.IgnoreAttack, defenderFactors, defenderFactors, attackerHero, attacker, log))); defense = System.Convert.ToInt32(defense * (1 - ExecuteFactor(FactorType.IgnoreDefense, attackerFactors, defenderFactors, attackerHero, attacker, log))); if (attack >= defense) { I1 = (decimal)0.05 * (attack - defense); if (I1 > 3) { I1 = 3; } log.WriteLine("Attack({1}) > Defense({2}), I1={0}", I1, attack, defense); } if (defense >= attack) { R1 = (decimal)0.025 * (defense - attack); if (R1 >= (decimal)0.7) { R1 = (decimal)0.7; } log.WriteLine("Defense({1}) > Attack({2}), R1={0}", R1, defense, attack); } I2 = ExecuteFactor(FactorType.I2, attackerFactors, defenderFactors, attackerHero, attacker, log); log.WriteLine("I2 value: {0}", I2); I3 = ExecuteFactor(FactorType.I3, attackerFactors, defenderFactors, attackerHero, attacker, log, I2); log.WriteLine("I3 value: {0}", I3); if (attackerRef.Luck) { I4 = 1; } log.WriteLine("I4 (luck) value: {0}", I4); I5 = ExecuteFactor(FactorType.I5, attackerFactors, defenderFactors, attackerHero, attacker, log); log.WriteLine("I5 value: {0}", I5); R2 = ExecuteFactor(FactorType.R2, defenderFactors, defenderFactors, defenderHero, defender, log, I2); log.WriteLine("R2 value: {0}", R2); R3 = ExecuteFactor(FactorType.R3, defenderFactors, defenderFactors, defenderHero, defender, log, I2, R2); log.WriteLine("R3 value: {0}", R3); R4 = ExecuteFactor(FactorType.R4, defenderFactors, defenderFactors, defenderHero, defender, log, I2, R2); log.WriteLine("R4 value: {0}", R4); if ((attackType == AttackType.Ranged && attackerRef.RangePenalty == Penalty.value50) || ((attackType == AttackType.Melee) && System.Array.Exists(attacker.AttackType, element => element == AttackType.Ranged) && !attackerFactors.ContainsKey(FactorType.NoMeleePenalty)) ) { R5 = (decimal)0.5; } log.WriteLine("R5 (melee or ranged penalty) value: {0}", R5); if (attackType == AttackType.Ranged && attackerRef.ObstaclePenalty == Penalty.value50) { R6 = (decimal)0.5; } log.WriteLine("R6 (obstacle penalty) value: {0}", R6); R7 = ExecuteFactor(FactorType.R7, defenderFactors, defenderFactors, attackerHero, attacker, log, I2, R2); log.WriteLine("R7 value: {0}", R7); R8 = ExecuteFactor(FactorType.R8, defenderFactors, defenderFactors, defenderHero, defender, log, I2, R2); log.WriteLine("R8 value: {0}", R8); decimal damageMin = DMGbmin * (1 + I1 + I2 + I3 + I4 + I5) * (1 - R1) * (1 - R2 - R3) * (1 - R4) * (1 - R5) * (1 - R6) * (1 - R7) * (1 - R8); decimal damageMax = DMGbmax * (1 + I1 + I2 + I3 + I4 + I5) * (1 - R1) * (1 - R2 - R3) * (1 - R4) * (1 - R5) * (1 - R6) * (1 - R7) * (1 - R8); log.WriteLine("Damage min: {0}, Damage max: {1}", damageMin, damageMax); int damageMinInt = System.Convert.ToInt32(System.Math.Ceiling(damageMin)); int damageMaxInt = System.Convert.ToInt32(System.Math.Ceiling(damageMax)); // side effect of Armorer - if damage is not int and defender has armorer secondardy skill then damage is decreased by 1 bool armorer = false; if (damageMin - damageMinInt == 0 || damageMax - damageMaxInt == 0) { int i = 0; foreach (object refItem in defenderHero.Items) { if (refItem is Reference && defenderHero.ItemsElementName[i].ToString() == "SecondarySkill") { if (((Reference)refItem).Name == "Armorer") { armorer = true; } } ++i; } if (armorer && damageMin - damageMinInt == 0) { damageMinInt--; log.WriteLine("Side effect of armorer for min damage added"); } if (armorer && damageMax - damageMaxInt == 0) { damageMaxInt--; log.WriteLine("Side effect of armorer for max damage added"); } } FightResult result = new FightResult(); result.DamageMin = damageMinInt; result.DamageMax = damageMaxInt; result.DamageAvg = (damageMinInt + damageMaxInt) / 2; result.KilledMin = System.Convert.ToInt32(System.Math.Floor((decimal)(result.DamageMin) / (decimal)defender.Health)); result.KilledMax = System.Convert.ToInt32(System.Math.Floor((decimal)(result.DamageMax) / (decimal)defender.Health)); result.KilledAvg = System.Convert.ToInt32(System.Math.Floor((decimal)(result.DamageAvg) / (decimal)defender.Health)); log.WriteLine("Left {0} damage for {1} from previous rounds", damageLeft, defenderRef.Name); if (damageLeft == 0) { damageLeft = defender.Health; } if (result.KilledMin > defenderCount) { result.KilledMin = defenderCount; } else { result.DamageLeftMin = damageLeft - result.DamageMin % defender.Health; if (result.DamageLeftMin <= 0) { if (result.DamageLeftMin < 0) { result.DamageLeftMin = defender.Health + result.DamageLeftMin; } ++result.KilledMin; } } if (result.KilledMax > defenderCount) { result.KilledMax = defenderCount; } else { result.DamageLeftMax = damageLeft - result.DamageMax % defender.Health; if (result.DamageLeftMax <= 0) { if (result.DamageLeftMax < 0) { result.DamageLeftMax = defender.Health + result.DamageLeftMax; } ++result.KilledMax; } } if (result.KilledAvg > defenderCount) { result.KilledAvg = defenderCount; } else { result.DamageLeftAvg = damageLeft - result.DamageAvg % defender.Health; if (result.DamageLeftAvg <= 0) { if (result.DamageLeftAvg < 0) { result.DamageLeftAvg = defender.Health + result.DamageLeftAvg; } ++result.KilledAvg; } } log.WriteLine("Damage min: {0} ronuded, Damage max: {1} rounded", damageMinInt, damageMaxInt); log.WriteLine("{0} killed min: {1}, max: {2} {3}", attacker.Name, result.KilledMin, result.KilledMax, defender.Name); if (attackType == AttackType.Ranged) { log.WriteLine("Ranged attack, no Retaliations"); result.Retaliations = 0; } else { if (attackerFactors.ContainsKey(FactorType.NoEnemyRetaliation)) { log.WriteLine("{0} has no Retaliations ability", attackerRef.Name); result.Retaliations = 0; } else { result.Retaliations = 1; log.WriteLine("{0} relaties once", defenderRef.Name); } } if (attackType == AttackType.Melee && attackerFactors.ContainsKey(FactorType.StrikesTwice)) { log.WriteLine("{0} has double attack", attackerRef.Name); result.DoubleAttack = true; } if (attackType == AttackType.Ranged && attackerFactors.ContainsKey(FactorType.ShootsTwice)) { log.WriteLine("{0} has double attack", attackerRef.Name); result.DoubleAttack = true; } return(result); }
private void CreatureFightSimulation(Fight fight, SimulationType type, FightSimulationResult.Info info, CreatureRef attackerRef, CreatureRef defenderRef, TextWriter log) { string val = string.Format("Fight simulation ({2}) between {0} and {1}", attackerRef.Name, defenderRef.Name, System.Enum.GetName(type.GetType(), type)); string dash = new string('-', val.Length); log.WriteLine(dash); log.WriteLine(val); log.WriteLine(dash); AttackType attackType = attackerRef.AttackType[0]; int attackerCount = attackerRef.Count; int attackerDamageLeft = 0; int defenderCount = defenderRef.Count; int defenderDamageLeft = 0; CreatureRef currentAttackerRef = attackerRef; CreatureRef currentDefenderRef = defenderRef; Hero attackerHero = Fight.Attacker; Hero defenderHero = Fight.Defender; int rounds = 0; do { log.WriteLine("ROUND: {0}", rounds + 1); log.WriteLine("*** Strike ***"); FightResult strike = CreatureFight(Fight, attackerHero, defenderHero, currentAttackerRef, currentDefenderRef, attackerCount, defenderCount, log, attackType, defenderDamageLeft); defenderCount = UpdateKillsCount(defenderCount, strike, type); defenderDamageLeft = GetLeftDamage(strike, type); FightResult counterStrike = new FightResult(); int retaliations = strike.Retaliations; if (retaliations > 0 && defenderCount > 0) { log.WriteLine("*** Counterstrike ***"); log.WriteLine("Conterstrike attack, atack type is always melee"); counterStrike = CreatureFight(Fight, defenderHero, attackerHero, currentDefenderRef, currentAttackerRef, defenderCount, attackerCount, log, AttackType.Melee, attackerDamageLeft); --retaliations; attackerCount = UpdateKillsCount(attackerCount, counterStrike, type); attackerDamageLeft = GetLeftDamage(counterStrike, type); } if (strike.DoubleAttack && attackerCount > 0) { log.WriteLine("*** Double Attack ***"); FightResult secondStrike = CreatureFight(Fight, attackerHero, defenderHero, currentAttackerRef, currentDefenderRef, attackerCount, defenderCount, log, attackType, defenderDamageLeft); defenderCount = UpdateKillsCount(defenderCount, secondStrike, type); defenderDamageLeft = GetLeftDamage(secondStrike, type); MergeFightResult(strike, secondStrike); } if (retaliations > 0 && defenderCount > 0) { log.WriteLine("*** Counterstrike ***"); log.WriteLine("Conterstrike attack, atack type is always melee"); FightResult secondCounterStrike = CreatureFight(Fight, defenderHero, attackerHero, currentDefenderRef, currentAttackerRef, defenderCount, attackerCount, log, AttackType.Melee, attackerDamageLeft); --retaliations; attackerCount = UpdateKillsCount(attackerCount, secondCounterStrike, type); attackerDamageLeft = GetLeftDamage(secondCounterStrike, type); MergeFightResult(counterStrike, secondCounterStrike); } if (attackerRef.AttackType[0] == AttackType.Melee || defenderRef.AttackType[0] == AttackType.Melee) { log.WriteLine("One of the fighers did melee attack, rest of the battle is melee."); attackType = AttackType.Melee; } // store info about first attack if (rounds == 0) { info.Strike = strike; switch (type) { case SimulationType.MinimalDamage: info.CounterMin = counterStrike; break; case SimulationType.MaximalDamage: info.CounterMax = counterStrike; break; case SimulationType.AverageDamage: info.CounterAvg = counterStrike; break; default: break; } } CreatureRef tmp = currentDefenderRef; int countTmp = defenderCount; int dmgLeftTmp = defenderDamageLeft; Hero heroTmp = defenderHero; currentDefenderRef = currentAttackerRef; currentAttackerRef = tmp; defenderCount = attackerCount; attackerCount = countTmp; defenderDamageLeft = attackerDamageLeft; attackerDamageLeft = dmgLeftTmp; defenderHero = attackerHero; attackerHero = heroTmp; ++rounds; }while (attackerCount > 0 && defenderCount > 0); FightFinalResult res = new FightFinalResult(); if (rounds % 2 > 0) { res.AttackerLeft = defenderCount; res.DefenderLeft = attackerCount; } else { res.AttackerLeft = attackerCount; res.DefenderLeft = defenderCount; } res.Rounds = rounds; switch (type) { case SimulationType.MinimalDamage: info.FinalMin = res; break; case SimulationType.MaximalDamage: info.FinalMax = res; break; case SimulationType.AverageDamage: info.FinalAvg = res; break; default: break; } }