\ExplSyntaxOn \NewDocumentCommand {\RpgCRExp} { m } { \str_case_e:nnF {#1} { {0} {#1~(0~\xpname)} {1/10} {0~(10~\xpname)} {1/8} {#1~(25~\xpname)} {1/4} {#1~(50~\xpname)} {1/2} {#1~(100~\xpname)} {1} {#1~(200~\xpname)} {2} {#1~(450~\xpname)} {3} {#1~(700~\xpname)} {4} {#1~(\numprint{1100}~\xpname)} {5} {#1~(\numprint{1800}~\xpname)} {6} {#1~(\numprint{2300}~\xpname)} {7} {#1~(\numprint{2900}~\xpname)} {8} {#1~(\numprint{3900}~\xpname)} {9} {#1~(\numprint{5000}~\xpname)} {10} {#1~(\numprint{5900}~\xpname)} {11} {#1~(\numprint{7200}~\xpname)} {12} {#1~(\numprint{8400}~\xpname)} {13} {#1~(\numprint{10000}~\xpname)} {14} {#1~(\numprint{11500}~\xpname)} {15} {#1~(\numprint{13000}~\xpname)} {16} {#1~(\numprint{15000}~\xpname)} {17} {#1~(\numprint{18000}~\xpname)} {18} {#1~(\numprint{20000}~\xpname)} {19} {#1~(\numprint{22000}~\xpname)} {20} {#1~(\numprint{25000}~\xpname)} {21} {#1~(\numprint{33000}~\xpname)} {22} {#1~(\numprint{41000}~\xpname)} {23} {#1~(\numprint{50000}~\xpname)} {24} {#1~(\numprint{62000}~\xpname)} {25} {#1~(\numprint{75000}~\xpname)} {26} {#1~(\numprint{90000}~\xpname)} {27} {#1~(\numprint{105000}~\xpname)} {28} {#1~(\numprint{120000}~\xpname)} {29} {#1~(\numprint{135000}~\xpname)} {30} {#1~(\numprint{155000}~\xpname)} } {#1} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Monster environments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Stat block made to look like the Monster Manual NPC definitions \DeclareTColorBox {RpgMonsterNoBg} { O{} m } { enhanced, frame~hidden, boxrule = 0pt, breakable, parbox = false, boxsep = 0pt, toptitle = 3mm, left = 0pt, right = 0pt, sharp~corners, opacityback = 0, colframe = titlered, fonttitle = \RpgFontStatBlockTitle, fontupper = \RpgFontStatBlockBody, fontlower = \RpgFontStatBlockBody, title = {#2}, coltitle = titlered, #1 } % Stat block made to look like stat blocks in the PHB. \DeclareTColorBox {RpgMonsterBg} { O{} m } { enhanced, frame~hidden, before~skip = 12pt plus 3pt minus 3pt, boxrule = 0pt, breakable, parbox = false, boxsep = 2pt, toptitle = 8pt, top = 0pt, left = 2pt, right = 2pt, bottom = 7pt, sharp~corners, oversize = 0pt, borderline~north = {3pt} {0pt} {titlered}, borderline~north = {2pt} {0.5pt} {statblockribbon}, borderline~south = {3pt} {0pt} {titlered}, borderline~south = {2pt} {0.5pt} {statblockribbon}, colback = statblockbg, colbacktitle = statblockbg, colframe = titlered, fonttitle = \RpgFontStatBlockTitle, coltitle = titlered, fontupper = \RpgFontStatBlockBody, fontlower = \RpgFontStatBlockBody, title = {#2}, #1 } % Alias RpgMonster to correct background type \bool_if:NTF \l__rpg_show_background_bool { \let\RpgMonster\RpgMonsterBg \let\endRpgMonster\endRpgMonsterBg }{ \let\RpgMonster\RpgMonsterNoBg \let\endRpgMonster\endRpgMonsterNoBg } % Italicized text appearing immediately after monster's name \NewDocumentCommand {\RpgMonsterType} {m} { \begin {hangingpar} \textit {#1} \end {hangingpar} } % Fancy DnD 5e stat block rule \NewDocumentCommand {\RpgMonsterLine} {} { \par \vspace{-2pt} \noindent \begin {tikzpicture} \draw [ rulered, fill = rulered ] ( 0, 0 ) -- ( 0, 0.1 ) -- ( \linewidth, 0.05 ); \end {tikzpicture} \par } % A description variant used to list creature attributes. \newlist {__rpg_monster_attributes} {description} {1} \setlist [__rpg_monster_attributes] { before = \color {titlered}, font = \RpgFontStatBlockBody, labelsep = \l__rpg_space_dim, nosep, } % Only prints the item label if the value was supplied \cs_new_protected_nopar:Npn \__rpg_if_monster_attribute:nn #1#2 { \tl_if_empty:NF {#1} { \item [#2] #1 } } %% Monster basics \keys_define:nn { rpg / monster / basics } { armor-class .tl_set:N = \l__armor_class_tl, armor-class .initial:n = 10, armor-class .value_required:n = true, armorclass .meta:n = { armor-class = {#1} }, hit-points .tl_set:N = \l__hit_points_tl, hit-points .initial:n = \RpgDice {1d8}, hit-points .value_required:n = true, hitpoints .meta:n = { hit-points = {#1} }, speed .tl_set:N = \l__speed_tl, speed .initial:n = 30 ~ \unitsname, speed .value_required:n = true, } \cs_new_protected_nopar:Npn \__rpg_monster_basics: { \begin {__rpg_monster_attributes} \item [\armorclassname] \l__armor_class_tl \item [\hitpointsname] \l__hit_points_tl \item [\speedname] \l__speed_tl \end {__rpg_monster_attributes} } \NewDocumentCommand {\RpgMonsterBasics} {o} { \group_begin: \keys_set:nn { rpg / monster / basics } {#1} \RpgMonsterLine \__rpg_monster_basics: \RpgMonsterLine \group_end: } %% Monster CR/XP helper % \l_tmpa_tl - CR % \l_tmpb_tl - XP \cs_new_protected_nopar:Npn \__rpg_cr_xp:N #1 { \tl_set:Nn \l_tmpa_tl {#1} \str_case_e:nnTF {#1} { {0} { \tl_set:Nn \l_tmpb_tl {0} } {0/10} { \tl_set:Nn \l_tmpa_tl {0} \tl_set:Nn \l_tmpb_tl {10} } {1/10} { \rpg@deprecate{ Challenge ~ 1/10 } {0.8} [ Use ~ challenge ~ 0/10 ~ instead. ] \tl_set:Nn \l_tmpa_tl {0} \tl_set:Nn \l_tmpb_tl {10} } {1/8} { \tl_set:Nn \l_tmpb_tl {25} } {1/4} { \tl_set:Nn \l_tmpb_tl {50} } {1/2} { \tl_set:Nn \l_tmpb_tl {100} } {1} { \tl_set:Nn \l_tmpb_tl {200} } {2} { \tl_set:Nn \l_tmpb_tl {450} } {3} { \tl_set:Nn \l_tmpb_tl {700} } {4} { \tl_set:Nn \l_tmpb_tl {1100} } {5} { \tl_set:Nn \l_tmpb_tl {1800} } {6} { \tl_set:Nn \l_tmpb_tl {2300} } {7} { \tl_set:Nn \l_tmpb_tl {2900} } {8} { \tl_set:Nn \l_tmpb_tl {3900} } {9} { \tl_set:Nn \l_tmpb_tl {5000} } {10} { \tl_set:Nn \l_tmpb_tl {5900} } {11} { \tl_set:Nn \l_tmpb_tl {7200} } {12} { \tl_set:Nn \l_tmpb_tl {8400} } {13} { \tl_set:Nn \l_tmpb_tl {10000} } {14} { \tl_set:Nn \l_tmpb_tl {11500} } {15} { \tl_set:Nn \l_tmpb_tl {13000} } {16} { \tl_set:Nn \l_tmpb_tl {15000} } {17} { \tl_set:Nn \l_tmpb_tl {18000} } {18} { \tl_set:Nn \l_tmpb_tl {20000} } {19} { \tl_set:Nn \l_tmpb_tl {22000} } {20} { \tl_set:Nn \l_tmpb_tl {25000} } {21} { \tl_set:Nn \l_tmpb_tl {33000} } {22} { \tl_set:Nn \l_tmpb_tl {41000} } {23} { \tl_set:Nn \l_tmpb_tl {50000} } {24} { \tl_set:Nn \l_tmpb_tl {62000} } {25} { \tl_set:Nn \l_tmpb_tl {75000} } {26} { \tl_set:Nn \l_tmpb_tl {90000} } {27} { \tl_set:Nn \l_tmpb_tl {105000} } {28} { \tl_set:Nn \l_tmpb_tl {120000} } {29} { \tl_set:Nn \l_tmpb_tl {135000} } {30} { \tl_set:Nn \l_tmpb_tl {155000} } } { \l_tmpa_tl\ ( \numprint {\l_tmpb_tl} ~ \xpname ) } { #1 } } %% Monster CR/PB helper % \l_tmpa_tl - CR % \l_tmpb_tl - PB \cs_new_protected_nopar:Npn \__rpg_cr_pb:N #1 { \tl_set:Nn \l_tmpa_tl {#1} \str_case_e:nnTF {#1} { {0} { \tl_set:Nn \l_tmpb_tl {+2} } {1/8} { \tl_set:Nn \l_tmpb_tl {+2} } {1/4} { \tl_set:Nn \l_tmpb_tl {+2} } {1/2} { \tl_set:Nn \l_tmpb_tl {+2} } {1} { \tl_set:Nn \l_tmpb_tl {+2} } {2} { \tl_set:Nn \l_tmpb_tl {+2} } {3} { \tl_set:Nn \l_tmpb_tl {+2} } {4} { \tl_set:Nn \l_tmpb_tl {+2} } {5} { \tl_set:Nn \l_tmpb_tl {+3} } {6} { \tl_set:Nn \l_tmpb_tl {+3} } {7} { \tl_set:Nn \l_tmpb_tl {+3} } {8} { \tl_set:Nn \l_tmpb_tl {+3} } {9} { \tl_set:Nn \l_tmpb_tl {+4} } {10} { \tl_set:Nn \l_tmpb_tl {+4} } {11} { \tl_set:Nn \l_tmpb_tl {+4} } {12} { \tl_set:Nn \l_tmpb_tl {+4} } {13} { \tl_set:Nn \l_tmpb_tl {+5} } {14} { \tl_set:Nn \l_tmpb_tl {+5} } {15} { \tl_set:Nn \l_tmpb_tl {+5} } {16} { \tl_set:Nn \l_tmpb_tl {+5} } {17} { \tl_set:Nn \l_tmpb_tl {+6} } {18} { \tl_set:Nn \l_tmpb_tl {+6} } {19} { \tl_set:Nn \l_tmpb_tl {+6} } {20} { \tl_set:Nn \l_tmpb_tl {+6} } {21} { \tl_set:Nn \l_tmpb_tl {+7} } {22} { \tl_set:Nn \l_tmpb_tl {+7} } {23} { \tl_set:Nn \l_tmpb_tl {+7} } {24} { \tl_set:Nn \l_tmpb_tl {+7} } {25} { \tl_set:Nn \l_tmpb_tl {+8} } {26} { \tl_set:Nn \l_tmpb_tl {+8} } {27} { \tl_set:Nn \l_tmpb_tl {+8} } {28} { \tl_set:Nn \l_tmpb_tl {+8} } {29} { \tl_set:Nn \l_tmpb_tl {+9} } {30} { \tl_set:Nn \l_tmpb_tl {+9} } } { \l_tmpb_tl } { #1 } } %% Monster details \keys_define:nn { rpg / monster / details } { saving-throws .tl_set:N = \l__saving_throws_tl, saving-throws .value_required:n = true, savingthrows .meta:n = { saving-throws = {#1} }, skills .tl_set:N = \l__skills_tl, skills .value_required:n = true, damage-vulnerabilities .tl_set:N = \l__damage_vulnerabilities_tl, damage-vulnerabilities .value_required:n = true, damagevulnerabilities .meta:n = { damage-vulnerabilities = {#1} }, damage-resistances .tl_set:N = \l__damage_resistances_tl, damage-resistances .value_required:n = true, damageresistances .meta:n = { damage-resistances = {#1} }, damage-immunities .tl_set:N = \l__damage_immunities_tl, damage-immunities .value_required:n = true, damageimmunities .meta:n = { damage-immunities = {#1} }, condition-immunities .tl_set:N = \l__condition_immunities_tl, condition-immunities .value_required:n = true, conditionimmunities .meta:n = { condition-immunities = {#1} }, senses .tl_set:N = \l__senses_tl, senses .initial:n = \defaultsensesname, senses .value_required:n = true, languages .tl_set:N = \l__languages_tl, languages .initial:n = ---, languages .value_required:n = true, challenge .tl_set:N = \l__challenge_tl, challenge .initial:n = 1, challenge .value_required:n = true, proficiency-bonus .tl_set:N = \l__proficiency_tl, proficiency-bonus .value_required:n = false, proficiency-bonus .default:n = *, proficiencybonus .meta:n = { proficiency-bonus = {#1} }, } \cs_new_protected_nopar:Npn \__rpg_monster_details: { \begin {__rpg_monster_attributes} \__rpg_if_monster_attribute:nn {\l__saving_throws_tl} {\savesname} \__rpg_if_monster_attribute:nn {\l__skills_tl} {\skillsname} \__rpg_if_monster_attribute:nn {\l__damage_vulnerabilities_tl} {\dvulname} \__rpg_if_monster_attribute:nn {\l__damage_resistances_tl} {\dresname} \__rpg_if_monster_attribute:nn {\l__damage_immunities_tl} {\dimmname} \__rpg_if_monster_attribute:nn {\l__condition_immunities_tl} {\cimmname} \item [\sensesname] \l__senses_tl \item [\languagesname] \l__languages_tl \item [\challengename] \__rpg_cr_xp:N {\l__challenge_tl} \tl_if_empty:NF {\l__proficiency_tl} { {\enit@svlabel{\enit@format{\pbonname}}} \hskip \labelsep \str_if_eq:VnTF \l__proficiency_tl * {\__rpg_cr_pb:N {\l__challenge_tl}} {\l__proficiency_tl} } \end {__rpg_monster_attributes} } \NewDocumentCommand {\RpgMonsterDetails} {o} { \group_begin: \keys_set:nn { rpg / monster / details } {#1} \RpgMonsterLine{} \__rpg_monster_details: \RpgMonsterLine{} \group_end: } %% Ability scores % Print ability score stats with auto-computed modifier % e.g. \stat{12} prints "12 (+1)" \cs_new_protected_nopar:Npn \__rpg_ability_score_modifier:N #1 { \regex_match:NnTF \c__pos_int_regex {#1} { \int_set:Nn \l_tmpa_int { \fp_eval:n { floor ( ( #1 - 10 ) / 2 ) } } #1 ~ ( \int_compare:nNnTF {\l_tmpa_int} < {0} { -- } {+} \int_abs:n \l_tmpa_int ) } {#1} } \keys_define:nn { rpg / monster / ability_scores } { str .tl_set:N = \l__str_tl, str .initial:n = 10, str .value_required:n = true, STR .meta:n = { str = #1 }, dex .tl_set:N = \l__dex_tl, dex .initial:n = 10, dex .value_required:n = true, DEX .meta:n = { dex = #1 }, con .tl_set:N = \l__con_tl, con .initial:n = 10, con .value_required:n = true, CON .meta:n = { con = #1 }, int .tl_set:N = \l__int_tl, int .initial:n = 10, int .value_required:n = true, INT .meta:n = { int = #1 }, wis .tl_set:N = \l__wis_tl, wis .initial:n = 10, wis .value_required:n = true, WIS .meta:n = { wis = #1 }, cha .tl_set:N = \l__cha_tl, cha .initial:n = 10, cha .value_required:n = true, CHA .meta:n = { cha = #1 }, } % Ability scores in a table \cs_new_protected_nopar:Npn \__rpg_monster_ability_scores: { \color {titlered} \par \vspace{1pt} \noindent \begin{tabularx} {\linewidth} {YYYYYY} \rule {0pt} {3.7mm} % adds space between hline and table \textbf {\strstatname} & \textbf {\dexstatname} & \textbf {\constatname} & \textbf {\intstatname} & \textbf {\wisstatname} & \textbf {\chastatname} \\ \exp_args:NV \__rpg_ability_score_modifier:N \l__str_tl & \exp_args:NV \__rpg_ability_score_modifier:N \l__dex_tl & \exp_args:NV \__rpg_ability_score_modifier:N \l__con_tl & \exp_args:NV \__rpg_ability_score_modifier:N \l__int_tl & \exp_args:NV \__rpg_ability_score_modifier:N \l__wis_tl & \exp_args:NV \__rpg_ability_score_modifier:N \l__cha_tl \end{tabularx} \par \vspace{4pt}% } \NewDocumentCommand {\RpgMonsterAbilityScores} {o} { \group_begin: \keys_set:nn { rpg / monster / ability_scores } {#1} \__rpg_monster_ability_scores: \group_end: } % Inline header for monster actions - similar to a paragraph \NewDocumentCommand {\RpgMonsterAction} {m} { \par \smallskip \noindent \textsl { \textbf {#1.} } } % Inline header for monster sub actions - similar to a subparagraph \NewDocumentCommand {\RpgMonsterSubAction} {m} { \par \textsl { \textbf {#1.} } } % Monster subsection header style \NewDocumentCommand {\RpgMonsterSection} {m} { \addvspace{6pt plus 2pt minus 2pt} \noindent \group_begin: \RpgFontStatBlockSection #1\nopagebreak[4] % \rule is a horizontal command, so placing it under the title incurs extra % line spacing. Use \hrule (a vertical command) instead. \vspace {2pt}\nopagebreak[4] \hrule height 0.6pt \group_end: \par \vspace{5pt} \noindent \ignorespaces } % Spellcasting levels \newlist {RpgMonsterSpells} {description} {1} \setlist [RpgMonsterSpells] { font = \normalfont \RpgFontStatBlockBody, labelsep = \l__rpg_space_dim, noitemsep, topsep = 6pt plus 2pt minus 2pt, } \NewDocumentCommand {\RpgEmphSpellString} {m} { \group_begin: \seq_set_from_clist:Nn \l_tmpa_seq {#1} \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq { \exp_not:n { \emph {##1} } } \seq_use:Nn \l_tmpb_seq { ,~ } \group_end: } \NewDocumentCommand {\RpgInnateSpellLevel} { O {\innateatwillname} m } { \item [ \regex_match:NnTF \c__pos_int_regex {#1} { \str_if_in:NnTF {#2} {,} { \__rpg_caption:nn {\numberperdayeachname} {#1} } { \__rpg_caption:nn {\numberperdayname} {#1} } } {#1} : ] \RpgEmphSpellString {#2} } \NewDocumentCommand {\RpgMonsterSpellLevel} { O{\spellcantripsname} O{\spellatwillname} m } { \item [ \str_case_e:nnF {#1} { {1} {\spellfirstlevelname} {2} {\spellsecondlevelname} {3} {\spellthirdlevelname} {4} {\spellfourthlevelname} {5} {\spellfifthlevelname} {6} {\spellsixthlevelname} {7} {\spellseventhlevelname} {8} {\spelleighthlevelname} {9} {\spellninthlevelname} } {#1} {~}( \str_case_e:nnF {#2} { {1} {\spelloneslotname} {2} {\spelltwoslotsname} {3} {\spellthreeslotsname} {4} {\spellfourslotsname} } {#2} ) : ] \RpgEmphSpellString{#3} } %% Monster attacks \tl_new:N \l__rpg_attack_distance_tl \tl_new:N \l__rpg_attack_type_tl \keys_define:nn { rpg / monster / attack } { name .tl_set:N = \l__name_tl, name .value_required:n = true, distance .choice:, distance .choices:nn = { both, melee, ranged } { \tl_set:Nn \l__rpg_attack_distance_tl {\l_keys_choice_tl} }, distance .initial:n = both, type .choice:, type / weapon .code:n = { \tl_set:Nn \l__rpg_attack_type_tl {\weaponname} }, type / spell .code:n = { \tl_set:Nn \l__rpg_attack_type_tl {\spellname} }, type .initial:n = weapon, mod .tl_set:N = \l__mod_tl, mod .value_required:n = true, reach .tl_set:N = \l__reach_tl, reach .initial:n = 5, reach .value_required:n = true, range .tl_set:N = \l__range_tl, range .initial:n = 20/60, range .value_required:n = true, targets .tl_set:N = \l__targets_tl, targets .initial:n = \defaulttargetsname, targets .value_required:n = true, dmg .tl_set:N = \l__dmg_tl, dmg .value_required:n = true, dmg-type .tl_set:N = \l__dmg_type_tl, dmg-type .value_required:n = true, plus-dmg .tl_set:N = \l__plus_dmg_tl, plus-dmg .value_required:n = true, plus-dmg-type .tl_set:N = \l__plus_dmg_type_tl, plus-dmg-type .value_required:n = true, or-dmg .tl_set:N = \l__or_dmg_tl, or-dmg .value_required:n = true, or-dmg-when .tl_set:N = \l__or_dmg_when_tl, or-dmg-when .value_required:n = true, extra .tl_set:N = \l__extra_tl, extra .value_required:n = true, } \cs_new_protected:Npn \__rpg_monster_reach: { \reachname\ \l__reach_tl\ \unitsname } \cs_new_protected:Npn \__rpg_monster_range: { \rangename\ \l__range_tl\ \unitsname } \cs_new_protected:Npn \__rpg_if_plus_dmg: { \tl_if_empty:NF {\l__plus_dmg_tl} { ~ \plusname\ \l__plus_dmg_tl\ \l__plus_dmg_type_tl\ \damagename } } \cs_new_protected_nopar:Npn \__rpg_if_or_dmg: { \tl_if_empty:NF {\l__or_dmg_tl} { , ~ \orname\ \l__or_dmg_tl\ \l__dmg_type_tl\ \damagename\ \l__or_dmg_when_tl \tl_if_empty:NF {\l__plus_dmg_tl} {,} } } \cs_new_protected:Npn \__rpg_monster_attack: { \__rpg_check_for_key:Nnn \l__name_tl {\RpgMonsterAttack} {name} \__rpg_check_for_key:Nnn \l__mod_tl {\RpgMonsterAttack} {mod} \begin{RpgMonsterAction} {\l__name_tl}~ \str_case_e:nnF {\l__rpg_attack_distance_tl} { { melee } { \textit{ \__rpg_caption:nn {\meleeattackname} {\l__rpg_attack_type_tl} : } ~ \__rpg_caption:nn {\tohitname} {\l__mod_tl}, ~ \__rpg_monster_reach: } { ranged } { \textit{ \__rpg_caption:nn {\rangedattackname} {\l__rpg_attack_type_tl} : } ~ \__rpg_caption:nn {\tohitname} {\l__mod_tl}, ~ \__rpg_monster_range: } } {% Melee and Ranged is the default \textit{ \__rpg_caption:nn {\meleeorrangedattackname} {\l__rpg_attack_type_tl} : } ~ \__rpg_caption:nn {\tohitname} {\l__mod_tl}, ~ \__rpg_monster_reach:\ \orname\ \__rpg_monster_range: } , ~ \l__targets_tl. ~ \textit { \hitname : } ~ \str_if_empty:NF {\l__dmg_tl} % Don't show any damage if `dmg' is not set. { \l__dmg_tl\ \l__dmg_type_tl\ \damagename \__rpg_if_or_dmg: \__rpg_if_plus_dmg: } % `extra' is any special text that goes after the final damage; do not % include the final full stop. \l__extra_tl . \end{RpgMonsterAction} } \NewDocumentCommand {\RpgMonsterAttack} {o} { \group_begin: \keys_set:nn { rpg / monster / attack } {#1} \__rpg_monster_attack: \group_end: } \NewDocumentCommand {\RpgMonsterMelee} {o} { \group_begin: \keys_set:nn { rpg / monster / attack } { #1, distance = melee } \__rpg_monster_attack: \group_end: } \NewDocumentCommand {\RpgMonsterRanged} {o} { \group_begin: \keys_set:nn { rpg / monster / attack } { #1, distance = ranged } \__rpg_monster_attack: \group_end: } %% Legendary Actions \newlist {RpgMonsterLegendaryActions} {description} {1} \setlist [RpgMonsterLegendaryActions] { font = \RpgFontStatBlockBody, labelsep = \l__rpg_space_dim, noitemsep, topsep = 6pt plus 2pt minus 2pt, } \NewDocumentCommand {\RpgMonsterLegendaryAction} { m m } { \item [ #1 . ] #2 }