Initial commit

Initial project scaffolding
This commit is contained in:
2025-03-10 18:09:50 -04:00
commit 7b33fef50e
66 changed files with 4486 additions and 0 deletions

14
lib/compat.sty Normal file
View File

@@ -0,0 +1,14 @@
\ExplSyntaxOn
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Compatibility with external packages
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\cs_if_free:NT \str_case_e:nnF
{
% \str_case_x was renamed \str_case_e mid-2018. \str_case_x will be removed
% at the end of 2019:
%
% https://github.com/latex3/latex3/blob/8fcb571ddda61c01773d9746d32cecdbe63afb26/l3kernel/l3obsolete.txt#L65
\cs_new_eq:NN \str_case_e:nnF \str_case_x:nnF
}

View File

@@ -0,0 +1,73 @@
\ExplSyntaxOn % Use tilde (~) for spaces.
\addto\captions<language> % Replace <language> tag with your language
{
% Monster basics
\renewcommand\armorclassname{Armor~Class}
\renewcommand\hitpointsname{Hit~Points}
\renewcommand\speedname{Speed}
% Monster ability scores
\renewcommand\strstatname{STR}
\renewcommand\dexstatname{DEX}
\renewcommand\constatname{CON}
\renewcommand\intstatname{INT}
\renewcommand\wisstatname{WIS}
\renewcommand\chastatname{CHA}
% Monster details
\renewcommand\skillsname{Skills}
\renewcommand\dimmname{Damage~Immunities}
\renewcommand\dvulname{Damage~Vulnerabilities}
\renewcommand\dresname{Damage~Resistances}
\renewcommand\cimmname{Condition~Immunities}
\renewcommand\savesname{Saving~Throws}
\renewcommand\sensesname{Senses}
\renewcommand\defaultsensesname{passive~Perception~10}
\renewcommand\languagesname{Languages}
\renewcommand\challengename{Challenge}
\renewcommand\xpname{XP}
% Monster attack
\renewcommand\unitsname{ft.}
\renewcommand\weaponname{Weapon}
\renewcommand\spellname{Spell}
\renewcommand\meleeattackname{Melee~|1|~Attack}
\renewcommand\rangedattackname{Ranged~|1|~Attack}
\renewcommand\meleeorrangedattackname{Melee~or~Ranged~|1|~Attack}
\renewcommand\orname{or}
\renewcommand\tohitname{|1|~to~hit}
\renewcommand\defaulttargetsname{one~target}
\renewcommand\reachname{reach}
\renewcommand\rangename{range}
\renewcommand\hitname{Hit}
\renewcommand\damagename{damage}
\renewcommand\plusname{plus}
% Spell levels
\renewcommand\spellcantripsname{Cantrips}
\renewcommand\spellfirstlevelname{1st~level}
\renewcommand\spellsecondlevelname{2nd~level}
\renewcommand\spellthirdlevelname{3rd~level}
\renewcommand\spellfourthlevelname{4th~level}
\renewcommand\spellfifthlevelname{5th~level}
\renewcommand\spellsixthlevelname{6th~level}
\renewcommand\spellseventhlevelname{7th~level}
\renewcommand\spelleighthlevelname{8th~level}
\renewcommand\spellninthlevelname{9th~level}
% Spell slots
\renewcommand\spellatwillname{at~will}
\renewcommand\spelloneslotname{1~slot}
\renewcommand\spelltwoslotsname{2~slots}
\renewcommand\spellthreeslotsname{3~slots}
\renewcommand\spellfourslotsname{4~slots}
% Innate spellcasting
\renewcommand\innateatwillname{At~will}
\renewcommand\numberperdayname{|1|/day}
\renewcommand\numberperdayeachname{|1|/day~each}
% Spell header
\renewcommand\spellcastingtimename{Casting~Time}
\renewcommand\spellrangename{Range}
\renewcommand\spellcomponentsname{Components}
\renewcommand\spelldurationname{Duration}
% Miscellaneous
\renewcommand\tocchapterabbreviationname{Ch.}
\renewcommand\pageabbreviationname{pg.}
\renewcommand\dname{d}
}

73
lib/languages/french.sty Normal file
View File

