summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/rpg-module/basic-stats.sty
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/rpg-module/basic-stats.sty
Initial commit
Diffstat (limited to 'macros/latex/contrib/rpg-module/basic-stats.sty')
-rw-r--r--macros/latex/contrib/rpg-module/basic-stats.sty399
1 files changed, 399 insertions, 0 deletions
diff --git a/macros/latex/contrib/rpg-module/basic-stats.sty b/macros/latex/contrib/rpg-module/basic-stats.sty
new file mode 100644
index 0000000000..a2f2fb134d
--- /dev/null
+++ b/macros/latex/contrib/rpg-module/basic-stats.sty
@@ -0,0 +1,399 @@
+%% basic-stats.sty
+%
+% Basic stat blocks for the Role-Playing Game Module class
+%
+% Copyright 2016 Michael C. Davis
+%
+% LICENSE FOR THE WORK
+%
+% This work consists of the following files:
+% rpg-module.cls
+% basic-stats.sty
+% basic-stats.def
+% doc/rpg-module.tex
+%
+% This work may be distributed and/or modified under the conditions of the LaTeX
+% Project Public License, either version 1.3 of this license or (at your option)
+% any later version. The latest version of this license can be found at:
+% http://www.latex-project.org/lppl.txt
+% and version 1.3 or later is part of all distributions of LaTeX version
+% 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `author-maintained'.
+%
+% The Author and Maintainer of this work is Michael C. Davis
+%
+%
+% LICENSE FOR COMPILED WORKS
+%
+% You may distribute compiled works generated using the work as specified in
+% Clause 3 of the LaTeX Project Public License. If you incorporate Open Gaming
+% Content into the compiled work, you must also comply with the terms of that
+% license.
+%
+%
+% USAGE
+%
+% See the file rpg-module.pdf (source file doc/rpg-module.tex) for documentation.
+% There are a number of worked examples in the examples/ directory.
+%
+% Technical support is provided on Dragonsfoot Forums:
+%
+% http://www.dragonsfoot.org/forums/viewtopic.php?f=87&t=73823
+
+\ProvidesPackage{basic-stats}[2016/04/25 Basic Stat Blocks for the Role-Playing Game Module class]
+
+\RequirePackage{tabularx}
+
+
+
+% Redefine which environment will be displayed
+\includecomment{ifbasicstats}
+
+% Armour class macro
+%
+% The default for Basic stats is to use the same descending AC that is used in
+% the Basic rulebook. However, three alternative styles are defined: ascending
+% AC style, B1 style and Swords & Wizardry style. Thanks to Zenopus archives
+% for pointing out that the B1 style is an early form of ascending AC, see:
+%
+% http://zenopusarchives.blogspot.com/2014/02/ascending-ac-in-holmes-basic.html
+
+\newcounter{acasc@module} % Counter for AC calculations
+
+\newcommand\ac@module[1]{%
+ \@ifundefined{acstyle@module}{\gdef\acstyle@module{desc}}{}% % Default AC style is descending
+ \ifnum\pdfstrcmp{\acstyle@module}{desc}=\z@ % Display descending AC
+ #1\ignorespaces
+ \else\ifnum\pdfstrcmp{#1}{---}=\z@
+ #1\ignorespaces
+ \else%
+ \setcounter{acasc@module}{19}%
+ \IfSubStr{#1}{\,}{\StrBefore{#1}{\,}[\tmpac]}{\def\tmpac{#1}}%
+ \IfBeginWith{\tmpac}{\minus}{%
+ \StrBehind{\tmpac}{\minus}[\tmpac]%
+ \addtocounter{acasc@module}{\tmpac}%
+ }{%
+ \addtocounter{acasc@module}{-\tmpac}%
+ }%
+ \ifnum\pdfstrcmp{\acstyle@module}{asc}=\z@ % Display ascending AC
+ \theacasc@module\ignorespaces
+ \else\ifnum\pdfstrcmp{\acstyle@module}{b1}=\z@ % Display AC using B1 notation
+ #1/\theacasc@module\ignorespaces
+ \else\ifnum\pdfstrcmp{\acstyle@module}{sw}=\z@ % Display AC using Swords & Wizardry notation
+ #1\,(\theacasc@module)\ignorespaces
+ \else
+ Unknown AC style \acstyle@module
+ \fi\fi\fi
+ \fi\fi
+}
+
+% Hit Dice : convert short form to long form for stat blocks
+
+\newcommand\hd@module[1]{\IfBeginWith{#1}{\half}{#1 (1-4 hp)}{#1}}
+
+% Saving throws : convert long form to short form for stat blocks
+
+\newcommand\sv@module[1]{\StrLeft{#1}{1}[\first]\StrBehind{#1}{ }[\second]\IfInteger{\second}{}{\StrLeft{\second}{1}[\second]}\first\second}
+
+% Morale macro : convert long form to short form for stat blocks
+
+\newcommand\ml@module[1]{\IfSubStr{#1}{ }{\StrBefore{#1}{ }}{#1}}
+
+% Alignment macro : convert long form to short form for stat blocks
+
+\newcommand\al@module[1]{%
+ \ifnum\pdfstrcmp{\pgfkeysvalueof{/#1/AL}}{Any}=\z@
+ N % For monsters with variable alignment, assume Neutral unless we specify with changealignment
+ \else
+ \StrLeft{\pgfkeysvalueof{/#1/AL}}{1}
+ \fi
+}
+
+% Change alignment macro, for monsters with Alignment ``Any'' or ``Variable''
+
+\newcommand{\changealignment}[2]{\pgfkeys{/#1/AL = {#2}}}
+
+
+
+% Basic stat block key-value pairs
+
+\newcommand{\setstatbasic}[2]{%
+ \ifcase\thecurrentstat
+ \pgfkeys{/#1/Type/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/SilverMagic/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/AC/.initial = \ac@module{#2}}
+ \or
+ \pgfkeys{/#1/HD/.initial = {#2}}
+ \pgfkeys{/#1/HDlong/.initial = \hd@module{#2}}
+ \or
+ \pgfkeys{/#1/MVturn/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/MVrd/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/MVspec/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/MVspec_turn/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/MVspec_rd/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/Attshort/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/Attlong/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/Dmg/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/Dmglong/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/SV/.initial = \sv@module{#2}}
+ \pgfkeys{/#1/SVlong/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/ML/.initial = \ml@module{#2}}
+ \pgfkeys{/#1/MLlong/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/AL/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/NoAppear/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/NoInLair/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/TT/.initial = {#2}}
+ \or
+ \pgfkeys{/#1/XP/.initial = {#2}}
+ \fi
+}
+
+% Define monsters using \setstatbasic
+
+\def\scan@stats#1|{%
+ \ifnum\pdfstrcmp{#1}{\relax}=\z@
+ \let\next\relax
+ \else
+ \setstatbasic{\currentmonster}{#1}\let\next\scan@stats
+ \stepcounter{currentstat}
+ \fi\next
+}
+
+
+
+% Display monster stats inline
+%
+% Usage: \stats[monster name]{monster key}{no. appearing}{hit points}
+
+\newcommand{\stats}[4][default]{%
+ \ifnum\pdfstrcmp{#1}{default}=\z@
+ \ifnum\pdfstrcmp{#3}{1}=\z@
+ \pgfkeys{/#2/SingleName}: % Use the generic name defined for this monster (single instance)
+ \else
+ \pgfkeys{/#2/PluralName} (#3): % Use the generic name defined for this monster (plural + number appearing)
+ \fi
+ \else
+ #1 % Override the generic name with the optional argument
+ \fi
+ AC~\pgfkeys{/#2/AC},
+ HD~\pgfkeys{/#2/HD},
+ hp~#4,
+ MV~\pgfkeys{/#2/MVturn}\thinspacebrk(\pgfkeys{/#2/MVrd}),
+\ifnum\pdfstrcmp{\pgfkeysvalueof{/#2/MVspec}}{}=\z@\else
+ \pgfkeys{/#2/MVspec}~\pgfkeys{/#2/MVspec_turn}\thinspacebrk(\pgfkeys{/#2/MVspec_rd}),
+\fi
+ Att~\pgfkeys{/#2/Attlong},
+ D~\pgfkeys{/#2/Dmglong},
+ Save~\pgfkeys{/#2/SV},
+ ML~\pgfkeys{/#2/ML},
+ AL~\al@module{#2},
+ XP~\pgfkeys{/#2/XP}%
+}
+
+% Display monster stats in a stat block
+%
+% Usage: \statblock[monster name]{monster key}{no. appearing}{hit points}
+
+\newcommand{\statblock}[4][default]{%
+ \begin{statblockfreestyle}
+ \stats[#1]{#2}{#3}{#4}
+ \end{statblockfreestyle}
+}
+
+
+
+% Table display format for wandering monsters
+
+\newcounter{wandering@module}
+
+
+\newenvironment{wanderingmonsters}[1][c]{\begin{center}\begin{tabular}{clccccccccc}
+\setcounter{wandering@module}{0}%
+\tableheader[#1]{Die Roll & Wandering Monster & No. & AC & HD & MV & Attacks & Damage & Save & ML & AL}}
+{\end{tabular}\end{center}}
+
+% Usage: \wanderitem[die roll]{monster key}{no. appearing}
+%
+% Leave no. appearing blank to use the value from the monster stats
+
+\newcommand{\wanderitem}[3][default]{%
+ \ifnum\pdfstrcmp{#1}{default}=\z@
+ \stepcounter{wandering@module}\thewandering@module
+ \else
+ \IfInteger{#1}{\setcounter{wandering@module}{#1}\thewandering@module}{#1}
+ \fi &
+ \IfStrEq{#3}{}{%
+ \if\pgfkeysvalueof{/#2/NoAppear}\string 1\pgfkeys{/#2/SingleName}\else\pgfkeys{/#2/PluralName}\fi & \pgfkeys{/#2/NoAppear} &
+ }{%
+ \ifnum\pdfstrcmp{#3}{1}=\z@\pgfkeys{/#2/SingleName}\else\pgfkeys{/#2/PluralName}\fi & #3 &
+ }
+ \pgfkeys{/#2/AC} & \pgfkeys{/#2/HD} & \pgfkeys{/#2/MVrd}%
+\ifnum\pdfstrcmp{\pgfkeysvalueof{/#2/MVspec}}{}=\z@\else
+ /\pgfkeys{/#2/MVspec_rd}%
+\fi
+ & \pgfkeys{/#2/Attshort} & \pgfkeys{/#2/Dmg} & \pgfkeys{/#2/SV} & \pgfkeys{/#2/ML} & \al@module{#2}\\
+}
+
+
+
+% Table display format for monster roster
+
+\newenvironment{monsterroster}[1][c]{\begin{center}\begin{tabular}{clcccccccccc}
+\tableheader[#1]{Room & Monster & No. & AC & HD & hp & MV & Attacks & Damage & Save & ML & AL}}
+{\end{tabular}\end{center}}
+
+% Usage: \rosteritem{room key}{monster key}{no. appearing}{hit points}
+%
+% If the room key is provided as a reference, the class will create a hyperlink from the monster
+% roster to the room description
+
+\newcommand{\rosteritem}[4]{%
+ #1 &
+ \ifnum\pdfstrcmp{#3}{1}=\z@
+ \pgfkeys{/#2/SingleName} &
+ \else
+ \pgfkeys{/#2/PluralName} &
+ \fi
+ #3 & \pgfkeys{/#2/AC} & \pgfkeys{/#2/HD} & #4 & \pgfkeys{/#2/MVrd}%
+\ifnum\pdfstrcmp{\pgfkeysvalueof{/#2/MVspec}}{}=\z@\else
+ /\pgfkeys{/#2/MVspec_rd}%
+\fi
+ & \pgfkeys{/#2/Attshort} & \pgfkeys{/#2/Dmg} & \pgfkeys{/#2/SV} & \pgfkeys{/#2/ML} & \al@module{#2}\\
+}
+
+
+
+%
+% New Monster environment
+%
+
+\newcommand{\newmonsterfont}{\Large\bfseries}
+\newcommand{\newmonsterbottomskip}{\topskip}
+
+\newcommand{\longname}[1]{%
+ \ifnum\pdfstrcmp{\pgfkeysvalueof{/#1/Type}}{}=\z@
+ \pgfkeysvalueof{/#1/SingleName}%
+ \else\ifnum\pdfstrcmp{\pgfkeysvalueof{/#1/Type}}{\pgfkeysvalueof{/#1/SingleName}}=\z@
+ \pgfkeysvalueof{/#1/SingleName}%
+ \else
+ \pgfkeysvalueof{/#1/Type}, \texorpdfstring{\protect\StrDel{\pgfkeysvalueof{/#1/SingleName}}{ \pgfkeysvalueof{/#1/Type}}}{}%
+ \fi\fi
+}
+
+\newenvironment{newmonster}[1]{%
+\@afterindentfalse\@afterheading\vspace{\topskip}
+\begin{tabularx}{\linewidth}{@{}l>{\raggedright\arraybackslash}Xl>{\raggedright\arraybackslash}X@{}}
+\multicolumn{4}{l}{\hspace{-\tabcolsep}\newmonsterfont\longname{#1}\pgfkeys{/#1/SilverMagic}%
+\phantomsection\addcontentsline{toc}{section}{\longname{#1}}}\\[\topskip]
+\ArmourClass: & \pgfkeys{/#1/AC} & No. Appearing: & \pgfkeys{/#1/NoAppear} (\pgfkeys{/#1/NoInLair})\\
+Hit Dice: & \pgfkeys{/#1/HDlong} & Save As: & \pgfkeys{/#1/SVlong}\\
+Move: & \pgfkeys{/#1/MVturn} (\pgfkeys{/#1/MVrd}) & Morale: & \pgfkeys{/#1/MLlong}\\
+\ifnum\pdfstrcmp{\pgfkeysvalueof{/#1/MVspec}}{}=\z@\else
+\hspace{1em}\pgfkeys{/#1/MVspec}: & \pgfkeys{/#1/MVspec_turn} (\pgfkeys{/#1/MVspec_rd})\\
+\fi
+Attacks: & \pgfkeys{/#1/Attlong} & Treasure Type: & \pgfkeys{/#1/TT}\\
+Damage: & \pgfkeys{/#1/Dmglong} & Alignment: & \pgfkeys{/#1/AL}\\
+\end{tabularx}\par\vspace{\newmonsterbottomskip}\noindent\ignorespaces}{\vspace{\newmonsterbottomskip}\par\aftergroup\@afterindentfalse\aftergroup\@afterheading}
+
+% Two-column version
+
+\newenvironment{newmonster2*}[4]{%
+\@afterindentfalse\@afterheading\vspace{\topskip}
+\begin{tabularx}{\linewidth}{@{}X>{\raggedright\arraybackslash}>{\raggedright\arraybackslash}X>{\raggedright\arraybackslash}X@{}}
+\ifnum\pdfstrcmp{#3}{}=\z@\else
+\multicolumn{3}{l}{\hspace{-\tabcolsep}\newmonsterfont#3#4%
+\phantomsection\addcontentsline{toc}{section}{#3}}\\[\newmonsterbottomskip]
+\fi
+ & \ifnum\pdfstrcmp{\pgfkeysvalueof{/#1/Type}}{\pgfkeysvalueof{/#1/SingleName}}=\z@
+ Normal
+\fi\pgfkeys{/#1/SingleName} & \pgfkeys{/#2/SingleName}\\
+\cmidrule(l{\tabcolsep}r{\tabcolsep}){2-2}
+\cmidrule(l{\tabcolsep}r{\tabcolsep}){3-3}
+\ArmourClass: & \pgfkeys{/#1/AC} & \pgfkeys{/#2/AC}\\
+Hit Dice: & \pgfkeys{/#1/HDlong} & \pgfkeys{/#2/HDlong}\\
+Move: & \pgfkeys{/#1/MVturn} (\pgfkeys{/#1/MVrd}) & \pgfkeys{/#2/MVturn} (\pgfkeys{/#2/MVrd})\\
+\ifnum\pdfstrcmp{\pgfkeysvalueof{/#1/MVspec}}{}=\z@\else
+\hspace{1em}\pgfkeys{/#1/MVspec}: & \pgfkeys{/#1/MVspec_turn} (\pgfkeys{/#1/MVspec_rd}) & \pgfkeys{/#2/MVspec_turn} (\pgfkeys{/#2/MVspec_rd})\\
+\fi
+Attacks: & \pgfkeys{/#1/Attlong} & \pgfkeys{/#2/Attlong}\\
+Damage: & \pgfkeys{/#1/Dmglong} & \pgfkeys{/#2/Dmglong}\\
+No. Appearing: & \pgfkeys{/#1/NoAppear} (\pgfkeys{/#1/NoInLair}) & \pgfkeys{/#2/NoAppear} (\pgfkeys{/#2/NoInLair})\\
+Save As: & \pgfkeys{/#1/SVlong} & \pgfkeys{/#2/SVlong}\\
+Morale: & \pgfkeys{/#1/MLlong} & \pgfkeys{/#2/MLlong}\\
+Treasure Type: & \pgfkeys{/#1/TT} & \pgfkeys{/#2/TT}\\
+Alignment: & \pgfkeys{/#1/AL} & \pgfkeys{/#2/AL}\\
+\end{tabularx}\par\vspace{\newmonsterbottomskip}\noindent\ignorespaces}{\vspace{\newmonsterbottomskip}\par\aftergroup\@afterindentfalse\aftergroup\@afterheading}
+
+\newenvironment{newmonster2}[2]{\begin{newmonster2*}{#1}{#2}{\pgfkeysvalueof{/#1/Type}}{\pgfkeysvalueof{/#1/SilverMagic}}}{\end{newmonster2*}}
+
+% Three-column version
+
+\newenvironment{newmonster3*}[5]{%
+\@afterindentfalse\@afterheading\vspace{\topskip}
+\begin{tabularx}{\linewidth}{@{}>{\raggedright\arraybackslash}X>{\raggedright\arraybackslash}X>{\raggedright\arraybackslash}X>{\raggedright\arraybackslash}X@{}}
+\ifnum\pdfstrcmp{#4}{}=\z@\else
+\multicolumn{4}{l}{\hspace{-\tabcolsep}\newmonsterfont#4#5%
+\phantomsection\addcontentsline{toc}{section}{#4}}\\[\newmonsterbottomskip]
+\fi
+ & \ifnum\pdfstrcmp{\pgfkeysvalueof{/#1/Type}}{\pgfkeysvalueof{/#1/SingleName}}=\z@
+ Normal
+\fi\pgfkeys{/#1/SingleName} & \pgfkeys{/#2/SingleName} & \pgfkeys{/#3/SingleName}\\
+\cmidrule(l{\tabcolsep}r{\tabcolsep}){2-2}
+\cmidrule(l{\tabcolsep}r{\tabcolsep}){3-3}
+\cmidrule(l{\tabcolsep}r{\tabcolsep}){4-4}
+\ArmourClass: & \pgfkeys{/#1/AC} & \pgfkeys{/#2/AC} & \pgfkeys{/#3/AC}\\
+Hit Dice: & \pgfkeys{/#1/HDlong} & \pgfkeys{/#2/HDlong} & \pgfkeys{/#3/HDlong}\\
+Move: & \pgfkeys{/#1/MVturn} (\pgfkeys{/#1/MVrd})
+ & \pgfkeys{/#2/MVturn} (\pgfkeys{/#2/MVrd})
+ & \pgfkeys{/#3/MVturn} (\pgfkeys{/#3/MVrd})\\
+\ifnum\pdfstrcmp{\pgfkeysvalueof{/#1/MVspec}}{}=\z@\else
+\hspace{1em}\pgfkeys{/#1/MVspec}: & \pgfkeys{/#1/MVspec_turn} (\pgfkeys{/#1/MVspec_rd})
+ & \pgfkeys{/#2/MVspec_turn} (\pgfkeys{/#2/MVspec_rd})
+ & \pgfkeys{/#3/MVspec_turn} (\pgfkeys{/#3/MVspec_rd})\\
+\fi
+Attacks: & \pgfkeys{/#1/Attlong} & \pgfkeys{/#2/Attlong} & \pgfkeys{/#3/Attlong}\\
+Damage: & \pgfkeys{/#1/Dmglong} & \pgfkeys{/#2/Dmglong} & \pgfkeys{/#3/Dmglong}\\
+No. Appearing: & \pgfkeys{/#1/NoAppear} (\pgfkeys{/#1/NoInLair})
+ & \pgfkeys{/#2/NoAppear} (\pgfkeys{/#2/NoInLair})
+ & \pgfkeys{/#3/NoAppear} (\pgfkeys{/#3/NoInLair})\\
+Save As: & \pgfkeys{/#1/SVlong} & \pgfkeys{/#2/SVlong} & \pgfkeys{/#3/SVlong}\\
+Morale: & \pgfkeys{/#1/MLlong} & \pgfkeys{/#2/MLlong} & \pgfkeys{/#3/MLlong}\\
+Treasure Type: & \pgfkeys{/#1/TT} & \pgfkeys{/#2/TT} & \pgfkeys{/#3/TT}\\
+Alignment: & \pgfkeys{/#1/AL} & \pgfkeys{/#2/AL} & \pgfkeys{/#3/AL}\\
+\end{tabularx}\par\vspace{\newmonsterbottomskip}\noindent\ignorespaces}{\vspace{\newmonsterbottomskip}\par\aftergroup\@afterindentfalse\aftergroup\@afterheading}
+
+\newenvironment{newmonster3}[3]{\begin{newmonster3*}{#1}{#2}{#3}{\pgfkeysvalueof{/#1/Type}}{\pgfkeysvalueof{/#1/SilverMagic}}}{\end{newmonster3*}}
+
+
+
+% A few special macros for stat blocks
+
+\newcommand\x{$\times$} % Text-mode multiplication symbol
+\newcommand\minus{$-$} % Text-mode minus sign
+\newcommand{\?}{\discretionary{/}{}{/}} % Breaking slash
+\newcommand{\+}{\discretionary{\,+}{}{\,+\,}} % Breaking + with 1/6 em space either side
+
+
+
+%
+% Load pre-defined monster stats
+%
+
+\input{basic-stats.def}