private DamageResult ResolveWeaponAttack(WeaponSystem weapon, int range, ScreenRating screenRating, int evasion = 0, int otherDRM = 0, Constants.DamageType damageTypeModifier = Constants.DamageType.None, AttackSpecialProperties attackPropertiesModifier = AttackSpecialProperties.None) { AttackSpecialProperties effectiveAttackProperties = weapon.FinalizeAttackProperties(attackPropertiesModifier); // Weapons with a hight TrackRating can ignore Evasion, offsetting up to the full Evasion DRM int totalDRM = weapon.FinalizeEvasionDRM(evasion) + otherDRM; // Weapons can ignore certain kinds of shields but not others int totalScreenRating = weapon.FinalizeScreenValue(screenRating, effectiveAttackProperties); Constants.DamageType effectiveDamageType = weapon.FinalizeDamageType(weapon.GetDamageType(), damageTypeModifier, effectiveAttackProperties.HasFlag(AttackSpecialProperties.Overrides_Weapon_DamageType)); // Roll dice here this.Logger.LogInformation($"Attack roll! {weapon.SystemName} -- range {range} | screen {screenRating.ToString()} | net DRM {totalDRM} | {effectiveDamageType.ToString()}-type damage | rating {weapon.Rating}"); /* "Basic" weapon behavior is to shoot like a non-penetrating beam: * 1D per Rating, diminishing with range * 1 damage on a 4 unless screened * 1 damage on a 5, always * 2 damage on a 6, unless double-screened -- then 1 */ DamageResult damageMatrix = FullThrustDieRolls.RollFTDamage(this.DiceUtility, weapon.GetAttackDice(), totalDRM, totalScreenRating, effectiveDamageType.HasFlag(Constants.DamageType.Penetrating)); return(damageMatrix); }
public void TestPenetratingDamageRollup_Screen1_DRM_Zero() { IDiceUtility roller = this.services.GetService <IDiceUtility>(); FullThrustDieRolls.RollFTSuccesses(roller, 1, out IEnumerable <int> rolls); var units = new List <GameUnit>(); var f = GameEngineTestUtilities.GenerateTestFormation(1, "Test Formation", ref units); var fu = f.Units.First(); var u = units[0]; var result = f.RollManeuverSpeedAndEvasion(this.services, f.Orders.First(), f.FormationId, 1, speedDRM: 0, evasionDRM: 0); // Console.WriteLine($"{u.Name} rolls {result.SpeedSuccesses} for Speed and {result.EvasionSuccesses} for Evasion."); // Console.WriteLine("Testing penetrating damage versus Screen Rating 2..."); var damageResult = FullThrustDieRolls .RollFTDamage( new DiceNotationUtility(), numberOfDice: 20, drm: 0, targetScreenRating: 1, dealPenetrating: true); // Console.WriteLine($"Dealt a total of {damageResult.Standard} standard damage and {damageResult.Penetrating} penetrating damage."); Assert.IsNotNull(damageResult); int natural6sOnInitialRoll = damageResult.StandardRolls.Count(r => r == 6); int natural5sOnInitialRoll = damageResult.StandardRolls.Count(r => r == 5); int natural4sOnInitialRoll = damageResult.StandardRolls.Count(r => r == 4); int natural6sOnPenetratingRolls = damageResult.PenetratingRolls.Count(r => r == 6); int natural5sOnPenetratingRolls = damageResult.PenetratingRolls.Count(r => r == 5); int natural4sOnPenetratingRolls = damageResult.PenetratingRolls.Count(r => r == 4); // Since ScreenRating is 1 and DRM is 0, 6s hit for 2 and penetrate; 5s hit for 1; and 4s miss. int expectedStandardDamage = (2 * natural6sOnInitialRoll) + natural5sOnInitialRoll + (0 * natural4sOnInitialRoll); // Penetrating damage ignores screens and DRM int expectedPenetratingDamage = (2 * natural6sOnPenetratingRolls) + natural5sOnPenetratingRolls + natural4sOnPenetratingRolls; Assert.AreEqual(expectedStandardDamage, damageResult.Standard); // Penetration dice all come from 6s in the original roll, OR ELSE from rerolls in the penetration pool Assert.AreEqual(damageResult.PenetratingRolls.Count - natural6sOnPenetratingRolls, natural6sOnInitialRoll); // Penetration dice are unaffected by DRM or screens Assert.AreEqual(expectedPenetratingDamage, damageResult.Penetrating); }
public void TestPenetratingDamageRollup_Screen2_DRM_Minus_One() { IDiceUtility roller = this.services.GetService <IDiceUtility>(); FullThrustDieRolls.RollFTSuccesses(roller, 1, out IEnumerable <int> rolls); var units = new List <GameUnit>(); var f = GameEngineTestUtilities.GenerateTestFormation(1, "Test Formation", ref units); var fu = f.Units.First(); var u = units[0]; var result = f.RollManeuverSpeedAndEvasion(services: this.services, formationOrders: f.Orders.First(), currentVolley: 1, formationId: f.FormationId, speedDRM: 0, evasionDRM: 0); // Console.WriteLine($"{u.Name} rolls {result.SpeedSuccesses} for Speed and {result.EvasionSuccesses} for Evasion."); // Console.WriteLine("Testing penetrating damage versus Screen Rating 2..."); var damageResult = FullThrustDieRolls .RollFTDamage( new DiceNotationUtility(), numberOfDice: 20, drm: -1, targetScreenRating: 2, dealPenetrating: true); // Console.WriteLine($"Dealt a total of {damageResult.Standard} standard damage and {damageResult.Penetrating} penetrating damage."); Assert.IsNotNull(damageResult); // Since ScreenRating is 2 and DRM is -1, only 6's hit (and they all penetrate). int natural6sOnInitialRoll = damageResult.StandardRolls.Count(r => r == 6); int natural6sOnPenetratingRolls = damageResult.PenetratingRolls.Count(r => r == 6); int natural4sAnd5sOnPenetratingRolls = damageResult.PenetratingRolls.Count(r => r == 4 || r == 5); Assert.AreEqual(natural6sOnInitialRoll, damageResult.Standard); Assert.IsTrue(damageResult.PenetratingRolls.Count >= natural6sOnInitialRoll); // Penetration dice all come from 6s in the original roll, OR ELSE from rerolls in the penetration pool Assert.AreEqual(damageResult.PenetratingRolls.Count - natural6sOnPenetratingRolls, natural6sOnInitialRoll); // Penetration dice are unaffected by DRM or screens var penetrationDamageCalc = (2 * natural6sOnPenetratingRolls) + natural4sAnd5sOnPenetratingRolls; Assert.AreEqual(penetrationDamageCalc, damageResult.Penetrating); }