Skip to content

Macros

tilttek/dice

An input may name macros: $attack + 2 takes the tree of the macro attack as an operand. The parser reads the name as one token — a $ and the letters and digits written against it, lower-cased —, and asks the Macros it was given for the macro's pool; it never replaces text, so that a macro a leaves aa, $aa and 2d6a10 alone, and a macro keeps its own parentheses: $attack*2 is (1d20+5)*2 when attack is 1d20+5.

use Tilttek\Dice\Contract\Macros;
use Tilttek\Dice\DiceRoller;
use Tilttek\Dice\Expression\Pool;

final class SheetMacros implements Macros
{
    public function __construct(private DiceRoller $dice) {}

    public function pool(string $name): ?Pool
    {
        return 'attack' === $name ? $this->dice->parse('1d20+5', macros: $this) : null;
    }
}

$dice = new DiceRoller();
$dice->write($dice->parse('$attack*2', macros: new SheetMacros($dice)));   // "(1d20+5)*2"
RuleExample
A name is a letter, then letters and digits, 32 at most$attack, $Stealth2 is stealth2
A macro of one instruction is an operand anywhere an operand is1d20i[>10]{$attack}
A macro of several instructions is the whole input, written alone$init is 1d20, $1+2
An unknown name is refused at its $No macro is named "sword" at position 2 of "1+$sword".
A macro that does not parse is refused with its reasonThe macro "broken" does not parse: Unexpected "x"
$ followed by digits stays a reference$1

Without Macros, $attack is refused as it always was. Macros::pool() resolves the macros a macro names, and raises InvalidExpression for one that names itself; the pool the input gives is checked against the limits once its macros are in it. tilttek/dice-bundle keeps macros for a site, a table and a member.