public static AttackOutcome RunCombat(Character _attacker, Character _defender, double AttackRoll, double DefendRoll, Utilities.BodyParts?location) { AttackOutcome outcome = new AttackOutcome(); _attacker.CombatStuff.aoForEnchantments = outcome; _defender.CombatStuff.aoForEnchantments = outcome; outcome.attackRoll = AttackRoll; outcome.defendRoll = DefendRoll; //this is to give the option of one-roll combat on the specific input of DefensiveRoll == -999.0 /* * if (DefendRoll == -999.0) * { * DefendRoll = 20 - AttackRoll; * }*/ outcome.Attacker = _attacker; outcome.Defender = _defender; Weapon _attackerSelectedWeapon = _attacker.CombatStuff.CombatWeapon; Weapon _defenderSelectedWeapon = _defender.CombatStuff.CombatWeapon; Shield _attackerSelectedShield = _attacker.CombatStuff.CombatShield; Shield _defenderSelectedShield = _defender.CombatStuff.CombatShield; outcome.Notes.attackerWeaponName = _attackerSelectedWeapon.ItemName; outcome.Notes.defenderWeaponName = _defenderSelectedWeapon.ItemName; outcome.Notes.stun = -1 * EffectHolder.GetValidEffectsByEffect(_defender, EffectHolder.EffectType.Focus); double _attackerWeightFactor = GetWeightFactor(_attacker); double _defenderWeightFactor = GetWeightFactor(_defender); double _attackerStaminaFactor = GetStaminaFactor(_attacker); double _defenderStaminaFactor = GetStaminaFactor(_defender); //primary calculators double offensiveCalculator = (AttackRoll + _attacker.CombatStuff.CombatOB + _attackerSelectedWeapon.OffensiveBonus + _attackerSelectedShield.OffensiveBonus + EffectHolder.GetValidEffectsByEffect(_attacker, EffectHolder.EffectType.OB) + _attackerWeightFactor) * _attackerStaminaFactor; double defensiveCalculator = (DefendRoll + _defender.CombatStuff.CombatDB + _defenderSelectedWeapon.DefensiveBonus + _defenderSelectedShield.DefensiveBonus + EffectHolder.GetValidEffectsByEffect(_defender, EffectHolder.EffectType.DB) + _defenderWeightFactor) * _defenderStaminaFactor; foreach (Armor a in _attacker.Armor) { offensiveCalculator += a.OffensiveBonus; } foreach (Armor a in _defender.Armor) { defensiveCalculator += a.DefensiveBonus; } outcome.Notes.attackroll = AttackRoll; outcome.Notes.attackValue = offensiveCalculator; outcome.Notes.defendRoll = DefendRoll; outcome.Notes.defendValue = defensiveCalculator; EnchantmentUtilities.triggerAllEnchantmentsForChar(_attacker, new EnchantmentParameters() { triggerSource = EnchantmentUtilities.SourceTypes.Attack }); EnchantmentUtilities.triggerAllEnchantmentsForChar(_defender, new EnchantmentParameters() { triggerSource = EnchantmentUtilities.SourceTypes.WasAttacked }); //generate reflex double defenderReflex = CalculateReflex(_defender, defensiveCalculator); //adjust by a percentage if stamina is low defenderReflex = defenderReflex * _defenderStaminaFactor; outcome.Notes.reflex = defenderReflex; //generate blocking difficulty double attackerBlockingDifficulty = _attackerSelectedWeapon.BlockingDifficulty + EffectHolder.GetValidEffectsByEffect(_attacker, EffectHolder.EffectType.BlockingDifficulty) + 0.2 * offensiveCalculator; outcome.Notes.blockingDifficulty = attackerBlockingDifficulty; //apply 25% of blocking difficulty defensiveCalculator -= attackerBlockingDifficulty * 0.25; //generate block double defenderBlock = defensiveCalculator * (_defenderSelectedShield.Coverage + EffectHolder.GetValidEffectsByEffect(_defender, EffectHolder.EffectType.ShieldCoverage)); outcome.Notes.block = defenderBlock; //apply rest of blocking difficulty defensiveCalculator -= attackerBlockingDifficulty * 0.75; //generate parry double defenderParry = defensiveCalculator * _defenderSelectedWeapon.ParryStrength / System.Math.Max(_attackerSelectedWeapon.ParryBreak, 0.01); outcome.Notes.parryBreak = _attackerSelectedWeapon.ParryBreak; outcome.Notes.parryStrength = _defenderSelectedWeapon.ParryStrength; outcome.Notes.parry = defenderParry; outcome.Notes.defendValueAfterBlockingDifficulty = defensiveCalculator; //perform dodge if (defenderReflex > 0) { offensiveCalculator -= defenderReflex; } //if the attack has been reduced to 0, it was dodged if (offensiveCalculator <= 0) { outcome.Othertext = Utilities.AttackResultType.Miss; outcome.HitCaliber = offensiveCalculator; return(outcome); } outcome.Notes.attackAfterReflex = offensiveCalculator; //perform block if (defenderBlock > 0) { offensiveCalculator -= defenderBlock; } //if the attack has been reduced to 0, it was blocked if (offensiveCalculator <= 0) { outcome.Othertext = Utilities.AttackResultType.Block; outcome.HitCaliber = offensiveCalculator; return(outcome); } outcome.Notes.attackAfterBlock = offensiveCalculator; //perform parry if (defenderParry > 0) { offensiveCalculator -= defenderParry; } //if the attack has been reduced to 0, it was parried if (offensiveCalculator <= 0) { outcome.Othertext = Utilities.AttackResultType.Parry; outcome.HitCaliber = offensiveCalculator; return(outcome); } outcome.Notes.attackAfterParry = offensiveCalculator; if (location == null) { Utilities.FindCritLocation(outcome); } else { outcome.HitLocation = (Utilities.BodyParts)location; } //otherwise, attacker hit! do damage/armor calculation Dictionary <Utilities.DamageType, Double> tempDamageValues = new Dictionary <Utilities.DamageType, double>(); foreach (Utilities.DamageType dt in _attackerSelectedWeapon.DamageTypes.Keys) { tempDamageValues.Add(dt, _attackerSelectedWeapon.DamageTypes[dt]); } foreach (Utilities.DamageType dt in Enum.GetValues(typeof(Utilities.DamageType))) { double addedDamage = EffectHolder.GetValidEffectsByEffectAndDamageType(_attacker, EffectHolder.EffectType.WeaponDamage, dt); if (addedDamage != 0) { if (tempDamageValues.ContainsKey(dt)) { tempDamageValues[dt] += addedDamage; } else { tempDamageValues.Add(dt, addedDamage); } } } foreach (Utilities.DamageType dt in tempDamageValues.Keys) { Double strikeAmountForDamageType = offensiveCalculator * tempDamageValues[dt]; outcome.HitStrength = outcome.HitStrength + strikeAmountForDamageType; outcome.Notes.damageBeforeArmor = outcome.HitStrength; //actually percentage of damage that will go through double damageResistance = 1.0 - EffectHolder.GetValidEffectsByEffectAndDamageType(_defender, EffectHolder.EffectType.DamageResistance, null); damageResistance -= EffectHolder.GetValidEffectsByEffectAndDamageType(_defender, EffectHolder.EffectType.DamageResistance, dt); foreach (Armor arm in _defender.Armor) { if (arm.CoveredAreas.Contains(outcome.HitLocation) && arm.DamageResistanceTypes.ContainsKey(dt)) { //subtraction because a lower percentage of the damage will get through damageResistance -= (arm.DamageResistanceTypes[dt]); } } outcome.DamageTypes.Add(dt, Math.Max(0, (strikeAmountForDamageType * damageResistance))); } double generalDamageReduction = EffectHolder.GetValidEffectsByEffectAndDamageType(_defender, EffectHolder.EffectType.DamageReduction, null); double totalDamageBeforeReduction = outcome.TotalStrikeAmountFromAllTypes(); //weird things happen if this is less than or equal to zero if (totalDamageBeforeReduction > 0) { foreach (Utilities.DamageType dt in tempDamageValues.Keys) { //the amount of damage that will be prevented outcome.DamageTypes[dt] -= generalDamageReduction * (outcome.DamageTypes[dt] / totalDamageBeforeReduction); outcome.DamageTypes[dt] -= EffectHolder.GetValidEffectsByEffectAndDamageType(_defender, EffectHolder.EffectType.DamageReduction, dt); foreach (Armor arm in _defender.Armor) { if (arm.CoveredAreas.Contains(outcome.HitLocation) && arm.DamageReductionTypes.ContainsKey(dt)) { outcome.DamageTypes[dt] -= (arm.DamageReductionTypes[dt]); } } if (outcome.DamageTypes[dt] < 0) { outcome.DamageTypes[dt] = 0; } } } outcome.Notes.damageAfterArmor = outcome.TotalStrikeAmountFromAllTypes(); outcome.Othertext = Utilities.AttackResultType.Hit; outcome.HitCaliber = offensiveCalculator; CritCalculator.CalculateCrit(outcome); EnchantmentUtilities.triggerAllEnchantmentsForChar(_attacker, new EnchantmentParameters() { triggerSource = EnchantmentUtilities.SourceTypes.PostAttack }); EnchantmentUtilities.triggerAllEnchantmentsForChar(_defender, new EnchantmentParameters() { triggerSource = EnchantmentUtilities.SourceTypes.PostWasAttacked }); return(outcome); }
private void button1_Click(object sender, EventArgs e) { if (!Utilities.ValidateComboBox(cboBoxChar1.Text)) { return; } if (!Utilities.ValidateComboBox(cboBoxChar2.Text)) { return;/* * if (!Utilities.ValidateComboBox(cboBoxWeapon1.Text)) * return; * if (!Utilities.ValidateComboBox(cboBoxWeapon2.Text)) * return;*/ } Character char1 = Utilities.getCharacterFromXmlOrCombatHolderByString(cboBoxChar1.Text); if (!CombatHolder._inCombatChars.Contains(char1)) { char1.HitPoints = CombatScripts.GetBaseHealth(char1); char1.Stamina = CombatScripts.GetBaseStamina(char1); } Character char2 = Utilities.getCharacterFromXmlOrCombatHolderByString(cboBoxChar2.Text); if (!CombatHolder._inCombatChars.Contains(char1)) { char2.HitPoints = CombatScripts.GetBaseHealth(char2); char2.Stamina = CombatScripts.GetBaseStamina(char2); } Character CharCopy1 = Utilities.GetSameCharWithCurrentState(char1); Character CharCopy2 = Utilities.GetSameCharWithCurrentState(char2); CharCopy1.CombatStuff.CombatOB = Utilities.ParseDoubleFromDangerousString(txtBoxOffensiveBonus.Text); CharCopy1.CombatStuff.CombatWeapon = char1.Weapons.Find(A => A.ItemName == cboBoxWeapon1.Text); CharCopy1.CombatStuff.CombatShield = char1.Shields.Find(A => A.ItemName == cboBoxShield1.Text); if (CharCopy1.CombatStuff.CombatShield == null) { CharCopy1.CombatStuff.CombatShield = new Shield(); } CharCopy2.CombatStuff.CombatDB = Utilities.ParseDoubleFromDangerousString(txtBoxDefensiveBonus.Text); CharCopy2.CombatStuff.CombatWeapon = char2.Weapons.Find(A => A.ItemName == cboBoxWeapon2.Text); CharCopy2.CombatStuff.CombatShield = char2.Shields.Find(A => A.ItemName == cboBoxShield2.Text); if (CharCopy2.CombatStuff.CombatShield == null) { CharCopy2.CombatStuff.CombatShield = new Shield(); } if (checkBoxStartup.Checked) { EnchantmentUtilities.triggerAllEnchantmentsForChar(CharCopy1, new EnchantmentParameters() { triggerSource = EnchantmentUtilities.SourceTypes.CombatEntry }); EnchantmentUtilities.triggerAllEnchantmentsForChar(CharCopy2, new EnchantmentParameters() { triggerSource = EnchantmentUtilities.SourceTypes.CombatEntry }); } _outcome = CombatScripts.RunCombat(Utilities.GetSameCharWithCurrentState(CharCopy1), Utilities.GetSameCharWithCurrentState(CharCopy2), Utilities.ParseDoubleFromDangerousString(txtBoxOffensiveRoll.Text), Utilities.ParseDoubleFromDangerousString(txtBoxDefensiveRoll.Text), null); txtBoxCrit.Text = _outcome.Othertext.ToString(); txtBoxDamage.Text = Convert.ToString(0); lblHitCaliber.Text = Convert.ToString(0); lblHitStrength.Text = Convert.ToString(0); if (_outcome.Othertext.ToString() == "Hit") { lblHitCaliber.Text = "Hit Caliber: " + _outcome.HitCaliber.ToString(); lblHitStrength.Text = "Hit Strength: " + _outcome.HitStrength.ToString(); double damage = _outcome.TotalStrikeAmountFromAllTypes(); txtBoxDamage.Text = Convert.ToString(damage); txtBoxCrit.Text = _outcome.HitLocation.ToString(); AttackOutcome cumulative = new AttackOutcome(); for (int i = 0; i < 1000; i++) { //calculate the same crit every time Utilities.FindCritLocation(_outcome); CritCalculator.CalculateCrit(_outcome); //store it in a different place so it doesnt get reset cumulative.bleed += _outcome.bleed; cumulative.harm += _outcome.harm; cumulative.disorientation += _outcome.disorientation; cumulative.impairment += _outcome.impairment; cumulative.ko += _outcome.ko; cumulative.trauma += _outcome.trauma; } Console.WriteLine("Harm: " + Convert.ToDouble(cumulative.harm) / 1000); Console.WriteLine("Bleed: " + Convert.ToDouble(cumulative.bleed) / 1000); Console.WriteLine("Disorientation: " + Convert.ToDouble(cumulative.disorientation) / 1000); Console.WriteLine("Impairment: " + Convert.ToDouble(cumulative.impairment) / 1000); Console.WriteLine("Trauma: " + Convert.ToDouble(cumulative.trauma) / 1000); Console.WriteLine("KO: " + Convert.ToDouble(cumulative.ko) / 1000); rtbAverageResults.Text = ""; rtbAverageResults.Text += "Harm: " + Convert.ToDouble(cumulative.harm) / 1000 + "\n"; rtbAverageResults.Text += "Bleed: " + Convert.ToDouble(cumulative.bleed) / 1000 + "\n"; rtbAverageResults.Text += "Disorientation: " + Convert.ToDouble(cumulative.disorientation) / 1000 + "\n"; rtbAverageResults.Text += "Impairment: " + Convert.ToDouble(cumulative.impairment) / 1000 + "\n"; rtbAverageResults.Text += "Trauma: " + Convert.ToDouble(cumulative.trauma) / 1000 + "\n"; rtbAverageResults.Text += "KO: " + Convert.ToDouble(cumulative.ko) / 1000 + "\n"; } if (chkBoxGraph.Checked) { AttackChart frmCreator = new AttackChart(Utilities.GetSameCharWithCurrentState(CharCopy1), Utilities.GetSameCharWithCurrentState(CharCopy2)); frmCreator.Show(); } }