1

I'm writing a little supplement for my friends, we use the GURPS tabletop role playing game system. This system uses a points pool to buy aspects of characters. I would like to have the point total of a character at the beginning of the stat block, but to calculate the point total, I have inserted counters into the stat block.

Since LaTeX does not really have look ahead for that kind of thing (hence the aux file and co), I'd like to just run the stat block twice, but suppress the output of the first pass.

I realize that this is 'cheapen it out' a bit and I should just create a local 'preamble' setup with only the data, but there are so many characters and I'm generating the statblock from an external tool and some processing inbetween.

Now, usually I would do the calculation of the total there, but there are some complications I don't want to go into detail here for brevity, I adjust some costs manually, etc.

Anyway. The core of the question is, is it possible to evaluate TeX without printing any text, and only do evaluations of variables and commands?

If so, what's the command for it?

I'm basically asking about something like \makeatletter and \makeatother.

A macro to wrap around the block like

\documentclass{article}
\mycounter
\begin{document}
\suppressPrinting %fictitious/unknown macro I am asking for here
My total is \themycounter 
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\resumePrinting

My total is \themycounter % now holds 150
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\setcounter{mycounter}{0}
\end{document}

I suppose my question is basically a duplicate of: Hiding output of a macro

But that one is nine years old. Anything changed in that regard?

9
  • See tex.stackexchange.com/questions/587462/… for one possibility. If you were able to edit your question and provide a small but complete code for what you are attempting (rather than just a code fragment), I might be able to adapt the referenced answer to it. But with just a code fragment, it is hard to fully interpret your need. Sep 14, 2021 at 11:04
  • 2
    why don't you want to use the aux-file and label/ref? That is much more robust and faster then parsing arbitrary text to find some commands. Sep 14, 2021 at 11:08
  • My intent is to hide text output while still evaluating all the macros. If I edited my post then I'd only add the documentclass preamble, begin and end document, and that's that. I have nothing else to add to that. That said, I think tex.stackexchange.com/questions/38338/hiding-output-of-a-macro Is the way to go for that, adding the contents to a 'box' and never using the box... Sep 14, 2021 at 11:08
  • @UlrikeFischer I use the aux and label/ref...for references. This is about evaluating some macros but not printing anything while doing so. Sorry for the confusion. Sep 14, 2021 at 11:10
  • ! Undefined control sequence. l.5 My total is \themycounter Sep 14, 2021 at 11:16

3 Answers 3

2

After fixing unrelated errors in your example, you can do the first pass in a box.

enter image description here

\documentclass{article}
\newcounter{mycounter}
\begin{document}

\begin{lrbox}{0}
My total is \themycounter\ 
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\end{lrbox}

My total is \themycounter\ % now holds 150
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\setcounter{mycounter}{0}
\end{document}

Alternatively just set the text once and use the standard \label/\ref mechanism to handle the forward reference via the aux file. Which requires two passes of LaTeX.

\documentclass{article}
\newcounter{mycounter}
\begin{document}


My total is \ref{thistot} % now holds 150
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
\addtocounter{mycounter}{-1}\refstepcounter{mycounter}\label{thistot}
\setcounter{mycounter}{0}
\end{document}
1

As I commented, my answer at LaTeX3: Elegant way to forward-reference a counter with a "future" value might provide a way forward, alleviating the need to enter the data twice.

It uses a token cycle to evaluate the tokens of the pointtracker environment, in search of point allocations corresponding to \addtopoints invocations. It then prints out the environment contents, placing the sum total of points allocated at the head of the environment.

While not shown here (see referenced answer), the environment may be nested.

