This uses the FastRandom class which you can find on the linked page.
using System.Collections.Generic; namespace GameDice { public enum DiceSides { d4 = 4, d6 = 6, d8 = 8, d10 = 10, d12 = 12, d20 = 20 } public class DiceRoll { FastRandom rand = new FastRandom(); //The game uses polyhedral dice with different numbers of //sides.You can find dice like these in game stores and in //many bookstores. //In these rules, the different dice are referred to by the //letter d followed by the number of sides: d4, d6, d8, d10, //d12, and d20. For instance, a d6 is a six-sided die (the //typical cube that many games use). public int Roll(DiceSides side) { return rand.Next((int)side); } //Percentile dice, or d100, work a little differently.You //generate a number between 1 and 100 by rolling two //different ten-sided dice numbered from 0 to 9. One die //(designated before you roll) gives the tens digit, and //the other gives the ones digit.If you roll a 7 and a 1, for //example, the number rolled is 71. Two 0s represent 100. //Some ten-sided dice are numbered in tens (00, 10, 20, //and so on), making it easier to distinguish the tens digit //from the ones digit.In this case, a roll of 70 and 1 is 71, //and 00 and 0 is 100. //When you need to roll dice, the rules tell you how many //dice to roll of a certain type, as well as what modifiers to //add. For example, “3d8 + 5” means you roll three eightsided dice, //add them together, and add 5 to the total. //The same d notation appears in the expressions “1d3” //and “1d2.” To simulate the roll of 1d3, roll a d6 and divide //the number rolled by 2 (round up). To simulate the roll of //1d2, roll any die and assign a 1 or 2 to the roll depending //on whether it was odd or even. (Alternatively, if the number rolled is //more than half the number of sides on the //die, it’s a 2.) public int PercentileRoll() { var value1 = rand.Next(10); var value2 = rand.Next(10); if (value1 == 0 && value2 == 0) return 100; return value1 * 10 + value2; } } public enum Advantages { Advantage, Disadvantage, None } public class D20 { DiceRoll dr = new DiceRoll(); bool TestMode; public D20(bool testMode) { TestMode = testMode; } private int GetRandomNumber(bool firstNumber) { if (TestMode) { if (firstNumber) { return 1; } else { return 2; } } return dr.Roll(DiceSides.d20); } public bool Roll(Advantages Advantage, List<int> Modifiers, int targetNumber) { int result; //1. Roll the die and add a modifier.Roll a d20 and add //the relevant modifier.This is typically the modifier derived from one of the six ability scores, and it sometimes //includes a proficiency bonus to reflect a character’s particular skill. (See chapter 1 for details on each ability and //how to determine an ability’s modifier.) result = GetRandomNumber(true); //Sometimes an ability check, attack roll, or saving throw //is modified by special situations called advantage and disadvantage. Advantage reflects the positive circumstances //surrounding a d20 roll, while disadvantage reflects the //opposite.When you have either advantage or disadvantage, you roll a second d20 when you make the roll. Use //the higher of the two rolls if you have advantage, and use //the lower roll if you have disadvantage. For example, if //you have disadvantage and roll a 17 and a 5, you use the //5.If you instead have advantage and roll those numbers, //you use the 17 if (Advantage == Advantages.Advantage || Advantage == Advantages.Disadvantage) { var result2 = GetRandomNumber(false); if (Advantage == Advantages.Advantage) { if (result2 > result) { result = result2; } } else { if (result2 < result) { result = result2; } } } //2. Apply circumstantial bonuses and penalties.A //class feature, a spell, a particular circumstance, or some //other effect might give a bonus or penalty to the check. foreach (var m in Modifiers) { result += m; } //3. Compare the total to a target number.If the total //equals or exceeds the target number, the ability check, //attack roll, or saving throw is a success. Otherwise, it’s a //failure.The DM is usually the one who determines target //numbers and tells players whether their ability checks, //attack rolls, and saving throws succeed or fail. if (result >= targetNumber) { return true; } return false; } } }