pywargame 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pywargame/__init__.py +2 -0
- pywargame/common/__init__.py +3 -0
- pywargame/common/collector.py +87 -0
- pywargame/common/dicedraw.py +363 -0
- pywargame/common/drawdice.py +40 -0
- pywargame/common/singleton.py +22 -0
- pywargame/common/test.py +25 -0
- pywargame/common/verbose.py +59 -0
- pywargame/common/verboseguard.py +53 -0
- pywargame/cyberboard/__init__.py +18 -0
- pywargame/cyberboard/archive.py +283 -0
- pywargame/cyberboard/base.py +63 -0
- pywargame/cyberboard/board.py +462 -0
- pywargame/cyberboard/cell.py +200 -0
- pywargame/cyberboard/collect.py +49 -0
- pywargame/cyberboard/collectgbx0pwd.py +30 -0
- pywargame/cyberboard/collectgbxext.py +30 -0
- pywargame/cyberboard/collectgsnexp.py +32 -0
- pywargame/cyberboard/collectgsnext.py +30 -0
- pywargame/cyberboard/draw.py +396 -0
- pywargame/cyberboard/exporter.py +1132 -0
- pywargame/cyberboard/extractor.py +240 -0
- pywargame/cyberboard/features.py +17 -0
- pywargame/cyberboard/gamebox.py +81 -0
- pywargame/cyberboard/gbxexp.py +76 -0
- pywargame/cyberboard/gbxext.py +64 -0
- pywargame/cyberboard/gsnexp.py +147 -0
- pywargame/cyberboard/gsnext.py +59 -0
- pywargame/cyberboard/head.py +111 -0
- pywargame/cyberboard/image.py +76 -0
- pywargame/cyberboard/main.py +47 -0
- pywargame/cyberboard/mark.py +102 -0
- pywargame/cyberboard/palette.py +36 -0
- pywargame/cyberboard/piece.py +169 -0
- pywargame/cyberboard/player.py +36 -0
- pywargame/cyberboard/scenario.py +115 -0
- pywargame/cyberboard/testgrid.py +156 -0
- pywargame/cyberboard/tile.py +121 -0
- pywargame/cyberboard/tray.py +68 -0
- pywargame/cyberboard/windows.py +41 -0
- pywargame/cyberboard/zeropwd.py +45 -0
- pywargame/cyberboard.py +2728 -0
- pywargame/gbx0pwd.py +2776 -0
- pywargame/gbxextract.py +2795 -0
- pywargame/gsnexport.py +16499 -0
- pywargame/gsnextract.py +2790 -0
- pywargame/latex/__init__.py +2 -0
- pywargame/latex/collect.py +34 -0
- pywargame/latex/latexexporter.py +4010 -0
- pywargame/latex/main.py +184 -0
- pywargame/vassal/__init__.py +66 -0
- pywargame/vassal/base.py +139 -0
- pywargame/vassal/board.py +243 -0
- pywargame/vassal/buildfile.py +60 -0
- pywargame/vassal/chart.py +79 -0
- pywargame/vassal/chessclock.py +197 -0
- pywargame/vassal/collect.py +98 -0
- pywargame/vassal/collectpatch.py +28 -0
- pywargame/vassal/command.py +21 -0
- pywargame/vassal/documentation.py +322 -0
- pywargame/vassal/dumpcollect.py +28 -0
- pywargame/vassal/dumpvsav.py +28 -0
- pywargame/vassal/element.py +439 -0
- pywargame/vassal/exporter.py +89 -0
- pywargame/vassal/extension.py +101 -0
- pywargame/vassal/folder.py +103 -0
- pywargame/vassal/game.py +940 -0
- pywargame/vassal/gameelements.py +1091 -0
- pywargame/vassal/globalkey.py +127 -0
- pywargame/vassal/globalproperty.py +433 -0
- pywargame/vassal/grid.py +573 -0
- pywargame/vassal/map.py +1061 -0
- pywargame/vassal/mapelements.py +1020 -0
- pywargame/vassal/merge.py +57 -0
- pywargame/vassal/merger.py +460 -0
- pywargame/vassal/moduledata.py +275 -0
- pywargame/vassal/mrgcollect.py +31 -0
- pywargame/vassal/patch.py +44 -0
- pywargame/vassal/patchcollect.py +28 -0
- pywargame/vassal/player.py +83 -0
- pywargame/vassal/save.py +495 -0
- pywargame/vassal/skel.py +380 -0
- pywargame/vassal/trait.py +224 -0
- pywargame/vassal/traits/__init__.py +36 -0
- pywargame/vassal/traits/area.py +50 -0
- pywargame/vassal/traits/basic.py +35 -0
- pywargame/vassal/traits/calculatedproperty.py +22 -0
- pywargame/vassal/traits/cargo.py +29 -0
- pywargame/vassal/traits/click.py +41 -0
- pywargame/vassal/traits/clone.py +28 -0
- pywargame/vassal/traits/delete.py +24 -0
- pywargame/vassal/traits/deselect.py +32 -0
- pywargame/vassal/traits/dynamicproperty.py +112 -0
- pywargame/vassal/traits/globalcommand.py +55 -0
- pywargame/vassal/traits/globalhotkey.py +26 -0
- pywargame/vassal/traits/globalproperty.py +54 -0
- pywargame/vassal/traits/hide.py +67 -0
- pywargame/vassal/traits/label.py +76 -0
- pywargame/vassal/traits/layer.py +105 -0
- pywargame/vassal/traits/mark.py +20 -0
- pywargame/vassal/traits/mask.py +85 -0
- pywargame/vassal/traits/mat.py +26 -0
- pywargame/vassal/traits/moved.py +35 -0
- pywargame/vassal/traits/movefixed.py +51 -0
- pywargame/vassal/traits/nonrect.py +95 -0
- pywargame/vassal/traits/nostack.py +55 -0
- pywargame/vassal/traits/place.py +104 -0
- pywargame/vassal/traits/prototype.py +20 -0
- pywargame/vassal/traits/report.py +34 -0
- pywargame/vassal/traits/restrictaccess.py +28 -0
- pywargame/vassal/traits/restrictcommand.py +32 -0
- pywargame/vassal/traits/return.py +40 -0
- pywargame/vassal/traits/rotate.py +62 -0
- pywargame/vassal/traits/sendto.py +59 -0
- pywargame/vassal/traits/sheet.py +129 -0
- pywargame/vassal/traits/skel.py +9 -0
- pywargame/vassal/traits/stack.py +28 -0
- pywargame/vassal/traits/submenu.py +27 -0
- pywargame/vassal/traits/trail.py +61 -0
- pywargame/vassal/traits/trigger.py +72 -0
- pywargame/vassal/turn.py +272 -0
- pywargame/vassal/upgrade.py +191 -0
- pywargame/vassal/vmod.py +323 -0
- pywargame/vassal/vsav.py +100 -0
- pywargame/vassal/widget.py +358 -0
- pywargame/vassal/withtraits.py +634 -0
- pywargame/vassal/xml.py +4 -0
- pywargame/vassal/zone.py +399 -0
- pywargame/vassal.py +12500 -0
- pywargame/vmodpatch.py +12548 -0
- pywargame/vsavdump.py +12533 -0
- pywargame/vslmerge.py +13015 -0
- pywargame/wgexport.py +16689 -0
- pywargame/ztexport.py +14351 -0
- pywargame/zuntzu/__init__.py +5 -0
- pywargame/zuntzu/base.py +82 -0
- pywargame/zuntzu/collect.py +38 -0
- pywargame/zuntzu/countersheet.py +250 -0
- pywargame/zuntzu/dicehand.py +48 -0
- pywargame/zuntzu/exporter.py +936 -0
- pywargame/zuntzu/gamebox.py +154 -0
- pywargame/zuntzu/map.py +36 -0
- pywargame/zuntzu/piece.py +37 -0
- pywargame/zuntzu/scenario.py +208 -0
- pywargame/zuntzu/ztexp.py +115 -0
- pywargame-0.3.1.dist-info/METADATA +353 -0
- pywargame-0.3.1.dist-info/RECORD +150 -0
- pywargame-0.3.1.dist-info/WHEEL +5 -0
- pywargame-0.3.1.dist-info/licenses/LICENSE +5 -0
- pywargame-0.3.1.dist-info/top_level.txt +1 -0
pywargame/latex/main.py
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
## BEGIN_IMPORTS
|
3
|
+
from latexexporter import LaTeXExporter
|
4
|
+
from vassal.vmod import VMod
|
5
|
+
from common import Verbose
|
6
|
+
## END_IMPORTS
|
7
|
+
|
8
|
+
from argparse import ArgumentParser
|
9
|
+
|
10
|
+
class DefaultSubcommandArgParse(ArgumentParser):
|
11
|
+
_default_subparser = None
|
12
|
+
|
13
|
+
def set_default_subparser(self, name):
|
14
|
+
self._default_subparser = name
|
15
|
+
|
16
|
+
def _parse_known_args(self, arg_strings, *args, **kwargs):
|
17
|
+
from argparse import _SubParsersAction
|
18
|
+
in_args = set(arg_strings)
|
19
|
+
d_sp = self._default_subparser
|
20
|
+
if d_sp is not None and not {'-h', '--help'}.intersection(in_args):
|
21
|
+
for x in self._subparsers._actions:
|
22
|
+
subparser_found = (
|
23
|
+
isinstance(x, _SubParsersAction) and
|
24
|
+
in_args.intersection(x._name_parser_map.keys())
|
25
|
+
)
|
26
|
+
if subparser_found:
|
27
|
+
break
|
28
|
+
else:
|
29
|
+
# insert default in first position, this implies no
|
30
|
+
# global options without a sub_parsers specified
|
31
|
+
arg_strings = [d_sp] + arg_strings
|
32
|
+
return super(DefaultSubcommandArgParse, self)._parse_known_args(
|
33
|
+
arg_strings, *args, **kwargs
|
34
|
+
)
|
35
|
+
# ====================================================================
|
36
|
+
def patchIt(args):
|
37
|
+
vmodname = args.output.name
|
38
|
+
patchname = args.patch.name
|
39
|
+
args.output.close()
|
40
|
+
args.patch .close()
|
41
|
+
|
42
|
+
VMod.patch(vmodname, patchname, args.verbose)
|
43
|
+
|
44
|
+
# ====================================================================
|
45
|
+
def exportIt(args):
|
46
|
+
|
47
|
+
vmodname = args.output.name
|
48
|
+
patchname = args.patch.name if args.patch is not None else None
|
49
|
+
|
50
|
+
args.output.close()
|
51
|
+
if args.patch is not None:
|
52
|
+
args.patch.close()
|
53
|
+
|
54
|
+
Verbose().setVerbose(args.verbose)
|
55
|
+
|
56
|
+
try:
|
57
|
+
if args.version.lower() == 'draft':
|
58
|
+
args.visible_grids = True
|
59
|
+
|
60
|
+
rulesname = args.rules.name if args.rules is not None else None
|
61
|
+
tutname = args.tutorial.name if args.tutorial is not None else None
|
62
|
+
|
63
|
+
exporter = LaTeXExporter(vmodname = vmodname,
|
64
|
+
pdfname = args.pdffile.name,
|
65
|
+
infoname = args.infofile.name,
|
66
|
+
title = args.title,
|
67
|
+
version = args.version,
|
68
|
+
description = args.description,
|
69
|
+
rules = rulesname,
|
70
|
+
tutorial = tutname,
|
71
|
+
patch = patchname,
|
72
|
+
visible = args.visible_grids,
|
73
|
+
vassalVersion = args.vassal_version,
|
74
|
+
nonato = args.no_nato_prototypes,
|
75
|
+
nochit = args.no_chit_information,
|
76
|
+
resolution = args.resolution,
|
77
|
+
counterScale = args.counter_scale,
|
78
|
+
imageFormat = args.image_format)
|
79
|
+
exporter.run()
|
80
|
+
except Exception as e:
|
81
|
+
from sys import stderr
|
82
|
+
print(f'Failed to build {vmodname}: {e}',file=stderr)
|
83
|
+
from os import unlink
|
84
|
+
try:
|
85
|
+
unlink(vmodname)
|
86
|
+
except:
|
87
|
+
pass
|
88
|
+
|
89
|
+
raise e
|
90
|
+
|
91
|
+
|
92
|
+
# ====================================================================
|
93
|
+
if __name__ == '__main__':
|
94
|
+
from argparse import ArgumentParser, FileType
|
95
|
+
|
96
|
+
ap = DefaultSubcommandArgParse(description='Create draft VASSAL module')
|
97
|
+
ap.set_default_subparser('export')
|
98
|
+
sp = ap.add_subparsers(dest='mode')
|
99
|
+
|
100
|
+
pp = sp.add_parser('patch',help='Patch VMod')
|
101
|
+
pp.add_argument('output',
|
102
|
+
help='Module to patch',
|
103
|
+
type=FileType('r'),
|
104
|
+
default='Draft.vmod')
|
105
|
+
pp.add_argument('patch',
|
106
|
+
help='A python script to patch generated module',
|
107
|
+
type=FileType('r'),
|
108
|
+
default='patch.py')
|
109
|
+
pp.add_argument('-V','--verbose',
|
110
|
+
help='Be verbose',
|
111
|
+
action='store_true')
|
112
|
+
|
113
|
+
|
114
|
+
ep = sp.add_parser('export',help='Export from PDF and JSON to VMod')
|
115
|
+
ep.add_argument('pdffile',
|
116
|
+
help='The PDF file to read images from',
|
117
|
+
type=FileType('r'),
|
118
|
+
default='export.pdf',
|
119
|
+
nargs='?')
|
120
|
+
ep.add_argument('infofile',
|
121
|
+
help='The JSON file to read image information from',
|
122
|
+
type=FileType('r'),
|
123
|
+
default='export.json',
|
124
|
+
nargs='?')
|
125
|
+
ep.add_argument('-o','--output',
|
126
|
+
help='Output file to write module to',
|
127
|
+
type=FileType('w'),
|
128
|
+
default='Draft.vmod')
|
129
|
+
ep.add_argument('-p','--patch',
|
130
|
+
help='A python script to patch generated module',
|
131
|
+
type=FileType('r'))
|
132
|
+
ep.add_argument('-V','--verbose',
|
133
|
+
help='Be verbose',
|
134
|
+
action='store_true')
|
135
|
+
ep.add_argument('-t','--title',
|
136
|
+
help='Module title', default='Draft',
|
137
|
+
type=str)
|
138
|
+
ep.add_argument('-v','--version',
|
139
|
+
help='Module version',
|
140
|
+
type=str,
|
141
|
+
default='draft')
|
142
|
+
ep.add_argument('-r','--rules',
|
143
|
+
help='Rules PDF file',
|
144
|
+
type=FileType('r'))
|
145
|
+
ep.add_argument('-T','--tutorial',
|
146
|
+
help='Tutorial (v)log file',
|
147
|
+
type=FileType('r'))
|
148
|
+
ep.add_argument('-d','--description',
|
149
|
+
help='Short description of module',
|
150
|
+
type=str,
|
151
|
+
default='draft of module')
|
152
|
+
ep.add_argument('-W','--vassal-version',
|
153
|
+
help='Vassal version number',
|
154
|
+
type=str,
|
155
|
+
default='3.7.12')
|
156
|
+
ep.add_argument('-G','--visible-grids',
|
157
|
+
action='store_true',
|
158
|
+
help='Make grids visible in the module')
|
159
|
+
ep.add_argument('-N','--no-nato-prototypes',
|
160
|
+
action='store_true',
|
161
|
+
help='Do not make prototypes for types,echelons,commands')
|
162
|
+
ep.add_argument('-C','--no-chit-information',
|
163
|
+
action='store_true',
|
164
|
+
help='Do not make properties from chit information')
|
165
|
+
ep.add_argument('-S','--counter-scale',
|
166
|
+
type=float, default=1,
|
167
|
+
help='Scale counters by factor')
|
168
|
+
ep.add_argument('-R','--resolution',
|
169
|
+
type=int, default=150,
|
170
|
+
help='Resolution of images')
|
171
|
+
ep.add_argument('-I','--image-format',
|
172
|
+
choices = ['png','svg'], default='png',
|
173
|
+
help='Image format to use')
|
174
|
+
|
175
|
+
args = ap.parse_args()
|
176
|
+
|
177
|
+
if args.mode == 'patch':
|
178
|
+
patchIt(args)
|
179
|
+
else:
|
180
|
+
exportIt(args)
|
181
|
+
|
182
|
+
#
|
183
|
+
# EOF
|
184
|
+
#
|
@@ -0,0 +1,66 @@
|
|
1
|
+
'''
|
2
|
+
Module to manipulate a VASSAL module (VMOD)
|
3
|
+
'''
|
4
|
+
from . base import *
|
5
|
+
from . element import *
|
6
|
+
from . folder import *
|
7
|
+
from . globalkey import *
|
8
|
+
from . gameelements import *
|
9
|
+
from . mapelements import *
|
10
|
+
from . globalproperty import *
|
11
|
+
from . turn import *
|
12
|
+
from . documentation import *
|
13
|
+
from . player import *
|
14
|
+
from . widget import *
|
15
|
+
from . grid import *
|
16
|
+
from . zone import *
|
17
|
+
from . board import *
|
18
|
+
from . map import *
|
19
|
+
from . chart import *
|
20
|
+
from . command import *
|
21
|
+
from . trait import *
|
22
|
+
from . withtraits import *
|
23
|
+
from . extension import *
|
24
|
+
from . traits.area import *
|
25
|
+
from . traits.clone import *
|
26
|
+
from . traits.dynamicproperty import *
|
27
|
+
from . traits.globalproperty import *
|
28
|
+
from . traits.prototype import *
|
29
|
+
from . traits.place import *
|
30
|
+
from . traits.report import *
|
31
|
+
from . traits.calculatedproperty import *
|
32
|
+
from . traits.restrictcommand import *
|
33
|
+
from . traits.label import *
|
34
|
+
from . traits.layer import *
|
35
|
+
from . traits.globalcommand import *
|
36
|
+
from . traits.globalhotkey import *
|
37
|
+
from . traits.nostack import *
|
38
|
+
from . traits.deselect import *
|
39
|
+
from . traits.restrictaccess import *
|
40
|
+
from . traits.rotate import *
|
41
|
+
from . traits.stack import *
|
42
|
+
from . traits.mark import *
|
43
|
+
from . traits.mask import *
|
44
|
+
from . traits.trail import *
|
45
|
+
from . traits.delete import *
|
46
|
+
from . traits.sendto import *
|
47
|
+
from . traits.moved import *
|
48
|
+
from . traits.skel import *
|
49
|
+
from . traits.submenu import *
|
50
|
+
from . traits.basic import *
|
51
|
+
from . traits.trigger import *
|
52
|
+
from . traits.nonrect import *
|
53
|
+
from . traits.click import *
|
54
|
+
from . traits.mat import MatTrait
|
55
|
+
from . traits.cargo import CargoTrait
|
56
|
+
from . traits.movefixed import MoveFixedTrait
|
57
|
+
from . traits.sheet import SheeTrait
|
58
|
+
from . traits.hide import HideTrait
|
59
|
+
from . traits.return import ReturnTrait
|
60
|
+
from . game import *
|
61
|
+
from . buildfile import *
|
62
|
+
from . moduledata import *
|
63
|
+
from . save import *
|
64
|
+
from . vsav import *
|
65
|
+
from . vmod import *
|
66
|
+
from . exporter import *
|
pywargame/vassal/base.py
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
# ====================================================================
|
2
|
+
# Key encoding
|
3
|
+
SHIFT = 65
|
4
|
+
CTRL = 130
|
5
|
+
ALT = 520
|
6
|
+
CTRL_SHIFT = CTRL+SHIFT
|
7
|
+
ALT_SHIFT = ALT+SHIFT
|
8
|
+
NONE = '\ue004'
|
9
|
+
NONE_MOD = 0
|
10
|
+
|
11
|
+
# --------------------------------------------------------------------
|
12
|
+
def key(let,mod=CTRL):
|
13
|
+
|
14
|
+
'''Encode a key sequence
|
15
|
+
|
16
|
+
down = 40,0
|
17
|
+
up = 38,0
|
18
|
+
left = 37,0
|
19
|
+
right = 39,0
|
20
|
+
|
21
|
+
Parameters
|
22
|
+
----------
|
23
|
+
let : str
|
24
|
+
Key code (Letter)
|
25
|
+
mod : int
|
26
|
+
Modifier mask
|
27
|
+
'''
|
28
|
+
if let is None:
|
29
|
+
return f'{ord(NONE)},{NONE_MOD}'
|
30
|
+
return f'{ord(let)},{mod}'
|
31
|
+
|
32
|
+
# --------------------------------------------------------------------
|
33
|
+
#
|
34
|
+
def hexcolor(s):
|
35
|
+
if isinstance(s,str):
|
36
|
+
s = s.replace('0x','')
|
37
|
+
if len(s) == 3:
|
38
|
+
r, g, b = [int(si,16)/16 for si in s]
|
39
|
+
elif len(s) == 6:
|
40
|
+
r = int(s[0:2],16) / 256
|
41
|
+
g = int(s[2:4],16) / 256
|
42
|
+
b = int(s[4:6],16) / 256
|
43
|
+
else:
|
44
|
+
raise RuntimeError('3 or 6 hexadecimal digits for color string')
|
45
|
+
elif isinstance(s,int):
|
46
|
+
r = ((s >> 16) & 0xFF) / 256
|
47
|
+
g = ((s >> 8) & 0xFF) / 256
|
48
|
+
b = ((s >> 0) & 0xFF) / 256
|
49
|
+
else:
|
50
|
+
raise RuntimeError('Hex colour must be string or integer')
|
51
|
+
|
52
|
+
return rgb(int(r*256),int(g*256),int(b*256))
|
53
|
+
|
54
|
+
# --------------------------------------------------------------------
|
55
|
+
# Colour encoding
|
56
|
+
def rgb(r,g,b):
|
57
|
+
'''Encode RGB colour
|
58
|
+
|
59
|
+
Parameters
|
60
|
+
----------
|
61
|
+
r : int
|
62
|
+
Red channel
|
63
|
+
g : int
|
64
|
+
Green channel
|
65
|
+
b : int
|
66
|
+
Blue channel
|
67
|
+
|
68
|
+
Returns
|
69
|
+
-------
|
70
|
+
colour : str
|
71
|
+
RGB colour as a string
|
72
|
+
'''
|
73
|
+
return ','.join([str(r),str(g),str(b)])
|
74
|
+
|
75
|
+
# --------------------------------------------------------------------
|
76
|
+
def rgba(r,g,b,a):
|
77
|
+
'''Encode RGBA colour
|
78
|
+
|
79
|
+
Parameters
|
80
|
+
----------
|
81
|
+
r : int
|
82
|
+
Red channel
|
83
|
+
g : int
|
84
|
+
Green channel
|
85
|
+
b : int
|
86
|
+
Blue channel
|
87
|
+
a : int
|
88
|
+
Alpha channel
|
89
|
+
|
90
|
+
Returns
|
91
|
+
-------
|
92
|
+
colour : str
|
93
|
+
RGBA colour as a string
|
94
|
+
'''
|
95
|
+
return ','.join([str(r),str(g),str(b),str(a)])
|
96
|
+
|
97
|
+
# --------------------------------------------------------------------
|
98
|
+
def dumpTree(node,ind=''):
|
99
|
+
'''Dump the tree of nodes
|
100
|
+
|
101
|
+
Parameters
|
102
|
+
----------
|
103
|
+
node : xml.dom.Node
|
104
|
+
Node to dump
|
105
|
+
ind : str
|
106
|
+
Current indent
|
107
|
+
'''
|
108
|
+
print(f'{ind}{node}')
|
109
|
+
for c in node.childNodes:
|
110
|
+
dumpTree(c,ind+' ')
|
111
|
+
|
112
|
+
# --------------------------------------------------------------------
|
113
|
+
def registerElement(cls,uniqueAttr=[],tag=None):
|
114
|
+
'''Register a TAG to element class, as well as unique attributes
|
115
|
+
to compare when comparing objects of that element class.
|
116
|
+
|
117
|
+
'''
|
118
|
+
## BEGIN_IMPORT
|
119
|
+
from . element import Element
|
120
|
+
## END_IMPORT
|
121
|
+
|
122
|
+
# Get class-level definitions of UNIQUE
|
123
|
+
uniqueCls = getattr(cls,'UNIQUE',None)
|
124
|
+
if uniqueCls:
|
125
|
+
try:
|
126
|
+
iter(uniqueCls)
|
127
|
+
except:
|
128
|
+
uniqueCls = list(uniqueCls)
|
129
|
+
else:
|
130
|
+
uniqueCls = []
|
131
|
+
|
132
|
+
tagName = cls.TAG if tag is None else tag
|
133
|
+
Element.known_tags [tagName] = cls
|
134
|
+
Element.unique_attrs[tagName] = uniqueAttr+uniqueCls
|
135
|
+
|
136
|
+
|
137
|
+
#
|
138
|
+
# EOF
|
139
|
+
#
|
@@ -0,0 +1,243 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . base import *
|
4
|
+
from . element import Element
|
5
|
+
from . gameelements import GameElement
|
6
|
+
from . mapelements import MapElement
|
7
|
+
from . zone import *
|
8
|
+
from . grid import *
|
9
|
+
## END_IMPORT
|
10
|
+
|
11
|
+
# --------------------------------------------------------------------
|
12
|
+
class BoardPicker(MapElement):
|
13
|
+
TAG = Element.MAP+'BoardPicker'
|
14
|
+
def __init__(self,doc,node=None,
|
15
|
+
addColumnText = 'Add column',
|
16
|
+
addRowText = 'Add row',
|
17
|
+
boardPrompt = 'Select board',
|
18
|
+
slotHeight = 125,
|
19
|
+
slotScale = 0.2,
|
20
|
+
slotWidth = 350,
|
21
|
+
title = 'Choose Boards'):
|
22
|
+
super(BoardPicker,self).__init__(doc,self.TAG,node=node,
|
23
|
+
addColumnText = addColumnText,
|
24
|
+
addRowText = addRowText,
|
25
|
+
boardPrompt = boardPrompt,
|
26
|
+
slotHeight = slotHeight,
|
27
|
+
slotScale = slotScale,
|
28
|
+
slotWidth = slotWidth,
|
29
|
+
title = title,
|
30
|
+
selected = '')
|
31
|
+
|
32
|
+
def addSetup(self,**kwargs):
|
33
|
+
'''Add a `Setup` element to this
|
34
|
+
|
35
|
+
Parameters
|
36
|
+
----------
|
37
|
+
kwargs : dict
|
38
|
+
Dictionary of attribute key-value pairs
|
39
|
+
|
40
|
+
Returns
|
41
|
+
-------
|
42
|
+
element : Setup
|
43
|
+
The added element
|
44
|
+
'''
|
45
|
+
if 'mapName' not in kwargs:
|
46
|
+
m = self.getMap()
|
47
|
+
kwargs['mapName'] = m.getAttribute('mapName')
|
48
|
+
|
49
|
+
return self.add(Setup,**kwargs)
|
50
|
+
def getSetups(self,single=False):
|
51
|
+
'''Get all or a sole `Setup` element(s) from this
|
52
|
+
|
53
|
+
Parameters
|
54
|
+
----------
|
55
|
+
single : bool
|
56
|
+
If `True`, there can be only one `Setup` child, otherwise fail.
|
57
|
+
If `False` return all `Setup` children in this element
|
58
|
+
|
59
|
+
Returns
|
60
|
+
-------
|
61
|
+
children : list
|
62
|
+
List of `Setup` children (even if `single=True`)
|
63
|
+
'''
|
64
|
+
return self.getAllElements(Setup,single=single)
|
65
|
+
def addBoard(self,**kwargs):
|
66
|
+
'''Add a `Board` element to this
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
kwargs : dict
|
71
|
+
Dictionary of attribute key-value pairs
|
72
|
+
|
73
|
+
Returns
|
74
|
+
-------
|
75
|
+
element : Board
|
76
|
+
The added element
|
77
|
+
'''
|
78
|
+
return self.add(Board,**kwargs)
|
79
|
+
def getBoards(self,asdict=True):
|
80
|
+
'''Get all Board element(s) from this
|
81
|
+
|
82
|
+
Parameters
|
83
|
+
----------
|
84
|
+
asdict : bool
|
85
|
+
If `True`, return a dictonary that maps key to `Board` elements. If `False`, return a list of all Board` children.
|
86
|
+
|
87
|
+
Returns
|
88
|
+
-------
|
89
|
+
children : dict or list
|
90
|
+
Dictionary or list of `Board` children
|
91
|
+
'''
|
92
|
+
return self.getElementsByKey(Board,'name',asdict=asdict)
|
93
|
+
|
94
|
+
def selectBoard(self,name):
|
95
|
+
if name is None:
|
96
|
+
self.setAttribute('selected','')
|
97
|
+
return
|
98
|
+
|
99
|
+
if name not in self.getBoards():
|
100
|
+
print(f'Board "{name}" not in "{self.getMap()["mapName"]}" picker')
|
101
|
+
return
|
102
|
+
|
103
|
+
escname = name.replace('|',' ')
|
104
|
+
self.setAttribute('selected',f'{self["selected"]}|{name}|')
|
105
|
+
#print(f'Added "{name}" to selected boards: {self["selected"]}')
|
106
|
+
|
107
|
+
def encode(self):
|
108
|
+
setups = self.getSetups()
|
109
|
+
if setups is not None and len(setups)>0:
|
110
|
+
return [setups[0]._node.childNodes[0].nodeValue]
|
111
|
+
|
112
|
+
ret = []
|
113
|
+
selected = self['selected']
|
114
|
+
#print(f'Selected boards: {selected}')
|
115
|
+
for bn in self.getBoards().keys():
|
116
|
+
escname = '|'+bn.replace('|',' ')+'|'
|
117
|
+
# if selected != '':
|
118
|
+
# print(f'Ignore board "{bn}" in map '
|
119
|
+
# f'{self.getMap()["mapName"]} '
|
120
|
+
# f'"{selected}" -> '
|
121
|
+
# f'{escname not in selected}')
|
122
|
+
if escname not in selected:
|
123
|
+
continue
|
124
|
+
ret.append(self.getMap()['mapName']+'BoardPicker\t'+bn+'\t0\t0')
|
125
|
+
|
126
|
+
return ret
|
127
|
+
|
128
|
+
registerElement(BoardPicker)
|
129
|
+
|
130
|
+
# --------------------------------------------------------------------
|
131
|
+
class Setup(Element):
|
132
|
+
TAG = 'setup'
|
133
|
+
def __init__(self,picker,node=None,
|
134
|
+
mapName = '',
|
135
|
+
maxColumns = 1,
|
136
|
+
boardNames = []):
|
137
|
+
super(Setup,self).__init__(picker,self.TAG,node=node)
|
138
|
+
col = 0
|
139
|
+
row = 0
|
140
|
+
lst = [f'{mapName}BoardPicker']
|
141
|
+
for bn in boardNames:
|
142
|
+
lst.extend([bn,str(col),str(row)])
|
143
|
+
col += 1
|
144
|
+
if col >= maxColumns:
|
145
|
+
col = 0
|
146
|
+
row += 1
|
147
|
+
|
148
|
+
txt = r' '.join(lst)
|
149
|
+
self.addText(txt)
|
150
|
+
|
151
|
+
def getPicker(self): return self.getParent(BoardPicker)
|
152
|
+
|
153
|
+
registerElement(Setup)
|
154
|
+
|
155
|
+
# --------------------------------------------------------------------
|
156
|
+
class Board(Element):
|
157
|
+
TAG = Element.PICKER+'Board'
|
158
|
+
UNIQUE = ['name']
|
159
|
+
def __init__(self,picker,node=None,
|
160
|
+
name = '',
|
161
|
+
image = '',
|
162
|
+
reversible = False,
|
163
|
+
color = rgb(255,255,255),
|
164
|
+
width = 0,
|
165
|
+
height = 0):
|
166
|
+
super(Board,self).__init__(picker,self.TAG,node=node,
|
167
|
+
image = image,
|
168
|
+
name = name,
|
169
|
+
reversible = reversible,
|
170
|
+
color = color,
|
171
|
+
width = width,
|
172
|
+
height = height)
|
173
|
+
|
174
|
+
def getPicker(self): return self.getParent(BoardPicker)
|
175
|
+
def getMap(self):
|
176
|
+
z = self.getPicker()
|
177
|
+
if z is not None:
|
178
|
+
return z.getMap()
|
179
|
+
return None
|
180
|
+
def addZonedGrid(self,**kwargs):
|
181
|
+
'''Add a `ZonedGrid` element to this
|
182
|
+
|
183
|
+
Parameters
|
184
|
+
----------
|
185
|
+
kwargs : dict
|
186
|
+
Dictionary of attribute key-value pairs
|
187
|
+
|
188
|
+
Returns
|
189
|
+
-------
|
190
|
+
element : ZonedGrid
|
191
|
+
The added element
|
192
|
+
'''
|
193
|
+
return self.add(ZonedGrid,**kwargs)
|
194
|
+
def getZonedGrids(self,single=True):
|
195
|
+
'''Get all or a sole `ZonedGrid` element(s) from this
|
196
|
+
|
197
|
+
Parameters
|
198
|
+
----------
|
199
|
+
single : bool
|
200
|
+
If `True`, there can be only one `ZonedGrid` child, otherwise fail.
|
201
|
+
If `False` return all `ZonedGrid` children in this element
|
202
|
+
|
203
|
+
Returns
|
204
|
+
-------
|
205
|
+
children : list
|
206
|
+
List of `ZonedGrid` children (even if `single=True`)
|
207
|
+
'''
|
208
|
+
return self.getAllElements(ZonedGrid,single=single)
|
209
|
+
def getZones(self,asdict=True):
|
210
|
+
'''Get all Zone element(s) from this
|
211
|
+
|
212
|
+
Parameters
|
213
|
+
----------
|
214
|
+
asdict : bool
|
215
|
+
If `True`, return a dictonary that maps key to `Zone` elements. If `False`, return a list of all Zone` children.
|
216
|
+
|
217
|
+
Returns
|
218
|
+
-------
|
219
|
+
children : dict or list
|
220
|
+
Dictionary or list of `Zone` children
|
221
|
+
'''
|
222
|
+
zoned = self.getZonedGrids(single=True)
|
223
|
+
if zoned is None: return None
|
224
|
+
|
225
|
+
return zoned[0].getZones(asdict=asdict)
|
226
|
+
|
227
|
+
def getWidth(self):
|
228
|
+
# print(f'Getting width of {self}: {self["width"]}')
|
229
|
+
if 'width' in self and int(self['width']) != 0:
|
230
|
+
return int(self['width'])
|
231
|
+
return 0
|
232
|
+
|
233
|
+
def getHeight(self):
|
234
|
+
# print(f'Getting height of {self}: {self["height"]}')
|
235
|
+
if 'height' in self and int(self['height']) != 0:
|
236
|
+
return int(self['height'])
|
237
|
+
return 0
|
238
|
+
|
239
|
+
registerElement(Board)
|
240
|
+
|
241
|
+
#
|
242
|
+
# EOF
|
243
|
+
#
|
@@ -0,0 +1,60 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . base import *
|
4
|
+
from . element import Element
|
5
|
+
from . game import Game
|
6
|
+
## END_IMPORT
|
7
|
+
|
8
|
+
# --------------------------------------------------------------------
|
9
|
+
class BuildFile(Element):
|
10
|
+
def __init__(self,root=None):
|
11
|
+
'''Construct from a DOM object, if given, otherwise make new'''
|
12
|
+
# from xml.dom.minidom import Document
|
13
|
+
super(BuildFile,self).__init__(None,'',None)
|
14
|
+
|
15
|
+
self._root = root
|
16
|
+
self._tag = 'buildFile'
|
17
|
+
if self._root is None:
|
18
|
+
self._root = xmlns.Document()
|
19
|
+
|
20
|
+
self._node = self._root
|
21
|
+
|
22
|
+
def addGame(self,**kwargs):
|
23
|
+
'''Add a `Game` element to this
|
24
|
+
|
25
|
+
Parameters
|
26
|
+
----------
|
27
|
+
kwargs : dict
|
28
|
+
Dictionary of attribute key-value pairs
|
29
|
+
|
30
|
+
Returns
|
31
|
+
-------
|
32
|
+
element : Game
|
33
|
+
The added element
|
34
|
+
'''
|
35
|
+
return Game(self,**kwargs)
|
36
|
+
|
37
|
+
def getGame(self):
|
38
|
+
'''Get the `Game`'''
|
39
|
+
try:
|
40
|
+
return Game(self,
|
41
|
+
node=self._root.\
|
42
|
+
getElementsByTagName('VASSAL.build.GameModule')[0])
|
43
|
+
except:
|
44
|
+
pass
|
45
|
+
|
46
|
+
return Game(self,
|
47
|
+
node=self._root.\
|
48
|
+
getElementsByTagName('VASSAL.launch.BasicModule')[0])
|
49
|
+
|
50
|
+
|
51
|
+
def encode(self):
|
52
|
+
'''Encode into XML'''
|
53
|
+
return self._root.toprettyxml(indent=' ',
|
54
|
+
encoding="UTF-8",
|
55
|
+
standalone=False)
|
56
|
+
|
57
|
+
|
58
|
+
#
|
59
|
+
# EOF
|
60
|
+
#
|