Recently I’ve been playing D&D with some friends. Tired of writing my small homebrew adventures in OpenOffice I turned into my old friend .
Seemed to me that a D&D adventure was specific enough to have its own document class, like article, book etc. And could not find it online, so right now I am writing one.html select jquery set selected
In this article I will explai how to write commands accepting more than the 9 default parameters.
as a user is easy and powerful, lets you use different classes without problem and produces clean documents. I love it and it is beautiful.
As a class developer, as I just discovered, is a pain in the ass.
I got a lot of problems while writing my class, and I had to throw away some ideas that just didn’t work. Now, we’ll see how to create commands with named parameters.
Objective
\newcommand \newenvironment
tags are nice and all, but are limited to 9 non-named arguments.
Being a D&D adventure document there are going to be monster tables, so I want to produce something like:
\begin{ddmonster} [name=Hobgoblin,level=3,hp=50,xp=150, role=Soldier, keywords=natural humanoid, initiative=7,Speed=5, AC=20,Fort=18,Refl=16,Will=16] %a lot more of stuff here. Powers, descriptions, stats \end{monster}
I just want a basic definition as a set of named arguments, the rest of the monster will be defined with commands.
Easy as pie
Creating a LaTeX command is quite easy, also the Wikibooks guide helps a lot with it. We just have to use the \newcommand
macro and populate it
\newcommand{name}[num]{definition}
So for example,
\newcommand{\myprintname}[1]{ my name is #1 } \myprintname{Jordi}
If I want my name and my surname,
\newcommand{\myprintname}[2]{ my name is #2 , #1 #2 } \myprintname{James}{Bond}
And I could keep going and going with parameters.
NOTE from the future:
There was a Typo in this post. Discovered (and commented) by Hikari Boulders on the number of parameters.
This is now fixed 😀
The bad news
- The bar closes at 9. No more arguments for you.
- More arguments would be ugly, so I agree with the limit.
errors will make you cry
The good news
keyval, xkeyval and others come to the rescue. I will work with xkeyval. Why? there is no specific reason, I picked that up and worked with it.
While they are easy to use, the documentation does not include a nice example, just very detailed definitions of what each macro does. For examples google and stackoverflow are your friends.
Using xkeyval
First we have to define all the keys that we want to use. There different types of keys: key, cmdkey, choicekey, booleankey
and its variations. I am just working with basic keys, and won’t bother to use other types right now.
The xkeyval documentation states:
\define@key[prefix]{family}{key} [default]{function} \define@cmdkey[prefix]{family}[mp]{key} [default]{function}
The prefix, family, key
parameters are only an identifier for the key. The define key will create a macro of the form \prefix@family@key
, the define cmkdkey something like \cmdprefix@family@key
to be used later.
\define@cmdkey[DMK]{ddm}{name}{} (...) %I can use it when initialized as: \cmdDMK@ddm@name
In this D&D monster example I want to define a lot of keys for the different possible attributes of the monster.
- name
- keywords
- role
- HP
- level
- HP
etc
\define@cmdkey [DMK] {ddm} {name} {} \define@cmdkey [DMK] {ddm} {keywords} {} \define@cmdkey [DMK] {ddm} {role} {} \define@cmdkey [DMK] {ddm} {HP} {} \define@cmdkey [DMK] {ddm} {lvl} {} \define@cmdkey [DMK] {ddm} {xp} {} \define@cmdkey [DMK] {ddm} {initiative}{} \define@cmdkey [DMK] {ddm} {perception}{} \define@cmdkey [DMK] {ddm} {AC} {} \define@cmdkey [DMK] {ddm} {Fort} {} \define@cmdkey [DMK] {ddm} {Refl} {} \define@cmdkey [DMK] {ddm} {Will} {} \define@cmdkey [DMK] {ddm} {speed} {} \define@cmdkey [DMK] {ddm} {AP} {} \define@cmdkey [DMK] {ddm} {save} {} \define@cmdkey [DMK] {ddm} {vision} {} \define@cmdkey [DMK] {ddm} {immune} {} \define@cmdkey [DMK] {ddm} {resist} {} \define@cmdkey [DMK] {ddm} {vulnerable}{}
The purpose of this big list is to be used as parameters of a \newcommand
or \newenvironment
. What xkeyval will do is parse a “string” of parameters. So for a newcommand there will be only one parameter to be parsed.
\newenvironment{ddmonster}[1][]{ \setkeys[DMK]{ddm}{#1} }{}
A simple full example
Finally, I post here what I missed when reading the xkeyval documentation, a full simple working example with basic keys.
\documentclass{article} \usepackage{xkeyval} %Two parameters command \newcommand{\myprintname}[2] { The name is #2, #1 #2 } %Maximum parameters command \newcommand{\mymaxparams}[9] { I can't hold nothing more than #1 #2 #3 #4 #5 #6 #7 #8 #9 } %This is needed for encapsulating. %changes the catcode of @ so it %can be used freely (not needed %when writing a package) \makeatletter \define@cmdkey [PRE] {fam} {d} {} \define@cmdkey [PRE] {fam} {u} {} \define@cmdkey [PRE] {fam} {p} {} \define@cmdkey [PRE] {fam} {l} {} \define@cmdkey [PRE] {fam} {i} {} \define@cmdkey [PRE] {fam} {c} {} \define@cmdkey [PRE] {fam} {a} {} \define@cmdkey [PRE] {fam} {t} {} \define@cmdkey [PRE] {fam} {e} {} \define@cmdkey [PRE] {fam} {s} {} \presetkeys [PRE] {fam} {d = 1, u = 2, p = 3, l = 4, i = 5, c = 6, a = 7, t = 8, e = 9, s = 10,}{} \newcommand{\myxkeyval}[1]{ %First thing to do, Set the keys %from the single parameter input \setkeys[PRE]{fam}{#1} \textbf{ \cmdPRE@fam@d \cmdPRE@fam@u \cmdPRE@fam@p \cmdPRE@fam@l \cmdPRE@fam@i \cmdPRE@fam@c \cmdPRE@fam@a \cmdPRE@fam@t \cmdPRE@fam@e \cmdPRE@fam@s } here you have your 10 parameters \newline } %Change again the @ catcode %to normal \makeatother \begin{document} %An example using newcommand with two parameters \myprintname{James}{Bond} %an example using a newcommand with maximum number of parameters \mymaxparams{un}{dos}{tres}{quatre}{cinc}{sis}{set}{vuit}{nou} \myxkeyval{} \myxkeyval{d=D,u=u,p=p,l=l,i=i,c=c,a=a,t=t,e=e,s=s has 10 different letters} \end{document}
Isograms are words that have no duplicate letter. I find it funny that “duplicates” is an Isogram 🙂
References
xkeyval documentation ⇒GO
xkeyval package at CTAN ⇒GO
keyval package at CTAN⇒GO
Pingback: The monster environment | Castells
I think there is an error in
\newcommand{\myprintname}[1]{
my name is #2 , #1 #2
}
\myprintname{James}{Bond}
The number of arguments should be 2, not 1.
Hello! You think and you are right! There are two arguments instead of 1.
I’ll fix it in the post.
Thanks for the tip