DnDGen.RollGen
17.0.0
See the version list below for details.
dotnet add package DnDGen.RollGen --version 17.0.0
NuGet\Install-Package DnDGen.RollGen -Version 17.0.0
<PackageReference Include="DnDGen.RollGen" Version="17.0.0" />
<PackageVersion Include="DnDGen.RollGen" Version="17.0.0" />
<PackageReference Include="DnDGen.RollGen" />
paket add DnDGen.RollGen --version 17.0.0
#r "nuget: DnDGen.RollGen, 17.0.0"
#:package DnDGen.RollGen@17.0.0
#addin nuget:?package=DnDGen.RollGen&version=17.0.0
#tool nuget:?package=DnDGen.RollGen&version=17.0.0
RollGen
Rolls a set of dice, as determined by the D20 die system.
Installing
The project is on NuGet.
dotnet add package DnDGen.RollGen
Version 17 requires .NET 10. Use version 16.x if you are still on .NET 8.
Syntax
Use
To use RollGen, simply use the verbose, fluid syntax:
var standardRoll = dice.Roll(4).d6().AsSum();
var customRoll = dice.Roll(92).d(66).AsSum();
var expressionRoll = dice.Roll("5+3d4*2").AsSum();
var chainedRolls = dice.Roll().d2().d(5).Keeping(1).d6().AsSum(); //1d2d5k1d6 Evaluated left to right -> ((1d2)d5k1)d6
var individualRolls = dice.Roll(4).d6().AsIndividualRolls();
var parsedRolls = dice.Roll("5+3d4*2").AsIndividualRolls(); //NOTE: This will only return 1 roll, the same as AsSum()
var keptRolls = dice.Roll(4).d6().Keeping(3).AsIndividualRolls(); //Returns the highest 3 rolls
var expressionKeptRolls = dice.Roll("3d4k2").AsSum(); //Returns the sum of 2 highest rolls
var averageRoll = dice.Roll(4).d6().AsPotentialAverage(); //Returns the average roll for the expression. For here, it will return 14.
var expressionAverageRoll = dice.Roll("5+3d4*3").AsPotentialAverage(); //5+7.5*3, returning 27.5
var minRoll = dice.Roll(4).d6().AsPotentialMinimum(); //Returns the minimum roll for the expression. For here, it will return 4.
var expressionMinRoll = dice.Roll("5+3d4*3").AsPotentialMinimum(); //5+3*3, returning 14
var maxRoll = dice.Roll(4).d6().AsPotentialMaximum(); //Returns the maximum roll for the expression. For here, it will return 24.
var expressionMaxRoll = dice.Roll("5+3d4*3").AsPotentialMaximum(); //5+12*3, returning 41
var success = dice.Roll().Percentile().AsTrueOrFalse(); //Returns true if high (51-100), false if low (1-50)
var customPercentageSuccess = dice.Roll().Percentile().AsTrueOrFalse(.9); //Returns true if > 90, false if <= 90
var customRollSuccess = dice.Roll().Percentile().AsTrueOrFalse(90); //Returns true if >= 90, false if < 90
var expressionSuccess = dice.Roll("5+3d4*2").AsTrueOrFalse(); //Returns true if high, false if low
var explicitExpressionSuccess = dice.Roll("2d6 >= 1d12").AsTrueOrFalse(); //Evaluates boolean expression after rolling
var containsRoll = dice.ContainsRoll("This contains a roll of 4d6k3 for rolling stats"); //will return true here
var summedSentence = dice.ReplaceRollsWithSumExpression("This contains a roll of 4d6k3 for rolling stats"); //returns "This contains a roll of (5 + 3 + 2) for rolling stats"
var rolledSentence = dice.ReplaceExpressionWithTotal("This contains a roll of 4d6k3 for rolling stats"); //returns "This contains a roll of 10 for rolling stats"
var rolledComplexSentenceMin = dice.ReplaceWrappedExpressions<double>("Fireball does {min(4d6,10) + 0.5} damage"); //returns "Fireball does 7.5 damage"
var rolledComplexSentenceMax = dice.ReplaceWrappedExpressions<double>("Fireball does {max(4d6,10) + 0.5} damage"); //returns "Fireball does 15.5 damage"
var optimizedRollWithFewestDice = RollHelper.GetRollWithFewestDice(1, 9); //returns "4d3-3", because it uses only 1 kind of dice compared to "1d8+1d2-1"
var optimizedRoll = RollHelper.GetRollWithMostEvenDistribution(4, 9); //returns "1d6+3", which is the most evenly-distributed roll possible, whether optimizing for dice or distribution
var optimizedRollWithMultipleDice = RollHelper.GetRollWithMostEvenDistribution(1, 9); //returns "1d8+1d2-1", because it more evenly-distributed than "4d3-3"
var optimizedRollWithMultipliers = RollHelper.GetRollWithMostEvenDistribution(1, 36, allowMultipliers: true); //returns "(1d12-1)*3+1d3"
var optimizedRollWithNonstandardDice = RollHelper.GetRollWithMostEvenDistribution(1, 36, allowNonstandardDice: true); //returns "1d36"
var optimizedRollWithMultipliersAndNonstandardDice = RollHelper.GetRollWithMostEvenDistribution(1, 45, true, true); //returns "(1d3-1)*15+(1d3-1)*5+1d5"
var explodedRolls = dice.Roll(4).d6().Explode().AsIndividualRolls(); //If a 6 is rolled, then an additional roll is performed. I.E., 3 + 6 + 5 + 4 + 1
var expressionExplodedRolls = dice.Roll("3d4!").AsSum(); //Return the sum of the rolls, including bonus rolls from explosion on rolls of 4
var expressionExplodedKeptRolls = dice.Roll("3d4!k2").AsSum(); //Returns the sum of 2 highest rolls, including bonus rolls from explosion on rolls of 4
var expressionExplodedMultipleRolls = dice.Roll("3d4!e3").AsSum(); //Return the sum of the rolls, including bonus rolls from explosion on rolls of 3 or 4
var expressionExplodedMultipleKeptRolls = dice.Roll("3d4e1e2k2").AsSum(); //Returns the sum of 2 highest rolls, including bonus rolls from explosion on rolls of 1 or 2
var transformedRolls = dice.Roll(3).d6().Transforming(1).AsIndividualRolls(); //If a 1 is rolled, we will count it as a 6. I.E., 3 + 1 + 6 = 3 + 6 + 6
var transformedMultipleRolls = dice.Roll("3d6t1t5").AsSum(); //Return the sum of the rolls, including 1's and 5's transformed to 6's
var transformedExplodedKeptRolls = dice.Roll("3d6!t1k2").AsSum(); //Returns the sum of 2 highest rolls, including bonus rolls from explosion and transforming 1's to 6's.
var transformedCustomRolls = dice.Roll("3d6t1:2").AsSum(); //Return the sum of the rolls, transforming 1's into 2's.
//Returns a qualitative description of the roll, based on percentages
var description = dice.Describe("3d6", 9); //Returns "Bad"
description = dice.Describe("3d6", 13); //Returns "Good"
description = dice.Describe("3d6", 12, "Bad", "Average", "Good"); //Returns "Average"
description = dice.Describe("3d6", 6, "Bad", "Average", "Good"); //Returns "Bad"
description = dice.Describe("3d6", 16, "Bad", "Average", "Good"); //Returns "Good"
//Returns whether the roll is valid
var valid = dice.IsValid("3d6+1"); //Returns TRUE
valid = dice.IsValid("(3)d(6)+1"); //Returns TRUE
valid = dice.IsValid("(1d2)d(3d4)+5d6"); //Returns TRUE
valid = dice.IsValid("10000d10000"); //Returns TRUE
valid = dice.IsValid("(100d100)d(100d100)"); //Returns TRUE
valid = dice.IsValid("(0)d(6)+1"); //Returns FALSE, because quantity is too low
valid = dice.IsValid("(3.1)d(6)+1"); //Returns FALSE, because decimals are not allowed for dice operations
valid = dice.IsValid("0d6+1"); //Returns FALSE, because quantity is too low
valid = dice.IsValid("10001d10000"); //Returns FALSE, because quantity is too high
valid = dice.IsValid("(100d100+1)d(100d100)"); //Returns FALSE, because quantity could potentially be above the 10,000 limit
valid = dice.IsValid("(3)d(-6)+1"); //Returns FALSE, because die is too low
valid = dice.IsValid("(3)d(6.1)+1"); //Returns FALSE, because decimals are not allowed for dice operations
valid = dice.IsValid("3d0+1"); //Returns FALSE, because die is too low
valid = dice.IsValid("10000d10001"); //Returns FALSE, because die is too high
valid = dice.IsValid("(100d100)d(100d100+1)"); //Returns FALSE, because die could potentially be above the 10,000 limit
valid = dice.IsValid("4d6k3"); //Returns TRUE
valid = dice.IsValid("(4)d(6)k(3)"); //Returns TRUE
valid = dice.IsValid("(4)d(6)k(-1)"); //Returns FALSE, because keep value is too low
valid = dice.IsValid("(4)d(6)k(3.1)"); //Returns FALSE, because decimals are not allowed for dice operations
valid = dice.IsValid("4d6k10000"); //Returns TRUE
valid = dice.IsValid("4d6k10001"); //Returns FALSE, because keep value is too high
valid = dice.IsValid("4d6k(100d100+1)"); //Returns FALSE, because keep value could potentially be above the 10,000 limit
valid = dice.IsValid("2d3!"); //Returns TRUE
valid = dice.IsValid("2d3!e2"); //Returns TRUE
valid = dice.IsValid("2d3!e2e1"); //Returns FALSE, because it explodes on all values
valid = dice.IsValid("3d6t1"); //Returns TRUE
valid = dice.IsValid("3d6t1t2"); //Returns TRUE
valid = dice.IsValid("3d6t7"); //Returns TRUE
valid = dice.IsValid("3d6t0"); //Returns FALSE, because transform target is too low
valid = dice.IsValid("3d6t6:0"); //Returns TRUE
valid = dice.IsValid("3d6t10001"); //Returns FALSE, because transform target is too high
valid = dice.IsValid("3d6t6:10001"); //Returns TRUE
valid = dice.IsValid("avg(1d12, 2d6, 3d4, 4d3, 6d2)"); //Returns TRUE, because this is a valid Albatross function
valid = dice.IsValid("bad(1d12, 2d6, 3d4, 4d3, 6d2)"); //Returns FALSE, because "bad" is not a valid Albatross function
valid = dice.IsValid("this is not a roll"); //Returns FALSE
valid = dice.IsValid("this contains 3d6, but is not a roll"); //Returns FALSE
valid = dice.IsValid("9266+90210-42*600/1337%1336+96d(783d82%45+922-2022/337)-min(1d2, 3d4, 5d6)+max(1d2, 3d4, 5d6)*avg(1d2, 3d4, 5d6)"); //Returns TRUE
Important things to note:
- When retrieving individual rolls from an expression, only the sum of the expression is returned. This is because determining what an "individual roll" is within a complex expression is not certain. As an example, what would individual rolls be for
1d2+3d4? - Mathematical expressions supported are
+,-,*,/, and%, as well as die rolls as demonstrated above. Spaces are allowed in the expression strings. Parenthetical expressions are also allowed. - For replacement methods on
Dice, there is an option to do "lenient" replacements (optional boolean). The difference:- "1d2 ghouls and 2d4 zombies" strict → "1 ghouls and 5 zombies"
- "1d2 ghouls and 2d4 zombies" lenient → "1 ghouls an3 zombies" (it reads "and 2d4" as "an(d 2d4)")
Order of Operations
In regards to the operators one can apply to a roll (Keeping, Exploding, Transforming), this is the order of operations:
- Explode
- Transform
- Keep
One can specify these commands in any order, as they will be evaluated in their order of operation. For example, all of these rolls will parse the same: 4d3!t2k1, 4d3!k1t2, 4d3t2!k1, 4d3t2k1!, 4d3k1!t2, 4d3k1t2! - all will be evaluated as 4d3, exploding on a 3, then transforming 2 into 3, then keeping the highest roll.
Beyond this, order of operations is respected as outlined by the Albatross documentation: https://rushuiguan.github.io/expression/articles/operations.html#the-precedence-of-infix-operations
The documentation also outlines supported functions (such as min and max) that can be used: https://rushuiguan.github.io/expression/articles/operations.html
Getting Dice Objects
Dice is an interface, and its implementation is internal to RollGen. Get an instance through Ninject, using the RollGenModuleLoader, or through DiceFactory if you are not using Ninject.
using DnDGen.RollGen.IoC;
using Ninject;
var kernel = new StandardKernel();
var rollGenModuleLoader = new RollGenModuleLoader();
rollGenModuleLoader.LoadModules(kernel);
Your particular syntax for how the Ninject injection should work will depend on your project (class library, web site, etc.). Each of the examples below work independently. You should use the one that is appropriate for your project.
[Inject] //Ninject property
public Dice MyDice { get; set; }
public MyClass()
{ }
public int Roll()
{
return MyDice.Roll(4).d6().Keeping(3).AsSum();
}
private readonly Dice myDice;
public MyClass(Dice dice) //This works if you are calling Ninject to build MyClass
{
myDice = dice;
}
public int Roll()
{
return myDice.Roll(4).d6().Keeping(3).AsSum();
}
public MyClass()
{ }
public int Roll()
{
var myDice = DiceFactory.Create(); //Located in DnDGen.RollGen.IoC
return myDice.Roll(4).d6().Keeping(3).AsSum();
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Albatross.Expression (>= 5.0.0)
- Ninject (>= 3.3.6)
NuGet packages (10)
Showing the top 5 NuGet packages that depend on DnDGen.RollGen:
| Package | Downloads |
|---|---|
|
DnDGen.TreasureGen
This generates items for the Dungeons and Dragons 3.5 system. One can generate treasure or individual items such as coins, goods, weapons, armor, and magical items. |
|
|
CharacterGen.Domain
This is a Ninject-based bootstrapper for CharacterGen |
|
|
DnDGen.Core
This provides common, core objects for the generators, including the Percentile and Collection selectors, with dependencies |
|
|
DnDGen.Infrastructure
This provides common, core objects for the generators, including the Percentile and Collection selectors, with dependencies |
|
|
DungeonGen.Domain
This is the Ninject-based bootstrapper for DungeonGen |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 18.0.2 | 82 | 11/10/2026 |
| 18.0.1 | 95 | 11/7/2026 |
| 18.0.0 | 126 | 10/30/2026 |
| 17.0.0 | 105 | 10/30/2026 |
| 16.0.7 | 564 | 5/11/2026 |
| 16.0.6 | 1,794 | 2/25/2026 |
| 16.0.5 | 2,463 | 2/17/2026 |
| 16.0.4 | 572 | 1/21/2026 |
| 16.0.3 | 1,806 | 8/13/2025 |
| 16.0.2 | 274 | 8/12/2025 |
| 16.0.1 | 5,836 | 11/21/2024 |
| 16.0.0 | 1,990 | 7/12/2024 |
| 15.5.7 | 1,396 | 1/11/2024 |
| 15.5.6 | 281 | 1/10/2024 |
| 15.5.4 | 1,051 | 12/14/2023 |
| 15.5.3 | 1,047 | 7/10/2023 |
| 15.5.2 | 363 | 7/7/2023 |
| 15.5.1 | 1,192 | 3/16/2023 |
| 15.5.0 | 576 | 3/9/2023 |
| 15.4.2 | 660 | 1/12/2023 |
Breaking: now targets .NET 10 (was .NET 8). Plain numbers skip the expression engine, and .5, 5., exponents (1e5), NaN and Infinity are now read as numbers. Added README to the package.