\documentclass{article}
\usepackage{tokcycle}[2021-05-27]
\usepackage{environ}
\newcounter{pointcount}
\newcommand\addtopoints[1]{(\textit{#1 point}%
  \ifnum#1=1\relax\else\textit{s}\fi)}
\def\z{\tcpop\Q\addtocounter{pointcount}{\Q}\tcpushgroup{\Q}}
\NewEnviron{pointtracker}[2][points]{%
  \par\bigskip\resettokcycle
  \setcounter{pointcount}{0}%
  \Macrodirective{\addcytoks{##1}\tctestifx{\addtopoints##1}{\z}{}}%
  \def\tmp{\tokencyclexpress{\Large\bfseries #2: \thepointcount{} #1}}%
  \expandafter\tmp\BODY\endtokencyclexpress
}
\begin{document}
\begin{pointtracker}[total points]{
Sum of Cool Abilities} % now holds 150

Cool ability A \addtopoints{50}

Cool ability B \addtopoints{50}

Cool ability C \addtopoints{50}
\end{pointtracker}
\end{document}

enter image description here

Above, I show a phrased (words and numbers) expression for the individual point values. To match something more simple, in line with the OP's code, one would merely simplify the definition of \addtopoints, for example, to

\newcommand\addtopoints[1]{[\textit{#1}]}
3
  • Very interesting, and I'd upvote it if I could. It's probably what I'll go with in the (near) future once I understand it better. Sep 14, 2021 at 12:14
  • @WormofLove See ctan.org/pkg/tokcycle for documentation and example files regarding tokcycle. It is a package to help users write tools that involve examining the individual tokens of the input stream. Sep 14, 2021 at 12:21
  • @WormofLove, the logic here is that the tokens of the environment are collected for later typesetting. However, if the macro \addtopoints is encountered along the way, it executes \z, which pops the next input (the point value), adds it to the cumulative count, and then pushes the point value back on the input stream, to allow the token collection to continue. At the conclusion of the collection, the environment output of collected tokens includes the total point tally at the outset. Sep 14, 2021 at 12:25
0

E.g., looking at

My total is \themycounter 
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}
Cool ability [50] \addtocounter{mycounter}{50}

the following questions arise:

  • What do you want to see in the resulting .pdf-file coming from \themycounter? (Obviously -- represented in decimal notation, using Arabic digits -- the value which the counter mycounter has at some moment in time. Which moment in time?)
  • What is the correlation betwween 50 in [50] and 50 in \addtocounter{mycounter}{50}?

If you think you can lightheartedly have TeX carry out the same token sequence twice, but once with suppressing outputting things to the output file/.pdf file, you may be overlooking some funny problems.

Let's imagine this token sequence does other things besides outputting to the .pdf file. All these other things are then done twice. You don't necessarily want that. E.g., you don't want to have a counter globally incremented twice. You don't want to have things like \immediate\write to be carried out twice. You don't want a random-number-generator to be carried out twice, the second time delivering a value differing from the value delivered the first time. But such things can happen even if you work with a box-register whose content is not typeset.

So you would need a mechanism where you can specify

  • which things to be done in the first pass (calculation of values of "variables").
  • which things to be done in the second pass (delivering stuff to be typeset to the output-file/.pdf-file).
  • whether the current pass is to be considered the first pass=the calculation-pass.
  • whether the current pass is to be considered the second pass=the delivering to output-file/.pdf-file-pass.

So you would end up with a mechanism where de facto calculation is separated from outputting -- of course you could easily do something like this:

\documentclass{article}
\newcounter{mycounter}
\newif\ifcalculate
\newif\ifdelivertooutputfile

\newcommand\DoCalculationsOnly{\calculatetrue\delivertooutputfilefalse}
\newcommand\DoDeliverToOutputfileOnly{\calculatefalse\delivertooutputfiletrue}

\begin{document}

\DoCalculationsOnly
\ifdelivertooutputfile\noindent My total is \themycounter\\\fi
\ifdelivertooutputfile Cool ability [50]\\\fi
\ifcalculate\addtocounter{mycounter}{50}\fi
\ifdelivertooutputfile Cool ability [50]\\\fi
\ifcalculate\addtocounter{mycounter}{50}\fi
\ifdelivertooutputfile Cool ability [50]\fi
\ifcalculate\addtocounter{mycounter}{50}\fi

\DoDeliverToOutputfileOnly
\ifdelivertooutputfile\noindent My total is \themycounter\\\fi
\ifdelivertooutputfile Cool ability [50]\\\fi
\ifcalculate\addtocounter{mycounter}{50}\fi
\ifdelivertooutputfile Cool ability [50]\\\fi
\ifcalculate\addtocounter{mycounter}{50}\fi
\ifdelivertooutputfile Cool ability [50]\fi
\ifcalculate\addtocounter{mycounter}{50}\fi

% \setcounter{mycounter}{0}
% In case the package hyperref is in use resetting counters leads to
% uniqueness of names of automatically created named destinations not
% being ensured any more, thus I suggest not doing this but doing
% something similar to what is done in my subsequent examples.

\end{document}

enter image description here

I guess that -- as Ulrike Fischer said -- you could probably easily use the cross-referencing-mechanism:

\documentclass{article}
\usepackage{hyperref}

\newcounter{mycounter}
\newcommand\mycountermacro{0}
\newcommand\resetmycounter{\gdef\mycountermacro{0}}
\makeatletter
\renewcommand\themycounter{\@arabic{\mycountermacro}}
\makeatother

\newcommand\AddAbility[2]{%
  \\%
  \xdef\mycountermacro{\number\numexpr\mycountermacro+#2\relax}%
  \refstepcounter{mycounter}%
  #1 [#2]%
}

\begin{document}

\resetmycounter
\noindent Total of character A is \ref*{TotalOfCharacterA}
\AddAbility{Cool ability of character A}{50}
\AddAbility{Another cool of character A}{40}
\AddAbility{Yet another cool ability of character A}{30}
\label{TotalOfCharacterA}

\noindent\hrulefill

\resetmycounter
\noindent Total of character B is \ref*{TotalOfCharacterB}
\AddAbility{Cool ability of character B}{5}
\AddAbility{Another cool of character B}{4}
\AddAbility{Yet another cool ability of character B}{3}
\label{TotalOfCharacterB}

\noindent\hrulefill

\resetmycounter
\noindent Total of character C is \ref*{TotalOfCharacterC}
\AddAbility{Cool ability of character C}{25}
\AddAbility{Another cool of character C}{20}
\AddAbility{Yet another cool ability of character C}{15}
\label{TotalOfCharacterC}

\end{document}

enter image description here



If you don't want to calculate in integers only, you can implement a similar approach, using some math-library, e.g., pgfmath:

\documentclass{article}
\usepackage{hyperref}
\usepackage{pgfmath}

\newcounter{mycounter}
\newcommand\mycountermacro{0}
\newcommand\resetmycounter{\gdef\mycountermacro{0}}
\renewcommand\themycounter{\mycountermacro}
\makeatletter
\newcommand\AddAbility[2]{%
  \\%
  \begingroup
  \pgfkeys{/pgf/number format/.cd,fixed,precision=2,fixed zerofill=true}%
  \pgfmathparse{\mycountermacro+#2}%
  \pgfmathroundtozerofill{\pgfmathresult}%
  \global\let\mycountermacro=\pgfmathresult
  \refstepcounter{mycounter}%
  #1 [\pgfmathparse{#2}\pgfmathroundtozerofill{\pgfmathresult}\pgfmathresult]%
  \expandafter\endgroup
  \expandafter\def\expandafter\@currentlabel\expandafter{\@currentlabel}%
}
\makeatother

\begin{document}

\resetmycounter
\noindent Total of character A is \ref*{TotalOfCharacterA}
\AddAbility{Cool ability of character A}{50.1}
\AddAbility{Another cool of character A}{40.69}
\AddAbility{Yet another cool ability of character A}{30.2}
\label{TotalOfCharacterA}

\noindent\hrulefill

\resetmycounter
\noindent Total of character B is \ref*{TotalOfCharacterB}
\AddAbility{Cool ability of character B}{5.15}
\AddAbility{Another cool of character B}{4.62}
\AddAbility{Yet another cool ability of character B}{3.22}
\label{TotalOfCharacterB}

\noindent\hrulefill

\resetmycounter
\noindent Total of character C is \ref*{TotalOfCharacterC}
\AddAbility{Cool ability of character C}{25.02}
\AddAbility{Another cool of character C}{20.06}
\AddAbility{Yet another cool ability of character C}{15.01}
\label{TotalOfCharacterC}

\end{document}

enter image description here



If a statblock is a component of a database, the package datatool might be of interest.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .