summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/wargame
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/wargame')
-rw-r--r--macros/latex/contrib/wargame/README.md2
-rw-r--r--macros/latex/contrib/wargame/doc/compat.pdfbin432819 -> 435053 bytes
-rw-r--r--macros/latex/contrib/wargame/doc/symbols.pdfbin184525 -> 186882 bytes
-rw-r--r--macros/latex/contrib/wargame/doc/tutorial/export.tex14
-rw-r--r--macros/latex/contrib/wargame/doc/tutorial/game.pdfbin588181 -> 590545 bytes
-rw-r--r--macros/latex/contrib/wargame/doc/wargame.pdfbin1444437 -> 1469771 bytes
-rw-r--r--macros/latex/contrib/wargame/source/Makefile2
-rw-r--r--macros/latex/contrib/wargame/source/chit/battle.dtx2
-rw-r--r--macros/latex/contrib/wargame/source/chit/misc.dtx52
-rw-r--r--macros/latex/contrib/wargame/source/chit/modifiers.dtx2
-rw-r--r--macros/latex/contrib/wargame/source/chit/oob.dtx197
-rw-r--r--macros/latex/contrib/wargame/source/chit/shape.dtx13
-rw-r--r--macros/latex/contrib/wargame/source/chit/table.dtx58
-rw-r--r--macros/latex/contrib/wargame/source/hex/labels.dtx2
-rw-r--r--macros/latex/contrib/wargame/source/hex/ridges.dtx5
-rw-r--r--macros/latex/contrib/wargame/source/hex/terrain.dtx24
-rw-r--r--macros/latex/contrib/wargame/source/tests/chits.dtx14
-rw-r--r--macros/latex/contrib/wargame/source/tests/test.tex13
-rw-r--r--macros/latex/contrib/wargame/source/util/export.dtx216
-rw-r--r--macros/latex/contrib/wargame/source/util/tikz.dtx17
-rwxr-xr-xmacros/latex/contrib/wargame/source/utils/wgexport.py971
21 files changed, 1392 insertions, 212 deletions
diff --git a/macros/latex/contrib/wargame/README.md b/macros/latex/contrib/wargame/README.md
index 3de32ab4d0..70eb286498 100644
--- a/macros/latex/contrib/wargame/README.md
+++ b/macros/latex/contrib/wargame/README.md
@@ -1,6 +1,6 @@
# A package to make Hex'n'Counter wargames in LaTeX
-## Version 0.5
+## Version 0.6
This package can help make classic [Hex'n'Counter
wargames](https://en.wikipedia.org/wiki/Wargame) using LaTeX. The
diff --git a/macros/latex/contrib/wargame/doc/compat.pdf b/macros/latex/contrib/wargame/doc/compat.pdf
index 2ba344d4ab..8f70ab6b2e 100644
--- a/macros/latex/contrib/wargame/doc/compat.pdf
+++ b/macros/latex/contrib/wargame/doc/compat.pdf
Binary files differ
diff --git a/macros/latex/contrib/wargame/doc/symbols.pdf b/macros/latex/contrib/wargame/doc/symbols.pdf
index cd8f0d3ddc..9722803067 100644
--- a/macros/latex/contrib/wargame/doc/symbols.pdf
+++ b/macros/latex/contrib/wargame/doc/symbols.pdf
Binary files differ
diff --git a/macros/latex/contrib/wargame/doc/tutorial/export.tex b/macros/latex/contrib/wargame/doc/tutorial/export.tex
index 6d6722d9ac..390b8785ae 100644
--- a/macros/latex/contrib/wargame/doc/tutorial/export.tex
+++ b/macros/latex/contrib/wargame/doc/tutorial/export.tex
@@ -77,9 +77,9 @@
% counter.
%
% \begin{macrocode}
-\doublechitimages[A]{\alla}
-\doublechitimages[B]{\allb}
-\doublechitimages[Markers]{{game turn chit}}
+\doublechitimages[A][chit drop shadows]{\alla}
+\doublechitimages[B][chit drop shadows]{\allb}
+\doublechitimages[Markers][chit drop shadows]{{game turn chit}}
% \end{macrocode}
%
% Again, the macros we made for the counters comes in handy. Note
@@ -96,7 +96,9 @@
% can.}.
%
% \begin{macrocode}
-\battlemarkers{12}
+\tikzset{}
+\battlemarkers[marker drop shadows]{12}
+\tikzset{every battle marker/.style={}}
% \end{macrocode}
%
% Furthermore, we can add ``odds'' and battle result markers. Odds
@@ -108,14 +110,14 @@
% in the markers.
%
% \begin{macrocode}
-\oddsmarkers{%
+\oddsmarkers[marker drop shadows]{%
1:3/red!25!white,%
1:2/red!15!white,%
1:1/orange!15!white,%
2:1/white,%
3:1/green!15!white,%
4:1/green!25!white}
-\resultmarkers{
+\resultmarkers[marker drop shadows]{
AE/red!50!white,
AR/red!25!white,
EX/white,
diff --git a/macros/latex/contrib/wargame/doc/tutorial/game.pdf b/macros/latex/contrib/wargame/doc/tutorial/game.pdf
index f4e8a22e2a..63ea8b0733 100644
--- a/macros/latex/contrib/wargame/doc/tutorial/game.pdf
+++ b/macros/latex/contrib/wargame/doc/tutorial/game.pdf
Binary files differ
diff --git a/macros/latex/contrib/wargame/doc/wargame.pdf b/macros/latex/contrib/wargame/doc/wargame.pdf
index 01a58c597b..9b608b4144 100644
--- a/macros/latex/contrib/wargame/doc/wargame.pdf
+++ b/macros/latex/contrib/wargame/doc/wargame.pdf
Binary files differ
diff --git a/macros/latex/contrib/wargame/source/Makefile b/macros/latex/contrib/wargame/source/Makefile
index e11c477bf7..8320c42419 100644
--- a/macros/latex/contrib/wargame/source/Makefile
+++ b/macros/latex/contrib/wargame/source/Makefile
@@ -2,7 +2,7 @@
#
#
NAME := wargame
-VERSION := 0.5
+VERSION := 0.6
LATEX_FLAGS := -interaction=nonstopmode \
-file-line-error \
--synctex=15 \
diff --git a/macros/latex/contrib/wargame/source/chit/battle.dtx b/macros/latex/contrib/wargame/source/chit/battle.dtx
index 5057d620a5..381f4e4aba 100644
--- a/macros/latex/contrib/wargame/source/chit/battle.dtx
+++ b/macros/latex/contrib/wargame/source/chit/battle.dtx
@@ -41,7 +41,7 @@
minimum size=8mm,
draw=black,
fill=#2,
- every odds marker/.try] at (.2,-.2) {#1};
+ every odds marker/.try] at (.16,-.16) {#1};
}
},
odds marker/.style args={#1,#2}{
diff --git a/macros/latex/contrib/wargame/source/chit/misc.dtx b/macros/latex/contrib/wargame/source/chit/misc.dtx
index a5b9a79b24..e5d4b4b708 100644
--- a/macros/latex/contrib/wargame/source/chit/misc.dtx
+++ b/macros/latex/contrib/wargame/source/chit/misc.dtx
@@ -4,6 +4,58 @@
% \fi
% \subsubsection{Some utilities}
%
+% This style allows us to add a fading drop-shadow to chits.
+%
+% \begin{macrocode}
+\usetikzlibrary{shadows.blur}
+\newif\ifwg@chit@drop\wg@chit@dropfalse
+\tikzset{
+ chit has drop/.is if=wg@chit@drop,
+ chit has drop/.default=true,
+ chit has drop/.initial=false,
+ /tikz/render blur shadow/.add code={%
+ \chit@dbg{2}{Number of blur steps: \pgfbs@steps}%
+ \ifnum\pgfbs@steps=0\else
+ \chit@dbg{2}{Making shadow blur}%
+ }{\fi}}
+\tikzset{%
+ chit drop/.code={%
+ %% \message{^^J Args `#1'}%
+ \pgfkeysalso{%
+ chit has drop=true,
+ /tikz/blur shadow={shadow blur steps=5,
+ shadow opacity=25,
+ shadow xshift=.05cm,
+ shadow yshift=-.05cm,
+ shadow blur radius=.05cm,
+ #1}}%
+ \ifnum\pgfbs@steps=0%
+ \gdef\wg@drop@margin{0pt}%
+ \else%
+ \ifwg@chit@drop%
+ \pgfmathparse{
+ \pgfbs@radius+
+ veclen(
+ \pgfkeysvalueof{/tikz/shadow xshift},
+ \pgfkeysvalueof{/tikz/shadow yshift})}
+ \xdef\wg@drop@margin{\pgfmathresult pt}%
+ \else%
+ \gdef\wg@drop@margin{0pt}%
+ \fi
+ %% \message{^^J Drop margin is `\wg@drop@margin'
+ %% `\pgfbs@radius'
+ %% `\pgfkeysvalueof{/tikz/shadow xshift}',
+ %% `\pgfkeysvalueof{/tikz/shadow yshift}'}%
+ \fi%
+ },%
+ chit drop/.default=,%
+ no chit drop/.code={%
+ \pgfkeysalso{
+ /tikz/blur shadow={shadow blur steps=0}}
+ \gdef\wg@drop@margin{0pt}%
+ }
+}%
+% \end{macrocode}
%
% Game turn marker
%
diff --git a/macros/latex/contrib/wargame/source/chit/modifiers.dtx b/macros/latex/contrib/wargame/source/chit/modifiers.dtx
index b42ee5790f..f2f47ee3a8 100644
--- a/macros/latex/contrib/wargame/source/chit/modifiers.dtx
+++ b/macros/latex/contrib/wargame/source/chit/modifiers.dtx
@@ -14,7 +14,7 @@
code={%
\path[fill=white,opacity=#1,pic actions] (-.6,-.6) rectangle(.6,.6);}},
pics/chit/eliminate/.style={
- code={%
+ code={%
\path[fill=red,opacity=#1,pic actions] (-.6,-.6) rectangle(.6,.6);}},
pics/chit/shade/.default=0.5,
pics/chit/eliminate/.default=0.25,
diff --git a/macros/latex/contrib/wargame/source/chit/oob.dtx b/macros/latex/contrib/wargame/source/chit/oob.dtx
index d640dadebf..9e5f0c4f93 100644
--- a/macros/latex/contrib/wargame/source/chit/oob.dtx
+++ b/macros/latex/contrib/wargame/source/chit/oob.dtx
@@ -37,8 +37,9 @@
\def\chit@oob@rowupdate(#1,#2)#3#4{%
\chit@dbg{2}{ Row update c=`#1',r=`#2',s=`#3',e=`#4'}
%\pgfmathparse{ifthenelse(#1>0,#2-#3,#2)}%
- \pgfmathparse{#2-#3)}%
+ \pgfmathparse{#2-#3-#4}%
\xdef#2{\pgfmathresult}%
+ \xdef#1{0}%\pgfmathresult}%
%\xdef#1{0}
\chit@dbg{2}{ \space\space-> update `\string#2'=#2}
}
@@ -71,6 +72,7 @@
% \begin{macrocode}
\newif\ifwg@oob@inv\wg@oob@invfalse
\def\chit@oob@spacer{hspace}
+\def\chit@oob@vspacer{vspace}
\def\wg@star@oob{\wg@oob@invtrue\wg@oob}
\def\wg@nostar@oob{\wg@oob@invfalse\wg@oob}
\def\oob{%
@@ -91,6 +93,8 @@
% \begin{macrocode}
\def\wg@oob#1#2#3#4{
\def\r{0}
+ \pgfmathparse{#3*(#2-1)}%
+ \edef\a{\pgfmathresult}
\chit@dbg{2}{OOB: `#1'}
\foreach[count=\ti from 0] \t/\y in #1{
\xdef\o{\r}
@@ -109,20 +113,28 @@
\ifx\m\@empty\def\m{1}\fi
\ifx\u\m\def\m{1}\fi
\foreach \n in {1,...,\m}{%
- \chit@dbg{2}{OOB Chit is `\u'}%
+ \chit@dbg{2}{OOB Chit is `\u' `\chit@oob@spacer'}%
\ifx\u\chit@oob@spacer%
\chit@dbg{3}{Chit `\u' is spacer `\chit@oob@spacer'}
\pgfmathparse{\c+#4}%
\xdef\c{\pgfmathresult}%
- \else
- \ifnum\chitdbglvl>2%
- \node[minimum width=#3cm,minimum height=#3cm,
- draw,transform shape] at (\c,\r) {};
+ \else%
+ \ifx\u\chit@oob@vspacer%
+ \chit@dbg{3}{Chit `\u' is vspacer `\chit@oob@vspacer'}
+ \pgfmathparse{ifthenelse(abs(\c)<0.0001,0,#3)}
+ \xdef\ll{\pgfmathresult}
+ \chit@dbg{2}{\string\ll=`\ll'}
+ \chit@oob@rowupdate(\c,\r){\ll}{#4}
+ \else
+ \ifnum\chitdbglvl>2%
+ \node[minimum width=#3cm,minimum height=#3cm,
+ draw,transform shape] at (\c,\r) {};
+ \fi
+ \ifx\u\chit@blank\else%
+ \chit[\u=\ti,zone oob point={\u}{\c}{\r}](\c,\r);%
+ \fi%
+ \chit@oob@cellupdate(\c,\r){#2}{#3}{\y}
\fi
- \ifx\u\chit@blank\else%
- \chit[\u=\ti,zone oob point={\u}{\c}{\r}](\c,\r);%
- \fi%
- \chit@oob@cellupdate(\c,\r){#2}{#3}{\y}
\fi
}
\fi
@@ -153,7 +165,7 @@
% \chit@dbg{2}{ \space Breaking loop \rr\space > \y}%
% \breakforeach%
%\else%
- \chit@oob@rowupdate(\c,\r){#3}{#4}
+ \chit@oob@rowupdate(\c,\r){#3}{0}% Extra spacing?
%\fi
}
\fi
@@ -166,6 +178,169 @@
\@ifnextchar;{\@gobble}{}}
% \end{macrocode}
%
+% Horizontal flow OOB
+%
+% \begin{macrocode}
+\def\wg@star@hoob{\wg@oob@invtrue\wg@hoob}
+\def\wg@nostar@hoob{\wg@oob@invfalse\wg@hoob}
+\def\hoob{%
+ \@ifstar{\wg@star@hoob%
+ }{\wg@nostar@hoob%
+ }%
+}
+% \end{macrocode}
+%
+% The inner macro of \cs{hoob}. The arguments are
+% \begin{enumerate}
+% \item The list of lists of chits styles
+% \item The maximum number of columns
+% \item The width of each cell
+% \item Additional row spacing between turns
+% \end{enumerate}
+%
+% \begin{macrocode}
+\def\wg@hoob#1#2#3#4{
+ \def\r{0}
+ \def\c{0}
+ \pgfmathparse{#3*(#2-1)}%
+ \edef\a{\pgfmathresult}
+ \chit@dbg{2}{OOB: `#1'}
+ \foreach[count=\ti from 0] \t/\y in #1{
+ \xdef\o{\r}
+ % \def\c{0}
+ \ifx\t\y\def\y{0}\fi
+ \chit@dbg{2}{Turn \ti\space(\r,\t,y=\y):'}
+ \ifx\t\empty\else
+ % Count how many are left for this turn
+ \chit@dbg{2}{At start of turn \t\space\string\c=\c}
+ \def\l{\c}%
+ \let\ig\empty
+ \foreach \u/\m in \t{
+ \ifx\ig\empty
+ \ifx\u\empty\else
+ \ifx\u\m\def\m{1}\fi
+ \ifx\u\chit@oob@spacer%
+ \pgfmathparse{\l+\m*#4}\xdef\l{\pgfmathresult}
+ \chit@dbg{2}{Got \m\space hspace (#4) -> \l}
+ \else
+ \ifx\u\chit@oob@vspace%
+ \xdef\ig{1}
+ \chit@dbg{2}{Got vspace -> \l (\ig)}
+ \else
+ \pgfmathparse{\l+\m*#3}
+ \xdef\l{\pgfmathresult}
+ \chit@dbg{2}{Got \m\space units -> \l}
+ \fi
+ \fi
+ \fi
+ \fi}
+ % Check if there's enough room
+ \chit@dbg{2}{To fill the rest of turn needs `\l' compared to
+ `\a' (#3*(#2-1))}
+ \pgfmathparse{ifthenelse(abs(\l)>=#3*(#2-1),0,1}%
+ \xdef\l{\pgfmathresult}%
+ \chit@dbg{2}{Break or not `\l'}
+ \ifnum\l=0\chit@oob@turnupdate(\c,\r){#3}{#4}\fi
+ \fi
+ \ifwg@oob@inv%
+ \pic[transform shape] at (\c+.5*#3,\r) {chit/oob turn=\ti};% was dx=0.5
+ \else
+ \pic[transform shape] at (\c+-.5*#3,\r) {chit/oob turn=\ti};% was dx=-0.5
+ \fi%
+ %\chit@oob@cellupdate(\c,\r){#2}{#3}{\y}
+ \ifx\t\empty\else%
+ \def\lv{0}
+ \foreach \u/\m in \t{
+ %% \chit@dbg{2}{ `\u'=`\m'}
+ \ifx\u\empty\else
+ \ifx\m\@empty\def\m{1}\fi
+ \ifx\u\m\def\m{1}\fi
+ \foreach \n in {1,...,\m}{%
+ \chit@dbg{2}{OOB Chit is `\u' `\chit@oob@spacer'}%
+ \ifx\u\chit@oob@spacer%
+ \chit@dbg{3}{Chit `\u' is spacer `\chit@oob@spacer'}
+ \pgfmathparse{\c+#4}%
+ \xdef\c{\pgfmathresult}%
+ \else%
+ \ifx\u\chit@oob@vspacer%
+ \chit@dbg{3}{Chit `\u' is vspacer `\chit@oob@vspacer'}
+ \pgfmathparse{ifthenelse(abs(\c)<0.0001,0,#3)}
+ \xdef\ll{\pgfmathresult}
+ \chit@dbg{2}{\string\ll=`\ll'}
+ \chit@oob@rowupdate(\c,\r){\ll}{#4}
+ \xdef\lv{1}
+ \else
+ \ifnum\chitdbglvl>2%
+ \node[minimum width=#3cm,minimum height=#3cm,
+ draw,transform shape] at (\c,\r) {};
+ \fi
+ \ifx\u\chit@blank\else%
+ \chit[\u=\ti,zone oob point={\u}{\c}{\r}](\c,\r);%
+ \fi%
+ \chit@oob@cellupdate(\c,\r){#2}{#3}{\y}
+ \fi
+ \fi
+ }
+ \fi
+ }
+ \fi
+ \chit@dbg{2}{ End of chits in turn
+ \ti\space(c=`\c',r=`\r',o='\o',y='\y')}
+ % --- Not relevant, I think
+ % IF no units where given, then we force \c to be non-zero so that
+ % \chit@oob@turnupdate increments the row
+ % \ifx\t\@empty
+ % \def\c{#3}
+ % \chit@dbg{2}{ Turn is empty, set c=`\c'}
+ % \fi
+ % ---
+ %\ifnum\y<0% No explicit number of rows given
+ % \def\c{#3}
+ % \chit@dbg{2}{ No explicit number of rows given, set c=`\c'}
+ %\fi
+ % In case the user gave and explicit number of rows, add the rows
+ % that are missing. \y is initially set to the number of
+ % requested rows, and then decremented every time we go down one
+ % row. So if the number of rows we did so far is N, and the
+ % requested number of rows is M, then the loop below adds M-N
+ % rows.
+ \ifnum\y>0%
+ \chit@dbg{2}{ Looping rows from 2 to \y, break when row > \y}%
+ \foreach \rr in {2,...,\y}{
+ %\ifnum\rr>\y% A little funny, but \y can be negative!
+ % \chit@dbg{2}{ \space Breaking loop \rr\space > \y}%
+ % \breakforeach%
+ %\else%
+ \chit@oob@rowupdate(\c,\r){#3}{0}% Extra spacing?
+ %\fi
+ }
+ \fi
+ % --- Not relevant I think
+ % This will zero \c. However, if on entry |\c|>0, then we also
+ % increment the row
+ % \chit@oob@turnupdate(\c,\r){#3}{#4}
+ % ---
+ % Horizontal spacer
+
+ %\pgfmathparse{ifthenelse(abs(\c)>=\a,1,0)}\xdef\l{\pgfmathresult}
+ \pgfmathparse{\c+1.5*#4}%
+ \xdef\c{\pgfmathresult}%
+ \ifnum\lv=1%
+ \pgfmathparse{\r-#4}
+ \chit@oob@rowupdate(\c,\r){0}{#4}
+ \else
+ \chit@oob@cellupdate(\c,\r){#2}{#3}{\y}
+ \ifnum\y<0
+ \chit@oob@turnupdate(\c,\r){#3}{#4}
+ \else
+ \fi
+ \fi
+ % \xdef\y{0}
+ \chit@dbg{2}{End of turn \ti\space(c=`\c',r=`\r',o='\o',y='\y')}
+ }
+ \chit@dbg{3}{End of OOB (c=`\c',r=`\r',y=`\y')}
+ \@ifnextchar;{\@gobble}{}}
+% \end{macrocode}
% \iffalse
% </chit>
% --------------------------------------------------------------------
diff --git a/macros/latex/contrib/wargame/source/chit/shape.dtx b/macros/latex/contrib/wargame/source/chit/shape.dtx
index 8a3d70fbd0..f68ea25a44 100644
--- a/macros/latex/contrib/wargame/source/chit/shape.dtx
+++ b/macros/latex/contrib/wargame/source/chit/shape.dtx
@@ -92,7 +92,7 @@
chit/symbol/.style={scale=.4,transform shape},
chit/parts/.style={shape=rectangle,transform shape},
chit/factors/.style={chit/parts,anchor=south},
- chit/left/.style={chit/parts,anchor=south,rotate=90},
+ chit/left/.style={chit/parts,anchor=base,rotate=90},%Anchor was south
chit/right/.style={chit/parts,anchor=north,rotate=90},
chit/upper left/.style={chit/parts,anchor=north west},
chit/upper right/.style={chit/parts,anchor=north east},
@@ -141,7 +141,8 @@
% \begin{macrocode}
\tikzset{%
chit/.code={%
- \pgfkeys{/tikz/transform shape,/tikz/shape=chit}
+ \chit@dbg{2}{chit arguments are `#1'}%
+ \pgfkeys{/tikz/transform shape,/tikz/shape=chit}%
\pgfkeys{/chit/.cd,#1}}}
% \end{macrocode}
% \end{TikzKey}
@@ -657,7 +658,11 @@
%
% The work horse. This simply makes a \cs{node} with the shape
% \texttt{chit}. Note, we allow for a trailing semi-colon
-% (\texttt{;}) to have a similar feel to other \TikZ{} macros.
+% (\texttt{;}) to have a similar feel to other \TikZ{} macros.
+%
+% The macro will execute the style \texttt{/tikz/every chit} if
+% defined. Note that this will be executed \emph{before} the usual
+% \texttt{every chip node} style.
%
% \begin{macrocode}
\def\chit@@@#1#2(#3){%
@@ -667,7 +672,7 @@
^^J Name: `#3'}
\let\name\pgfutil@empty%
\chit@dbg{1}{=== Before chit node}%
- \node[chit={every chit/.try,id=#3,#1}] (tmp) at (#2) {};
+ \node[chit={/tikz/every chit/.try,id=#3,#1}] (tmp) at (#2) {};
\chit@dbg{2}{=== After chit node}%
\ifx|#3|\relax%
\else%
diff --git a/macros/latex/contrib/wargame/source/chit/table.dtx b/macros/latex/contrib/wargame/source/chit/table.dtx
index 7094e436ed..f99236119e 100644
--- a/macros/latex/contrib/wargame/source/chit/table.dtx
+++ b/macros/latex/contrib/wargame/source/chit/table.dtx
@@ -7,7 +7,9 @@
% \begin{macrocode}
\tikzset{
chit/cell background/.style={fill=black},
+ %chit/cell background flipped/.style={fill=black},
blank chit/.style={/chit/frame={draw=none,fill=none}},
+ chit/grid lines/.style={dashed},
}
% \end{macrocode}
%
@@ -20,6 +22,10 @@
\def\chit@cellbg(#1,#2)#3{%
\draw[chit/cell background](#1-#3/2,#2-#3/2) rectangle++(#3,#3);
}
+\def\chit@celldblbg(#1,#2)#3{%
+ \draw[chit/cell background,chit/cell background flipped/.try]%
+ (#1-#3/2,#2-#3/2) rectangle++(#3,#3);
+}
% \end{macrocode}
%
% \begin{Macro}{\ifchits@reset}
@@ -83,6 +89,27 @@
\@ifnextchar;{\@gobble}{}}
% \end{macrocode}
% \end{Macro}
+% \begin{Macro}{\chitgrid}
+% \begin{enumerate}
+% \item columns
+% \item rows
+% \item cell-size
+% \end{enumerate}
+%
+% \begin{macrocode}
+\def\chitgrid#1#2#3{%
+ \pgfmathparse{#3/2}\edef\rmin{\pgfmathresult}%
+ \pgfmathparse{#2*#3-#3/2}\edef\rmax{\pgfmathresult}%
+ %\draw[red](-#3/2,\rmin)rectangle(#3*#1-#3/2,-\rmax);
+ \foreach \cc in {0,...,#1}{
+ \draw[chit/grid lines] (\cc*#3-#3/2,3*#3/4)--(\cc*#3-#3/2,-\rmax-#3/4);}
+ %\chit@dbg{0}{Drawing horizontal lines from `\rmin, `-\rmin', ..., `-\rmax'}
+ \foreach \rr in {\rmin,-\rmin,...,-\rmax}{
+ %\chit@dbg{0}{Horizontal line at `\rr'}
+ \draw[chit/grid lines] (-3*#3/4,\rr)--(#1*#3-#3/4,\rr);}
+}
+% \end{macrocode}
+% \end{Macro}
%
% \begin{Macro}{\doublechits,
% \@doublechits,
@@ -154,7 +181,7 @@
\chit@cellbg(\c,\r){#3}
\chit[\u=\ti](\c,\r)
\chit@dbl@flip(\c,\r){#3}
- \chit@cellbg(\mc,\r){#3}
+ \chit@celldblbg(\mc,\r){#3}
\chit[\u\space flipped=\ti,zone turn=\t,zone mult=\n](\mc,\r)
\chit@dbl@cellupdate(\c,\r){#2}{#3}
\fi
@@ -166,10 +193,39 @@
\draw[dashed](0,-3*#3/4)--(0,\r-#3/4);%
\draw[dashed,<-] (#3/5,-2*#3/3)--(#3/2,-2*#3/3) node[transform shape,anchor=west]{Back};%
\draw[dashed,<-] (-#3/5,-2*#3/3)--(-#3/2,-2*#3/3) node[transform shape,anchor=east]{Front};%
+ % \foreach \cc in {0,...,#2}{
+ % \draw[dashed] (\cc*#3,-3*#3/4)--(\cc*#3,\r-#3/4);
+ % \draw[dashed] (-\cc*#3,-3*#3/4)--(-\cc*#3,\r-#3/4);}
+ % \pgfmathparse{#3/2}\edef\rmin{\pgfmathresult}%
+ % \chit@dbg{0}{Drawing horizontal lines from `-\rmin, `\rmin', ..., `\r'}
+ % \foreach \rr in {-\rmin,\rmin,...,\r}{
+ % \chit@dbg{0}{Horizontal line at `\rr'}
+ % \draw[dashed] (-#2*#3-#3/4,\rr)--(#2*#3+#3/4,\rr);}
\@ifnextchar;{\@gobble}{}}
% \end{macrocode}
% \end{Macro}
%
+% \begin{Macro}{\doublechitgrid}
+% \begin{enumerate}
+% \item columns
+% \item rows
+% \item cell-size
+% \end{enumerate}
+%
+% \begin{macrocode}
+\def\doublechitgrid#1#2#3{%
+ \pgfmathparse{#3/2}\edef\rmin{\pgfmathresult}%
+ \pgfmathparse{#2*#3-#3/2}\edef\rmax{\pgfmathresult}%
+ \foreach \cc in {0,...,#1}{
+ \draw[chit/grid lines] (\cc*#3,-3*#3/4)--(\cc*#3,\rmax+#3/4);
+ \draw[chit/grid lines] (-\cc*#3,-3*#3/4)--(-\cc*#3,\rmax+#3/4);}
+ %\chit@dbg{0}{Drawing horizontal lines from `-\rmin, `\rmin', ..., `\rmax'}
+ \foreach \rr in {-\rmin,\rmin,...,\rmax}{
+ %\chit@dbg{0}{Horizontal line at `\rr'}
+ \draw[chit/grid lines] (-#1*#3-#3/4,\rr)--(#1*#3+#3/4,\rr);}
+}
+% \end{macrocode}
+% \end{Macro}
% \iffalse
% </chit>
% --------------------------------------------------------------------
diff --git a/macros/latex/contrib/wargame/source/hex/labels.dtx b/macros/latex/contrib/wargame/source/hex/labels.dtx
index 7767dcc661..f622bf6cda 100644
--- a/macros/latex/contrib/wargame/source/hex/labels.dtx
+++ b/macros/latex/contrib/wargame/source/hex/labels.dtx
@@ -132,7 +132,7 @@
%
% \begin{macrocode}
\def\hex@do@label{%
- \hex@dbg{1}{Hex label: `\meaning\hex@label'}%
+ \hex@dbg{3}{Hex label: `\meaning\hex@label'}%
\edef\hex@l@tmp{[%
/hex/label/.cd,%
rotate=0,%
diff --git a/macros/latex/contrib/wargame/source/hex/ridges.dtx b/macros/latex/contrib/wargame/source/hex/ridges.dtx
index 24552e36e2..658f55888b 100644
--- a/macros/latex/contrib/wargame/source/hex/ridges.dtx
+++ b/macros/latex/contrib/wargame/source/hex/ridges.dtx
@@ -157,11 +157,12 @@
\xdef\hex@r@p{\hex@r@p ($(300:\hex@r@r)+(-120:\hex@r@t/2)$)}
\fi
\ifhex@r@ne
- \xdef\hex@r@p{\hex@r@p --cycle}
+ %\xdef\hex@r@p{\hex@r@p --cycle}
+ \xdef\hex@r@p{\hex@r@p -- (0:\hex@r@r)}
\else
\xdef\hex@r@p{\hex@r@p --(.5:\hex@r@r)}
\fi
- \hex@dbg{4}{Ridge along se: `\hex@r@p'}
+ \hex@dbg{4}{Ridge along south east: `\hex@r@p'}
\fi
\hex@dbg{3}{ Ridges path: \hex@r@p}
% \draw[red] \hex@r@p;
diff --git a/macros/latex/contrib/wargame/source/hex/terrain.dtx b/macros/latex/contrib/wargame/source/hex/terrain.dtx
index 4c486adf77..9d15a555ec 100644
--- a/macros/latex/contrib/wargame/source/hex/terrain.dtx
+++ b/macros/latex/contrib/wargame/source/hex/terrain.dtx
@@ -37,6 +37,7 @@
% select the common terrains.
%
% \begin{macrocode}
+\newif\if@hex@t@rot\@hex@t@rotfalse%
\tikzset{%
/hex/terrain/.search also={/tikz},%
/hex/terrain/.cd,%
@@ -44,6 +45,7 @@
image/.store in=\hex@t@image,%
code/.store in=\hex@t@code,%
clip/.store in=\hex@t@clip,%
+ random rotation/.is if=@hex@t@rot,
pic/.default=,
image/.default=,
code/.default=,
@@ -137,8 +139,23 @@
\@ifundefined{hex@t@code}{\let\hex@t@code\empty}{}
% \end{macrocode}
%
+% Possible make rotation. We define a scope and rotate within that.
+%
+% \begin{macrocode}
+ \def\hex@t@angle{0}%
+ \if@hex@t@rot%
+ \pgfmathrandominteger{\hex@t@angle}{0}{5}
+ \pgfmathparse{int(60*\hex@t@angle)}\edef\hex@t@angle{\pgfmathresult}%
+ \fi%
+ \hex@dbg{5}{Will rotate terrain by `\hex@t@angle'}%
+% \end{macrocode}
+%
+% If we have specified code for the terrain, then execute that.
+%
% \begin{macrocode}
- \ifx\hex@t@code\empty\else\hex@t@code\fi%
+ \scope[rotate=\hex@t@angle]%
+ \ifx\hex@t@code\empty\else\hex@t@code\fi%
+ \endscope% End rotate code
% \end{macrocode}
% First we check if we have not got terrain images, but terrain
% pictures. If we have that, we process these in turn. Note, the
@@ -154,7 +171,9 @@
\hex@dbg{5}{Terrain pictures}%
\pgfpointorigin\wg@tmpa=\pgf@x\wg@tmpb=\pgf@y%
\foreach \i in \hex@t@pic{%
- \wg@pic@all{\i}{}{\the\wg@tmpa,\the\wg@tmpb}{}}%
+ \wg@pic@all{\i}{}{\the\wg@tmpa,\the\wg@tmpb}{%
+ rotate=\hex@t@angle,
+ transform shape}}%
\fi% We have pictures.
% \end{macrocode}
%
@@ -172,6 +191,7 @@
\expandafter\wg@node{%
\includegraphics[width=2cm]{\i}}\@endwg@node %
{}{\wg@tmpa,\wg@tmpb}{%
+ rotate=\hex@t@angle,%
shape=rectangle,%
anchor=center,%
transform shape,%
diff --git a/macros/latex/contrib/wargame/source/tests/chits.dtx b/macros/latex/contrib/wargame/source/tests/chits.dtx
index 7dcf26c50d..966e3b4a9f 100644
--- a/macros/latex/contrib/wargame/source/tests/chits.dtx
+++ b/macros/latex/contrib/wargame/source/tests/chits.dtx
@@ -6,7 +6,11 @@
% Some chits for testing stuff
%
% \begin{macrocode}
-\def\firstchit{
+\makeatletter
+\def\firstchit{%
+ \@ifnextchar[{\@firstchit}{\@firstchit[]}%]
+}%
+\def\@firstchit[#1]{
% \chitdbglvl=5
% \natoappdbglvl=5
\chit[symbol={
@@ -17,13 +21,14 @@
left={text=A},
frame={fill=yellow!50!black},
ultra thick,
- command=land},
+ command=land,
+ },
left={chit/identifier={1}},
right={chit/identifier={2}},
factors={chit/2 factors={4,8}},
frame={draw=black},
- color=white,text=yellow,fill={blue}]}
-\makeatletter
+ color=white,text=yellow,fill={blue},
+ #1]}
\def\secondchit{%
\@ifnextchar({\second@chit}{\second@chit(0,0)}%)
}
@@ -34,6 +39,7 @@
command=air](0,-.15)},
left={[{red,font=\noexpand\sffamily}]chit/identifier={Fighter}},
right={chit/identifier={USAF}},
+ fill=white,
factors={chit/1 factor=3}}] at (#1){};}
\def\thirdchit{
\chit[symbol={[echelon=battalion,
diff --git a/macros/latex/contrib/wargame/source/tests/test.tex b/macros/latex/contrib/wargame/source/tests/test.tex
index 5833d679f2..49062b70f0 100644
--- a/macros/latex/contrib/wargame/source/tests/test.tex
+++ b/macros/latex/contrib/wargame/source/tests/test.tex
@@ -2,6 +2,7 @@
\usepackage{wargame}
\usetikzlibrary{decorations.markings}
+\usetikzlibrary{shadows.blur}
\title{A test of \textsf{wargame}}
\author{}
\date{}
@@ -28,7 +29,7 @@
\section{Some chits}
-\begin{tikzpicture}
+\begin{tikzpicture}[every chit node/.style={blur shadow={shadow blur steps=5}}]
\fill[red!50] (1,-1) rectangle (3,1);
\firstchit(0,0)%
%\secondchit(2,0)%
@@ -45,18 +46,20 @@
\end{tikzpicture}
\section{Chits on a board}
-\begin{tikzpicture}
+\begin{tikzpicture}[every chit/.style={chit drop}]
+ \chitdbglvl=5
\begin{scope}[every hex/.style={/hex/label=auto},transform shape]
\boardframe[0.5](c=0,r=0)(c=3,r=3)
\boardclip(c=0,r=0)(c=3,r=3){fill=white}
\testmap{}
- \firstchit(hex cs:c=2,r=1)
- \secondchit(hex cs:c=3,r=0)
+ \firstchit[no chit drop](hex cs:c=2,r=2)
+ %\secondchit(hex cs:c=3,r=0)
\thirdchit(hex cs:c=0,r=3)
\stackchits(hex cs:c=0,r=1)(.3,.3){
\noexpand\firstchit,
- \noexpand\secondchit/\noexpand\chit[{full=chit/eliminate}]}
+ \noexpand\secondchit%/\noexpand\eliminatechit
+ }
\begin{scope}[m/.style={hex/long move=green}]
\path[m] (hex cs:c=3,r=0) -- (hex cs:c=3,r=1)--(hex cs:c=3,r=2);
diff --git a/macros/latex/contrib/wargame/source/util/export.dtx b/macros/latex/contrib/wargame/source/util/export.dtx
index fde067dfe8..09f74c0513 100644
--- a/macros/latex/contrib/wargame/source/util/export.dtx
+++ b/macros/latex/contrib/wargame/source/util/export.dtx
@@ -72,6 +72,7 @@
%
% Preceed all images (\textsf{tikzpicture}) with this command
%
+%
% First argument is the name of the image. This can be anything.
% Note that for counters, if the name ends in \texttt{flipped} then it
% is considered the backside of a counter.
@@ -140,13 +141,32 @@
%
% Make separate images for each counter (single sided).
%
+% First optional argument is the group to put the chits into.
+% Second optional argument is options to give to each Tikz picture
+% environment. Third, mandatory, argument is the list of chit
+% identifiers to render.
+%
% \begin{macrocode}
-\newcommand\chitimages[2][]{%
+\def\wg@add@drop@margin{%
+ \@ifundefined{wg@drop@margin}{}{
+ \dimen0=\wg@drop@margin
+ % \ifwg@chit@drop
+ \ifdim\dimen0>0pt%
+ \path ($(current bounding box.north east)+(45:\wg@drop@margin)$)
+ -- ($(current bounding box.south west)+(225:\wg@drop@margin)$);
+ \fi}}
+\def\chitimages{%
+ \@ifnextchar[{\@chitimages}{\chitimages[]}%]
+}%
+\def\@chitimages[#1]{%
+ \@ifnextchar[{\@@chitimages[#1]}{\@@chitimages[#1][]}%]
+}%
+\def\@@chitimages[#1][#2]#3{%
\begingroup%
\let\chit@report\do@chit@report%
\let\natoapp@report\do@natoapp@report%
- \chit@dbg{2}{chits to make images of `#2'}%
- \foreach[count=\ti from 0] \t/\x in #2{%
+ \chit@dbg{2}{chits to make images of `#3'}%
+ \foreach[count=\ti from 0] \t/\x in #3{%
\chit@dbg{2}{^^JRow: `\t' (`\x')}
\ifx\t\empty\else% Ignore empty rows
\chit@dbg{5}{^^JSubcategory: `\x' (default `#1')}
@@ -156,14 +176,17 @@
\ifx\u\empty\else% Ignore empty cells
\ifx\u\chit@blank\else%
\chit@dbg{2}{Next chit `\u' with possible multiplicity `\m'}%
- \ifx\m\@empty\def\m{1}\fi% If not multiplicity defined
+ \ifx\m\@empty\def\m{1}\fi% If no multiplicity defined
\ifx\u\m\def\m{1}\fi% If the same as unit
\chit@dbg{2}{Next chit `\u' multiplicity `\m'}%
%% We only make one copy of the chit, since we can duplicate
%% it in VASSAL
\info*{\u}{counter}{\x}
- \begin{tikzpicture}
+ \nopagecolor%
+ \gdef\wg@drop@margin{0pt}%
+ \begin{tikzpicture}[chit has drop=false,#2]
\chit[\u=\ti]%
+ \wg@add@drop@margin%
\end{tikzpicture}
\end@info%
%% \foreach \n in {1,...,\m}{% Make a number of copies
@@ -189,14 +212,25 @@
%
% Make separate images for each counter (double sided). The back-side
% counters must be defined by append `\texttt{ flipped}' the front
-% face name
+% face name.
+%
+% First optional argument is the group to put the chits into.
+% Second optional argument is options to give to each Tikz picture
+% environment. Third, mandatory, argument is the list of chit
+% identifiers to render.
%
% \begin{macrocode}
-\newcommand\doublechitimages[2][]{%
+\def\doublechitimages{%
+ \@ifnextchar[{\@doublechitimages}{\doublechitimages[]}%]
+}%
+\def\@doublechitimages[#1]{%
+ \@ifnextchar[{\@@doublechitimages[#1]}{\@@doublechitimages[#1][]}%]
+}%
+\def\@@doublechitimages[#1][#2]#3{%
\begingroup%
\let\chit@report\do@chit@report%
\let\natoapp@report\do@natoapp@report%
- \foreach[count=\ti from 0] \t/\x in #2{%
+ \foreach[count=\ti from 0] \t/\x in #3{%
\ifx\t\empty\else% Ignore empty rows
\chit@dbg{5}{^^JSubcategory: `\x' (default `#1')}
% Take sub-category or default
@@ -213,13 +247,18 @@
%% We only make one copy of the chit, since we can duplicate
%% it in VASSAL
\info*{\u}{counter}{\x}%
- \begin{tikzpicture}%
+ \nopagecolor%
+ \gdef\wg@drop@margin{0pt}%
+ \begin{tikzpicture}[chit has drop=false,#2]%
\chit[\u=\ti]%
+ \wg@add@drop@margin%
\end{tikzpicture}%
\end@info%
\info*{\s}{counter}{\x}%
- \begin{tikzpicture}%
+ \nopagecolor%
+ \begin{tikzpicture}[chit has drop=false,#2]%
\chit[\s=\ti]%
+ \wg@add@drop@margin%
\end{tikzpicture}%
\end@info%
%% \foreach \n in {1,...,\m}{% Make a number of copies
@@ -414,7 +453,7 @@
\def\hex@col{0}%
\def\hex@row{0}%
\node[hex,inner sep=0,outer sep=0]{%
- \message{^^JHex label: `\meaning\hex@label'}%
+ %\message{^^JHex label: `\meaning\hex@label'}%
\global\let\mk@label\hex@label}}}%
% \end{macrocode}
%
@@ -427,7 +466,7 @@
\edef\mk@i{\mk@i\space}
%% Everything is made into centimeters
\mk@w{ \mk@i "units": "cm",}
- \hex@dbg{0}{Label: `\meaning\mk@label'}
+ \hex@dbg{3}{Label: `\meaning\mk@label'}
\@ifundefined{mk@label}{}{\mk@w{ \mk@i "labels": "\mk@label",}}
%% Write out coordinate options as "coords" object
\mk@w{ \mk@i"coords": \@lbchar}%
@@ -577,7 +616,7 @@
% optional is the group to add the markers to.
%
% \begin{macrocode}
-\def\wg@gennumberm@rkers#1#2#3{
+\def\wg@gennumberm@rkers#1#2#3#4{
\message{^^JNumbered markers: Type=`#1' Max=`#2' Category=`#3'}
\def\markers{}
\def\keys{}
@@ -585,24 +624,37 @@
\xdef\keys{/tikz/#1 \i/.style={/tikz/#1=\i},\keys}
\xdef\markers{\markers,#1 \i}}
{%
- \nopagecolor\pgfkeysalsofrom{\keys}\chitimages[#3]{\markers}}}%
+ \nopagecolor\pgfkeysalsofrom{\keys}\chitimages[#3][#4]{\markers}}}%
\tikzset{
wg hidden unit/.pic={},
wg hidden unit/.style={
chit={
+ no chit drop,
frame={draw=none,fill=none},
full=wg hidden unit}}}
-\DeclareRobustCommand\battlemarkers[2][BattleMarkers]{%
- \wg@gennumberm@rkers{battle marker}{#2}{#1}%
+%
+% First optional argument are extra styles
+% Second is category
+% Third is number of markers
+%
+\def\battlemarkers{%
+ \@ifnextchar[{\@battlemarkers}{\battlemarkers[]}%]
+}%
+\def\@battlemarkers[#1]{%
+ \@ifnextchar[{\@@battlemarkers[#1]}{\battlemarkers[#1][BattleMarkers]}%]
+}%
+\def\@@battlemarkers[#1][#2]#3{%
+ \wg@gennumberm@rkers{battle marker}{#3}{#2}{#1}%
\message{^^JMake a hidden unit and add to Markers category}
{%
\nopagecolor%
\chitimages[Markers]{{wg hidden unit}}%
%
\info{battle-marker-icon}{icon}{}%
- \tikz[scale=.7,transform shape]{\pic{battle marker=0};}%
+ \tikz[scale=.7,transform shape,auto icon more/.try]{%
+ \pic{battle marker=0};}%
\info{clear-battles-icon}{icon}{}
- \tikz[scale=.4,transform shape]{%
+ \tikz[scale=.4,transform shape,auto icon more/.try]{%
\pic{eliminate icon};
\pic[scale=.7,transform shape] at (-.3,0) {battle marker=0};}%
}%
@@ -613,21 +665,40 @@
% Optional is the group to add the markers to.
%
% \begin{macrocode}
-\def\wg@gencolorm@rkers#1#2#3{%
+\def\wg@gencolorm@rkers#1#2#3#4{%
\def\markers{}
\def\keys{}
- \foreach \o/\f in {#2}{%
+ \foreach \o/\f/\n [count=\i] in {#2}{%
+ \ifx\n\f\def\n{\o}\fi%
\ifx\o\f\def\f{white}\fi%
- \message{^^JOdds marker `#1 \o' w/fill `\f'}%
- \xdef\keys{/tikz/#1 \o/.style={/tikz/#1={\o,\f}},\keys}
- \xdef\markers{\markers,#1 \o}}
- {\nopagecolor\pgfkeysalsofrom{\keys}\chitimages[#3]{\markers}}}%
-\DeclareRobustCommand\oddsmarkers[2][OddsMarkers]{%
- \wg@gencolorm@rkers{odds marker}{#2}{#1}%
+ \message{^^JColour no \i marker `#1 \n' w/fill `\f' text `\o'}%
+ \protected@xdef\keys{/tikz/#1 \n/.style={/tikz/#1={\o,\f}},\keys}
+ \xdef\markers{\markers,#1 \n}
+ }%
+ {%
+ \nopagecolor%
+ \pgfkeysalsofrom{\keys}%
+ \chitimages[#3][#4]{\markers}%
+ }%
+}%
+%
+% First optional argument are extra styles
+% Second is category
+% Third is marker list
+%
+\def\oddsmarkers{%
+ \@ifnextchar[{\@oddsmarkers}{\oddsmarkers[]}%]
+}%
+\def\@oddsmarkers[#1]{%
+ \@ifnextchar[{\@@oddsmarkers[#1]}{\oddsmarkers[#1][OddsMarkers]}%]
+}%
+\def\@@oddsmarkers[#1][#2]#3{%
+ \wg@gencolorm@rkers{odds marker}{#3}{#2}{#1}%
\info{odds-battles-icon}{icon}{}
- \tikz[scale=.5,transform shape]{\pic{odds marker={?:?,white}}}
+ \tikz[scale=.5,transform shape,auto icon more/.try]{%
+ \pic{odds marker={?:?,white}}}
\info{resolve-battles-icon}{icon}{}
- \tikz[scale=.3,transform shape]{%
+ \tikz[scale=.3,transform shape,auto icon more/.try]{%
\pic{dice};
\pic[scale=1.2,transform shape] at (-.2,-.2) {battle marker=0};}%
}
@@ -636,40 +707,51 @@
% Make results markers. Mandatory argument is a list of results and
% fill colours. Optional is the group to add the markers to.
%
+%
+% First optional argument are extra styles
+% Second is category
+% Third is marker list
+%
% \begin{macrocode}
-\DeclareRobustCommand\resultmarkers[2][ResultMarkers]{%
- \wg@gencolorm@rkers{result marker}{#2}{#1}}
+\def\resultmarkers{%
+ \@ifnextchar[{\@resultmarkers}{\resultmarkers[]}%]
+}%
+\def\@resultmarkers[#1]{%
+ \@ifnextchar[{\@@resultmarkers[#1]}{\resultmarkers[#1][ResultMarkers]}%]
+}%
+\def\@@resultmarkers[#1][#2]#3{%
+ \wg@gencolorm@rkers{result marker}{#3}{#2}{#1}}%
% \end{macrocode}
%
% Common icons used by many modules
%
% \begin{macrocode}
-\DeclareRobustCommand\commonicons[2]{%
+\DeclareRobustCommand\commonicons[3][]{%
\begingroup%
\nopagecolor%
- \tikzset{icon/.style={scale=.4,transform shape}}%
+ \tikzset{auto icon/.style={scale=.4,transform shape,#1}}%
%
\info{pool-icon}{icon}{}
- \tikz[icon]{\pic{pool icon};}
+ \tikz[auto icon,auto icon more/.try]{\pic{pool icon};}
%
\info{oob-icon}{icon}{}%
- \tikz[icon]{\pic{oob icon={#1}{#2}};}%
+ \tikz[auto icon,auto icon more/.try]{\pic{oob icon={#2}{#3}};}%
%
\info{flip-icon}{icon}{}%
- \tikz[icon]{\pic{flip icon};}%
+ \tikz[auto icon,auto icon more/.try]{\pic{flip icon};}%
%
\info{eliminate-icon}{icon}{}%
- \tikz[icon]{\pic{eliminate icon};}%
+ \tikz[auto icon,auto icon more/.try]{\pic{eliminate icon};}%
%
\info{restore-icon}{icon}{}%
- \tikz[icon]{\pic{restore icon};}%
+ \tikz[auto icon,auto icon more/.try]{\pic{restore icon};}%
%
\info{dice-icon}{icon}{}%
- \tikz[icon,scale=.9]{\pic{dice};}%
+ \tikz[auto icon,scale=.9,auto icon more/.try]{\pic{dice};}%
%
\info{unit-icon}{icon}{}%
- \tikz[icon,scale=.7]{%
- \chit[fill=#1,
+ \tikz[auto icon,scale=.7,auto icon more/.try]{%
+ \chit[fill=#2,
symbol={[
scale line widths,
line width=1pt,
@@ -677,7 +759,29 @@
command=land,
main=infantry,
scale=1.3](0,-.15)}]}%
- \endgroup%
+ %
+ \info{layer-icon}{icon}{}%
+ \begin{tikzpicture}[scale=.25]
+ \foreach \i in {-1,0,1}{
+ \scoped[shift={(0,\i*.15)}]{
+ \draw[black,fill=white] (-.5,0)
+ --(0,.3)--(.5,0)--(0,-.3)--cycle;
+ }
+ }
+ \end{tikzpicture}%
+ %
+ \info{los-icon}{icon}{}
+ \begin{tikzpicture}[scale=.25]
+ \draw[scale line widths,line width=2pt,fill=white](-.5,0)
+ to[out=70,in=110] (.5,0)
+ to[out=-110,in=-70] cycle;
+ \begin{scope}[even odd rule]
+ \clip circle(.2);
+ \fill circle(.2) (125:.18) circle(.1);
+ \end{scope}
+ \end{tikzpicture}%
+ %
+ \endgroup%
}
% \end{macrocode}
%
@@ -708,9 +812,11 @@
\foreach \v/\p in {#5}{%
\info{#3-\v}{die-roll}{#3}
\tikz[#1]{
- \node[shape=#4,transform shape,draw=none,fill=black,opacity=.5]
- at (.05,-.03){};
- \node[shape=#4,#2,transform shape]{\p};}}}
+ %\node[shape=#4,transform shape,draw=none,fill=black,opacity=.5]
+ %at (.05,-.03){};
+ \node[shape=#4,#2,transform shape,
+ chit drop
+ ]{\p};\wg@add@drop@margin{}}}}
% \end{macrocode}
%
% \subsubsection{Hooks into chits, etc.}
@@ -809,6 +915,28 @@
\mk@w{ \mk@i\space "end": 0}
\mk@w{ \mk@i \@rbchar}
}
+\tikzset{
+ chit drop margin/.store in=\wg@drop@margin,
+ chit drop shadows/.code={
+ \pgfkeysalso{%
+ /tikz/every chit node/.prefix style={chit drop={#1}},
+ /tikz/chit has drop=true}
+ },
+ chit drop shadows/.default=,
+ marker drop shadows/.code={
+ \pgfkeysalso{%
+ /tikz/every battle marker/.prefix style={chit drop={#1}},
+ /tikz/every odds marker/.prefix style={chit drop={#1}},
+ /tikz/every result marker/.prefix style={chit drop={#1}},
+ /tikz/auto icon more/.prefix style={no chit drop}}},
+ marker drop shadows/.default={
+ chit has drop=false,
+ shadow xshift=0.04cm,
+ shadow yshift=-0.04cm,
+ shadow blur radius=0.04cm}
+}
+
+
% \end{macrocode}
%
%
diff --git a/macros/latex/contrib/wargame/source/util/tikz.dtx b/macros/latex/contrib/wargame/source/util/tikz.dtx
index fa31a7b58c..2f6dbefc17 100644
--- a/macros/latex/contrib/wargame/source/util/tikz.dtx
+++ b/macros/latex/contrib/wargame/source/util/tikz.dtx
@@ -86,12 +86,17 @@
% Save pgf rounded corners macro
% \let\wg@pgfsetcornersarced\pgfsetcornersarced
\def\wg@setcornersarched#1{%
- \ifx|#1|\else%
- \edef\pgf@corner@arc{{#1}{#1}}%
- \pgf@arccornerstrue%
- \ifdim#1=0pt%
- \pgf@arccornersfalse%
- \fi\fi}
+ \def\arg{#1}%
+ \let\isarched\relax% Cannot set \ifpgf@arccorners directly inside
+ % other \if
+ \ifx\arg\@empty\else%
+ \edef\pgf@corner@arc{{#1}{#1}}%
+ \let\isarched\pgf@arccornerstrue%
+ \ifdim#1=0pt%
+ \let\isarched\pgf@arccornersfalse%
+ \fi%
+ \fi%
+ \isarched}
\newdimen\wg@lw@scaled\wg@lw@scaled=1pt
\def\wg@getscale{%
\pgfgettransformentries{%
diff --git a/macros/latex/contrib/wargame/source/utils/wgexport.py b/macros/latex/contrib/wargame/source/utils/wgexport.py
index a09a7e4257..d573b63d36 100755
--- a/macros/latex/contrib/wargame/source/utils/wgexport.py
+++ b/macros/latex/contrib/wargame/source/utils/wgexport.py
@@ -208,6 +208,8 @@ CTRL_SHIFT = CTRL+SHIFT
ALT_SHIFT = ALT+SHIFT
NONE = '\ue004'
NONE_MOD = 0
+
+# --------------------------------------------------------------------
def key(let,mod=CTRL):
'''Encode a key sequence
@@ -220,6 +222,8 @@ def key(let,mod=CTRL):
Modifier mask
'''
return f'{ord(let)},{mod}'
+
+# --------------------------------------------------------------------
#
def hexcolor(s):
if isinstance(s,str):
@@ -241,6 +245,7 @@ def hexcolor(s):
return rgb(int(r*256),int(g*256),int(b*256))
+# --------------------------------------------------------------------
# Colour encoding
def rgb(r,g,b):
'''Encode RGB colour
@@ -261,6 +266,7 @@ def rgb(r,g,b):
'''
return ','.join([str(r),str(g),str(b)])
+# --------------------------------------------------------------------
def rgba(r,g,b,a):
'''Encode RGBA colour
@@ -282,6 +288,7 @@ def rgba(r,g,b,a):
'''
return ','.join([str(r),str(g),str(b),str(a)])
+# --------------------------------------------------------------------
def dumpTree(node,ind=''):
'''Dump the tree of nodes
@@ -296,6 +303,12 @@ def dumpTree(node,ind=''):
for c in node.childNodes:
dumpTree(c,ind+' ')
+# --------------------------------------------------------------------
+def registerElement(cls):
+
+ Element.known_tags[cls.TAG] = cls
+
+
#
# EOF
#
@@ -310,6 +323,8 @@ class Element:
MAP = MODULE + 'map.'
PICKER = MAP + 'boardPicker.'
BOARD = PICKER + 'board.'
+ known_tags = {}
+
def __init__(self,parent,tag,node=None,**kwargs):
'''Create a new element
@@ -429,9 +444,14 @@ class Element:
return {c[key] : c for c in cand}
return cand
- def getParent(self,cls,checkTag=True):
+ def getParent(self,cls=None,checkTag=True):
if self._node.parentNode is None:
return None
+ if cls is None:
+ cls = self.getTagClass(self._node.parentNode.tagName)
+ checkTag = False
+ if cls is None:
+ return None
if checkTag and self._node.parentNode.tagName != cls.TAG:
return None
return cls(self,node=self._node.parentNode)
@@ -440,6 +460,10 @@ class Element:
'''Searches back until we find the parent with the right
class, or none
'''
+ try:
+ iter(cls)
+ except:
+ cls = [cls]
t = {c.TAG: c for c in cls}
p = self._node.parentNode
while p is not None:
@@ -447,6 +471,11 @@ class Element:
if c is not None: return c(self,node=p)
p = p.parentNode
return None
+
+ def getTagClass(self,tag):
+ '''Get class corresponding to the tag'''
+ if tag not in self.known_tags: return None;
+ return self.known_tags[tag]
# ----------------------------------------------------------------
# Adders
@@ -518,7 +547,83 @@ class DummyElement(Element):
'''
super(DummyElement,self).__init__(parent,'Dummy',node=node)
+# --------------------------------------------------------------------
+class ToolbarElement(Element):
+ def __init__(self,
+ parent,
+ tag,
+ node = None,
+ name = '', # Toolbar element name
+ tooltip = '', # Tool tip
+ text = '', # Button text
+ icon = '', # Button icon,
+ hotkey = '', # Named key or key stroke
+ canDisable = False,
+ propertyGate = '',
+ disabledIcon = '',
+ **kwargs):
+ '''Base class for toolbar elements.
+ Parameters
+ ----------
+ parent : Element
+ Parent element if any
+ tag : str
+ Element tag
+ node : XMLNode
+ Possible node - when reading back
+ name : str
+ Name of element (user reminder). If not set, and tooltip is set,
+ set to tooltip
+ toolttip : str
+ Tool tip when hovering. If not set, and name is set, then
+ use name as tooltip.
+ text : str
+ Text of button
+ icon : str
+ Image path for button image
+ hotkey : str
+ Named key or key-sequence
+ canDisable : bool
+ If true, then the element can be disabled
+ propertyGate : str
+ Name of a global property. When this property is `true`,
+ then this element is _disabled_. Note that this _must_ be
+ the name of a property - it cannot be a BeanShell
+ expression.
+ disabledIcon : str
+ Path to image to use when the element is disabled.
+ kwargs : dict
+ Other attributes to set on the element
+ '''
+ if name == '' and tooltip != '': name = tooltip
+ if name != '' and tooltip == '': tooltip = name
+
+ # Build arguments for super class
+ args = {
+ 'node': node,
+ 'name': name,
+ 'icon': icon,
+ 'tooltip': tooltip,
+ 'hotkey': hotkey,
+ 'canDisable': canDisable,
+ 'propertyGate': propertyGate,
+ 'disabledIcon': disabledIcon }
+ bt = kwargs.pop('buttonText',None)
+ # If the element expects buttonText attribute, then do not set
+ # the text attribute - some elements interpret that as a
+ # legacy name attribute,
+ if bt is not None:
+ args['buttonText'] = bt
+ else:
+ args['text'] = text
+ args.update(kwargs)
+
+ super(ToolbarElement,self).__init__(parent,
+ tag,
+ **args)
+ # print('Attributes\n','\n'.join([f'- {k}="{v}"' for k,v in self._node.attributes.items()]))
+
#
# EOF
#
@@ -526,26 +631,28 @@ class DummyElement(Element):
# From globalkey.py
# --------------------------------------------------------------------
-class GlobalKey(Element):
+class GlobalKey(ToolbarElement):
SELECTED = 'MAP|false|MAP|||||0|0||true|Selected|true|EQUALS'
def __init__(self,
parent,
tag,
node = None,
name = '',
+ icon = '',
+ tooltip = '',
buttonHotkey = '',
- hotkey = '',
buttonText = '',
canDisable = False,
+ propertyGate = '',
+ disabledIcon = '',
+ # Local
+ hotkey = '',
deckCount = '-1',
filter = '',
- propertyGate = '',
reportFormat = '',
reportSingle = False,
singleMap = True,
- target = SELECTED,
- tooltip = '',
- icon = ''):
+ target = SELECTED):
'''
Parameters
----------
@@ -569,28 +676,26 @@ class GlobalKey(Element):
Default targets are selected units
'''
- nme = (name if len(name) > 0 else
- tooltip if len(tooltip) > 0 else '')
- tip = (tooltip if len(tooltip) > 0 else
- name if len(name) > 0 else '')
+
super(GlobalKey,self).\
__init__(parent,
tag,
node = node,
- name = nme,
+ name = name,
+ icon = icon,
+ tooltip = tooltip,
buttonHotkey = buttonHotkey, # This hot key
- hotkey = hotkey, # Target hot key
buttonText = buttonText,
canDisable = canDisable,
+ propertyGate = propertyGate,
+ disabledIcon = disabledIcon,
+ hotkey = hotkey, # Target hot key
deckCount = deckCount,
filter = filter,
- propertyGate = propertyGate,
reportFormat = reportFormat,
reportSingle = reportSingle,
singleMap = singleMap,
- target = target,
- tooltip = tip,
- icon = icon)
+ target = target)
#
# EOF
#
@@ -600,7 +705,7 @@ class GlobalKey(Element):
# --------------------------------------------------------------------
class GameElementService:
def getGame(self):
- return self.getParent(Game)
+ return self.getParentOfClass(Game)
# --------------------------------------------------------------------
class GameElement(Element,GameElementService):
@@ -608,23 +713,34 @@ class GameElement(Element,GameElementService):
super(GameElement,self).__init__(game,tag,node=node,**kwargs)
# --------------------------------------------------------------------
-class Notes(GameElement):
+class Notes(ToolbarElement,GameElementService):
TAG = Element.MODULE+'NotesWindow'
def __init__(self,elem,node=None,
- name = 'Notes',
- buttonText = '',
- hotkey = key('N',ALT),
- icon = '/images/notes.gif',
- tooltip = 'Show notes window'):
- super(Notes,self).__init__(elem,self.TAG,node=node,
- name = name,
- buttonText = buttonText,
- hotkey = hotkey,
- icon = icon,
- tooltip = tooltip)
+ name = 'Notes', # Toolbar element name
+ tooltip = 'Show notes window', # Tool tip
+ text = '', # Button text
+ icon = '/images/notes.gif', # Button icon,
+ hotkey = key('N',ALT), # Named key or key stroke
+ canDisable = False,
+ propertyGate = '',
+ disabledIcon = '',
+ description = ''):
+ super(Notes,self).__init__(elem,self.TAG,
+ node = node,
+ name = name,
+ tooltip = tooltip,
+ text = text,
+ icon = icon,
+ hotkey = hotkey,
+ canDisable = canDisable,
+ propertyGate = propertyGate,
+ disabledIcon = disabledIcon,
+ description = description)
def encode(self):
return ['NOTES\t\\','PNOTES']
+registerElement(Notes)
+
# --------------------------------------------------------------------
class PredefinedSetup(GameElement):
TAG = Element.MODULE+'PredefinedSetup'
@@ -673,6 +789,7 @@ class PredefinedSetup(GameElement):
+registerElement(PredefinedSetup)
# --------------------------------------------------------------------
class GlobalTranslatableMessages(GameElement):
@@ -690,11 +807,15 @@ class GlobalTranslatableMessages(GameElement):
super(GlobalTranslatableMessages,self).\
__init__(elem,self.TAG,node=node)
+registerElement(GlobalTranslatableMessages)
+
# --------------------------------------------------------------------
class Language(GameElement):
TAG = 'VASSAL.i18n.Language'
def __init__(self,elem,node=None,**kwargs):
super(Languate,self).__init__(sele,self.TAG,node=none,**kwargs)
+
+registerElement(Language)
# --------------------------------------------------------------------
class Chatter(GameElement):
@@ -712,6 +833,8 @@ class Chatter(GameElement):
Attributes
'''
super(Chatter,self).__init__(elem,self.TAG,node=node,**kwargs)
+
+registerElement(Chatter)
# --------------------------------------------------------------------
class KeyNamer(GameElement):
@@ -730,6 +853,8 @@ class KeyNamer(GameElement):
'''
super(KeyNamer,self).__init__(elem,self.TAG,node=node,**kwargs)
+registerElement(KeyNamer)
+
# --------------------------------------------------------------------
# <VASSAL.build.module.GlobalOptions
@@ -883,6 +1008,7 @@ class GlobalOptions(GameElement):
return retd
+registerElement(GlobalOptions)
# --------------------------------------------------------------------
class Option(Element):
@@ -894,6 +1020,8 @@ class Option(Element):
def getGlobalOptions(self):
return self.getParent(GlobalOptions)
+registerElement(Option)
+
# --------------------------------------------------------------------
class Preference(Element):
PREFS = 'VASSAL.preferences.'
@@ -947,6 +1075,9 @@ class IntPreference(Preference):
default = str(default),
desc = desc,
tab = tab)
+
+registerElement(IntPreference)
+
# --------------------------------------------------------------------
class FloatPreference(Preference):
TAG = Preference.PREFS+'DoublePreference'
@@ -964,6 +1095,9 @@ class FloatPreference(Preference):
default = str(default),
desc = desc,
tab = tab)
+
+registerElement(FloatPreference)
+
# --------------------------------------------------------------------
class BoolPreference(Preference):
TAG = Preference.PREFS+'BooleanPreference'
@@ -982,6 +1116,9 @@ class BoolPreference(Preference):
else 'false'),
desc = desc,
tab = tab)
+
+registerElement(BoolPreference)
+
# --------------------------------------------------------------------
class StrPreference(Preference):
TAG = Preference.PREFS+'StringPreference'
@@ -999,6 +1136,9 @@ class StrPreference(Preference):
default = default,
desc = desc,
tab = tab)
+
+registerElement(StrPreference)
+
# --------------------------------------------------------------------
class TextPreference(Preference):
TAG = Preference.PREFS+'TextPreference'
@@ -1017,6 +1157,9 @@ class TextPreference(Preference):
.replace('\n','&#10;')),
desc = desc,
tab = tab)
+
+registerElement(TextPreference)
+
# --------------------------------------------------------------------
class EnumPreference(Preference):
TAG = Preference.PREFS+'EnumPreference'
@@ -1042,39 +1185,42 @@ class EnumPreference(Preference):
tab = tab,
list = sl)
+
+registerElement(EnumPreference)
+
# --------------------------------------------------------------------
# CurrentMap == &quot;Board&quot;
-class Inventory(GameElement):
+class Inventory(ToolbarElement,GameElementService):
TAG = Element.MODULE+'Inventory'
def __init__(self,doc,node=None,
- canDisable = False,
- centerOnPiece = True,
- disabledIcon = '',
- drawPieces = True,
- foldersOnly = False,
- forwardKeystroke = True,
- groupBy = '',
- hotkey = key('I',ALT),
- icon = '/images/inventory.gif',
- include = '{}',
- launchFunction = 'functionHide',
- leafFormat = '$PieceName$',
- name = '',
- nonLeafFormat = '$PropertyValue$',
- pieceZoom = '0.33',
- pieceZoom2 = '0.5',
- pieceZoom3 = '0.6',
- propertyGate = '',
- refreshHotkey = key('I',ALT_SHIFT),
- showMenu = True,
- sides = '',
- sortFormat = '$PieceName$',
- sortPieces = True,
- sorting = 'alpha',
- text = '',
- tooltip = 'Show inventory of all pieces',
- zoomOn = False):
+ name = '',
+ icon = '/images/inventory.gif',
+ text = '',
+ tooltip = 'Show inventory of all pieces',
+ hotkey = key('I',ALT),
+ canDisable = False,
+ propertyGate = '',
+ disabledIcon = '',
+ centerOnPiece = True,
+ drawPieces = True,
+ foldersOnly = False,
+ forwardKeystroke = True,
+ groupBy = '',
+ include = '{}',
+ launchFunction = 'functionHide',
+ leafFormat = '$PieceName$',
+ nonLeafFormat = '$PropertyValue$',
+ pieceZoom = '0.33',
+ pieceZoom2 = '0.5',
+ pieceZoom3 = '0.6',
+ refreshHotkey = key('I',ALT_SHIFT),
+ showMenu = True,
+ sides = '',
+ sortFormat = '$PieceName$',
+ sortPieces = True,
+ sorting = 'alpha',
+ zoomOn = False):
super(Inventory,self).__init__(doc,self.TAG,node=node,
canDisable = canDisable,
centerOnPiece = centerOnPiece,
@@ -1104,16 +1250,7 @@ class Inventory(GameElement):
tooltip = tooltip,
zoomOn = zoomOn)
-
-
-
-
-
-
-
-
-
-
+registerElement(Inventory)
# --------------------------------------------------------------------
class Prototypes(GameElement):
@@ -1149,17 +1286,21 @@ class Prototypes(GameElement):
'''
return self.getElementsByKey(Prototype,'name',asdict=asdict)
-
-
+registerElement(Prototypes)
# --------------------------------------------------------------------
-class DiceButton(GameElement):
+class DiceButton(ToolbarElement,GameElementService):
TAG=Element.MODULE+'DiceButton'
def __init__(self,elem,node=None,
- addToTotal = 0,
- canDisable = False,
- hotkey = key('6',ALT),
+ name = '1d6',
+ tooltip = 'Roll a 1d6',
+ text = '1d6',
icon = '/images/die.gif',
+ hotkey = key('6',ALT),
+ canDisable = False,
+ propertyGate = '',
+ disabledIcon = '',
+ addToTotal = 0,
keepCount = 1,
keepDice = False,
keepOption = '>',
@@ -1169,19 +1310,16 @@ class DiceButton(GameElement):
lockSides = False,
nDice = 1,
nSides = 6,
- name = '1d6',
plus = 0,
prompt = False,
- propertyGate = '',
- reportFormat = '** $name$ = $result$ *** <$PlayerName$>;',
+ reportFormat = '$name$ = $result$',
reportTotal = False,
- sortDice = False,
- text = '1d6',
- tooltip = 'Roll a 1d6'):
+ sortDice = False):
super(DiceButton,self).\
__init__(elem,self.TAG,node=node,
addToTotal = addToTotal,
canDisable = canDisable,
+ disabledIcon = disabledIcon,
hotkey = hotkey,
icon = icon,
keepCount = keepCount,
@@ -1203,24 +1341,27 @@ class DiceButton(GameElement):
text = text,
tooltip = tooltip)
+registerElement(DiceButton)
+
# --------------------------------------------------------------------
class GameMassKey(GlobalKey,GameElementService):
TAG = Element.MODULE+'GlobalKeyCommand'
def __init__(self,map,node=None,
name = '',
- buttonHotkey = '',
- hotkey = '',
buttonText = '',
+ tooltip = '',
+ icon = '',
canDisable = False,
+ propertyGate = '',
+ disabledIcon = '',
+ buttonHotkey = '',
+ hotkey = '',
deckCount = '-1',
filter = '',
- propertyGate = '',
reportFormat = '',
reportSingle = False,
singleMap = True,
- target = GlobalKey.SELECTED,
- tooltip = '',
- icon = ''):
+ target = GlobalKey.SELECTED):
'''Default targets are selected units'''
super(GameMassKey,self).\
__init__(map,
@@ -1241,6 +1382,8 @@ class GameMassKey(GlobalKey,GameElementService):
tooltip = tooltip,
icon = icon)
+registerElement(GameMassKey)
+
# --------------------------------------------------------------------
class StartupMassKey(GlobalKey,GameElementService):
TAG = Element.MODULE+'StartupGlobalKeyCommand'
@@ -1287,21 +1430,24 @@ class StartupMassKey(GlobalKey,GameElementService):
if node is None:
self['whenToApply'] = whenToApply
+registerElement(StartupMassKey)
+
# --------------------------------------------------------------------
class Menu(GameElement):
TAG = Element.MODULE+'ToolbarMenu'
def __init__(self,
game,
node = None,
+ name = '',
+ tooltip = '',
+ text = '', # Menu name
canDisable = False,
- description = '',
+ propertyGate = '',
disabledIcon = '',
+ description = '',
hotkey = '',
icon = '',
- menuItems = [],# Button texts
- propertyGate = '',
- text = '',# Menu name
- tooltip = ''):
+ menuItems = []):
if len(description) <= 0 and len(tooltip) > 0:
description = tooltip
if len(tooltip) <= 0 and len(description) > 0:
@@ -1310,6 +1456,7 @@ class Menu(GameElement):
__init__(game,
self.TAG,
node = node,
+ name = name,
canDisable = canDisable,
description = description,
disabledIcon = disabledIcon,
@@ -1320,6 +1467,8 @@ class Menu(GameElement):
text = text,
tooltip = tooltip)
+registerElement(Menu)
+
# --------------------------------------------------------------------
class SymbolicDice(GameElement):
@@ -1370,6 +1519,8 @@ class SymbolicDice(GameElement):
def getSymbolicDice(self):
return self.getParent(SymbolicDice)
+registerElement(SymbolicDice)
+
# --------------------------------------------------------------------
class SpecialDie(GameElement):
@@ -1399,8 +1550,7 @@ class SpecialDie(GameElement):
def getSymbolicDice(self):
return self.getParent(SymbolicDice)
-
-
+registerElement(SpecialDie)
# --------------------------------------------------------------------
class DieFace(GameElement):
@@ -1421,6 +1571,9 @@ class DieFace(GameElement):
def getSpecialDie(self):
return self.getParent(SpecialDie)
+
+registerElement(DieFace)
+
#
# EOF
#
@@ -1451,6 +1604,223 @@ class MapElement(Element,MapElementService):
# --------------------------------------------------------------------
+class PieceLayers(MapElement):
+ TAG=Element.MAP+'LayeredPieceCollection'
+ def __init__(self,map,node=None,
+ property = 'PieceLayer',
+ description = '',
+ layerOrder = []):
+ super(PieceLayers,self).__init__(map,self.TAG,node=node,
+ property = property,
+ description = description,
+ layerOrder = ','.join(layerOrder))
+
+ def addControl(self,**kwargs):
+ '''Add `LayerControl` element to this
+
+ Parameters
+ ----------
+ kwargs : dict
+ Dictionary of attribute key-value pairs
+ Returns
+ -------
+ element : LayerControl
+ The added element
+ '''
+ return self.add(LayerControl,**kwargs)
+ def getControls(self,asdict=True):
+ '''Get all `LayerControl` element(s) from this
+
+ Parameters
+ ----------
+ asdict : bool
+ If `True`, return a dictonary that maps name to
+ `LayerControl` elements. If `False`, return a list of all
+ `LayerControl` children.
+
+ Returns
+ -------
+ children : dict or list
+ Dictionary or list of `LayerControl` children
+
+ '''
+ return self.getElementsByKey(LayerControl,'name',asdict)
+
+registerElement(PieceLayers)
+
+# --------------------------------------------------------------------
+class LayerControl(MapElement):
+ TAG=Element.MAP+'LayerControl'
+ CYCLE_UP='Rotate Layer Order Up'
+ CYCLE_DOWN='Rotate Layer Order Down'
+ ENABLE='Make Layer Active'
+ DISABLE='Make Layer Inactive'
+ TOGGLE='Switch Layer between Active and Inactive'
+ RESET='Reset All Layers'
+ def __init__(self,col,node=None,
+ name = '',
+ tooltip = '',
+ text = '',
+ hotkey = '',
+ icon = '',
+ canDisable = False,
+ propertyGate = '', #Property name, disable when property false
+ disabledIcon = '',
+ command = TOGGLE,
+ skip = False,
+ layers = [],
+ description = ''):
+ super(LayerControl,self).__init__(col,self.TAG,node=node,
+ name = name,
+ tooltip = tooltip,
+ text = text,
+ buttonText = text,
+ hotkey = hotkey,
+ icon = icon,
+ canDisable = canDisable,
+ propertyGate = propertyGate,
+ disabledIcon = disabledIcon,
+ command = command,
+ skip = skip,
+ layers = ','.join(layers),
+ description = description)
+
+ def getLayers(self):
+ '''Get map - either a Map or WidgetMap'''
+ return self.getParentOfClass([PieceLayers])
+
+registerElement(LayerControl)
+
+
+# --------------------------------------------------------------------
+class LineOfSight(MapElement):
+ TAG=Element.MAP+'LOS_Thread'
+ ROUND_UP = 'Up'
+ ROUND_DOWN = 'Down'
+ ROUND_NEAREST = 'Nearest whole number'
+ FROM_LOCATION = 'FromLocation'
+ TO_LOCATION = 'ToLocation'
+ CHECK_COUNT = 'NumberOfLocationsChecked'
+ CHECK_LIST = 'AllLocationsChecked'
+ RANGE = 'Range'
+ NEVER = 'Never'
+ ALWAYS = 'Always'
+ WHEN_PERSISTENT = 'When persistent'
+ CTRL_CLICK = 'Cltr-Click & Drag'
+
+ def __init__(self,map,
+ node=None,
+ threadName = 'LOS',
+ hotkey = key('L',ALT),
+ tooltip = 'Trace line of sight',
+ iconName = '/images/thread.gif', #'los-icon.png',
+ label = '',
+ snapLOS = False,
+ snapStart = True,
+ snapEnd = True,
+ report = (f'{{"Range from "+{FROM_LOCATION}'
+ f'+" to "+{TO_LOCATION}+" is "'
+ f'+{RANGE}+" (via "+{CHECK_LIST}+")"}}'),
+ persistent = CTRL_CLICK,
+ persistentIconName = '/images/thread.gif',
+ globl = ALWAYS,
+ losThickness = 3,
+ threadColor = rgb(255,0,0),
+ drawRange = True,
+ # rangeBg = rgb(255,255,255),
+ # rangeFg = rgb(0,0,0),
+ rangeScale = 0,
+ hideCounters = True,
+ hideOpacity = 50,
+ round = ROUND_UP,
+ canDisable = False,
+ propertyGate = '',
+ disabledIcon = ''):
+ '''Make Line of Sight interface
+
+ Parameters
+ ----------
+ threadName : str
+ Name of interface
+ hotkey : str
+ Start LOS key
+ tooltip : str
+ Tool tip text
+ iconName : str
+ Path to button icon
+ label : str
+ Button text
+ snapLOS : bool
+ Wether to snap both ends
+ snapStart : bool
+ Snap to start
+ snapEnd: bool
+ Snap to end
+ report : str
+ Report format
+ persistent : str
+ When persistent
+ persistentIconName : str
+ Icon when persistent(?)
+ globl : str
+ Visisble to opponents
+ losThickness : int
+ Thickness in pixels
+ losColor : str
+ Colour of line
+ drawRange : bool
+ Draw the range next to LOST thread
+ rangeBg : str
+ Range backgroung colour
+ rangeFg : str
+ Range foregrond colour
+ rangeScale : int
+ Scale of range - pixels per unit
+ round : str
+ How to round range
+ hideCounters :bool
+ If true, hide counters while making thread
+ hideOpacity : int
+ Opacity of hidden counters (percent)
+ canDisable : bool
+ IF true, then can be hidden
+ propertyGate : str
+ Name of property. When that property is TRUE, then the
+ interface is disabled. Must be a property name, not an expression.
+ disabledIcon : str
+ Icon to use when disabled
+ '''
+ super(LineOfSight,self).__init__(map,self.TAG,
+ node = node,
+ threadName = threadName,
+ hotkey = hotkey,
+ tooltip = tooltip,
+ iconName = iconName,
+ label = label,
+ snapLOS = snapLOS,
+ snapStart = snapStart,
+ snapEnd = snapEnd,
+ report = report,
+ persistent = persistent,
+ persistentIconName = persistentIconName,
+ losThickness = losThickness,
+ threadColor = threadColor,
+ drawRange = drawRange,
+ #rangeBg = rangeBg,
+ #rangeFg = rangeFg,
+ rangeScale = rangeScale,
+ hideCounters = hideCounters,
+ hideOpacity = hideOpacity,
+ round = round,
+ canDisable = canDisable,
+ propertyGate = propertyGate,
+ disabledIcon = disabledIcon)
+ self.setAttribute('global',globl)
+
+
+registerElement(LineOfSight)
+
+# --------------------------------------------------------------------
class StackMetrics(MapElement):
TAG=Element.MAP+'StackMetrics'
def __init__(self,map,node=None,
@@ -1474,6 +1844,8 @@ class StackMetrics(MapElement):
unexSepY = unexSepY,
up = up)
+registerElement(StackMetrics)
+
# --------------------------------------------------------------------
class ImageSaver(MapElement):
TAG=Element.MAP+'ImageSaver'
@@ -1491,6 +1863,9 @@ class ImageSaver(MapElement):
icon = icon,
propertyGate = propertyGate,
tooltip = tooltip)
+
+registerElement(ImageSaver)
+
# --------------------------------------------------------------------
class TextSaver(MapElement):
TAG=Element.MAP+'TextSaver'
@@ -1509,6 +1884,7 @@ class TextSaver(MapElement):
propertyGate = propertyGate,
tooltip = tooltip)
+registerElement(TextSaver)
# --------------------------------------------------------------------
class ForwardToChatter(MapElement):
@@ -1516,30 +1892,40 @@ class ForwardToChatter(MapElement):
def __init__(self,map,node=None,**kwargs):
super(ForwardToChatter,self).__init__(map,self.TAG,node=node,**kwargs)
+registerElement(ForwardToChatter)
+
# --------------------------------------------------------------------
class MenuDisplayer(MapElement):
TAG=Element.MAP+'MenuDisplayer'
def __init__(self,map,node=None,**kwargs):
super(MenuDisplayer,self).__init__(map,self.TAG,node=node,**kwargs)
+registerElement(MenuDisplayer)
+
# --------------------------------------------------------------------
class MapCenterer(MapElement):
TAG=Element.MAP+'MapCenterer'
def __init__(self,map,node=None,**kwargs):
super(MapCenterer,self).__init__(map,self.TAG,node=node,**kwargs)
+registerElement(MapCenterer)
+
# --------------------------------------------------------------------
class StackExpander(MapElement):
TAG=Element.MAP+'StackExpander'
def __init__(self,map,node=None,**kwargs):
super(StackExpander,self).__init__(map,self.TAG,node=node,**kwargs)
+registerElement(StackExpander)
+
# --------------------------------------------------------------------
class PieceMover(MapElement):
TAG=Element.MAP+'PieceMover'
def __init__(self,map,node=None,**kwargs):
super(PieceMover,self).__init__(map,self.TAG,node=node,**kwargs)
+registerElement(PieceMover)
+
# --------------------------------------------------------------------
class SelectionHighlighters(MapElement):
TAG=Element.MAP+'SelectionHighlighters'
@@ -1547,12 +1933,16 @@ class SelectionHighlighters(MapElement):
super(SelectionHighlighters,self).\
__init__(map,self.TAG,node=node,**kwargs)
+registerElement(SelectionHighlighters)
+
# --------------------------------------------------------------------
class KeyBufferer(MapElement):
TAG=Element.MAP+'KeyBufferer'
def __init__(self,map,node=None,**kwargs):
super(KeyBufferer,self).__init__(map,self.TAG,node=node,**kwargs)
+registerElement(KeyBufferer)
+
# --------------------------------------------------------------------
class HighlightLastMoved(MapElement):
TAG=Element.MAP+'HighlightLastMoved'
@@ -1565,6 +1955,8 @@ class HighlightLastMoved(MapElement):
enabled = enabled,
thickness = thickness)
+registerElement(HighlightLastMoved)
+
# --------------------------------------------------------------------
class CounterDetailViewer(MapElement):
TAG=Element.MAP+'CounterDetailViewer'
@@ -1587,7 +1979,7 @@ class CounterDetailViewer(MapElement):
extraTextPadding = 0,
fgColor = rgb(0,0,0),
fontSize = 9,
- graphicsZoom = 1.0,
+ graphicsZoom = 1.0,# Zoom on counters
hotkey = key('\n',0),
layerList = '',
minDisplayPieces = 2,
@@ -1649,6 +2041,8 @@ class CounterDetailViewer(MapElement):
verticalTopText = verticalTopText,
zoomlevel = zoomlevel)
+registerElement(CounterDetailViewer)
+
# --------------------------------------------------------------------
class GlobalMap(MapElement):
TAG=Element.MAP+'GlobalMap'
@@ -1668,6 +2062,8 @@ class GlobalMap(MapElement):
scale = scale,
tooltip = 'Show/Hide overview window')
+registerElement(GlobalMap)
+
# --------------------------------------------------------------------
class Zoomer(MapElement):
TAG = Element.MAP+'Zoomer'
@@ -1687,6 +2083,7 @@ class Zoomer(MapElement):
zoomOutKey = key('-'),
zoomPickKey = key('='),
zoomStart = 3):
+
'''Zoom start is counting from the back (with default zoom levels,
and zoom start, the default zoom is 1'''
lvls = ','.join([str(z) for z in zoomLevels])
@@ -1707,6 +2104,8 @@ class Zoomer(MapElement):
zoomPickKey = zoomPickKey,
zoomStart = zoomStart)
+registerElement(Zoomer)
+
# --------------------------------------------------------------------
class HidePiecesButton(MapElement):
TAG=Element.MAP+'HidePiecesButton'
@@ -1724,6 +2123,8 @@ class HidePiecesButton(MapElement):
showingIcon = showingIcon,
tooltip = tooltip)
+registerElement(HidePiecesButton)
+
# --------------------------------------------------------------------
class MassKey(GlobalKey,MapElementService):
TAG = Element.MAP+'MassKeyCommand'
@@ -1760,6 +2161,7 @@ class MassKey(GlobalKey,MapElementService):
tooltip = tooltip,
icon = icon)
+registerElement(MassKey)
# --------------------------------------------------------------------
class Flare(MapElement):
@@ -1783,10 +2185,13 @@ class Flare(MapElement):
flarePulsesPerSec = flarePulsesPerSec,
reportFormat = '')
+registerElement(Flare)
+
# --------------------------------------------------------------------
class AtStart(MapElement):
TAG = Element.MODULE+'map.SetupStack'
- def __init__(self,map,node=None,
+ def __init__(self,map,
+ node = None,
name = '',
location = '',
useGridLocation = True,
@@ -1861,6 +2266,8 @@ class AtStart(MapElement):
'''
return self.getElementsWithKey(PieceSlot,'entryName',asdict)
+registerElement(AtStart)
+
#
# EOF
#
@@ -1894,6 +2301,7 @@ class GlobalProperties(Element):
def getProperties(self):
return getElementsByKey(GlobalProperty,'name')
+registerElement(GlobalProperties)
# --------------------------------------------------------------------
class GlobalProperty(Element):
@@ -1919,6 +2327,7 @@ class GlobalProperty(Element):
def getGlobalProperties(self):
return self.getParent(GlobalProperties)
+registerElement(GlobalProperty)
#
# EOF
@@ -2099,7 +2508,8 @@ class TurnTrack(TurnLevel):
return []
-
+registerElement(TurnTrack)
+
# --------------------------------------------------------------------
class TurnCounter(TurnLevel):
TAG = Element.MODULE+"turn.CounterTurnLevel"
@@ -2118,6 +2528,8 @@ class TurnCounter(TurnLevel):
loopLimit = loopLimit,
turnFormat = turnFormat)
+registerElement(TurnCounter)
+
# --------------------------------------------------------------------
class TurnList(TurnLevel):
TAG = Element.MODULE+"turn.ListTurnLevel"
@@ -2135,6 +2547,8 @@ class TurnList(TurnLevel):
configList = configList,
turnFormat = turnFormat)
+registerElement(TurnList)
+
# --------------------------------------------------------------------
class TurnGlobalHotkey(Element):
TAG = Element.MODULE+'turn.TurnGlobalHotkey'
@@ -2172,6 +2586,8 @@ class TurnGlobalHotkey(Element):
'''Get the turn track'''
return self.getParent(TurnTrack)
+registerElement(TurnGlobalHotkey)
+
#
# EOF
#
@@ -2316,6 +2732,7 @@ class Documentation(GameElement):
return txt
+registerElement(Documentation)
# --------------------------------------------------------------------
class AboutScreen(Element):
@@ -2343,6 +2760,8 @@ class AboutScreen(Element):
'''Get Parent element'''
return self.getParent(Documentation)
+registerElement(AboutScreen)
+
# --------------------------------------------------------------------
class BrowserPDFFile(Element):
TAG = Element.MODULE+'documentation.BrowserPDFFile'
@@ -2368,6 +2787,8 @@ class BrowserPDFFile(Element):
'''Get Parent element'''
return self.getParent(Documentation)
+registerElement(BrowserPDFFile)
+
# --------------------------------------------------------------------
class HelpFile(Element):
TAG = Element.MODULE+'documentation.HelpFile'
@@ -2400,6 +2821,8 @@ class HelpFile(Element):
'''Get Parent element'''
return self.getParent(Documentation)
+registerElement(HelpFile)
+
# --------------------------------------------------------------------
class BrowserHelpFile(Element):
TAG = Element.MODULE+'documentation.BrowserHelpFile'
@@ -2427,7 +2850,9 @@ class BrowserHelpFile(Element):
def getDocumentation(self):
'''Get Parent element'''
return self.getParent(Documentation)
-
+
+registerElement(BrowserHelpFile)
+
# --------------------------------------------------------------------
class Tutorial(Element):
TAG = Element.MODULE+'documentation.Tutorial'
@@ -2468,6 +2893,8 @@ class Tutorial(Element):
'''Get Parent element'''
return self.getParent(Documentation)
+registerElement(Tutorial)
+
#
# EOF
@@ -2517,6 +2944,8 @@ class PlayerRoster(GameElement):
'''Encode for save'''
return ['PLAYER\ta\ta\t<observer>']
+registerElement(PlayerRoster)
+
# --------------------------------------------------------------------
class PlayerSide(Element):
TAG = 'entry'
@@ -2540,6 +2969,8 @@ class PlayerSide(Element):
'''Get Parent element'''
return self.getParent(PlayerRoster)
+registerElement(PlayerSide)
+
#
# EOF
@@ -2614,7 +3045,9 @@ class ChessClock(Element):
def getControl(self):
'''Get Parent element'''
return self.getParent(ChessClockControl)
-
+
+registerElement(ChessClock)
+
# ====================================================================
class ChessClockControl(GameElement):
TAG=Element.MODULE+'ChessClockControl'
@@ -2727,6 +3160,7 @@ class ChessClockControl(GameElement):
'''Return dictionary of clocs'''
return self.getElementsByKey(ChessClock,'side',asdict)
+registerElement(ChessClockControl)
#
# EOF
@@ -2961,6 +3395,8 @@ class PieceWindow(GameElement,WidgetElement):
tooltip = tooltip,
icon = icon)
+registerElement(PieceWindow)
+
# --------------------------------------------------------------------
class ComboWidget(Element,WidgetElement):
TAG=Element.WIDGET+'BoxWidget'
@@ -2972,6 +3408,8 @@ class ComboWidget(Element,WidgetElement):
width = width,
height = height)
+registerElement(ComboWidget)
+
# --------------------------------------------------------------------
class TabWidget(Element,WidgetElement):
TAG=Element.WIDGET+'TabWidget'
@@ -2981,6 +3419,8 @@ class TabWidget(Element,WidgetElement):
node = node,
entryName = entryName)
+registerElement(TabWidget)
+
# --------------------------------------------------------------------
class ListWidget(Element,WidgetElement):
TAG=Element.WIDGET+'ListWidget'
@@ -2997,6 +3437,8 @@ class ListWidget(Element,WidgetElement):
scale = scale,
divider = divider)
+registerElement(ListWidget)
+
# --------------------------------------------------------------------
class PanelWidget(Element,WidgetElement):
TAG=Element.WIDGET+'PanelWidget'
@@ -3011,6 +3453,8 @@ class PanelWidget(Element,WidgetElement):
nColumns = nColumns,
vert = vert)
+registerElement(PanelWidget)
+
# --------------------------------------------------------------------
class MapWidget(Element):
TAG=Element.WIDGET+'MapWidget'
@@ -3046,6 +3490,8 @@ class MapWidget(Element):
'''
return self.getElementsByKey(WidgetMap,'mapName',asdict=asdict)
+registerElement(MapWidget)
+
#
# EOF
#
@@ -3258,6 +3704,8 @@ class HexGrid(BaseGrid):
width = self.getZone().getWidth()
return floor(width / self.getDeltaY() + .5)
+registerElement(HexGrid)
+
# --------------------------------------------------------------------
class SquareGrid(BaseGrid):
TAG = Element.BOARD+'SquareGrid'
@@ -3307,6 +3755,8 @@ class SquareGrid(BaseGrid):
width = self.getZone().getWidth()
return floor(width / self.getDeltaX() + .5)
+registerElement(SquareGrid)
+
# --------------------------------------------------------------------
class HexNumbering(BaseNumbering):
TAG = Element.BOARD+'mapgrid.HexGridNumbering'
@@ -3368,6 +3818,8 @@ class HexNumbering(BaseNumbering):
return x,y
+registerElement(HexNumbering)
+
# --------------------------------------------------------------------
class SquareNumbering(BaseNumbering):
TAG = Element.BOARD+'mapgrid.SquareGridNumbering'
@@ -3395,6 +3847,7 @@ class SquareNumbering(BaseNumbering):
return x,y
+registerElement(SquareNumbering)
# --------------------------------------------------------------------
class RegionGrid(Element):
@@ -3452,6 +3905,8 @@ class RegionGrid(Element):
return None
+registerElement(RegionGrid)
+
# --------------------------------------------------------------------
class Region(Element):
TAG = Element.BOARD+'Region'
@@ -3527,6 +3982,8 @@ class Region(Element):
return b.getMap()
return None
+registerElement(Region)
+
#
# EOF
#
@@ -3579,7 +4036,7 @@ class ZonedGrid(Element):
children : list
List of `Highligter` children (even if `single=True`)
'''
- return self.getAllElements(ZonedGridHighliger,single=single)
+ return self.getAllElements(ZonedGridHighlighter,single=single)
def addZone(self,**kwargs):
'''Add a `Zone` element to this
@@ -3607,6 +4064,8 @@ class ZonedGrid(Element):
'''
return self.getElementsByKey(Zone,'name',asdict=asdict)
+registerElement(ZonedGrid)
+
# --------------------------------------------------------------------
class ZonedGridHighlighter(Element):
TAG=Element.BOARD+'mapgrid.ZonedGridHighlighter'
@@ -3614,6 +4073,96 @@ class ZonedGridHighlighter(Element):
super(ZonedGridHighlighter,self).__init__(zoned,self.TAG,node=node)
def getZonedGrid(self): return self.getParent(ZonedGrid)
+ def addZoneHighlight(self,**kwargs):
+ '''Add a `ZoneHighlight` element to this
+
+ Parameters
+ ----------
+ kwargs : dict
+ Dictionary of attribute key-value pairs
+ Returns
+ -------
+ element : ZoneHighlight
+ The added element
+ '''
+ return self.add(ZoneHighlight,**kwargs)
+ def getZoneHighlights(self,asdict=True):
+ '''Get all ZoneHighlight element(s) from this
+
+ Parameters
+ ----------
+ asdict : bool
+ If `True`, return a dictonary that maps key to `Zone` elements. If `False`, return a list of all Zone` children.
+ Returns
+ -------
+ children : dict or list
+ Dictionary or list of `Zone` children
+ '''
+ return self.getElementsByKey(ZoneHighlight,'name',asdict=asdict)
+
+registerElement(ZonedGridHighlighter)
+
+# --------------------------------------------------------------------
+class ZoneHighlight(Element):
+ TAG=Element.BOARD+'mapgrid.ZoneHighlight'
+ FULL='Entire Zone',
+ BORDER='Zone Border',
+ PLAIN='Plain',
+ STRIPED='Striped'
+ CROSS='Crosshatched',
+ TILES='Tiled Image'
+ def __init__(self,
+ highlighters,
+ node = None,
+ name = '',
+ color = rgb(255,0,0),
+ coverage = FULL,
+ width = 1,
+ style = PLAIN,
+ image = '',
+ opacity = 50):
+ super(ZoneHighlight,self).__init__(highlighters,
+ self.TAG,
+ node = node,
+ name = name,
+ color = color,
+ coverage = coverage,
+ width = width,
+ style = style,
+ image = image,
+ opacity = int(opacity))
+ def getZonedGridHighlighter(self):
+ return self.getParent(ZonedGridHighlighter)
+
+
+registerElement(ZoneHighlight)
+
+
+# --------------------------------------------------------------------
+class ZoneProperty(Element):
+ TAG = Element.MODULE+'properties.ZoneProperty'
+ def __init__(self,zone,node=None,
+ name = '',
+ initialValue = '',
+ isNumeric = False,
+ min = "null",
+ max = "null",
+ wrap = False,
+ description = ""):
+ super(ZoneProperty,self).__init__(zone,self.TAG,
+ node = node,
+ name = name,
+ initialValue = initialValue,
+ isNumeric = isNumeric,
+ min = min,
+ max = max,
+ wrap = wrap,
+ description = description)
+
+ def getZone(self):
+ return self.getParent(Zone)
+
+registerElement(ZoneProperty)
# --------------------------------------------------------------------
class Zone(Element):
@@ -3693,6 +4242,19 @@ class Zone(Element):
The added element
'''
return self.add(RegionGrid,**kwargs)
+ def addProperty(self,**kwargs):
+ '''Add a `Property` element to this
+
+ Parameters
+ ----------
+ kwargs : dict
+ Dictionary of attribute key-value pairs
+ Returns
+ -------
+ element : Property
+ The added element
+ '''
+ return self.add(ZoneProperty,**kwargs)
def getHexGrids(self,single=True):
'''Get all or a sole `HexGrid` element(s) from this
@@ -3758,6 +4320,17 @@ class Zone(Element):
if g is not None: return g
return g
+ def getProperties(self):
+ '''Get all `Property` element from this
+
+ Parameters
+ ----------
+ Returns
+ -------
+ children : dict
+ dict of `Property` children
+ '''
+ return getElementsByKey(ZoneProperty,'name')
def getPath(self):
p = self['path'].split(';')
@@ -3785,6 +4358,8 @@ class Zone(Element):
def getYOffset(self):
return self.getBB()[1]
+registerElement(Zone)
+
#
# EOF
#
@@ -3879,6 +4454,8 @@ class BoardPicker(MapElement):
return ret
+registerElement(BoardPicker)
+
# --------------------------------------------------------------------
class Setup(Element):
TAG = 'setup'
@@ -3901,7 +4478,9 @@ class Setup(Element):
self.addText(txt)
def getPicker(self): return self.getParent(BoardPicker)
-
+
+registerElement(Setup)
+
# --------------------------------------------------------------------
class Board(Element):
TAG = Element.PICKER+'Board'
@@ -3982,6 +4561,7 @@ class Board(Element):
return int(self['height'])
return 0
+registerElement(Board)
#
# EOF
@@ -4340,6 +4920,57 @@ class BaseMap(Element):
picker = self.getPicker()
if picker is None: return None
return picker[0].getBoards(asdict=asdict)
+ def getLayers(self,asdict=True):
+ '''Get all `PieceLayer` element(s) from this
+
+ Parameters
+ ----------
+ asdict : bool
+ If `True`, return a dictonary that maps property name
+ `PieceLayers` elements. If `False`, return a list of all
+ `PieceLayers` children.
+
+ Returns
+ -------
+ children : dict or list
+ Dictionary or list of `PieceLayers` children
+
+ '''
+ return self.getElementsByKey(PieceLayers,'property',asdict)
+ def getMenus(self,asdict=True):
+ '''Get all Menu element(s) from this
+
+ Parameters
+ ----------
+ asdict : bool
+ If `True`, return a dictonary that maps key to `Board`
+ elements. If `False`, return a list of all Board`
+ children.
+
+ Returns
+ -------
+ children : dict or list
+ Dictionary or list of `Board` children
+
+ '''
+ return self.getElementsByKey(Menu,'name',asdict)
+ def getLOSs(self,asdict=True):
+ '''Get all Menu element(s) from this
+
+ Parameters
+ ----------
+ asdict : bool
+ If `True`, return a dictonary that maps key to `Board`
+ elements. If `False`, return a list of all Board`
+ children.
+
+ Returns
+ -------
+ children : dict or list
+ Dictionary or list of `Board` children
+
+ '''
+ return self.getElementsByKey(LineOfSight,'threadName',asdict)
def addBoardPicker(self,**kwargs):
'''Add a `BoardPicker` element to this
@@ -4600,6 +5231,47 @@ class BaseMap(Element):
The added element
'''
return self.add(AtStart,**kwargs)
+
+
+ def addLayers(self,**kwargs):
+ '''Add `PieceLayers` element to this
+
+ Parameters
+ ----------
+ kwargs : dict
+ Dictionary of attribute key-value pairs
+ Returns
+ -------
+ element : PieceLayers
+ The added element
+ '''
+ return self.add(PieceLayers,**kwargs)
+ def addMenu(self,**kwargs):
+ '''Add a `Menu` element to this
+
+ Parameters
+ ----------
+ kwargs : dict
+ Dictionary of attribute key-value pairs
+ Returns
+ -------
+ element : Menu
+ The added element
+ '''
+ return self.add(Menu,**kwargs)
+ def addLOS(self,**kwargs):
+ '''Add a `Menu` element to this
+
+ Parameters
+ ----------
+ kwargs : dict
+ Dictionary of attribute key-value pairs
+ Returns
+ -------
+ element : Menu
+ The added element
+ '''
+ return self.add(LineOfSight,**kwargs)
# --------------------------------------------------------------------
class Map(BaseMap):
@@ -4657,7 +5329,9 @@ class Map(BaseMap):
def getGame(self):
return self.getParent(Game)
-
+
+registerElement(Map)
+
# --------------------------------------------------------------------
class WidgetMap(BaseMap):
TAG = Element.WIDGET+'WidgetMap'
@@ -4669,6 +5343,8 @@ class WidgetMap(BaseMap):
def getMapWidget(self):
return self.getParent(MapWidget)
+registerElement(WidgetMap)
+
#
# EOF
@@ -4721,7 +5397,7 @@ class ChartWindow(GameElement,WidgetElement):
'''
return self.getElementsById(Chart,'chartName',asdict=asdict)
-
+registerElement(ChartWindow)
# --------------------------------------------------------------------
class Chart(Element):
@@ -4735,6 +5411,8 @@ class Chart(Element):
description = description,
fileName = fileName)
+registerElement(Chart)
+
#
# EOF
#
@@ -4766,7 +5444,7 @@ class Trait:
this actually holds state that isn't reflected elsewhere in
the DOM. This means that the data here is local to the
object. So when we do
-
+
piece = foo.getPieceSlots()[0]
traits = p.getTraits()
for trait in traits:
@@ -5040,6 +5718,15 @@ class WithTraits(Element):
Identifier
'''
+ last = traits[-1]
+ # A little hackish to use the name of the class, but needed
+ # because of imports into patch scripts.
+ if not isinstance(last,BasicTrait) and \
+ not last.__class__.__name__.endswith('BasicTrait'):
+ from sys import stderr
+ print(f'Warning - last trait NOT a BasicTrait, but a {type(last)}',
+ file=stderr)
+
types = []
states = []
for trait in traits:
@@ -5165,7 +5852,9 @@ class DummyWithTraits(WithTraits):
if parent is not None:
parent.remove(self)
-
+
+registerElement(DummyWithTraits)
+
# --------------------------------------------------------------------
class PieceSlot(WithTraits):
TAG = Element.WIDGET+'PieceSlot'
@@ -5226,6 +5915,7 @@ class PieceSlot(WithTraits):
piece.setTraits(*traits)
return piece
+registerElement(PieceSlot)
# --------------------------------------------------------------------
class Prototype(WithTraits):
@@ -5255,6 +5945,8 @@ class Prototype(WithTraits):
name = name,
description = description)
+registerElement(Prototype)
+
#
# EOF
#
@@ -5262,16 +5954,21 @@ class Prototype(WithTraits):
# From traits/dynamicproperty.py
# --------------------------------------------------------------------
-# Base class for property (piece or global) change traits. Encodes
-# constraints and commands.
+#
+#
class ChangePropertyTrait(Trait):
DIRECT = 'P'
+ INCREMENT = 'I'
def __init__(self,
*commands,
numeric = False,
min = 0,
max = 100,
wrap = False):
+ '''Base class for property (piece or global) change traits.
+
+ Encodes constraints and commands.
+ '''
# assert name is not None and len(name) > 0, \
# 'No name specified for ChangePropertyTriat'
super(ChangePropertyTrait,self).__init__()
@@ -5293,8 +5990,11 @@ class ChangePropertyTrait(Trait):
# print(cmd)
com = cmd[0] + ':' + cmd[1].replace(',',r'\,') + ':' + cmd[2]
if cmd[2] == self.DIRECT:
- com += f'\,'+cmd[3].replace(':',r'\:')
+ com += f'\,'+cmd[3].replace(',',r'\\,').replace(':',r'\:')
+ elif cmd[2] == self.INCREMENT:
+ com += f'\,'+cmd[3].replace(',',r'\\,').replace(':',r'\:')
cmds.append(com)
+ # print(cmds)
return ','.join(cmds)
def decodeCommands(self,commands):
@@ -5305,6 +6005,8 @@ class ChangePropertyTrait(Trait):
# print('parts',parts)
if parts[-1][0] == self.DIRECT:
parts = parts[:-1]+Trait.decodeKeys(parts[-1],',')
+ if parts[-1][0] == self.INCREMENT:
+ parts = parts[:-1]+Trait.decodeKeys(parts[-1],',')
ret.append(parts)
# print(commands,parts)
return ret
@@ -5840,7 +6542,7 @@ class NoStackTrait(Trait):
canStack = False,
ignoreGrid = False,
description = ''):
-
+ '''No stacking trait'''
selectionOptions = (select +
(self.IGNORE_GRID if ignoreGrid else '') +
bandSelect)
@@ -7319,6 +8021,7 @@ class Game(Element):
'''
return self.getAllElements(AtStart,single)
+registerElement(Game)
# --------------------------------------------------------------------
class BasicCommandEncoder(GameElement):
@@ -7326,6 +8029,8 @@ class BasicCommandEncoder(GameElement):
def __init__(self,doc,node=None):
super(BasicCommandEncoder,self).__init__(doc,self.TAG,node=node)
+registerElement(BasicCommandEncoder)
+
#
# EOF
#
@@ -8446,7 +9151,8 @@ class LaTeXExporter(Exporter):
vassalVersion = '3.6.7',
nonato = False,
nochit = False,
- counterScale = 1):
+ counterScale = 1,
+ resolution = 150):
'''Exports a PDF and associated JSON files to a VASSAL module.
Parameters
@@ -8473,6 +9179,8 @@ class LaTeXExporter(Exporter):
Make grids visible
vassalVersion : str
VASSAL version to encode this module for
+ resolution : int
+ Resolution for images (default 150)
'''
self._vmodname = vmodname
self._pdfname = pdfname
@@ -8487,6 +9195,7 @@ class LaTeXExporter(Exporter):
self._vassalVersion = vassalVersion
self._nonato = nonato
self._nochit = nochit
+ self._resolution = resolution
self._counterScale = counterScale
self._battleMark = 'wgBattleMarker'
self._battleMarks = []
@@ -8572,6 +9281,7 @@ class LaTeXExporter(Exporter):
v(f'Tutorial log: {self._tutorial}')
v(f'Patch scripts: {self._patch}')
v(f'Visible grids: {self._visible}')
+ v(f'Resolution: {self._resolution}')
v(f'Scale of counters: {self._counterScale}')
def setup(self):
@@ -8704,6 +9414,7 @@ class LaTeXExporter(Exporter):
args = ['pdftocairo',
'-transp',
'-singlefile',
+ '-r', str(self._resolution),
'-f', str(page),
'-l', str(page),
'-png' ]
@@ -8772,9 +9483,9 @@ class LaTeXExporter(Exporter):
imgsinfo = self.getImagesInfo()
if len(imgsinfo) - 1 != docinfo['Pages']:
- raise RuntimeError(f'Number of pages in {pdfname} '
- f'(doc["Pages"]) not matched in JSON '
- f'{self._infoname} -> {len(imagesinfo)}')
+ raise RuntimeError(f'Number of pages in {self._pdfname} '
+ f'{docinfo["Pages"]} not matched in JSON '
+ f'{self._infoname} -> {len(imgsinfo)}')
with VerboseGuard(f'Converting {docinfo["Pages"]} '
f'pages in {self._pdfname}') as v:
@@ -9126,10 +9837,16 @@ class LaTeXExporter(Exporter):
'property': 'Phase',
'names': self._sides } })
turns.addHotkey(hotkey = self._clearMoved+'Phase',
- name = 'Clear moved markers')
+ name = 'Clear moved markers',
+ reportFormat = (f'{{{self._verbose}?('
+ f'"`Clear all moved markers, "+'
+ f'""):""}}'))
if len(self._battleMarks) > 0:
turns.addHotkey(hotkey = self._clearBattlePhs,
- name = 'Clear battle markers')
+ name = 'Clear battle markers',
+ reportFormat = (f'{{{self._verbose}?('
+ f'"`Clear all battle markers, "+'
+ f'""):""}}'))
self._dice = self._categories\
.get('die-roll',{})
@@ -9153,7 +9870,9 @@ class LaTeXExporter(Exporter):
# f'+" <img src=\'{die}-"+result1'
# f'+".png\' width=24 height=24>"'
f'}}'),
- resultWindow = True);
+ resultWindow = True,
+ windowX = str(int(67 * self._resolution/150)),
+ windowY = str(int(65 * self._resolution/150)));
sdie = symb.addDie(name = die);
for face, fdata in faces.items():
fn = fdata['filename']
@@ -10186,13 +10905,14 @@ class LaTeXExporter(Exporter):
# ----------------------------------------------------------------
def factionTraits(self,faction):
- traits = [ReportTrait(self._eliminateKey,
- self._restoreKey,
- self._trailKey),
+ offX = 36 * self._counterScale * self._resolution/150
+ offY = -38 * self._counterScale * self._resolution/150
+ traits = [#ReportTrait(self._eliminateKey,
+ # self._restoreKey,
+ # self._trailKey),
TrailTrait(),
RotateTrait(),
- MovedTrait(xoff = int( 36 * self._counterScale),
- yoff = int(-38 * self._counterScale)),
+ MovedTrait(xoff = int(offX),yoff = int(offY)),
DeleteTrait(),
SendtoTrait(mapName = 'DeadMap',
boardName = f'{faction} pool',
@@ -11308,7 +12028,10 @@ class LaTeXExporter(Exporter):
pc = p["coords"]
if j == 0: vv(f'',end='')
vv(f'[{pn}] ',end='',flush=True,noindent=True)
-
+
+ if pn.endswith(' flipped'):
+ pn = pn[:-len(' flipped')]
+
x, y = tran(*pc)
r = grid.addRegion(name = pn,
originx = x,
@@ -11499,7 +12222,7 @@ class LaTeXExporter(Exporter):
def addDie(self):
'''Add a `Die` element to the module
'''
- if self._dice is not None:
+ if self._dice is not None and len(self._dice) > 0:
return
self._game.addDiceButton(name = '1d6',
hotkey = self._diceKey)
@@ -11568,6 +12291,9 @@ if __name__ == '__main__':
ap.add_argument('-S','--counter-scale',
type=float, default=1,
help='Scale counters by factor')
+ ap.add_argument('-R','--resolution',
+ type=int, default=150,
+ help='Resolution of images')
args = ap.parse_args()
@@ -11600,6 +12326,7 @@ if __name__ == '__main__':
vassalVersion = args.vassal_version,
nonato = args.no_nato_prototypes,
nochit = args.no_chit_information,
+ resolution = args.resolution,
counterScale = args.counter_scale)
exporter.run()
except Exception as e: