core-book/lib/rpgutility.sty
Joe bellus 7b33fef50e Initial commit
Initial project scaffolding
2025-03-10 18:21:53 -04:00

75 lines
2.8 KiB
TeX

\ExplSyntaxOn
% Useful regex strings
\regex_const:Nn \c__pos_int_regex { \d+ }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Dice macro
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Matches { # | #d# | #d# + # | #d# - # } while ignoring spaces
\regex_const:Nn \c__valid_dice_regex { \A\s*(\d+)(?:[dD](\d+)\s*(?:([+\-])\s*(\d+))?)?\s*\Z }
\seq_new:N \l__dice_args_seq
\tl_new:N \l__dice_number_tl
\tl_new:N \l__dice_sides_tl
\tl_new:N \l__dice_mod_sign_tl
\tl_new:N \l__dice_mod_tl
\msg_new:nnn { rpg } { dice / invalid_argument } { Invalid~argument~``#1''~passed~to~\noexpand\RpgDice. }
\NewDocumentCommand { \RpgDice } { m }
{
\group_begin:
\regex_extract_once:NnNTF { \c__valid_dice_regex } { #1 } \l__dice_args_seq
{
\seq_pop_left:NN \l__dice_args_seq \l_tmpa_str % Don't need the full match
\seq_pop_left:NN \l__dice_args_seq \l__dice_number_tl % # of dice
\seq_pop_left:NN \l__dice_args_seq \l__dice_sides_tl % # of sides
\seq_pop_left:NN \l__dice_args_seq \l__dice_mod_sign_tl % +/- for add/sub
\seq_pop_left:NN \l__dice_args_seq \l__dice_mod_tl % modifier
\str_if_empty:NTF { \l__dice_sides_tl } % are there dice ?
{ \l__dice_number_tl } % No, just a number
{ %Yes, break down the roll
\fp_eval:n { floor ( \l__dice_number_tl * ( \l__dice_sides_tl + 1 ) / 2 )\l__dice_mod_sign_tl \l__dice_mod_tl }~
(
\l__dice_number_tl \dname \l__dice_sides_tl
\str_case_e:nn { \l__dice_mod_sign_tl }
{
{ + } { ~+~\l__dice_mod_tl }
{ - } { ~--~\l__dice_mod_tl }
}
)
}
}
{ \msg_error:nnn { rpg } { dice / invalid_argument } { #1 }}
\group_end:
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Gets the width of a space
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\box_new:N \l__rpg_space_box
\hbox_set:Nn \l__rpg_space_box {~}
\dim_new:N \l__rpg_space_dim
\dim_set:Nn \l__rpg_space_dim { \box_wd:N \l__rpg_space_box }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some keys are required for proper execution of macros.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\msg_new:nnn { rpg } { key_required } { #1~requires~key~``#2''~to~be~set. }
% #1 - key value
% #2 - macro name
% #3 - key name
\cs_new_protected:Npn \__rpg_check_for_key:Nnn #1#2#3
{
\group_begin:
\str_set:Nx \l_tmpa_str { #1 }
\str_if_empty:NT { \l_tmpa_str }
{ \msg_error:nnnn { rpg } { key_required } { #2 } { #3 } }
\group_end:
}