public void DiceChainShouldBeValidlySerialized()
 {
     deserializedD2d20mr3t6p40 = (DiceChain)diceChainSerializer.ReadObject(serializedD2d20mr3t6p40);
     serializedD2d20mr3t6p40.Close();
     Assert.AreEqual(d2d20mr3t6p40.Maximum, deserializedD2d20mr3t6p40.Maximum, "Serialized die maximum is wrong");
     Assert.AreEqual(d2d20mr3t6p40.Minimum, deserializedD2d20mr3t6p40.Minimum, "Serialized die minimum is wrong");
     Assert.AreEqual(d2d20mr3t6p40.ToString(), deserializedD2d20mr3t6p40.ToString(), "Serialized die repr is wrong");
 }
예제 #2
0
        public void BurningHands()
        {
            // Let's create a smart sorcerer first:
            var sorcerer = new Character {
                Int = 16, BurningHandsSpellLevel = 1
            };
            // Then let's create a provider for a modifier derived from the sorcerer's Intelligence:
            var intMod = new IntModProvider {
                Character = sorcerer
            };
            // Create a provider for a spell damage dice count, which depends on the sorcerer's current spell level.
            var spellDiceCount = new BurningHandsDiceCountProvider {
                Character = sorcerer
            };

            // Merge these into a chain:
            DiceChain damageDice = Dice.Take(spellDiceCount).D(8).EachPlus(intMod);
            // Let's burn some poor fella:
            double damage = damageDice.Roll();

            // Let's say we want to display the spell damage, so check the dice chain stats:
            Trace.WriteLine("Damage: " + damageDice.Minimum + " to " + damageDice.Maximum);
            // Outputs 'Damage: 4 to 11', which is equal to '1d8+3', looks good.

            // What if sorcerer gains two levels of proficiency in the spell?
            sorcerer.BurningHandsSpellLevel += 2;
            Console.WriteLine("Damage: " + damageDice.Minimum + " to " + damageDice.Maximum);
            // Outputs 'Damage: 8 to 22', which is equal to '2d8(+3)', once again looks good.
            // Parens mean that 3 is apllied to each die separately instead of affecting dice sum.


            // Now let's say when you miss an enemy with burning hands, you still can deal some damage.
            // In this case damage dealt to the target equals to sum of each damage die that rolled its maximum result.
            // Normally you don't want to deal with individual roll values when using dice chain,
            // but there is a method just in case:

            List <DiceChainRollStep> rollParts;

            // Normal hit damage is returned by dice chain as usual:
            damage = damageDice.RollStepByStep(out rollParts);
            // Damage on a miss is calculated as a sum of each damage die that rolled its maximum result.
            // Looking at dice chain 'Xd8+Y' we can see that damage dice are rolled in the first (leftmost) step.
            double missedDamage = rollParts[0].Rolls.Where(roll => roll == Dice.D8.Maximum).Sum();


            // For the sake of completeness, there is a way of achieving the same thing without a dice chain.
            // That way we have to do all calculations manually.
            // Let's bundle D8 with spell damage dice count:
            var rawSpellDamage = new SeveralDice(Dice.D8, spellDiceCount);
            // Make a damage roll, rolling each die separately:
            var rawRolls = rawSpellDamage.RollSeparately().ToArray();

            // .ToArray() is important here. Otherwise different roll values would be generated on each enumeration.
            // Damage on a miss:
            missedDamage = rawRolls.Where(roll => roll == Dice.D8.Maximum).Sum();
            // Damage on a hit:
            damage = rawRolls.Select(roll => roll + intMod.Roll()).Sum();
        }
예제 #3
0
        /// <summary> Initializes a new instance of the <see cref="DiceChainSetup" /> struct. </summary>
        /// <param name="amountProvider">The amount of dice added to the created <see cref="DiceChain" />.</param>
        /// <param name="previousOperation">The operation to use with previous <see cref="DiceChain"/>.</param>
        /// <param name="previousDice">The previous <see cref="DiceChain"/> to carry on to next one.</param>
        public DiceChainSetup(IDie amountProvider, DiceOperation previousOperation,
                              DiceChain previousDice)
        {
            Contract.Requires(previousOperation != DiceOperation.None);
            Contract.Requires(amountProvider != null);

            Amount            = amountProvider;
            PreviousOperation = previousOperation;
            PreviousDice      = previousDice;
        }
예제 #4
0
        /// <summary> Initializes a new instance of the <see cref="DiceChainSetup" /> struct. </summary>
        /// <param name="amountProvider">The amount of dice added to the created <see cref="DiceChain" />.</param>
        /// <param name="previousOperation">The operation to use with previous <see cref="DiceChain"/>.</param>
        /// <param name="previousDice">The previous <see cref="DiceChain"/> to carry on to next one.</param>
        public DiceChainSetup(IDie amountProvider, DiceOperation previousOperation,
            DiceChain previousDice)
        {
            Contract.Requires(previousOperation != DiceOperation.None);
            Contract.Requires(amountProvider != null);

            Amount = amountProvider;
            PreviousOperation = previousOperation;
            PreviousDice = previousDice;
        }
예제 #5
0
        private DiceChain AppendDie(IDie die)
        {
            Contract.Requires(die != null);

            var result = PreviousDice;

            if (result != null)
            {
                if (PreviousOperation == DiceOperation.None)
                {
                    throw new InvalidOperationException("Can't append dice with unknown operation.");
                }

                result.Append(PreviousOperation, new SeveralDice(die, Amount));
            }
            else
            {
                result = new DiceChain(new SeveralDice(die, Amount));
            }

            return(result);
        }
예제 #6
0
        public void EntryLevel()
        {
            // Roll a standard cubic die one time:
            var d6   = new Die(6);
            var roll = d6.Roll();

            // Roll an interval die from 10 to 20 four times:
            var interval10t20 = new Die(10, 20);

            roll = interval10t20.Roll(4).Sum();

            // There is also a fixed die, which always returns the same value.
            // It's useful when something expects IDie as value provider and you want to pass a constant value:
            var fixed50 = new FixedDie(50);

            // Roll two d10's:
            var d2d10 = new SeveralDice(Dice.D10, 2);

            roll = d2d10.Roll(); // Compared to simple Dice.D10.Roll(2), SeveralDice provides statistics and serialization
            Console.WriteLine("Possible roll value range: " + d2d10.Minimum + " to " + d2d10.Maximum);

            // Roll a d4d10 / d2 * 3:
            var d4d10divD2mul3 = Dice.Take(Dice.D4).D(10).Divide(Dice.D2).Multiply(3);  // This is a dice chain.

            // Math operations in dice chains are always executed from left to right, so this chain translates to:
            // take a 1-4 of d10 dice and divide their roll value by 2 with 50 % chance, then multiply resulting roll value by 3.
            roll = d4d10divD2mul3.Roll();
            // Dice chains also provide statistics and serialization.

            // This chain was created via fluent interface, but it is also possible to create such chain in a more explicit way:
            d4d10divD2mul3 = new DiceChain(
                new SeveralDice(new Die(10), new Die(4)))                         // d4d10
                             .Append(DiceOperation.Divide, new SeveralDice(2))    // / 2
                             .Append(DiceOperation.Multiply, new SeveralDice(3)); // * 3

            // Oh, and where is a random number generator? Built-in dice get it from thread-local `Dice.Random`.
        }
 public void CreatedD10D100Em50P10()
 {
     d10d100em50p10 = Dice.Take(Dice.D10).D(100).EachMinus(50).Plus(10);
 }
 public void CreatedD2D20()
 {
     d2d20mr3t6p40 = Dice.Take(Dice.D2).D(20).MultiplyTake(Dice.D4).I(3, 6).Plus(40);
 }
 public void CreatedDiceChainD2D20Mr3T6P40()
 {
     d2d20mr3t6p40 = Dice.Take(Dice.D2).D(20).MultiplyTake(1).I(3, 6).Plus(40);
 }
예제 #10
0
 public void D3D8WithPlus3ToEach()
 {
     c3d8ep3 = Dice.Take(3).D(8).EachPlus(3);
 }
예제 #11
0
 public void D4D6MinusInterval2to5()
 {
     cd4d6mr2t5 = Dice.Take(Dice.D4).D(6).Minus(new Die(2, 5));
 }
예제 #12
0
        public void DieWith6FacesShowingADifferentIntegralNumberFrom1To6()
        {
            var c2d6 = new DiceChain(new SeveralDice(new Die(6), 2));

            c2d6p3 = c2d6.Append(DiceOperation.Plus, new SeveralDice(3));
        }
예제 #13
0
 public void D2D10DivideByD2MultiplyBy2()
 {
     d2d10div2mul2 = Dice.Take(Dice.D2).D(10).Divide(Dice.D2).Multiply(2);
 }
예제 #14
0
        private DiceChain AppendDie(IDie die)
        {
            Contract.Requires(die != null);

            var result = PreviousDice;
            if (result != null) {
                if (PreviousOperation == DiceOperation.None) {
                    throw new InvalidOperationException("Can't append dice with unknown operation.");
                }

                result.Append(PreviousOperation, new SeveralDice(die, Amount));
            }
            else {
                result = new DiceChain(new SeveralDice(die, Amount));
            }

            return result;
        }