pif_DiceSimulator is a library that can be used to go beyond the native functionality of the DM language in terms of simulation of dice rolls. Its intended use is to allow programmers to implement nonstandard dice of various sorts, and to let them simulate rolling them either individually or as collections of dice. Furthermore, as collection of die one can maintain a state of rolled dice for arbitrarily long and perform inspection and filtration of these die.
The primary builtin functions that one would use to simulate dice rolls are roll(), pick(), and rand(). roll() is limited, in that while it is able to simulate the rolling of arbitrarily many die with arbitrarilymany sides, these die are always 'standard'. That is, the die it simulates are always numbered with {1, ..., k} where k >= 1 is some natural number. Thus, it can not simulate biased die or coins, nontransitive die, or any other interesting die that result from uneven probabilities. Furthermore, the result of multiple die is always summed and output, precluding any sort of filtration or inspection of individual die.
pick() can mitigate these issues by allowing for the simulation of nonstandard die, but it does not allow for the easy inspection and filtration of die without what would be, effectively, reimplementing this library. rand() is similar in this regard, in that while this library uses rand() for its random numbers, to mimic this library's functionality you would effectively be reimplementing the library.
How to Use
This library comes with two parts: the simulation of individual dice, and the handling of collections of die.
Basic Dice
Basic dice refers to any dice that can be stored as a list of sides. For example, standard die such as a sixsided die could be stored as list(1, 2, 3, 4, 5, 6), while a die with a slight bias for 1 and a slightly stronger bias for 6 could be stored as list(1, 1, 2, 3, 4, 5, 6, 6, 6).
These sorts of die can be implemented without any extension of the native classes. To do this, one must simply pass the list as either a /list object or a list of arguments to the constructor of the
/pif_DiceSimulator/Dice class. For example, a standard sixsided die could be implemented on the fly as
var/pif_DiceSimulator/Dice/d6 = new(1, 2, 3, 4, 5, 6)
Then, to simulate a dice roll, one would simply use the
/Dice.Roll() method:
world << d6.Roll() // Would output 1, 2, 3, 4, 5, or 6.
Common Dice
To simplify things, seven common types of dice (including all dice derived from Platonic solids) are preimplemented as children of the
/Dice class.
 A twosided die (a.k.a. a coin), under /pif_DiceSimulator/d2 and with an alias under /pif_DiceSimulator/coin (technically a child of /d2 without any changes). In addition to the standard /Dice.Roll() method, it also has a /d2.Flip() method which is an alias for Roll(). Additionally, the Map() method will output "heads" and "tails".
 A foursided die, implemented under /pif_DiceSimulator/d4.
 A sixsided die (the prototypical type of die), implemented under /pif_DiceSimulator/d6.
 An eightsided die, under /pif_DiceSimulator/d8.
 A tensided die, under /pif_DiceSimulator/d10.
 A twentysided die, under /pif_DiceSimulator/d20.
 A fudge die, used in the Fudge roleplaying system. This die has numeric sides given by [1, 1, 0, 0, 1, 1] when using the Roll() method, and text sides given by ["", "", " ", " ", "+", "+"] when using the Map() method.
Custom Dice
In addition to simple dice, one may also extend the
/pif_DiceSimulator/Dice class in order to create die with more complex behaviors. To do this, one would create a child class of the
/Dice class and modify its
Roll() method and possibly its
Map() method.
The
Roll() method should
only produce numeric outputs, or else functionality of this library will break. If you wish to associate a text (or other) value with the sides, the
Map() method should be used instead. When this method is not supplied an argument, it will simulate a dice roll (by calling the
Roll() method) and then outputs the associated value of the simulated roll.
Collections of Dice
While simulating dice rolls is the first part of this library, the second part is the handling of rolling collections of various dice. This is done by the
/pif_DiceSimulator/Collection class. This class is instantiated in one of the following two ways.
new /pif_DiceSimulator/Collection(D1, ... ,Dk)
new /pif_DiceSimulator/Collection("NdS")
In the first, D1 through Dk are
/Dice objects that will be simulated being rolled. In the latter, "NdS" is a string where N is an optional, positive natural number indicating the number of dice to roll, and S is a positive natural number indicating the number of sides on the die being rolled. If N is left off (i.e., the string is "dS" instead of "NdS") it defaults to 1.
When you wish to roll a collection of dice, you call the
Roll() method. This method will, as it simulates the roll, order the data from smallest to largest based on the numerical value of the roll, and also generate a list of data pulled from
Map() for each roll, arranged using the order data of the numeric values. This data is stored until it is cleared either by another call to
Roll() or by calling the
Clear() method.
The
/Collection class also has several filtration methods, allowing you to sort out rolls that don't meet certain criteria. These are
Above(),
Below(),
Inside(), and
Outside():
 Above() returns only rolls that are at or above a certain bound.
 Below() returns only rolls that are at or below a certain bound.
 Inside() returns only rolls that are within an upper and lower bound, inclusive.
 Outside() returns only rolls that are above a certain upper bound or below a certain lower bound, inclusive.
There is also
MapAbove(),
MapBelow(),
MapInside(), and
MapOutside( for the
Map() values of these rolls.
Both the inspection and filtration methods are useful because they result in much different probability distributions that you would get from just taking the sum of the die, though this is still possible via the
Sum() method. Thus, they allow you to skew results in favor of one outcome or another by choosing die in a certain manner—though not with absolute certainty. In terms of game design, this can make for interesting choices for the player.
Release Notes
Version 1.1.20191223.
 Changed class naming conventions to be consistent with future libraries (capitalized the first letter of class names).
 Updated documentation.

 Changed class naming convention to match class implementation.
 Added some extra class information.
 Documented the PIF_DICESIMULATOR_INCLUDED preprocessor.
 Added Release Notes section.
 Note: Apparently this update has been sitting on my hard drive since late October 2015, and I never actually got around to putting it up on the hub. Whoops!
Version 1.0.20151016.
The MIT License
Copyright (c) 2019 Timothy "popisfizzy" Reilly
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.