@@ -0,0 +1,73 @@
\ExplSyntaxOn % Use tilde (~) for spaces.
\addto\captionsfrench%
{
% Monster basics
\renewcommand\armorclassname{Classe~d'armure}
\renewcommand\hitpointsname{Points~de~vie}
\renewcommand\speedname{Vitesse}
% Monster ability scores
\renewcommand\strstatname{FOR}
\renewcommand\dexstatname{DEX}
\renewcommand\constatname{CON}
\renewcommand\intstatname{INT}
\renewcommand\wisstatname{SAG}
\renewcommand\chastatname{CHA}
% Monster details
\renewcommand\skillsname{Compétences}
\renewcommand\dimmname{Immunité~contre~les~dégâts}
\renewcommand\dvulname{Vulnérabilité~aux~dégâts}
\renewcommand\dresname{Résistances~aux~dégâts}
\renewcommand\cimmname{Immunité~contre~les~états}
\renewcommand\savesname{Jets~de~sauvegarde}
\renewcommand\sensesname{Sens}
\renewcommand\defaultsensesname{Perception~passive~10}
\renewcommand\languagesname{Langues}
\renewcommand\challengename{Dangerosité}
\renewcommand\xpname{PX}
% Monster attack
\renewcommand\unitsname{m}
\renewcommand\weaponname{d'arme}
\renewcommand\spellname{de~sort}
\renewcommand\meleeattackname{Attaque~|1|~au~corps~à~corps}
\renewcommand\rangedattackname{Attaque~|1|~à~distance}
\renewcommand\meleeorrangedattackname{Attaque~|1|~au~corps~à~corps~ou~à~distance}
\renewcommand\orname{ou}
\renewcommand\tohitname{|1|~pour~toucher}
\renewcommand\defaulttargetsname{une~cible}
\renewcommand\reachname{allonge}
\renewcommand\rangename{portée}
\renewcommand\hitname{Touché}
\renewcommand\damagename{dégâts}
\renewcommand\plusname{plus}
% Spell levels
\renewcommand\spellcantripsname{Tour~de~magie}
\renewcommand\spellfirstlevelname {Niveau~1}
\renewcommand\spellsecondlevelname {Niveau~2}
\renewcommand\spellthirdlevelname {Niveau~3}
\renewcommand\spellfourthlevelname {Niveau~4}
\renewcommand\spellfifthlevelname {Niveau~5}
\renewcommand\spellsixthlevelname {Niveau~6}
\renewcommand\spellseventhlevelname{Niveau~7}
\renewcommand\spelleighthlevelname {Niveau~8}
\renewcommand\spellninthlevelname {Niveau~9}
% Spell slots
\renewcommand\spellatwillname{à~volonté}
\renewcommand\spelloneslotname{1~emplacement}
\renewcommand\spelltwoslotsname{2~emplacements}
\renewcommand\spellthreeslotsname{3~emplacements}
\renewcommand\spellfourslotsname{4~emplacements}
% Innate spellcasting
\renewcommand\innateatwillname{À~volonté}
\renewcommand\numberperdayname{|1|/jour}
\renewcommand\numberperdayeachname{|1|/jour~chacun}
% % Spell header
\renewcommand\spellcastingtimename{Durée~d'incantation}
\renewcommand\spellrangename{Portée}
\renewcommand\spellcomponentsname{Composantes}
\renewcommand\spelldurationname{Durée}
% % Miscellaneous
\renewcommand\pageabbreviationname{p.}
\renewcommand\dname{d}
\renewcommand\tocchapterabbreviationname{Ch.}
}

75
lib/languages/italian.sty Normal file
View File

@@ -0,0 +1,75 @@
\ExplSyntaxOn
% Use tilde (~) for spaces.
% Italian captions
\addto\captionsitalian
{
% Monster basics
\renewcommand\armorclassname{Classe~Armatura}
\renewcommand\hitpointsname{Punti~Ferita}
\renewcommand\speedname{Velocit\`a}
% Monster ability scores
\renewcommand\strstatname{FOR}
\renewcommand\dexstatname{DES}
\renewcommand\constatname{COS}
\renewcommand\intstatname{INT}
\renewcommand\wisstatname{SAG}
\renewcommand\chastatname{CAR}
% Monster details
\renewcommand\skillsname{Abilit\`a}
\renewcommand\dimmname{Immunità~Danni}
\renewcommand\dvulname{Debolezze~Danni}
\renewcommand\dresname{Resistenze~Danni}
\renewcommand\cimmname{Immunit\`a~Condizioni}
\renewcommand\savesname{Tiri~Salvezza}
\renewcommand\sensesname{Sensi}
% \renewcommand\defaultsensesname{passive~Perception~10}
\renewcommand\languagesname{Linguaggi}
\renewcommand\challengename{Sfida}
\renewcommand\xpname{PE}
% Monster attack
\renewcommand\unitsname{m.}
\renewcommand\weaponname{Arma}
\renewcommand\spellname{Sillabare}
\renewcommand\meleeattackname{Attacco~con~|1|~da~Mischia}
\renewcommand\rangedattackname{Attacco~con~|1|~a~Distanza}
\renewcommand\meleeorrangedattackname{Attacco~con~|1|~da~Mischia~o~a~Distanza}
\renewcommand\orname{o}
\renewcommand\tohitname{|1|~per~colpire}
% \renewcommand\defaulttargetsname{one~target}
\renewcommand\reachname{portata}
\renewcommand\rangename{gittata}
\renewcommand\hitname{Colpito}
\renewcommand\damagename{danno}
% \renewcommand\plusname{plus}
% Spell levels
\renewcommand\spellcantripsname{Trucchetti}
\renewcommand\spellfirstlevelname{1\degree{}~livello}
\renewcommand\spellsecondlevelname{2\degree{}~livello}
\renewcommand\spellthirdlevelname{3\degree{}~livello}
\renewcommand\spellfourthlevelname{4\degree{}~livello}
\renewcommand\spellfifthlevelname{5\degree{}~livello}
\renewcommand\spellsixthlevelname{6\degree{}~livello}
\renewcommand\spellseventhlevelname{7\degree{}~livello}
\renewcommand\spelleighthlevelname{8\degree{}~livello}
\renewcommand\spellninthlevelname{9\degree{}~livello}
% Spell slots
\renewcommand\spellatwillname{a~volont\`a}
\renewcommand\spelloneslotname{1~slot}
\renewcommand\spelltwoslotsname{2~slot}
\renewcommand\spellthreeslotsname{3~slot}
\renewcommand\spellfourslotsname{4~slot}
% Innate spellcasting
\renewcommand\innateatwillname{A~volont\`a}
\renewcommand\numberperdayname{|1|/giorno}
\renewcommand\numberperdayeachname{|1|/g.~ciascuno}
% Spell header
\renewcommand\spellcastingtimename{Tempo~di~Lancio}
\renewcommand\spellrangename{Gittata}
\renewcommand\spellcomponentsname{Componenti}
\renewcommand\spelldurationname{Durata}
% Miscellaneous
% \renewcommand\pageabbreviationname{pg.}
% \renewcommand\dname{d}
% \newcommand\tocchapterabbreviationname{Ch.}
}

View File

@@ -0,0 +1,72 @@
\ExplSyntaxOn % Use tilde (~) for spaces.
% Japanese captions
\addto\captionsjapanese
{
% Monster basics
\renewcommand\armorclassname{AC}
\renewcommand\hitpointsname{hp}
\renewcommand\speedname{移動速度:}
% Monster ability scores
\renewcommand\strstatname{【筋】}
\renewcommand\dexstatname{【敏】}
\renewcommand\constatname{【耐】}
\renewcommand\intstatname{【知】}
\renewcommand\wisstatname{【判】}
\renewcommand\chastatname{【魅】}
% Monster details
\renewcommand\skillsname{技能:}
\renewcommand\dimmname{ダメージ完全耐性:}
\renewcommand\dvulname{ダメージ脆弱性:}
\renewcommand\dresname{ダメージ抵抗:}
\renewcommand\cimmname{状態完全耐性:}
\renewcommand\savesname{セーブ:}
\renewcommand\sensesname{感覚:}
\renewcommand\defaultsensesname{受動〈知覚〉10}
\renewcommand\languagesname{言語:}
\renewcommand\challengename{脅威度:}
\renewcommand\xpname{XP}
% Monster attack
\renewcommand\unitsname{フィート}
\renewcommand\meleeattackname{近接武器攻撃:}
\renewcommand\rangedattackname{遠隔武器攻撃:}
\renewcommand\meleeorrangedattackname{近接/遠隔武器攻撃:}
\renewcommand\orname{または}
\renewcommand\tohitname{攻撃|1|}
\renewcommand\defaulttargetsname{目標1つ}
\renewcommand\reachname{間合い}
\renewcommand\rangename{射程}
\renewcommand\hitname{ヒット:}
\renewcommand\damagename{ダメージ}
\renewcommand\plusname{および}
% Spell levels
\renewcommand\spellcantripsname{初級呪文}
\renewcommand\spellfirstlevelname{1レベル}
\renewcommand\spellsecondlevelname{2レベル}
\renewcommand\spellthirdlevelname{3レベル}
\renewcommand\spellfourthlevelname{4レベル}
\renewcommand\spellfifthlevelname{5レベル}
\renewcommand\spellsixthlevelname{6レベル}
\renewcommand\spellseventhlevelname{7レベル}
\renewcommand\spelleighthlevelname{8レベル}
\renewcommand\spellninthlevelname{9レベル}
% Spell slots
\renewcommand\spellatwillname{無限回}
\renewcommand\spelloneslotname{1スロット}
\renewcommand\spelltwoslotsname{2スロット}
\renewcommand\spellthreeslotsname{3スロット}
\renewcommand\spellfourslotsname{4スロット}
% Innate spellcasting
\renewcommand\innateatwillname{無限回}
\renewcommand\numberperdayname{|1|回/日}
\renewcommand\numberperdayeachname{各|1|回/日}
% Spell header
\renewcommand\spellcastingtimename{発動時間}
\renewcommand\spellrangename{射程}
\renewcommand\spellcomponentsname{構成要素}
\renewcommand\spelldurationname{持続時間}
% Miscellaneous
\renewcommand\tocchapterabbreviationname{章} % TODO: Update to 第|1|章 when https://github.com/rpgtex/DND-5e-LaTeX-Template/issues/308 is closed
\renewcommand\pageabbreviationname{ページ} % TODO: Update to |1|ページ when https://github.com/rpgtex/DND-5e-LaTeX-Template/issues/308 is closed
\renewcommand\dname{d}
}

68
lib/languages/ngerman.sty Normal file
View File

@@ -0,0 +1,68 @@
\ExplSyntaxOn % Use tilde (~) for spaces.
% German captions
\addto\captionsngerman
{
\renewcommand\armorclassname{Rüstungsklasse}
\renewcommand\hitpointsname{Trefferpunkte}
\renewcommand\speedname{Bewegungsrate}
\renewcommand\strstatname{STR}
\renewcommand\dexstatname{GES}
\renewcommand\constatname{KON}
\renewcommand\intstatname{INT}
\renewcommand\wisstatname{WEI}
\renewcommand\chastatname{CHA}
\renewcommand\skillsname{Fertigkeiten}
\renewcommand\dimmname{Schadensimmunitäten}
\renewcommand\dvulname{Schadensanfälligkeiten}
\renewcommand\dresname{Schadensresistenzen}
\renewcommand\cimmname{Zustandsimmunitäten}
\renewcommand\savesname{Rettungswürfe}
\renewcommand\sensesname{Sinne}
\renewcommand\languagesname{Sprachen}
\renewcommand\challengename{Herausforderungsgrad}
\renewcommand\xpname{EP}
% Monster attack
\renewcommand\unitsname{m}
\renewcommand\meleeattackname{Nahkampf-Waffenangriff}
\renewcommand\rangedattackname{Fernkampf-Waffenangriff}
\renewcommand\meleeorrangedattackname{Nah-~oder~Fernkampf-Waffenangriff}
\renewcommand\orname{oder}
\renewcommand\tohitname{|1|~zum~Treffen}
\renewcommand\defaulttargetsname{ein~Ziel}
\renewcommand\reachname{Reichweite}
\renewcommand\rangename{Reichweite}
\renewcommand\hitname{Treffer}
\renewcommand\damagename{Schaden}
\renewcommand\plusname{plus}
% Spell levels
\renewcommand\spellcantripsname{Zaubertricks}
\renewcommand\spellfirstlevelname{1.~Grad}
\renewcommand\spellsecondlevelname{2.~Grad}
\renewcommand\spellthirdlevelname{3.~Grad}
\renewcommand\spellfourthlevelname{4.~Grad}
\renewcommand\spellfifthlevelname{5.~Grad}
\renewcommand\spellsixthlevelname{6.~Grad}
\renewcommand\spellseventhlevelname{7.~Grad}
\renewcommand\spelleighthlevelname{8.~Grad}
\renewcommand\spellninthlevelname{9.~Grad}
% Spell slots
\renewcommand\spellatwillname{beliebig oft}
\renewcommand\spelloneslotname{1~Platz}
\renewcommand\spelltwoslotsname{2~Plätze}
\renewcommand\spellthreeslotsname{3~Plätze}
\renewcommand\spellfourslotsname{4~Plätze}
% Innate spellcasting
\renewcommand\innateatwillname{Willentlich}
\renewcommand\numberperdayname{|1|/Tag}
\renewcommand\numberperdayeachname{jeweils~|1|/Tag}
% Spell header
\renewcommand\spellcastingtimename{Zeitaufwand}
\renewcommand\spellrangename{Reichweite}
\renewcommand\spellcomponentsname{Komponenten}
\renewcommand\spelldurationname{Wirkungsdauer}
% Miscellaneous
\renewcommand\pageabbreviationname{S.}
\renewcommand\dname{W}
\renewcommand\tocchapterabbreviationname{Kap.}
}

View File

@@ -0,0 +1,73 @@
\ExplSyntaxOn % Use tilde (~) for spaces.
\addto\captionsportuguese
{
% Monster basics
\renewcommand\armorclassname{Classe~de~Armadura}
\renewcommand\hitpointsname{Pontos~de~Vida}
\renewcommand\speedname{Deslocamento}
% Monster ability scores
\renewcommand\strstatname{FOR}
\renewcommand\dexstatname{DES}
\renewcommand\constatname{CON}
\renewcommand\intstatname{INT}
\renewcommand\wisstatname{SAB}
\renewcommand\chastatname{CAR}
% Monster details
\renewcommand\skillsname{Habilidades}
\renewcommand\dimmname{Imunidade~a~Dano}
\renewcommand\dvulname{Vulnerabilidade~a~Dano}
\renewcommand\dresname{Resistência~a~Dano}
\renewcommand\cimmname{Imunidade~a~Condição}
\renewcommand\savesname{Testes~de~Resistência}
\renewcommand\sensesname{Sentidos}
\renewcommand\defaultsensesname{Percepção~passiva~10}
\renewcommand\languagesname{Idiomas}
\renewcommand\challengename{Nível~de~Desafio}
\renewcommand\xpname{XP}
% Monster attack
\renewcommand\unitsname{m}
\renewcommand\weaponname{Arma}
\renewcommand\spellname{Magia}
\renewcommand\meleeattackname{Ataque~Corpo-a-Corpo~com~|1|}
\renewcommand\rangedattackname{Ataque~à~Distância~com~|1|}
\renewcommand\meleeorrangedattackname{Ataque~Corpo-a-Corpo~ou~à~Distancia~com~|1|}
\renewcommand\orname{ou}
\renewcommand\tohitname{|1|~para~atingir}
\renewcommand\defaulttargetsname{um~alvo}
\renewcommand\reachname{alcance}
\renewcommand\rangename{alcance}
\renewcommand\hitname{Acerto}
\renewcommand\damagename{dano}
\renewcommand\plusname{e}
% Spell levels
\renewcommand\spellcantripsname{Truques}
\renewcommand\spellfirstlevelname{1º~nível}
\renewcommand\spellsecondlevelname{2º~nível}
\renewcommand\spellthirdlevelname{3º~nível}
\renewcommand\spellfourthlevelname{4º~nível}
\renewcommand\spellfifthlevelname{5º~nível}
\renewcommand\spellsixthlevelname{6º~nível}
\renewcommand\spellseventhlevelname{7º~nível}
\renewcommand\spelleighthlevelname{8º~nível}
\renewcommand\spellninthlevelname{9º~nível}
% Spell slots
\renewcommand\spellatwillname{à~vontade}
\renewcommand\spelloneslotname{1~espaço}
\renewcommand\spelltwoslotsname{2~espaços}
\renewcommand\spellthreeslotsname{3~espaços}
\renewcommand\spellfourslotsname{4~espaços}
% Innate spellcasting
\renewcommand\innateatwillname{À~vontade}
\renewcommand\numberperdayname{|1|/dia}
\renewcommand\numberperdayeachname{|1|/dia~cada}
% Spell header
\renewcommand\spellcastingtimename{Tempo~de~Conjuração}
\renewcommand\spellrangename{Alcance}
\renewcommand\spellcomponentsname{Componentes}
\renewcommand\spelldurationname{Duração}
% Miscellaneous
\renewcommand\dname{d}
\renewcommand\pageabbreviationname{pág.}
\renewcommand\tocchapterabbreviationname{cap.}
}

74
lib/languages/russian.sty Normal file
View File

@@ -0,0 +1,74 @@
\ExplSyntaxOn % Use tilde (~) for spaces.
% Russian captions
\addto\captionsrussian
{
% Monster basics
\renewcommand\armorclassname{Класс~Доспехов}
\renewcommand\hitpointsname{Хиты}
\renewcommand\speedname{Скорость}
% Monster ability scores
\renewcommand\strstatname{СИЛ}
\renewcommand\dexstatname{ЛОВ}
\renewcommand\constatname{ТЕЛ}
\renewcommand\intstatname{ИНТ}
\renewcommand\wisstatname{МДР}
\renewcommand\chastatname{ХАР}
% Monster details
\renewcommand\skillsname{Навыки}
\renewcommand\dimmname{Иммунитет~к~урону}
\renewcommand\dvulname{Уязвимость~к~урону}
\renewcommand\dresname{Сопротивление~урону}
\renewcommand\cimmname{Иммунитет~к~состояниям}
\renewcommand\savesname{Спасброски}
% \renewcommand\defaultsensesname{passive~Perception~10}
\renewcommand\sensesname{Чувства}
\renewcommand\languagesname{Языки}
\renewcommand\challengename{Опасность}
% \renewcommand\xpname{XP}
% Monster attack
% \renewcommand\unitsname{ft.}
% \renewcommand\weaponname{Weapon}
% \renewcommand\spellname{Spell}
% \renewcommand\meleeattackname{Melee~|1|~Attack}
% \renewcommand\rangedattackname{Ranged~|1|~Attack}
% \renewcommand\meleeorrangedattackname{Melee~or~Ranged~|1|~Attack}
% \renewcommand\orname{or}
% \renewcommand\tohitname{|1|~to~hit}
% \renewcommand\defaulttargetsname{one~target}
% \renewcommand\reachname{reach}
% \renewcommand\rangename{range}
% \renewcommand\hitname{Hit}
% \renewcommand\damagename{damage}
% \renewcommand\plusname{plus}
% Spell levels
% \renewcommand\spellcantripsname{Cantrips}
% \renewcommand\spellfirstlevelname{1st~level}
% \renewcommand\spellsecondlevelname{2nd~level}
% \renewcommand\spellthirdlevelname{3rd~level}
% \renewcommand\spellfourthlevelname{4th~level}
% \renewcommand\spellfifthlevelname{5th~level}
% \renewcommand\spellsixthlevelname{6th~level}
% \renewcommand\spellseventhlevelname{7th~level}
% \renewcommand\spelleighthlevelname{8th~level}
% \renewcommand\spellninthlevelname{9th~level}
% Spell slots
% \renewcommand\spellatwillname{at~will}
% \renewcommand\spelloneslotname{1~slot}
% \renewcommand\spelltwoslotsname{2~slots}
% \renewcommand\spellthreeslotsname{3~slots}
% \renewcommand\spellfourslotsname{4~slots}
% Innate spellcasting
% \renewcommand\innateatwillname{At~will}
% \renewcommand\numberperdayname{|1|/day}
% \renewcommand\numberperdayeachname{|1|/day~each}
% % Spell header
% \renewcommand\spellcastingtimename{Casting~Time}
% \renewcommand\spellrangename{Range}
% \renewcommand\spellcomponentsname{Components}
% \renewcommand\spelldurationname{Duration}
% % Miscellaneous
% \renewcommand\pageabbreviationname{pg.}
% \renewcommand\dname{d}
% \newcommand\tocchapterabbreviationname{Ch.}
}

73
lib/languages/spanish.sty Executable file
View File

@@ -0,0 +1,73 @@
\ExplSyntaxOn % Use tilde (~) for spaces.
\addto\captionsspanish
{
% Monster basics
\renewcommand\armorclassname{Clase~de~Armadura}
\renewcommand\hitpointsname{Puntos~de~Golpe}
\renewcommand\speedname{Velocidad}
% Monster ability scores
\renewcommand\strstatname{FUE}
\renewcommand\dexstatname{DES}
\renewcommand\constatname{CON}
\renewcommand\intstatname{INT}
\renewcommand\wisstatname{SAB}
\renewcommand\chastatname{CAR}
% Monster details
\renewcommand\skillsname{Habilidades}
\renewcommand\dimmname{Inmunidad~a~daño}
\renewcommand\dvulname{Vulnerabilidad~a~daño}
\renewcommand\dresname{Resistencia~a~daño}
\renewcommand\cimmname{Inmunidad~a~estados}
\renewcommand\savesname{Tiradas~de~salvación}
\renewcommand\sensesname{Sentidos}
\renewcommand\defaultsensesname{Percepción~pasiva~10}
\renewcommand\languagesname{Idiomas}
\renewcommand\challengename{Desafío}
\renewcommand\xpname{PE}
% Monster attack
\renewcommand\unitsname{pies}
\renewcommand\weaponname{arma}
\renewcommand\spellname{Hechizo}
\renewcommand\meleeattackname{Ataque~con~|1|~cuerpo~a~cuerpo}
\renewcommand\rangedattackname{Ataque~con~|1|~a~distancia}
\renewcommand\meleeorrangedattackname{Ataque~con~|1|~cuerpo~a~cuerpo~o~a~distancia}
\renewcommand\orname{o}
\renewcommand\tohitname{|1|~a~impactar}
\renewcommand\defaulttargetsname{un~objetivo}
\renewcommand\reachname{alcance}
\renewcommand\rangename{alcance}
\renewcommand\hitname{Impacto}
\renewcommand\damagename{daño}
\renewcommand\plusname{y}
% Spell levels
\renewcommand\spellcantripsname{Trucos}
\renewcommand\spellfirstlevelname{Nivel~1}
\renewcommand\spellsecondlevelname{Nivel~2}
\renewcommand\spellthirdlevelname{Nivel~3}
\renewcommand\spellfourthlevelname{Nivel~4}
\renewcommand\spellfifthlevelname{Nivel~5}
\renewcommand\spellsixthlevelname{Nivel~6}
\renewcommand\spellseventhlevelname{Nivel~7}
\renewcommand\spelleighthlevelname{Nivel~8}
\renewcommand\spellninthlevelname{Nivel~9}
% Spell slots
\renewcommand\spellatwillname{a~voluntad}
\renewcommand\spelloneslotname{1~espacio}
\renewcommand\spelltwoslotsname{2~espacios}
\renewcommand\spellthreeslotsname{3~espacios}
\renewcommand\spellfourslotsname{4~espacios}
% Innate spellcasting
\renewcommand\innateatwillname{A~voluntad}
\renewcommand\numberperdayname{|1|~al~día}
\renewcommand\numberperdayeachname{|1|~al~día~cada~uno}
% Spell header
\renewcommand\spellcastingtimename{Tiempo~de~lanzamiento}
\renewcommand\spellrangename{Alcance}
\renewcommand\spellcomponentsname{Componentes}
\renewcommand\spelldurationname{Duración}
% Miscellaneous
\renewcommand\dname{d}
\renewcommand\pageabbreviationname{pág.}
\renewcommand\tocchapterabbreviationname{cap.}
}

56
lib/rpgcolors.sty Normal file
View File

@@ -0,0 +1,56 @@
\ExplSyntaxOn
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Define colors, sampled from the books.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Page
\definecolor {bgtan} {HTML} {F7F2E5} % RpgReadAloud background
\definecolor {bgtan2018}{HTML} {F9EFD6} % lighter version of bgtan from the 2018 Basic Rules
\definecolor {pagegold} {HTML} {B89A67} % pagenumbers and footer
% Type
\definecolor {titlered} {HTML} {58180D} % titles
\definecolor {titlegold} {HTML} {C9AD6A} % titlerules
\definecolor {rulered} {HTML} {9C2B1B} % triangular rule in statsblock
\definecolor {contourgray} {HTML} {CACCBE} % outline color in part & chapter font
% Type aliases
\colorlet {contourgrey} {contourgray}
% Trim
\definecolor {BrGreen} {HTML} {E8E6DC} % Basic Rules
\definecolor {PhbLightGreen} {HTML} {E0E5C1} % PHB Part 1
\definecolor {PhbLightCyan} {HTML} {B5CEB8} % PHB Part 2
\definecolor {PhbMauve} {HTML} {DCCCC5} % PHB Part 3
\definecolor {PhbTan} {HTML} {E5D5AC} % PHB appendix
\definecolor {DmgLavender} {HTML} {E3CED3} % DMG Part 1
\definecolor {DmgCoral} {HTML} {F3D7C1} % DMG Part 2
\definecolor {DmgSlateGray} {HTML} {DBE4E4} % DMG Part 3
\definecolor {DmgLilac} {HTML} {D7D4D6} % DMG appendix
% Trim aliases
\colorlet {DmgSlateGrey} {DmgSlateGray}
% The color used in \RpgSetThemeColor when a new color is not set
\colorlet {themecolor} {PhbLightGreen} % Set the default theme to Part 1 of the PHB.
% Element colors that change when \RpgSetThemeColor is used
\colorlet {commentcolor} {themecolor} % RpgComment background
\colorlet {sidebarcolor} {themecolor} % RpgSidebar background
\colorlet {tablecolor} {themecolor} % RpgTable even row background
% Element colors that do not respond to \RpgSetThemeColor
\colorlet {readaloudcolor} {bgtan} % RpgReadAloud background
\definecolor {statblockribbon} {HTML} {E69A28} % stat block top/bottom borders (gold)
\definecolor {statblockbg} {HTML} {FDF1DC} % stat block background (tan)
% Sets the themecolor and colors for all themed elements
% If called without the optional color, resets the color of all themed elements to the current themecolor
\NewDocumentCommand {\RpgSetThemeColor} { O {themecolor} }
{
\colorlet {themecolor} {#1}
\colorlet {commentcolor} {#1}
\colorlet {sidebarcolor} {#1}
\colorlet {tablecolor} {#1}
}

78
lib/rpgcomment.sty Normal file
View File

@@ -0,0 +1,78 @@
\ExplSyntaxOn
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Environment for comments.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Standard for every comment
\DeclareTColorBox {__rpg_comment} {o}
{
before~upper =
{
\bool_if:NT \l__rpg_layout_bool
{
\bool_if:NF \l__rpg_justified_bool
{ \RaggedRight }
}
},
code = {\linespread{.9}},
frame~hidden,
boxrule = 0pt,
breakable,
enhanced,
before~skip = 13pt plus 4pt minus 4pt,
toptitle = 2pt,
boxsep = 3pt,
left = 6pt,
right = 6pt,
top = 0pt,
bottom = 2pt,
sharp~corners,
fonttitle = \RpgFontCommentTitle,
fontupper = \RpgFontCommentBody,
fontlower = \RpgFontCommentBody,
parbox = false,
coltitle = black,
after~skip = 13pt plus 4pt minus 4pt,
#1,
}
% Extra key for controlling the color of the title and the background
\keys_define:nn { rpg / comment }
{
color .tl_set:N = \l__rpg_comment_color_tl,
color .initial:n = commentcolor,
color .value_required:n = true,
}
% This function, through its variant, forces the expansion of the tcb keys
% passed to the environment by the user before it invokes the tcolorbox
\cs_new_protected:Nn \__rpg_start_comment:nn
{
\begin {__rpg_comment} [ #1, #2 ]
}
\cs_generate_variant:Nn \__rpg_start_comment:nn { nV }
% The RpgComment environment
% #1 - keys. We handle the custom color key before passing other keys on
% #2 - title.
\NewDocumentEnvironment {RpgComment} { o m }
{
\group_begin:
\keys_set_known:nnN { rpg / comment } {#1} \l_tmpa_tl
\str_if_eq:VnT \l_tmpa_tl { -NoValue- }
{ \tl_set_eq:NN \l_tmpa_tl \c_empty_tl }
\__rpg_start_comment:nV
{
colback = \l__rpg_comment_color_tl,
colbacktitle = \l__rpg_comment_color_tl,
title = {#2},
}
{ \l_tmpa_tl }
}
{
\end {__rpg_comment}
\group_end:
}

620
lib/rpgdeprecated.sty Normal file
View File

@@ -0,0 +1,620 @@
\RequirePackage {keycommand}
\ExplSyntaxOn
\NewDocumentCommand{\RpgDeprecate}{ mmm }
{
\__rpg_deprecated:nnn {#1} {#2} {#3}
}
\ExplSyntaxOff
% Either hilariously, or infuriatingly, the \ifcommandkey
% implementation is buggy. Here is a re-implementation
% from tex.stackexchange.
\begingroup
\makeatletter
\catcode`\/=8 %
\@firstofone
{
\endgroup
\renewcommand{\ifcommandkey}[1]{%
\csname @\expandafter \expandafter \expandafter
\expandafter \expandafter \expandafter \expandafter
\kcmd@nbk \commandkey {#1}//{first}{second}//oftwo\endcsname
}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rpgcolors.sty - to be removed in version 1.0.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Sets the themecolor and colors for all themed elements
% If called without the optional color, resets the color of all themed elements to the current themecolor
\newcommand{\setthemecolor}[1][themecolor]{%
\RpgDeprecate{\noexpand\setthemecolor}{1.0.0}{Use \noexpand\RpgSetThemeColor to set the theme color.}%
\colorlet{themecolor}{#1}
\colorlet{commentcolor}{#1}
\colorlet{sidebarcolor}{#1}
\colorlet{tablecolor}{#1}
}
% Backwards-compatible aliases and colours
\colorlet {commentgreen} {PhbLightGreen}
\colorlet {itemtablepink} {DmgCoral}
\colorlet {monstertan} {statblockbg}
\definecolor {monstertandark} {HTML} {F0DBB5}
% Old interface
\colorlet {commentboxcolor} {commentcolor}
\colorlet {paperboxcolor} {sidebarcolor}
\colorlet {quoteboxcolor} {readaloudcolor}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rpgcomment.sty - to be removed in version 1.0.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Usage \begin{commentbox}[options]{title}[color]
\ExplSyntaxOn
\DeclareTColorBox{commentbox}{O{} m O{commentboxcolor}}{%
before~upper={%
\bool_if:NT \l__rpg_layout_bool
{
\bool_if:NF \l__rpg_justified_bool
{ \RaggedRight }
}
},
code={\RpgDeprecate{\noexpand\commentbox}{1.0.0}{Use~\noexpand\RpgComment~for~breakable~comment~boxes.}\linespread{.9}},
frame~hidden,
boxrule=0pt,
breakable,
enhanced,
before~skip=13pt plus 4pt minus 4pt,
toptitle=2pt,
boxsep=3pt,
left=6pt,
right=6pt,
top=0pt,
bottom=2pt,
sharp~corners,
fonttitle=\RpgFontCommentTitle,
fontupper=\RpgFontCommentBody,
fontlower=\RpgFontCommentBody,
title={#2},
parbox=false,
colback=#3,
colbacktitle=#3,
coltitle=black,
after~skip=13pt plus 4pt minus 4pt,
#1
}
\ExplSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rpgmonster.sty - to be removed in version 1.0.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Fancy DnD 5e stat block rule
\newcommand{\rpgline}{%
\RpgDeprecate{\noexpand\rpgline}{1.0.0}{Use \noexpand\RpgMonsterLine for stat block rules.}%
\noindent
\begin{tikzpicture}[]
\draw [rulered, fill=rulered] (0, 0) --(0,0.1) -- (\textwidth, 0.05);
\end{tikzpicture}%
\par%
}
\RequirePackage{fp}
\RequirePackage{xstring}
% Macro to print stats with auto-computed modifier
% e.g. \stat{12} prints "12 (+1)"
\newcommand{\stat}[1]{%
\RpgDeprecate{\noexpand\stat}{1.0.0}{Use \noexpand\RpgMonsterAbilityScores for the stat block ability score table.}%
\FPeval{\mod}{(#1 - 10)/2}%
\FPifpos\mod%
\FPeval{\mod}{clip(trunc(mod,0))}#1\ (+\mod)%
\else%
\FPeval{\mod}{clip(abs(trunc(mod-0.5,0)))}#1\ (--\mod)%
\fi%
}
% Macro to print avarage dice based value
% e.g. \dice{2d6+3} prints "10 (2d6 + 3)"
\newcommand{\dice}[1]{%
\RpgDeprecate{\noexpand\dice}{1.0.0}{Use \noexpand\RpgDice to typeset a dice roll with the average value.}%
\StrSubstitute{#1}{ }{}[\DiceArg]% strip whitespaces
\StrCut{\DiceArg}{d}\DiceNum\DiceSides% split string
\StrCut{\DiceSides}{+}\DiceSides\DiceAddMod%
\StrCut{\DiceSides}{-}\DiceSides\DiceSubMod%
\FPeval{\DiceAvg}{(\DiceSides+1)/2*\DiceNum}% calculate avg roll
\IfInteger{\DiceAddMod}{%
\FPadd{\DiceAvg}{\DiceAvg}{\DiceAddMod}% add value
\def\DiceMod{ + \DiceAddMod}%
}{%
\IfInteger{\DiceSubMod}{%
\FPsub{\DiceAvg}{\DiceAvg}{\DiceSubMod}% subtract value
\def\DiceMod{ -- \DiceSubMod}%
}{%
\def\DiceMod{}%
}%
}%
\FPtrunc{\DiceAvg}{\DiceAvg}{0}% round down
\FPprint{\DiceAvg\ (\DiceNum \dname\DiceSides\DiceMod)}%
}
% Stat block without the background
\newtcolorbox{monsterboxnobg}[2][]{
enhanced,
code={\RpgDeprecate{\noexpand\monsterboxnobg}{1.0.0}{Use \noexpand\RpgMonsterNoBg for stat blocks without a background.}},
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 with background
\newtcolorbox{monsterboxbg}[2][]{
enhanced,
code={\RpgDeprecate{\noexpand\monsterboxbg}{1.0.0}{Use \noexpand\RpgMonsterBg for stat blocks with a background.}},
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
}
\ExplSyntaxOn
\bool_if:NTF \l__rpg_show_background_bool
{
\let\monsterbox\monsterboxbg%
\let\endmonsterbox\endmonsterboxbg%
}
{
\let\monsterbox\monsterboxnobg%
\let\endmonsterbox\endmonsterboxnobg%
}
\ExplSyntaxOff
% Define Monster subsection header style
\newcommand{\monstersection}[1]{%
\RpgDeprecate{\noexpand\monstersection}{1.0.0}{Use \noexpand\RpgMonsterSection for stat blocks sections.}%
\begingroup
\par\medskip\noindent
\RpgFontStatBlockSection #1
% \rule is a horizontal command, so placing it under the title incurs extra
% line spacing. Use \hrule (a vertical command) instead.
\vspace{3pt}
\hrule height 0.6pt
\vspace{2pt}
\endgroup%
}
\NewDocumentEnvironment{monsteraction}{o}{%
\RpgDeprecate{\noexpand\monsteraction}{1.0.0}{Use \noexpand\RpgMonsterAction for stat block actions.}%
\IfValueTF{#1}{%
\par\medskip\noindent\emph{\textbf{#1.}}%
}{\unskip}%
}{\par}
% A description variant used to list creature attributes.
\newlist{rpg@monsterattrs}{description}{1}
\ExplSyntaxOn
\setlist[rpg@monsterattrs]{
before=\color{titlered},
font=\RpgFontStatBlockBody,
labelsep=\l__rpg_space_dim,
noitemsep,
nosep,
}
\ExplSyntaxOff
% A rpg@monsterattrs helper macro that always displays an attribute.
\newcommand{\rpg@monsterattr}[2]{%
\item[#2] \commandkey{#1}
}
% A rpg@monsterattrs helper macro that displays an attribute if the user defined
% it.
\newcommand{\rpg@ifmonsterattr}[2]{%
\ifcommandkey{#1}{%
\item[#2] \commandkey{#1}
}{}%
}
%
% Macros for use within the monster environment
%
\newkeycommand\basics[armorclass=0, hitpoints=0, speed=0]{%
\RpgDeprecate{\noexpand\basics}{1.0.0}{Use \noexpand\RpgMonsterBasics for stat block AC, HP, and speed.}%
\begin{rpg@monsterattrs}
\rpg@monsterattr{armorclass}{\armorclassname}
\rpg@monsterattr{hitpoints}{\hitpointsname}
\rpg@monsterattr{speed}{\speedname}
\end{rpg@monsterattrs}%
}
% Taubular enviornment for stats-block
\newkeycommand\stats[%
STR=\stat{10},
DEX=\stat{10},
CON=\stat{10},
INT=\stat{10},
WIS=\stat{10},
CHA=\stat{10}]{%
\RpgDeprecate{\noexpand\stats}{1.0.0}{Use \noexpand\RpgMonsterAbilityScores for the stat block ability score table.}%
\begingroup%
\color{titlered}%
\par\vspace{5pt}\noindent%
\begin{tabularx}{\linewidth}{YYYYYY}
\textbf{\strstatname} &
\textbf{\dexstatname} &
\textbf{\constatname} &
\textbf{\intstatname} &
\textbf{\wisstatname} &
\textbf{\chastatname} \\
\commandkey{STR} &
\commandkey{DEX} &
\commandkey{CON} &
\commandkey{INT} &
\commandkey{WIS} &
\commandkey{CHA}
\end{tabularx}%
\par\vspace{4pt}%
\endgroup%
}
\newkeycommand\details[
skills=,
damageimmunities=,
savingthrows=,
conditionimmunities=,
damageresistances=,
damagevulnerabilities=,
senses=---,
languages=---,
challenge=1,
]{%
\RpgDeprecate{\noexpand\details}{1.0.0}{Use \noexpand\RpgMonsterDetails for stat block details like resistances and CR.}%
\begin{rpg@monsterattrs}
\rpg@ifmonsterattr{savingthrows}{\savesname}
\rpg@ifmonsterattr{skills}{\skillsname}
\rpg@ifmonsterattr{damagevulnerabilities}{\dvulname}
\rpg@ifmonsterattr{damageresistances}{\dresname}
\rpg@ifmonsterattr{damageimmunities}{\dimmname}
\rpg@ifmonsterattr{conditionimmunities}{\cimmname}
\rpg@monsterattr{senses}{\sensesname}
\rpg@monsterattr{languages}{\languagesname}
\item[\challengename] \RpgCRExp{\commandkey{challenge}}
\end{rpg@monsterattrs}%
}
\ExplSyntaxOn
\newcommand{\rpg@hit}[1]{%
\__rpg_caption:nn {\tohitname} {#1}
}
\ExplSyntaxOff
\newcommand{\rpg@damage}[2]{%
\commandkey{#1}\ \commandkey{#2}\ \damagename%
}
\newcommand{\rpg@ifplusdmg}[2]{%
\ifcommandkey{#1}{%
{ }\plusname\ \commandkey{#1}\ \commandkey{#2}\ \damagename%
}{}%
}
\newcommand{\rpg@ifordmg}[5]{%
\ifcommandkey{#1}{%
, \orname\ \commandkey{#1}\ \commandkey{#2}\ \damagename\rpg@ifplusdmg{#4}{#5}\ \commandkey{#3}%
}{}%
}
\newkeycommand+[\|]\monstermelee[
name=Club,
mod=+0,
reach=5,
targets=\defaulttargetsname,
dmg=\dice{1d4},
dmgtype=bludgeoning,
plusdmg=,
plusdmgtype=,
ordmg=,
ordmgwhen=,
extra=,
]{%
|\monsterattack|[
name={\commandkey{name}},
type=melee,
mod={\commandkey{mod}},
reach={\commandkey{reach}},
targets={\commandkey{targets}},
dmg={\commandkey{dmg}},
dmgtype={\commandkey{dmgtype}},
plusdmg={\commandkey{plusdmg}},
plusdmgtype={\commandkey{plusdmgtype}},
ordmg={\commandkey{ordmg}},
ordmgwhen={\commandkey{ordmgwhen}},
extra={\commandkey{extra}},
]
}
\newkeycommand+[\|]\monsterranged[
name=Shortbow,
mod=+0,
range=80/320,
targets=\defaulttargetsname,
dmg=\dice{1d6},
dmgtype=piercing,
plusdmg=,
plusdmgtype=,
ordmg=,
ordmgwhen=,
extra=,
]{%
|\monsterattack|[
name={\commandkey{name}},
type=ranged,
mod={\commandkey{mod}},
range={\commandkey{range}},
targets={\commandkey{targets}},
dmg={\commandkey{dmg}},
dmgtype={\commandkey{dmgtype}},
plusdmg={\commandkey{plusdmg}},
plusdmgtype={\commandkey{plusdmgtype}},
ordmg={\commandkey{ordmg}},
ordmgwhen={\commandkey{ordmgwhen}},
extra={\commandkey{extra}},
]
}
\newkeycommand\monsterattack[
name=Dagger,
enum* type={both,melee,ranged},
mod=+0,
reach=5,
range=20/60,
targets=\defaulttargetsname,
dmg=\dice{1d4},
dmgtype=piercing,
plusdmg=,
plusdmgtype=,
ordmg=,
ordmgwhen=,
extra=,
]{%
\RpgDeprecate{\noexpand\monsterattack}{1.0.0}{Use \noexpand\RpgMonsterMelee, \noexpand\RpgMonsterRanged, or \noexpand\RpgMonsterAttack for attacks that are melee, ranged, or both, respectively.}%
\begin{monsteraction}[\commandkey{name}]
\IfStrEqCase{\commandkey{type}}{%
{melee}{\textit{\RpgCaption{\meleeattackname}{\weaponname}:} \rpg@hit{mod}, \reachname\ \commandkey{reach} \unitsname}%
{ranged}{\textit{\RpgCaption{\rangedattackname}{\weaponname}:} \rpg@hit{mod}, \rangename\ \commandkey{range} \unitsname}%
{both}{\textit{\RpgCaption{\meleeorrangedattackname}{\weaponname}:} \rpg@hit{mod}, \reachname\ \commandkey{reach} \unitsname\ \orname\ \rangename\ \commandkey{range} \unitsname}%
}[]%
, \commandkey{targets}.
\textit{\hitname:} \rpg@damage{dmg}{dmgtype}%
\rpg@ifplusdmg{plusdmg}{plusdmgtype}%
\rpg@ifordmg{ordmg}{dmgtype}{ordmgwhen}{plusdmg}{plusdmgtype}%
\ifcommandkey{extra}{\commandkey{extra}}{}.
\end{monsteraction}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rpgpaperbox.sty - to be removed in version 1.0.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Usage \begin{paperbox}[options]{title}[color]
\ExplSyntaxOn
\DeclareTColorBox{paperbox}{O{} m O{paperboxcolor}}{%
before~upper={%
\bool_if:NT \l__rpg_layout_bool
{
\bool_if:NF \l__rpg_justified_bool
{\RaggedRight}
}
},
code={\RpgDeprecate{\noexpand\paperbox}{1.0.0}{Use \noexpand\RpgSidebar for sidebars.}\linespread{.9}},
frame~hidden,
boxrule=0pt,
enhanced,
before~skip=13pt plus 4pt minus 4pt,
toptitle=2pt,
boxsep=3pt,
left=6pt,
right=6pt,
top=0pt,
bottom=3pt,
fonttitle=\RpgFontSidebarTitle,
fontupper=\RpgFontSidebarBody,
fontlower=\RpgFontSidebarBody,
title={#2},
sharp~corners,
parbox=false,
borderline~north={1pt}{-0.5pt}{black},
borderline~south={1pt}{-0.5pt}{black},
colback=#3,
colbacktitle=#3,
coltitle=black,
fuzzy~shadow={0mm}{-3.5pt}{-0.5pt}{0.4mm}{black!60!white},
overlay={%
\fill[black] (frame.south~west) -- ++ (7pt,0) -- ++ (0,-5pt) -- cycle;
\fill[black] (frame.north~west) -- ++ (7pt,0) -- ++ (0,5pt) -- cycle;
\fill[black] (frame.north~east) -- ++ (-7pt,0) -- ++ (0,5pt) -- cycle;
\fill[black] (frame.south~east) -- ++ (-7pt,0) -- ++ (0,-5pt) -- cycle;
},
after~skip=14pt plus 4pt minus 4pt,
#1
}
\ExplSyntaxOn
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rpgquote.sty - to be removed in version 1.0.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Usage \begin{quotebox}[options][color]
\ExplSyntaxOn
\DeclareTColorBox{quotebox}{O{} O{quoteboxcolor}}{%
before~upper={%
\bool_if:NT \l__rpg_layout_bool
{
\bool_if:NF \l__rpg_justified_bool
{\RaggedRight}
}
},
code={\RpgDeprecate{\noexpand\quotebox}{1.0.0}{Use~\noexpand\RpgReadAloud~for~read-aloud~text.}\linespread{1.1}},
enhanced~jigsaw,
frame~hidden,
boxrule=0pt,
breakable,
enhanced,
before~skip=13pt plus 4pt minus 4pt,
boxsep=8pt,
top=0pt,
left=0pt,
right=0pt,
bottom=0pt,
colback=#2,
sharp~corners,
parbox=false,
borderline~west={1pt}{-0.5pt}{titlered},
borderline~east={1pt}{-0.5pt}{titlered},
fontupper=\RpgFontReadAloud,
fontlower=\RpgFontReadAloud,
overlay={%
\foreach\n in {north~east,north~west,south~east,south~west}
{\draw[titlered, fill=titlered] (frame.\n) circle (1.5pt); }; },
after~skip=13pt plus 4pt minus 4pt,
#1
}
\ExplSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rpgsections.sty - to be removed in version 1.0.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Special command for magic items, traps, and the like.
\newcommand{\subtitlesection}[2]{%
\RpgDeprecate{\noexpand\subtitlesection}{1.0.0}{Use \noexpand\RpgItemHeader for item headers.}%
\subsubsection{#1}%
\textit{#2}
\par\vspace{3pt plus 1pt minus 1pt}\noindent\ignorespaces}
% Map Areas and their References
% Labelling helpers
\newcommand{\AreaLabel@Prefix}{area}
\newcommand{\SetAreaLabelPrefix}[1]{%
\renewcommand{\AreaLabel@Prefix}{#1}}
\newcounter{Area}
\newcommand\ResetAreas{%
\RpgDeprecate{\noexpand\ResetAreas}{1.0.0}{Use \noexpand\RpgResetAreas to reset area counters.}%
\setcounter{Area}{0}
}
\NewDocumentCommand\area{mo}{%
\RpgDeprecate{\noexpand\area}{1.0.0}{Use \noexpand\RpgArea to typeset a section with an area counter.}%
\refstepcounter{Area}%
\IfNoValueTF{#2}%
{\label{\AreaLabel@Prefix:#1}}%
{\label{\AreaLabel@Prefix:#2}}%
\subsection{\arabic{Area}. #1}%
}
% defines sub-areas, like '5a', '5b'
\newcounter{SubArea}[Area]
\NewDocumentCommand\subarea{mo}{%
\RpgDeprecate{\noexpand\subarea}{1.0.0}{Use \noexpand\RpgSubArea to typeset a section with an sub-area counter.}%
\refstepcounter{SubArea}%
\IfNoValueTF{#2}%
{\label{\AreaLabel@Prefix:#1}}%
{\label{\AreaLabel@Prefix:#2}}%
\subsubsection{\arabic{Area}\alph{SubArea}. #1}%
}
% sub area references should be '5a', '5b', not '1', '2'
\renewcommand\p@SubArea{\arabic{Area}}
\renewcommand\theSubArea{\alph{SubArea}}
\newcounter{DetailArea}[subsection]
\newcommand{\DetailArea@Prefix}{}
\newcommand{\SetDetailAreaPrefix}[1]{\renewcommand{\DetailArea@Prefix}
{#1--\arabic{DetailArea}\par\expandafter\ignorespaces\noindent}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rpgspell.sty - to be removed in version 1.0.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\spellheader}[6]{%
\RpgDeprecate{\noexpand\spellheader}{1.0.0}{Use \noexpand\RpgSpellHeader to typeset a spell header.}%
\subtitlesection{#1}{#2}
\begin{description}[noitemsep,nosep,after=\smallskip,leftmargin=1em]
\item[\spellcastingtimename:] #3
\item[\spellrangename:] #4
\item[\spellcomponentsname:] #5
\item[\spelldurationname:] #6
\end{description}
}
\newenvironment{spell}[6]
{\spellheader{#1}{#2}{#3}{#4}{#5}{#6}}
% Environment encloses description.
{}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% rpgtable.sty - to be removed in version 1.0.0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Table Header
\newcommand{\header}[1]{%
\begingroup%
\par\vspace{10pt plus 3 pt minus 3pt}%
\noindent%
\RpgFontTableTitle%
#1%
\endgroup%
}
% Table Environment
\NewDocumentEnvironment{rpgtable}{O{XX} O{tablecolor}}{%
\RpgDeprecate{\noexpand\rpgtable}{1.0.0}{Use \noexpand\RpgTable for tables.}%
\par\vspace{2pt plus 1pt minus 1pt}%
\noindent%
\RpgFontTableBody%
\setlength{\extrarowheight}{3pt}%
\rowcolors{1}{}{#2}%
\tabularx{\linewidth}{#1}%
}{%
\endtabularx%
\par\vspace{10pt plus 3 pt minus 3pt}%
}

348
lib/rpgfonts.sty Normal file
View File

@@ -0,0 +1,348 @@
\ExplSyntaxOn
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Font definitions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{lettrine}
\RequirePackage{Royal}
\RequirePackage[auto]{contour}
\bool_if:NT \l__rpg_layout_bool
{
\RequirePackage{bookman}
\RequirePackage[type1]{gillius2}
\RequirePackage[notext,nomath,nott]{kpfonts}
\RequirePackage[T1]{fontenc}
\renewcommand{\sfdefault}{jkpss}
}
\cs_new_protected:Npn \__rpg_sf_initial_family:
{
\bool_if:NTF \l__rpg_layout_bool
{ \gilliustwo }
{ \sffamily }
}
\keys_define:nn { rpg / fonts }
{
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Sectioning commands
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Part
part-family .tl_set:N = \l__rpg_part_family_tl,
part-family .initial:n = \normalfont,
part-family .value_required:n = true,
part-style .tl_set:N = \l__rpg_part_style_tl,
part-style .initial:n = \color{titlered} \Huge \scshape,
part-style .value_required:n = true,
% Chapter
chapter-family .tl_set:N = \l__rpg_chapter_family_tl,
chapter-family .initial:n = \normalfont,
chapter-family .value_required:n = true,
chapter-style .tl_set:N = \l__rpg_chapter_style_tl,
chapter-style .initial:n = \linespread{.9} \color{titlered} \Huge \scshape,
chapter-style .value_required:n = true,
% Section
section-family .tl_set:N = \l__rpg_section_family_tl,
section-family .initial:n = \normalfont,
section-family .value_required:n = true,
section-style .tl_set:N = \l__rpg_section_style_tl,
section-style .initial:n = \linespread{.9} \color{titlered} \huge \scshape \RaggedRight,
section-style .value_required:n = true,
% Subsection
subsection-family .tl_set:N = \l__rpg_subsection_family_tl,
subsection-family .initial:n = \normalfont,
subsection-family .value_required:n = true,
subsection-style .tl_set:N = \l__rpg_subsection_style_tl,
subsection-style .initial:n = \linespread{.9} \color{titlered} \Large \scshape \RaggedRight,
subsection-style .value_required:n = true,
% subsubsection
subsubsection-family .tl_set:N = \l__rpg_subsubsection_family_tl,
subsubsection-family .initial:n = \normalfont,
subsubsection-family .value_required:n = true,
subsubsection-style .tl_set:N = \l__rpg_subsubsection_style_tl,
subsubsection-style .initial:n = \linespread{.9} \color{titlered} \large \scshape \RaggedRight,
subsubsection-style .value_required:n = true,
% paragraph
paragraph-family .tl_set:N = \l__rpg_paragraph_family_tl,
paragraph-family .value_required:n = true,
paragraph-style .tl_set:N = \l__rpg_paragraph_style_tl,
paragraph-style .initial:n = \bfseries \slshape,
paragraph-style .value_required:n = true,
% subparagraph
subparagraph-family .tl_set:N = \l__rpg_subparagraph_family_tl,
subparagraph-family .value_required:n = true,
subparagraph-style .tl_set:N = \l__rpg_subparagraph_style_tl,
subparagraph-style .initial:n = \bfseries \slshape,
subparagraph-style .value_required:n = true,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Tables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Table title
table-title-family .tl_set:N = \l__rpg_table_title_family_tl,
table-title-family .initial:n = \sffamily,
table-title-family .value_required:n = true,
table-title-style .tl_set:N = \l__rpg_table_title_style_tl,
table-title-style .initial:n = \bfseries \scshape \large,
table-title-style .value_required:n = true,
% Table header
table-header-family .tl_set:N = \l__rpg_table_header_family_tl,
table-header-family .initial:n = \sffamily,
table-header-family .value_required:n = true,
table-header-style .tl_set:N = \l__rpg_table_header_style_tl,
table-header-style .initial:n = \bfseries,
table-header-style .value_required:n = true,
% Table body
table-body-family .tl_set:N = \l__rpg_table_body_family_tl,
table-body-family .initial:n = \__rpg_sf_initial_family:,
table-body-family .value_required:n = true,
table-body-style .tl_set:N = \l__rpg_table_body_style_tl,
table-body-style .initial:n = \small,
table-body-style .value_required:n = true,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Comment boxes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Comment title
comment-title-family .tl_set:N = \l__rpg_comment_title_family_tl,
comment-title-family .initial:n = \sffamily,
comment-title-family .value_required:n = true,
comment-title-style .tl_set:N = \l__rpg_comment_title_style_tl,
comment-title-style .initial:n = \bfseries \scshape,
comment-title-style .value_required:n = true,
% Comment body
comment-body-family .tl_set:N = \l__rpg_comment_body_family_tl,
comment-body-family .initial:n = \__rpg_sf_initial_family:,
comment-body-family .value_required:n = true,
comment-body-style .tl_set:N = \l__rpg_comment_body_style_tl,
comment-body-style .initial:n = \small,
comment-body-style .value_required:n = true,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Sidebars
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Sidebar title
sidebar-title-family .tl_set:N = \l__rpg_sidebar_title_family_tl,
sidebar-title-family .initial:n = \sffamily,
sidebar-title-family .value_required:n = true,
sidebar-title-style .tl_set:N = \l__rpg_sidebar_title_style_tl,
sidebar-title-style .initial:n = \bfseries \scshape,
sidebar-title-style .value_required:n = true,
% Sidebar body
sidebar-body-family .tl_set:N = \l__rpg_sidebar_body_family_tl,
sidebar-body-family .initial:n = \__rpg_sf_initial_family:,
sidebar-body-family .value_required:n = true,
sidebar-body-style .tl_set:N = \l__rpg_sidebar_body_style_tl,
sidebar-body-style .initial:n = \small,
sidebar-body-style .value_required:n = true,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Read-aloud boxes
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
readaloud-family .tl_set:N = \l__rpg_readaloud_family_tl,
readaloud-family .initial:n = \__rpg_sf_initial_family:,
readaloud-family .value_required:n = true,
readaloud-style .tl_set:N = \l__rpg_readaloud_style_tl,
readaloud-style .initial:n = \small,
readaloud-style .value_required:n = true,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Table of Contents
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Part
toc-part-family .tl_set:N = \l__rpg_toc_part_family_tl,
toc-part-family .initial:n = \normalfont,
toc-part-family .value_required:n = true,
toc-part-style .tl_set:N = \l__rpg_toc_part_style_tl,
toc-part-style .initial:n = \Large \scshape \color{titlered},
toc-part-style .value_required:n = true,
% Chapter
toc-chapter-family .tl_set:N = \l__rpg_toc_chapter_family_tl,
toc-chapter-family .initial:n = \normalfont,
toc-chapter-family .value_required:n = true,
toc-chapter-style .tl_set:N = \l__rpg_toc_chapter_style_tl,
toc-chapter-style .initial:n = \large \scshape \color{titlered},
toc-chapter-style .value_required:n = true,
% Section
toc-section-family .tl_set:N = \l__rpg_toc_section_family_tl,
toc-section-family .initial:n = \normalfont,
toc-section-family .value_required:n = true,
toc-section-style .tl_set:N = \l__rpg_toc_section_style_tl,
toc-section-style .initial:n = \normalsize,
toc-section-style .value_required:n = true,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Stat blocks
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Stat block title
stat-block-title-family .tl_set:N = \l__rpg_stat_block_title_family_tl,
stat-block-title-family .initial:n = \normalfont,
stat-block-title-family .value_required:n = true,
stat-block-title-style .tl_set:N = \l__rpg_stat_block_title_style_tl,
stat-block-title-style .initial:n = \bfseries \scshape \LARGE,
stat-block-title-style .value_required:n = true,
% Stat block body
stat-block-body-family .tl_set:N = \l__rpg_stat_block_body_family_tl,
stat-block-body-family .initial:n = \__rpg_sf_initial_family:,
stat-block-body-family .value_required:n = true,
stat-block-body-style .tl_set:N = \l__rpg_stat_block_body_style_tl,
stat-block-body-style .initial:n = \small,
stat-block-body-style .value_required:n = true,
% Stat block section
stat-block-section-family .tl_set:N = \l__rpg_stat_block_section_family_tl,
stat-block-section-family .initial:n = \sffamily,
stat-block-section-family .value_required:n = true,
stat-block-section-style .tl_set:N = \l__rpg_stat_block_section_style_tl,
stat-block-section-style .initial:n = \color{titlered} \scshape \large,
stat-block-section-style .value_required:n = true,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Miscellaneous
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Footer
footer-family .tl_set:N = \l__rpg_footer_family_tl,
footer-family .initial:n = \normalfont,
footer-family .value_required:n = true,
footer-style .tl_set:N = \l__rpg_footer_style_tl,
footer-style .initial:n = \scriptsize \textcolor{pagegold},
footer-style .value_required:n = true,
% Page number
page-number-family .tl_set:N = \l__rpg_page_number_family_tl,
page-number-family .initial:n = \normalfont,
page-number-family .value_required:n = true,
page-number-style .tl_set:N = \l__rpg_page_number_style_tl,
page-number-style .initial:n = \scriptsize \textcolor{pagegold},
page-number-style .value_required:n = true,
% Drop caps
drop-cap-family .tl_set:N = \l__rpg_drop_cap_family_tl,
drop-cap-family .initial:n = \Royal,
drop-cap-family .value_required:n = true,
drop-cap-style .tl_set:N = \l__rpg_drop_cap_style_tl,
drop-cap-style .value_required:n = true,
}
\NewDocumentCommand { \RpgSetFonts } { o }
{
\keys_set:nn { rpg / fonts } { #1 }
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Font access functions combine the selected family and style
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Sectioning commands
\NewDocumentCommand{\RpgFontPart}{}
{ \l__rpg_part_family_tl \l__rpg_part_style_tl}
\NewDocumentCommand{\RpgFontChapter}{}
{ \l__rpg_chapter_family_tl \l__rpg_chapter_style_tl }
\NewDocumentCommand{\RpgFontSection}{}
{ \l__rpg_section_family_tl \l__rpg_section_style_tl }
\NewDocumentCommand{\RpgFontSubsection}{}
{ \l__rpg_subsection_family_tl \l__rpg_subsection_style_tl }
\NewDocumentCommand{\RpgFontSubsubsection}{}
{ \l__rpg_subsubsection_family_tl \l__rpg_subsubsection_style_tl }
\NewDocumentCommand{\RpgFontParagraph}{}
{ \l__rpg_paragraph_family_tl \l__rpg_paragraph_style_tl }
\NewDocumentCommand{\RpgFontSubaragraph}{}
{ \l__rpg_subparagraph_family_tl \l__rpg_subparagraph_style_tl }
% Tables
\NewDocumentCommand{\RpgFontTableTitle}{}
{ \l__rpg_table_title_family_tl \l__rpg_table_title_style_tl }
\NewDocumentCommand{\RpgFontTableHeader}{}
{ \l__rpg_table_header_family_tl \l__rpg_table_header_style_tl }
\NewDocumentCommand{\RpgFontTableBody}{}
{ \l__rpg_table_body_family_tl \l__rpg_table_body_style_tl }
% Comment boxes
\NewDocumentCommand{\RpgFontCommentTitle}{}
{ \l__rpg_comment_title_family_tl \l__rpg_comment_title_style_tl }
\NewDocumentCommand{\RpgFontCommentBody}{}
{ \l__rpg_comment_body_family_tl \l__rpg_comment_body_style_tl }
% Sidebars
\NewDocumentCommand{\RpgFontSidebarTitle}{}
{ \l__rpg_sidebar_title_family_tl \l__rpg_sidebar_title_style_tl }
\NewDocumentCommand{\RpgFontSidebarBody}{}
{ \l__rpg_sidebar_body_family_tl \l__rpg_sidebar_body_style_tl }
% Read-aloud boxes
\NewDocumentCommand{\RpgFontReadAloud}{}
{ \l__rpg_readaloud_family_tl \l__rpg_readaloud_style_tl }
% Table of Contents
\NewDocumentCommand{\RpgFontTocPart}{}
{ \l__rpg_toc_part_family_tl \l__rpg_toc_part_style_tl}
\NewDocumentCommand{\RpgFontTocChapter}{}
{ \l__rpg_toc_chapter_family_tl \l__rpg_toc_chapter_style_tl}
\NewDocumentCommand{\RpgFontTocSection}{}
{ \l__rpg_toc_section_family_tl \l__rpg_toc_section_style_tl}
% Stat blocks
\NewDocumentCommand{\RpgFontStatBlockTitle}{}
{ \l__rpg_stat_block_title_family_tl \l__rpg_stat_block_title_style_tl }
\NewDocumentCommand{\RpgFontStatBlockBody}{}
{ \l__rpg_stat_block_body_family_tl \l__rpg_stat_block_body_style_tl }
\NewDocumentCommand{\RpgFontStatBlockSection}{}
{ \l__rpg_stat_block_section_family_tl \l__rpg_stat_block_section_style_tl }
% Miscellaneous
\NewDocumentCommand{\RpgFontFooter}{}
{ \l__rpg_footer_family_tl \l__rpg_footer_style_tl }
\NewDocumentCommand{\RpgFontPageNumber}{}
{ \l__rpg_page_number_family_tl \l__rpg_page_number_style_tl }
\NewDocumentCommand{\RpgFontDropCap}{}
{ \l__rpg_drop_cap_family_tl \l__rpg_drop_cap_style_tl }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Drop Caps
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\renewcommand{\LettrineFontHook}
{ \l__rpg_drop_cap_family_tl \l__rpg_drop_cap_style_tl }
% Usage: RpgDropCapLine[<lettrine options>]{<first letter>}{<small caps line>}
% It takes trial and error to get the 2nd argument to align with
% the linebreak. Lettrine package will not play nicely with \FirstLine. See
% the lettrine package for options.
\NewDocumentCommand{\RpgDropCapLine}{ O{} m m }
{
\lettrine[
lines = 4,
depth = 0,
findent = \l__rpg_space_dim,
nindent = 0pt,
#1
]
{#2}
{#3}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Contour that can break across lines. Can accept \newline to force a break.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\cs_new_protected:Npn \__rpg_contour_preserve_space:nn #1#2
{
\group_begin:
\seq_set_split:Nnn \l_tmpa_seq { ~ } { #2 }
\seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq { \exp_not:n {\contour{#1}{##1}} }
\seq_use:Nn \l_tmpb_seq { ~ }
\group_end:
}
\NewDocumentCommand{\RpgContour}{ O{contourgray} m }
{
\group_begin:
\seq_set_split:Nnn \l_tmpa_seq { \newline } { #2 }
\seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq { \exp_not:n {\__rpg_contour_preserve_space:nn{#1}{##1}} }
\seq_use:Nn \l_tmpb_seq { \newline }
\group_end:
}

74
lib/rpgheader.sty Normal file
View File

@@ -0,0 +1,74 @@
\ExplSyntaxOn
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Custom headers and footers
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\bool_if:NT \l__rpg_layout_bool
{
\RequirePackage {fancyhdr} % Adaptation of the footers
% Setup for custom footer
\pagestyle {fancy}
\cs_if_free:NF \chaptermark
{
\renewcommand*{\chaptermark}[1]
{
\markboth
{
\MakeUppercase
{
\ifnum\value{secnumdepth}>-1
\chaptertitlename\ \thechapter :~
\fi
#1
}
}
{}
}
}
\renewcommand*{\headrulewidth}{0pt} % no rule for header
\renewcommand*{\footrulewidth}{0pt} % no rule for footer
\fancyhf {} % clear all headers and footers
% Header is used to include the page background
\fancyhead{
\bool_if:NT \l__rpg_show_background_bool
{
\begin{tikzpicture}[remember~picture,overlay]
\node[inner~sep=0pt] at (current~page.center) {\includegraphics[width=\paperwidth,height=\paperheight]{img/paper}};
\end{tikzpicture}
}
}
% Left-even page footer
\fancyfoot[LE]{%
\RpgFontFooter \leftmark
\begin{tikzpicture}[remember~picture,overlay]
\bool_if:NT \l__rpg_show_footer_scroll_bool {
\node[xscale=-1,inner~sep=0pt,anchor=south,nearly~opaque] at (current~page.south) {\includegraphics[width=\paperwidth,height=.6in]{img/footerscroll}};
}
\node[inner~sep=0pt,anchor=south,xshift=.28in,yshift=.39in] at (current~page.south~west) {\RpgFontPageNumber \thepage};
\end{tikzpicture}
}
% Right-odd page footer
\fancyfoot[RO]{%
\RpgFontFooter \leftmark
\begin{tikzpicture}[remember~picture,overlay]
\bool_if:NT \l__rpg_show_footer_scroll_bool {
\node[inner~sep=0pt,anchor=south,nearly~opaque] at (current~page.south) {\includegraphics[width=\paperwidth,height=.6in]{img/footerscroll}};
}
\node[inner~sep=0pt,anchor=south,xshift=-.28in,yshift=.39in] at (current~page.south~east) {\RpgFontPageNumber \thepage};
\end{tikzpicture}
}
\fancypagestyle {plain} {}
\fancypagestyle{empty}{%
\fancyfoot{}
}
}

671
lib/rpgmonster.sty Normal file
View File

@@ -0,0 +1,671 @@
\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
}

80
lib/rpgreadaloud.sty Normal file
View File

@@ -0,0 +1,80 @@
\ExplSyntaxOn
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Environment for read-aloud text.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Standard for every read-aloud text
\DeclareTColorBox {__rpg_read_aloud} {o}
{
before~upper =
{
\bool_if:NT \l__rpg_layout_bool
{
\bool_if:NF \l__rpg_justified_bool
{\RaggedRight}
}
},
code = {\linespread {1.1} },
enhanced~jigsaw,
frame~hidden,
boxrule = 0pt,
breakable,
enhanced,
before~skip = 13pt plus 4pt minus 4pt,
boxsep = 8pt,
top = 0pt,
left = 0pt,
right = 0pt,
bottom = 0pt,
sharp~corners,
parbox = false,
borderline~west = {1pt} {-0.5pt} {titlered},
borderline~east = {1pt} {-0.5pt} {titlered},
fontupper = \RpgFontReadAloud,
fontlower = \RpgFontReadAloud,
overlay =
{
\foreach\n ~ in ~ { north~east, north~west, south~east, south~west }
{\draw [ titlered, fill = titlered ] ( frame.\n ) circle (1.5pt); };
},
after~skip = 13pt plus 4pt minus 4pt,
#1,
}
% Extra key for controlling the color of the title and the background
\keys_define:nn { rpg / read_aloud }
{
color .tl_set:N = \l__rpg_read_aloud_color_tl,
color .initial:n = readaloudcolor,
color .value_required:n = true,
}
% This function, through its variant, forces the expansion of the tcb keys
% passed to the environment by the user before it invokes the tcolorbox
\cs_new_protected:Nn \__rpg_start_read_aloud:nn
{
\begin {__rpg_read_aloud} [ #1, #2 ]
}
\cs_generate_variant:Nn \__rpg_start_read_aloud:nn { nV }
% The RpgReadAloud environment
% #1 - keys. We handle the custom color key before passing other keys on
\NewDocumentEnvironment {RpgReadAloud} {o}
{
\group_begin:
\keys_set_known:nnN { rpg / read_aloud } {#1} \l_tmpa_tl
\str_if_eq:VnT \l_tmpa_tl { -NoValue- }
{ \tl_set_eq:NN \l_tmpa_tl \c_empty_tl }
\__rpg_start_read_aloud:nV
{
colback = \l__rpg_read_aloud_color_tl,
}
{\l_tmpa_tl}
}
{
\end {__rpg_read_aloud}
\group_end:
}

244
lib/rpgsections.sty Normal file
View File

@@ -0,0 +1,244 @@
\ExplSyntaxOn
\bool_if:NT \l__rpg_layout_bool
{
% Change part numbering to Arabic numbers from Roman numerals
\renewcommand{\thepart}{\arabic{part}}
% Set spacing around floats
\setlength{\textfloatsep}{11pt plus 4pt minus 4pt}
\setlength{\intextsep}{11pt plus 4pt minus 4pt}
\setlength{\dbltextfloatsep}{11pt plus 4pt minus 4pt}
% Remove Numbering (If you want Numbering set secnumdepth to the appropriate depth)
\setcounter{secnumdepth}{0}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Section formatting
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Part
\titleformat {\part}
[display]
{ \centering \RpgFontPart } % format
{ \RpgContour{\partname\ \thepart} } % label
{ 2ex } % sep
{ \RpgContour } % before-code
% Chapter
\titleformat {\chapter}
{ \RpgFontChapter } % format
{ \RpgContour{\chaptertitlename\ \thechapter :} } % label
{ \wordsep } % sep
{ \RpgContour } % before-code
\titlespacing* {\chapter}
{ 0pt } % left
{ .3ex } % before-sep
{ 2.8ex } % after-sep
% Section
\titleformat {\section}
{ \RpgFontSection } % format
{ \thesection } % label
{ 1em } % sep
{ \nopagebreak } % before-code
\titlespacing* { \section }
{ 0pt } % left
{ 1.3ex plus .43ex minus .43ex } % before-sep
{ 0pt } % after-sep
% Subsection
\titleformat {\subsection}
{ \RpgFontSubsection } % format
{ \thesubsection } % label
{ 1em } % sep
{ \nopagebreak } % before-code
[ \vspace{-.3ex} \titleline{ \color{titlegold} \titlerule[1pt] } ] % after-code
\titlespacing*{ \subsection }
{ 0pt } % left
{ 1.4ex plus .47ex minus .47ex } % before-sep
{ 1.2ex } % after-sep
% Subsubsection
\titleformat {\subsubsection}
{ \RpgFontSubsubsection } % format
{ \thesubsubsection } % label
{ 1em } % sep
{ \nopagebreak } % before-code
\titlespacing* { \subsubsection }
{ 0pt } % left
{ 2ex plus .67ex minus .67ex } % before-sep
{ .2ex } % after-sep
% Paragraph
\titleformat {\paragraph} [runin]
{ \RpgFontParagraph } % format
{ \theparagraph \quad } % label
{0pt} % sep
{} % before-code
[.] % after-code
\titlespacing* {\paragraph}
{0pt} % left
{\parskip} % before-sep
{\wordsep} % after-sep
% Subparagraph
\titleformat {\subparagraph} [runin]
{ \RpgFontSubaragraph } % format
{ \thesubparagraph \quad } % label
{0pt} % sep
{} % before-code
[.] % after-code
\titlespacing* {\subparagraph}
{\parindent} % left
{\parskip} % before-sep
{\wordsep} % after-sep
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Special command for magic items, traps, and the like.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentCommand {\RpgFeatHeader} { m o }
{
\subsection {#1}
\IfValueT{#2}
{
\textit {#2}
\par \vspace{3pt} \noindent \ignorespaces
}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Special command for magic items, traps, and the like.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentCommand {\RpgItemHeader} { m m }
{
\subsubsection {#1}
\textit {#2}
\par \vspace{3pt} \noindent \ignorespaces
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Special command for spells.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% #1 - Name
% #2 - Level and school
% #3 - Casting time
% #4 - Range
% #5 - Components
% #6 - Duration
\NewDocumentCommand {\RpgSpellHeader} { m m m m m m }
{
\RpgItemHeader {#1} {#2}
\begin{description}
[
nosep,
labelsep = \l__rpg_space_dim,
after = { \vspace{4pt plus 1pt minus 1pt} },
]
\item [ \spellcastingtimename : ] #3
\item [ \spellrangename : ] #4
\item [ \spellcomponentsname : ] #5
\item [ \spelldurationname : ] #6
\end{description}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Map Areas and their References
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\tl_new:N \l__rpg_area_num_depth_tl
% Options
\keys_define:nn { rpg / areas }
{
area-label .tl_set:N = \l__rpg_area_label_tl,
area-label .initial:n = area,
area-label .value_required:n = true,
sub-area-label .tl_set:N = \l__rpg_sub_area_label_tl,
sub-area-label .initial:n = subarea,
sub-area-label .value_required:n = true,
region .tl_set:N = \l__rpg_region_tl,
region .value_required:n = true,
area-num-depth .choice:,
area-num-depth .choices:nn =
{ 1, 2, 3, 4 }
{ \tl_set:Nn \l__rpg_area_num_depth_tl {\l_keys_choice_tl} },
area-num-depth .initial:n = 2, % subsection
}
\NewDocumentCommand {\RpgSetAreaOptions} {o}
{
\keys_set:nn { rpg / areas } { #1 }
}
% Counters
\newcounter {RpgAreaCounter}
\NewDocumentCommand {\RpgResetAreas} {}
{
\setcounter {RpgAreaCounter} {0}
}
\newcounter {RpgSubAreaCounter} [RpgAreaCounter]
% sub area references should be '5a', '5b', not '51', '52'
\renewcommand \p@RpgSubAreaCounter { \arabic {RpgAreaCounter} }
\renewcommand \theRpgSubAreaCounter { \alph {RpgSubAreaCounter} }
% Functions to create an area including text and label
\NewDocumentCommand {\RpgArea} {m}
{
\refstepcounter {RpgAreaCounter}
\label { \l__rpg_region_tl \l__rpg_area_label_tl :#1 }
\tl_set:Nn \l_tmpa_tl { \l__rpg_region_tl \arabic {RpgAreaCounter} . ~ #1 }
\str_case_e:nn {\l__rpg_area_num_depth_tl}
{
{1} { \section {\l_tmpa_tl} }
{2} { \subsection {\l_tmpa_tl} }
{3} { \subsubsection {\l_tmpa_tl} }
{4} { \paragraph {\l_tmpa_tl} }
}
}
\NewDocumentCommand {\RpgSubArea} {m}
{
\refstepcounter {RpgSubAreaCounter}
\label { \l__rpg_region_tl \l__rpg_sub_area_label_tl : #1 }
\tl_set:Nn \l_tmpa_tl { \l__rpg_region_tl \arabic {RpgAreaCounter} \alph {RpgSubAreaCounter} . ~ #1 }
\str_case_e:nn {\l__rpg_area_num_depth_tl}
{
{1} { \subsection {\l_tmpa_tl} }
{2} { \subsubsection {\l_tmpa_tl} }
{3} { \paragraph {\l_tmpa_tl} }
{4} { \subparagraph {\l_tmpa_tl} }
}
}
% Functions to reference a label
\NewDocumentCommand {\RpgAreaRef} { o m }
{
\group_begin:
\keys_set:nn { rpg / areas } {#1} % Temp set keys to reference other regions
#2 ~ ( \pageabbreviationname\ \pageref { \l__rpg_region_tl \l__rpg_area_label_tl : #2 } )
\group_end:
}
\NewDocumentCommand {\RpgSubAreaRef} { o m }
{
\group_begin:
\keys_set:nn { rpg / areas } { #1 } % Temp set keys to reference other regions
#2 ~ ( \pageabbreviationname\ \pageref { \l__rpg_region_tl \l__rpg_sub_area_label_tl : #2 } )
\group_end:
}

87
lib/rpgsidebar.sty Normal file
View File

@@ -0,0 +1,87 @@
\ExplSyntaxOn
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Environment for sidebars.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Standard for every sidebar
\DeclareTColorBox {__rpg_sidebar} {o}
{
before~upper =
{
\bool_if:NT \l__rpg_layout_bool
{
\bool_if:NF \l__rpg_justified_bool
{\RaggedRight}
}
},
code={\linespread{.9}},
frame~hidden,
boxrule = 0pt,
enhanced,
before~skip = 13pt plus 4pt minus 4pt,
toptitle = 2pt,
boxsep = 3pt,
left = 6pt,
right = 6pt,
top = 0pt,
bottom = 2pt,
fonttitle = \RpgFontSidebarTitle,
fontupper = \RpgFontSidebarBody,
fontlower = \RpgFontSidebarBody,
sharp~corners,
parbox = false,
borderline~north = {1pt} {-0.5pt} {black},
borderline~south = {1pt} {-0.5pt} {black},
coltitle = black,
fuzzy~shadow = {0mm} {-3.5pt} {-0.5pt} {0.4mm} {black!60!white},
overlay =
{
\fill [black] ( frame.south~west ) -- ++ ( 7pt, 0 ) -- ++ ( 0, -5pt ) -- cycle;
\fill [black] ( frame.north~west ) -- ++ ( 7pt, 0 ) -- ++ ( 0, 5pt ) -- cycle;
\fill [black] ( frame.north~east ) -- ++ ( -7pt, 0 ) -- ++ ( 0, 5pt ) -- cycle;
\fill [black] ( frame.south~east ) -- ++ ( -7pt, 0 ) -- ++ ( 0, -5pt ) -- cycle;
},
after~skip = 14pt plus 4pt minus 4pt,
#1,
}
% Extra key for controlling the color of the title and the background
\keys_define:nn { rpg / sidebar }
{
color .tl_set:N = \l__rpg_sidebar_color_tl,
color .initial:n = sidebarcolor,
color .value_required:n = true,
}
% This function, through its variant, forces the expansion of the tcb keys
% passed to the environment by the user before it invokes the tcolorbox
\cs_new_protected:Nn \__rpg_start_sidebar:nn
{
\begin {__rpg_sidebar} [ #1, #2 ]
}
\cs_generate_variant:Nn \__rpg_start_sidebar:nn { nV }
% The RpgSidebar environment
% #1 - keys. We handle the custom color key before passing other keys on
% #2 - title.
\NewDocumentEnvironment {RpgSidebar} { o m }
{
\group_begin:
\keys_set_known:nnN { rpg / sidebar } {#1} \l_tmpa_tl
\str_if_eq:VnT \l_tmpa_tl { -NoValue- }
{ \tl_set_eq:NN \l_tmpa_tl \c_empty_tl }
\__rpg_start_sidebar:nV
{
colback = \l__rpg_sidebar_color_tl,
colbacktitle = \l__rpg_sidebar_color_tl,
title = {#2},
}
{\l_tmpa_tl}
}
{
\end {__rpg_sidebar}
\group_end:
}

143
lib/rpgstrings.sty Executable file
View File

@@ -0,0 +1,143 @@
\ExplSyntaxOn % Use tilde (~) for spaces.
% \addto\captions<language> cannot handle macros with parameters
% We need to make our own parameters
% |1| represents parameter 1
\cs_new_protected:Npn \__rpg_caption:nn #1#2
{
\group_begin:
\str_set:Nx \l_tmpa_str { #1 }
\str_set:Nx \l_tmpb_str { #2 }
\exp_args:NNnx \str_replace_all:Nnn \l_tmpa_str { |1| } { #2 }
\str_use:N \l_tmpa_str
\group_end:
}
% Document-level version for backwards compatibility
\NewDocumentCommand{\RpgCaption}{ m m }
{ \__rpg_caption:nn {#1} {#2} }
% Define all strings as new macros instead of hardcoding them in the
% TeX files. This then allows us to add captions for multilanguage support.
% If you add or update a caption here, add it to languages/_template.sty
% as well.
%% Monster
% Basics
\newcommand\armorclassname{Armor~Class}
\newcommand\hitpointsname{Hit~Points}
\newcommand\speedname{Speed}
% Ability Scores
\newcommand\strstatname{STR}
\newcommand\dexstatname{DEX}
\newcommand\constatname{CON}
\newcommand\intstatname{INT}
\newcommand\wisstatname{WIS}
\newcommand\chastatname{CHA}
% Details
\newcommand\skillsname{Skills}
\newcommand\dimmname{Damage~Immunities}
\newcommand\dvulname{Damage~Vulnerabilities}
\newcommand\dresname{Damage~Resistances}
\newcommand\cimmname{Condition~Immunities}
\newcommand\savesname{Saving~Throws}
\newcommand\sensesname{Senses}
\newcommand\defaultsensesname{passive~Perception~10}
\newcommand\languagesname{Languages}
\newcommand\challengename{Challenge}
\newcommand\pbonname{Proficiency~Bonus}
\newcommand\xpname{XP}
% Attacks
\newcommand\unitsname{ft.}
\newcommand\weaponname{Weapon}
\newcommand\spellname{Spell}
\newcommand\meleeattackname{Melee~|1|~Attack}
\newcommand\rangedattackname{Ranged~|1|~Attack}
\newcommand\meleeorrangedattackname{Melee~or~Ranged~|1|~Attack}
\newcommand\orname{or}
\newcommand\tohitname{|1|~to~hit}
\newcommand\defaulttargetsname{one~target}
\newcommand\reachname{reach}
\newcommand\rangename{range}
\newcommand\hitname{Hit}
\newcommand\damagename{damage}
\newcommand\plusname{plus}
% Spell Levels
\newcommand\spellcantripsname{Cantrips}
\newcommand\spellfirstlevelname{1st~level}
\newcommand\spellsecondlevelname{2nd~level}
\newcommand\spellthirdlevelname{3rd~level}
\newcommand\spellfourthlevelname{4th~level}
\newcommand\spellfifthlevelname{5th~level}
\newcommand\spellsixthlevelname{6th~level}
\newcommand\spellseventhlevelname{7th~level}
\newcommand\spelleighthlevelname{8th~level}
\newcommand\spellninthlevelname{9th~level}
% Spell Slots
\newcommand\spellatwillname{at~will}
\newcommand\spelloneslotname{1~slot}
\newcommand\spelltwoslotsname{2~slots}
\newcommand\spellthreeslotsname{3~slots}
\newcommand\spellfourslotsname{4~slots}
% Innate spellcasting
\newcommand\innateatwillname{At~will}
\newcommand\numberperdayname{|1|/day}
\newcommand\numberperdayeachname{|1|/day~each}
% Spell Header
\newcommand\spellcastingtimename{Casting~Time}
\newcommand\spellrangename{Range}
\newcommand\spellcomponentsname{Components}
\newcommand\spelldurationname{Duration}
% Miscellaneous
\newcommand\pageabbreviationname{pg.}
\newcommand\dname{d}
\newcommand\tocchapterabbreviationname{Ch.}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Adding languages
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% To add captions for other languages:
% 1. Copy and paste languages/_template.sty to languages/<language>.sty
% 2. Substitute the <language> token in the file with the language name
% (i.e. \addto\captionsfrench).
% 3. Replace the English strings with the translations and comment any captions
% that you do not translate. Please keep the captions in the same order.
% 4. Add \RequirePackage{lib/languages/<language>} to the following function.
\cs_new_protected_nopar:Npn \__rpg_input_languages:
{
\RequirePackage{lib/languages/italian}
\RequirePackage{lib/languages/japanese} % Requires LuaTeX or XeTeX
\RequirePackage{lib/languages/ngerman}
\RequirePackage{lib/languages/russian}
\RequirePackage{lib/languages/spanish}
\RequirePackage{lib/languages/french}
\RequirePackage{lib/languages/portuguese}
}
% Delay loading captions until after the user has imported a language package.
% Enables using babel/polyglossia with the rpgbook document class as well as the
% rpg package.
%
% Both language packages use \AtBeginDocument. Use \AtEndPreamble (etoolbox)
% instead to side-step load order issues.
\AtEndPreamble{
% Check if either babel or polyglossia have been loaded,
% in which case load the string captions
\@ifpackageloaded{babel}{
\__rpg_input_languages:
}{}
\@ifpackageloaded{polyglossia}{
\__rpg_input_languages:
}{}
}

66
lib/rpgtable.sty Normal file
View File

@@ -0,0 +1,66 @@
\ExplSyntaxOn
% Special Columns
\newcolumntype {Y} { > {\centering\arraybackslash } X }
\newcolumntype {`} { > {\global\let\currentrowstyle\relax } }
\newcolumntype {^} { > {\currentrowstyle} }
% Matches {, }, >, , and any other character
\regex_const:Nn \c__preamble_regex {>\s*{.*}\s*\S|\S}
\newcommand{\rowstyle}[1]
{
\gdef\currentrowstyle{#1}#1\ignorespaces
}
% Table options
\keys_define:nn { rpg / table }
{
color .tl_set:N = \l__rpg_table_color_tl,
color .initial:n = tablecolor,
color .value_required:n = true,
header .tl_set:N = \l__rpg_table_header_tl,
header .value_required:n = true,
width .dim_set:N = \l__rpg_table_width_dim,
width .value_required:n = true,
}
% Table Definition
\NewDocumentEnvironment {RpgTable} { o m }
{
\group_begin:
\dim_set:Nn \l__rpg_table_width_dim { \linewidth }
\tl_if_novalue:nF {#1}
{ \keys_set:nn { rpg / table } {#1} }
\par \vspace { 9pt plus 3pt minus 3pt } \noindent
\tl_if_empty:NF \l__rpg_table_header_tl
{
\group_begin:
\RpgFontTableTitle \l__rpg_table_header_tl \nopagebreak
\par \vspace{ 5pt plus 2pt minus 2pt } \noindent
\group_end:
}
\RpgFontTableBody
\rowcolors {1} {} {\l__rpg_table_color_tl}
\regex_extract_all:NnNTF \c__preamble_regex {#2} \l_tmpa_seq
{
\tl_set:Nn \l_tmpa_tl {\seq_use:Nn \l_tmpa_seq {^}}
\use:x { \exp_not:n {\tabularx{\l__rpg_table_width_dim}}{`\l_tmpa_tl}}
\rowstyle{\RpgFontTableHeader}
}
{
\tabularx {\l__rpg_table_width_dim} {#2}
}
}
{
\endtabularx \vspace { 9pt plus 3pt minus 3pt }
\group_end:
}

37
lib/rpgtoc.sty Normal file
View File

@@ -0,0 +1,37 @@
\ExplSyntaxOn
\bool_if:NT \l__rpg_layout_bool
{
\RequirePackage{titletoc}
% Makes the TOC go to section depth
\setcounter{tocdepth}{2}
\titlecontents{part}
[0pt] % left
{ \addvspace{.06in} \RpgFontTocPart } % above-code
{\partname\ \thecontentslabel :~ } % numbered-entry-format
{} % numberless-entry-format
{} % filler-page-format
[ \addvspace{-.03in} \titleline{ \color{titlegold} \titlerule[1pt] } \addvspace{.05in } ] % below-code
\titlecontents{chapter}
[0pt] % left
{ \addvspace{.1in} \RpgFontTocChapter } % above-code
{ \tocchapapp\ \thecontentslabel :~ } % numbered-entry-format
{} % numberless-entry-format
{\titlerule*{.}\contentspage} % filler-page-format
\titlecontents{section}
[0pt] % left
{\RpgFontTocSection} % above-code
{\thecontentslabel :~ } % numbered-entry-format
{} % numberless-entry-format
{\titlerule*{.}\contentspage} % filler-page-format
\newcommand\tocchapapp{\tocchapterabbreviationname}
\g@addto@macro\appendix{%
\addtocontents{toc}{\protect\renewcommand{\protect\@chapapp}{\appendixname}}%
\addtocontents{toc}{\protect\renewcommand{\protect\tocchapapp}{\appendixname}}%
}
}

74
lib/rpgutility.sty Normal file
View File

@@ -0,0 +1,74 @@
\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:
}