\ProvidesPackage{playerlist}

\RequirePackage{graphicx}
\RequirePackage{times}

% check commands not taken
\newcommand\if@map{} \newcommand\@maptrue{} \newcommand\@mapfalse{}
\newif\if@map
\DeclareOption{map}{\@maptrue}
\DeclareOption{nomap}{\@mapfalse}
\ExecuteOptions{map} % default
\ProcessOptions*

\geometry{landscape,dvips}
\geometry{nomarginpar}
\geometry{margin=.5in}
\geometry{offset={-.75in,-.5in}}

\special{header=tumble}

\parindent 0pt

\newcommand\playerlist[1]{%
  \begingroup
    \?\newcommand\@list@template\end@toss
    \aftergroup{ \@make@template#1\de@lim\de@lim \aftergroup}%
  \endgroup
  \begingroup
    \?\newcommand\@list@header\end@toss
    \aftergroup{ \@make@header#1\de@lim\de@lim \aftergroup}%
  \endgroup
  \begingroup
    \?\newcommand\plistentry[1]\end@toss
    \aftergroup{ \aftergroup\cr \@make@entry#1\de@lim\de@lim \aftergroup}%
  \endgroup
}
\newcommand\@make@template[2]{%
  \def\@temp@{#1}%
  \ifx\@temp@\de@lim
    \?####\tabskip0pt\cr\end@toss
    \let\@NEXT@\relax
  \else
    \?####\hfil&\end@toss
    \let\@NEXT@\@make@template
  \fi
  \@NEXT@
}
\newcommand\@make@header[2]{%
  \def\@temp@{#1}%
  \ifx\@temp@\de@lim
    \let\@NEXT@\relax
  \else
    \?#1&\end@toss
    \let\@NEXT@\@make@header
  \fi
  \@NEXT@
}
\newcommand\@make@entry[2]{%
  \def\@temp@{#2}%
  \ifx\@temp@\de@lim
    \let\@NEXT@\relax
  \else
    \?##1{#2}&\end@toss
    \let\@NEXT@\@make@entry
  \fi
  \@NEXT@
}

% sneak into game.cls info combo magic (``PLAYERLIST@orderby'' combo)
\newcommand\orderby[1]{%
  \expandafter\gdef\csname COMP-PLAYERLIST@orderby\endcsname{#1}%
}
\orderby{last; first; middle; player}  % default until overridden


\newcommand\clump@start[2]{%  clump, header
  \ensure@halign  % start halign if not already started
  \expandafter\gdef\csname clump-#1-status\endcsname{placed}%
  \gdef\cur@clump{#1}%
  \cr \noalign{\filbreak}\cr {#2}\hidewidth &\relax
}

\newcommand\npl{}  % check name not taken
\newcount\npl

% check various names not taken
\newcommand\cur@clump{}
\newcommand\char@clump{}


\newdef\clumpasis[2]{%  clump, header; order ``as is''
  \clump@start{#1}{#2}%
  \gdef\eachcharaction##1{%
    ##1{\def\char@clump{clump}}%
    \ifx\cur@clump\char@clump
      \plistentry##1\relax
    \fi
  }%
  \eachchar
}

\newcommand\thenby{}  % check name not taken
\newmuskip\thenby  % just want it to be not expanded by \edef
\newcommand\then@by{\thenby}

\newcommand\numberfy@end{\numberfy@end}
\newcommand\numberfy@tmp{}
\newcommand\numberfy@info[1]{%
  \renewcommand\numberfy@tmp{#1}%
  \ifx\numberfy@tmp\numberfy@end
    \?-100:\end@toss
    \let\numberfy@info\relax  % will only be done inside group
  \else
    \ifx\numberfy@tmp\then@by
      \?-10:\end@toss
      \npl=-1\relax  % skip leading spaces of next section
    \fi
    \ifcat A\noexpand#1\relax
      \ifnum\npl=1\relax \?-1:\end@toss \fi  % deal with any waiting space
      \npl=\lccode`#1\relax
      \expandafter\?\the\npl:\end@toss
      \npl=0\relax  % ok to do spaces
    \fi
    \if\noexpand#1\noexpand~\relax
      \ifnum\npl=0\relax\npl=1\relax\fi % have space waiting
    \fi
  \fi
  \numberfy@info
}

% check names not taken
\newcommand\if@comparison{} 
\newcommand\@comparisontrue{} 
\newcommand\@comparisonfalse{}
% ok, now use
\newif\if@comparison
% check names not used
\newcommand\compare@info{}
\newcommand\compare@delim{}
\newcommand\compare@next{}
% This should not be passed strings that are exactly equal!
\def\compare@info#1:#2\compare@delim#3:#4\compare@delim{%
  \let\compare@next\relax
  \ifnum#1>#3\relax
    \@comparisontrue
  \else
    \ifnum#1=#3\relax
      \def\compare@next{\compare@info#2\compare@delim#4\compare@delim}%
    \fi
  \fi
  \compare@next  % if #1<#3, quietly leave with comparison false (set outside)
}
      


\newcommand\clump@list{}  % check name not taken
\newcommand\order@info{}
\newcommand\order@num{}

\newdef\clump[2]{%  clump, header
  \clump@start{#1}{#2}%
  \gdef\clump@list{}%
  \gdef\eachcharaction##1{%
    ##1{\def\char@clump{clump}}%
    \ifx\cur@clump\char@clump
      % put this character in the clump list
      \add@to@macro\clump@list{\clump@char##1}%
      % initialize position to zero
      \expandafter\gdef\csname clump-position-\string##1\endcsname{0}%
      % put \orderby info into \order@info
      ##1{\def\order@info{PLAYERLIST@orderby}}%
      % refine \order@info by expanding regular macros in it
      \begingroup
        \aftergroup\edef \aftergroup\order@info
        \aftergroup{\relax \expandafter\?\order@info\end@toss \aftergroup}%
      \endgroup
      % refine \order@info by losing braces and turning spaces to tildes
      \begingroup
        \toss@without@braces  % provided by game.cls; set *locally* only
        \def\space@tossed{~}% % used by game.cls; set *locally* only
        \aftergroup\def \aftergroup\order@info
        \aftergroup{\relax \expandafter\?\order@info\end@toss \aftergroup}%
      \endgroup
      % refine \order@info into numerical sequence
      \begingroup
        \npl=-1\relax
        \aftergroup\tmp@str
        \aftergroup{\relax
        \expandafter\numberfy@info\order@info\numberfy@end
        \aftergroup}\relax
      \endgroup
      \expandafter\edef\csname clump-info-\string##1\endcsname{\the\tmp@str}%
    \fi
  }%
  % do it!
  \eachchar 
  % now we have the list for this clump, and the order info for each.  process!
  \begingroup
    \let\end@clump@list\relax
    \def\clump@char##1##2\end@clump@list{%
      \begingroup
        \edef\outer@clump@char{\csname clump-info-\string##1\endcsname}%
        \def\clump@char####1####2\end@clump@list{%
          \edef\inner@clump@char{\csname clump-info-\string####1\endcsname}%
          \ifx\inner@clump@char\outer@clump@char
            \@comparisontrue
          \else
            \@comparisonfalse
            \begingroup
              \aftergroup\compare@info
              \expandafter\?\inner@clump@char\end@toss
              \aftergroup\compare@delim
              \expandafter\?\outer@clump@char\end@toss
              \aftergroup\compare@delim
            \endgroup
          \fi
          \if@comparison
            \npl=\csname clump-position-\string##1\endcsname
            \advance\npl by 1\relax
            \expandafter\xdef\csname clump-position-\string##1\endcsname
              {\the\npl}%
          \else  % includes ties!
            \npl=\csname clump-position-\string####1\endcsname
            \advance\npl by 1\relax
            \expandafter\xdef\csname clump-position-\string####1\endcsname
              {\the\npl}%
          \fi
          ####2\end@clump@list  % inner tail-recurse
        }%
        ##2\end@clump@list  % start inner tail-recursion
      \endgroup
      ##2\end@clump@list  % outer tail-recurse
    }%
    \clump@list\end@clump@list  % start outer tail-recursion
    % chars now know their positions in the clump.  invert this mapping.
    \npl=-1\relax
    \def\clump@char##1{%
      \edef\num{\csname clump-position-\string##1\endcsname}%
      \expandafter\gdef\csname clumpchar-\num\endcsname{\plistentry##1}%
      \ifnum\npl<\num\relax \npl=\num\relax \fi
    }%
    \clump@list
    % cause entries to be made, in order, after the group
    \loop \ifnum\npl>-1\relax
      \expandafter\aftergroup\csname clumpchar-\the\npl\endcsname
      \advance\npl by -1\relax
    \repeat
  \endgroup
}



\newcommand\ensure@halign{%  % starts halign, then becomes impotent
  \tabskip 0pt plus1fil
  \halign to \hsize\expandafter\bgroup\@list@template  \@list@header
  \global\let\ensure@halign\relax
}

\def\un@listed{unlisted}
\AtEndDocument{%
  \ensure@halign  % in case there were no clumps at all
  \cr\egroup
  \gdef\eachcharaction#1{%
    #1{\def\char@clump{clump}}%
    \ifx\char@clump\un@listed
    \else
      \expandafter\ifx\csname clump-\char@clump-status\endcsname\relax
        \@warn{Playerlist clump \char@clump\space not placed}%
        % only warn once per clump:
        \expandafter\gdef\csname clump-\char@clump-status\endcsname{warned}%
      \fi
    \fi
  }%
  \eachchar
}


\newdimen\pagesize
\newdimen\scratchdim

\AtBeginDocument{
  % avoid automatic page-cutting; do that specially later
  \pagesize=\vsize\relax
  \multiply\vsize by 10\relax
  \it
}

\output={%
  % \special's
  \setbox0=\vsplit255 to 0pt  \unvbox0\relax
  % table header
  \setbox1=\vsplit255 to 0pt
  % measure remaining page (measuring 255 is weird)
  \setbox5=\vbox{\unvcopy255}%
  \scratchdim=\ht5\relax
  \advance\scratchdim by \dp5\relax
  % total header = game header + table header
  \global\setbox0=\vbox{%
    {\large \hfil \gamename \hfil \gamedate \hfil} \break \unvbox1}%
  \advance\scratchdim by \ht0\relax
  \advance\scratchdim by \dp0\relax
  \global\vsize=\pagesize
  \ifdim\scratchdim>\pagesize
    \advance\scratchdim by -\pagesize
    \advance\scratchdim by \ht0\relax
    \advance\scratchdim by \dp0\relax
    \setbox5=\vsplit255 to \scratchdim
    \vbox{\unvbox5}%
    \global\@mapfalse % since no room for it
    \global\advance\vsize by -\ht0\relax
    \global\advance\vsize by -\dp0\relax
  \fi
  \unvbox255\relax
  \global\output={%
    \setbox5=\vbox{\@begindvi \unvbox255}%  % 1st pass gets \AtBeginDvi stuff
    \ifdim\wd5>0pt
      \shipout\vbox{%
        \vbox to 0pt{\vskip-.25in \hskip.5in
          \includegraphics[origin=c,angle=-90]{dagger.eps}%
        }
        \unvcopy0\relax
        \unvbox5\relax
      }%
      \if@map\shipout\vbox{\vskip-.5in \includegraphics
        [natwidth=\textwidth,natheight=\textheight,origin=c,angle=-90]{map.ps}%
      }\fi
    \fi
  }%
}

\vfuzz=10in      % shut up about overfull \vbox's!
\vbadness=10000  % and underfull ones
\hfuzz=10in      % and overfull \hbox's
\hbadness=10000  % and underfull ones
