Example #1
0
        private static SeveralDice ParseBuiltinDice(string nodeRepresentation)
        {
            Contract.Requires(!String.IsNullOrEmpty(nodeRepresentation));

            SeveralDice result = null;
            double      fixedValue;

            // Try to match the simplest fixed die first:
            if (Double.TryParse(nodeRepresentation, out fixedValue))
            {
                result = new SeveralDice(new FixedDie(fixedValue));
            }
            else    // Then try to match other known die types:
            {
                foreach (var nodePattern in knownNodePatterns)
                {
                    var dieMatches = Regex.Matches(nodeRepresentation, nodePattern, RegexOptions.Compiled);
                    result = MatchToBuiltinDiceNode(dieMatches);
                    if (result != null)
                    {
                        break;
                    }                               // Stop trying on successful match.
                }
            }

            return(result);
        }
Example #2
0
        /// <summary> Appends a new chain node to the dice chain using a specified operation.</summary>
        /// <remarks> Append(DiceOperation.Minus, Dice.D10) is equivalent to Minus(Dice.D10). </remarks>
        /// <param name="linkOperation">The operation used to operate on dice rolls between chain nodes.</param>
        /// <param name="linkContent">Actual content of the chain node.</param>
        /// <returns>Dice chain with new node appended.</returns>
        public DiceChain Append(DiceOperation linkOperation, SeveralDice linkContent)
        {
            Contract.Requires(linkOperation != DiceOperation.None);
            Contract.Requires(linkContent != null);

            LastLink = new DiceChainLink(linkOperation, linkContent, LastLink);
            return(this);
        }
Example #3
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();
        }
Example #4
0
        /// <summary> Converts string representation of a single node in a dice chain to an actual node. </summary>
        private static SeveralDice ToNode(string nodeRepresentation)
        {
            SeveralDice result = null;

            foreach (var parser in nodeParsers)      // Parsers should not throw, but let's enforce the rule.
            {
                try { result = parser(nodeRepresentation); }
                catch { result = null; }

                if (result != null)
                {
                    break;
                }
            }

            return(result);
        }
Example #5
0
        /// <summary> Initializes a new instance of the <see cref="DiceChain"/> class. </summary>
        /// <param name="node">The first node for the dice chain.</param>
        public DiceChain(SeveralDice node)
        {
            Contract.Requires(node != null);

            LastLink = new DiceChainLink(DiceOperation.Plus, node);
        }
Example #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`.
        }
Example #7
0
        /// <summary> Appends a new chain node to the dice chain using a specified operation.</summary>
        /// <remarks> Append(DiceOperation.Minus, Dice.D10) is equivalent to Minus(Dice.D10). </remarks>
        /// <param name="linkOperation">The operation used to operate on dice rolls between chain nodes.</param>
        /// <param name="linkContent">Actual content of the chain node.</param>
        /// <returns>Dice chain with new node appended.</returns>
        public DiceChain Append(DiceOperation linkOperation, SeveralDice linkContent)
        {
            Contract.Requires(linkOperation != DiceOperation.None);
            Contract.Requires(linkContent != null);

            LastLink = new DiceChainLink(linkOperation, linkContent, LastLink);
            return this;
        }
Example #8
0
        /// <summary> Initializes a new instance of the <see cref="DiceChain"/> class. </summary>
        /// <param name="node">The first node for the dice chain.</param>
        public DiceChain(SeveralDice node)
        {
            Contract.Requires(node != null);

            LastLink = new DiceChainLink(DiceOperation.Plus, node);
        }