public static DamageResult RollFTDamage(IDiceUtility roller, int numberOfDice, int drm = 0, int targetScreenRating = 0, bool dealPenetrating = false, int recursionDepth = 0)
        {
            var indent           = string.Empty.PadRight(4 * recursionDepth);
            var penetrationCount = 0;
            var damageResult     = new DamageResult();

            var diceRolled = roller.RollStandardDice(numberOfDice);
            var rolls      = diceRolled.ToList().OrderByDescending(v => v);

/*
 *          Console.WriteLine(
 * $@"{indent}[Rolled {numberOfDice}] dice
 * with DRM {drm}, screen {targetScreenRating}{(dealPenetrating ? ", penetrating" : ", non-penetrating")}
 * : {string.Join(",", rolls)}");
 */
            foreach (var roll in rolls)
            {
                var dieDamage = CountSuccessesOnRoll(roll, drm, targetScreenRating);
                damageResult.StandardRolls.Add(roll);

                if (dieDamage > 0)
                {
                    // Console.WriteLine($"{indent}Roll of {roll} deals {dieDamage} damage");
                    damageResult.Standard += dieDamage;

                    if (roll >= Constants.MinRollForDoubleSuccess && dealPenetrating)
                    {
                        penetrationCount++;
                    }
                }

                // Exit early if dieDamage == 0, since dice are sorted in descending order?
            }

            if (penetrationCount > 0)
            {
                // Console.WriteLine($"{indent}Rolling {penetrationCount} penetrating dice: [");

                // On a "natural" max roll, deal recursive, shield-ignoring, DRM-ignoring, penetrating followup damage
                var penetrationFollowup = FullThrustDieRolls.RollFTDamage(roller, penetrationCount, 0, 0, true, recursionDepth + 1);
                damageResult.Penetrating += penetrationFollowup.Standard;

                // Penetrating damage could ITSELF penetrate, but it all rolls up to just one count of penetrating damage
                // TODO: revisit this; what about the case of multiple layers of armor + multiple penetrating recursions?
                damageResult.Penetrating += penetrationFollowup.Penetrating;

                damageResult.PenetratingRolls.AddRange(penetrationFollowup.StandardRolls);
                damageResult.PenetratingRolls.AddRange(penetrationFollowup.PenetratingRolls);
            }

            return(damageResult);
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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);
        }
        public static int RollFTSuccesses(IDiceUtility roller, int numberOfDice, out IEnumerable <int> rolls, int drm = 0, int difficultyLevel = 0)
        {
            if (numberOfDice == 0)
            {
                rolls = new List <int>();
                return(0); // No successes possible if no dice rolled!
            }

            int    successes  = 0;
            string expression = $"{numberOfDice}D6";

            rolls = roller.RollStandardDice(numberOfDice).OrderByDescending(i => i);

            foreach (int roll in rolls)
            {
                successes += CountSuccessesOnRoll(roll, drm, difficultyLevel);
            }

            return(successes);
        }