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.
Files changed (150) hide show
  1. pywargame/__init__.py +2 -0
  2. pywargame/common/__init__.py +3 -0
  3. pywargame/common/collector.py +87 -0
  4. pywargame/common/dicedraw.py +363 -0
  5. pywargame/common/drawdice.py +40 -0
  6. pywargame/common/singleton.py +22 -0
  7. pywargame/common/test.py +25 -0
  8. pywargame/common/verbose.py +59 -0
  9. pywargame/common/verboseguard.py +53 -0
  10. pywargame/cyberboard/__init__.py +18 -0
  11. pywargame/cyberboard/archive.py +283 -0
  12. pywargame/cyberboard/base.py +63 -0
  13. pywargame/cyberboard/board.py +462 -0
  14. pywargame/cyberboard/cell.py +200 -0
  15. pywargame/cyberboard/collect.py +49 -0
  16. pywargame/cyberboard/collectgbx0pwd.py +30 -0
  17. pywargame/cyberboard/collectgbxext.py +30 -0
  18. pywargame/cyberboard/collectgsnexp.py +32 -0
  19. pywargame/cyberboard/collectgsnext.py +30 -0
  20. pywargame/cyberboard/draw.py +396 -0
  21. pywargame/cyberboard/exporter.py +1132 -0
  22. pywargame/cyberboard/extractor.py +240 -0
  23. pywargame/cyberboard/features.py +17 -0
  24. pywargame/cyberboard/gamebox.py +81 -0
  25. pywargame/cyberboard/gbxexp.py +76 -0
  26. pywargame/cyberboard/gbxext.py +64 -0
  27. pywargame/cyberboard/gsnexp.py +147 -0
  28. pywargame/cyberboard/gsnext.py +59 -0
  29. pywargame/cyberboard/head.py +111 -0
  30. pywargame/cyberboard/image.py +76 -0
  31. pywargame/cyberboard/main.py +47 -0
  32. pywargame/cyberboard/mark.py +102 -0
  33. pywargame/cyberboard/palette.py +36 -0
  34. pywargame/cyberboard/piece.py +169 -0
  35. pywargame/cyberboard/player.py +36 -0
  36. pywargame/cyberboard/scenario.py +115 -0
  37. pywargame/cyberboard/testgrid.py +156 -0
  38. pywargame/cyberboard/tile.py +121 -0
  39. pywargame/cyberboard/tray.py +68 -0
  40. pywargame/cyberboard/windows.py +41 -0
  41. pywargame/cyberboard/zeropwd.py +45 -0
  42. pywargame/cyberboard.py +2728 -0
  43. pywargame/gbx0pwd.py +2776 -0
  44. pywargame/gbxextract.py +2795 -0
  45. pywargame/gsnexport.py +16499 -0
  46. pywargame/gsnextract.py +2790 -0
  47. pywargame/latex/__init__.py +2 -0
  48. pywargame/latex/collect.py +34 -0
  49. pywargame/latex/latexexporter.py +4010 -0
  50. pywargame/latex/main.py +184 -0
  51. pywargame/vassal/__init__.py +66 -0
  52. pywargame/vassal/base.py +139 -0
  53. pywargame/vassal/board.py +243 -0
  54. pywargame/vassal/buildfile.py +60 -0
  55. pywargame/vassal/chart.py +79 -0
  56. pywargame/vassal/chessclock.py +197 -0
  57. pywargame/vassal/collect.py +98 -0
  58. pywargame/vassal/collectpatch.py +28 -0
  59. pywargame/vassal/command.py +21 -0
  60. pywargame/vassal/documentation.py +322 -0
  61. pywargame/vassal/dumpcollect.py +28 -0
  62. pywargame/vassal/dumpvsav.py +28 -0
  63. pywargame/vassal/element.py +439 -0
  64. pywargame/vassal/exporter.py +89 -0
  65. pywargame/vassal/extension.py +101 -0
  66. pywargame/vassal/folder.py +103 -0
  67. pywargame/vassal/game.py +940 -0
  68. pywargame/vassal/gameelements.py +1091 -0
  69. pywargame/vassal/globalkey.py +127 -0
  70. pywargame/vassal/globalproperty.py +433 -0
  71. pywargame/vassal/grid.py +573 -0
  72. pywargame/vassal/map.py +1061 -0
  73. pywargame/vassal/mapelements.py +1020 -0
  74. pywargame/vassal/merge.py +57 -0
  75. pywargame/vassal/merger.py +460 -0
  76. pywargame/vassal/moduledata.py +275 -0
  77. pywargame/vassal/mrgcollect.py +31 -0
  78. pywargame/vassal/patch.py +44 -0
  79. pywargame/vassal/patchcollect.py +28 -0
  80. pywargame/vassal/player.py +83 -0
  81. pywargame/vassal/save.py +495 -0
  82. pywargame/vassal/skel.py +380 -0
  83. pywargame/vassal/trait.py +224 -0
  84. pywargame/vassal/traits/__init__.py +36 -0
  85. pywargame/vassal/traits/area.py +50 -0
  86. pywargame/vassal/traits/basic.py +35 -0
  87. pywargame/vassal/traits/calculatedproperty.py +22 -0
  88. pywargame/vassal/traits/cargo.py +29 -0
  89. pywargame/vassal/traits/click.py +41 -0
  90. pywargame/vassal/traits/clone.py +28 -0
  91. pywargame/vassal/traits/delete.py +24 -0
  92. pywargame/vassal/traits/deselect.py +32 -0
  93. pywargame/vassal/traits/dynamicproperty.py +112 -0
  94. pywargame/vassal/traits/globalcommand.py +55 -0
  95. pywargame/vassal/traits/globalhotkey.py +26 -0
  96. pywargame/vassal/traits/globalproperty.py +54 -0
  97. pywargame/vassal/traits/hide.py +67 -0
  98. pywargame/vassal/traits/label.py +76 -0
  99. pywargame/vassal/traits/layer.py +105 -0
  100. pywargame/vassal/traits/mark.py +20 -0
  101. pywargame/vassal/traits/mask.py +85 -0
  102. pywargame/vassal/traits/mat.py +26 -0
  103. pywargame/vassal/traits/moved.py +35 -0
  104. pywargame/vassal/traits/movefixed.py +51 -0
  105. pywargame/vassal/traits/nonrect.py +95 -0
  106. pywargame/vassal/traits/nostack.py +55 -0
  107. pywargame/vassal/traits/place.py +104 -0
  108. pywargame/vassal/traits/prototype.py +20 -0
  109. pywargame/vassal/traits/report.py +34 -0
  110. pywargame/vassal/traits/restrictaccess.py +28 -0
  111. pywargame/vassal/traits/restrictcommand.py +32 -0
  112. pywargame/vassal/traits/return.py +40 -0
  113. pywargame/vassal/traits/rotate.py +62 -0
  114. pywargame/vassal/traits/sendto.py +59 -0
  115. pywargame/vassal/traits/sheet.py +129 -0
  116. pywargame/vassal/traits/skel.py +9 -0
  117. pywargame/vassal/traits/stack.py +28 -0
  118. pywargame/vassal/traits/submenu.py +27 -0
  119. pywargame/vassal/traits/trail.py +61 -0
  120. pywargame/vassal/traits/trigger.py +72 -0
  121. pywargame/vassal/turn.py +272 -0
  122. pywargame/vassal/upgrade.py +191 -0
  123. pywargame/vassal/vmod.py +323 -0
  124. pywargame/vassal/vsav.py +100 -0
  125. pywargame/vassal/widget.py +358 -0
  126. pywargame/vassal/withtraits.py +634 -0
  127. pywargame/vassal/xml.py +4 -0
  128. pywargame/vassal/zone.py +399 -0
  129. pywargame/vassal.py +12500 -0
  130. pywargame/vmodpatch.py +12548 -0
  131. pywargame/vsavdump.py +12533 -0
  132. pywargame/vslmerge.py +13015 -0
  133. pywargame/wgexport.py +16689 -0
  134. pywargame/ztexport.py +14351 -0
  135. pywargame/zuntzu/__init__.py +5 -0
  136. pywargame/zuntzu/base.py +82 -0
  137. pywargame/zuntzu/collect.py +38 -0
  138. pywargame/zuntzu/countersheet.py +250 -0
  139. pywargame/zuntzu/dicehand.py +48 -0
  140. pywargame/zuntzu/exporter.py +936 -0
  141. pywargame/zuntzu/gamebox.py +154 -0
  142. pywargame/zuntzu/map.py +36 -0
  143. pywargame/zuntzu/piece.py +37 -0
  144. pywargame/zuntzu/scenario.py +208 -0
  145. pywargame/zuntzu/ztexp.py +115 -0
  146. pywargame-0.3.1.dist-info/METADATA +353 -0
  147. pywargame-0.3.1.dist-info/RECORD +150 -0
  148. pywargame-0.3.1.dist-info/WHEEL +5 -0
  149. pywargame-0.3.1.dist-info/licenses/LICENSE +5 -0
  150. pywargame-0.3.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,154 @@
1
+ ## BEGIN_IMPORTS
2
+ from base import DomInspect
3
+ from map import ZTMap
4
+ from piece import ZTPiece
5
+ from countersheet import ZTCounterSheet
6
+ from dicehand import ZTDiceHand
7
+ from common import VerboseGuard
8
+ from scenario import ZTScenario
9
+ ## END_IMPORTS
10
+
11
+ # --------------------------------------------------------------------
12
+ class ZTGameBox(DomInspect):
13
+
14
+ def __init__(self,file):
15
+ from zipfile import ZipFile
16
+ from xml.dom.minidom import parse
17
+
18
+ with VerboseGuard('Reading gamebox') as v:
19
+ self._zip = ZipFile(file,'r')
20
+
21
+ with self._zip.open('game-box.xml','r') as xml:
22
+ self._gamebox =parse(xml)
23
+
24
+ self._root = self._gamebox.firstChild
25
+ self._name = self._get_attr(self._root,'name')
26
+ self._desc = self._get_attr(self._root,'description')
27
+ self._copy = self._get_attr(self._root,'copyright')
28
+ self._start = self._get_attr(self._root,'startup-scenario')
29
+ self._icon = self._get_attr(self._root,'icon',None)
30
+ self._splash = None
31
+ self._sheets_map = {}
32
+
33
+ if not self._icon and 'icon.bmp' in self._zip.namelist():
34
+ self._icon = 'icon.bmp'
35
+ v(f'Icon is {self._icon}')
36
+
37
+ if self._icon:
38
+ self._splash = self._read_image(self._zip, self._icon)
39
+ v(f'Got splash screen {self._icon}: {self._splash}')
40
+
41
+ self._dice_hands = [
42
+ self.parse_dice_hand(dh)
43
+ for dh in self._root.getElementsByTagName('dice-hand')]
44
+ # IF no dice was defined add a 1d6
45
+ if len(self._dice_hands) <= 0:
46
+ self._dice_hands = [ ZTDiceHand(None) ]
47
+
48
+ self._maps = [
49
+ self.parse_map(mp)
50
+ for mp in self._root.getElementsByTagName('map')]
51
+
52
+ self._scenarios = [
53
+ self.parse_scenario(fn)
54
+ for fn in self._zip.namelist() if fn.endswith('.zts')]
55
+
56
+ # counter-sheet or terrain-sheet
57
+ self._counter_sheets = [
58
+ self.parse_counter_sheet(sh)
59
+ for sh in self._find_children(self._root,
60
+ 'counter-sheet',
61
+ 'terrain-sheet')]
62
+
63
+ self._pieces = sum([c._piece for c in self._counter_sheets],[])
64
+ self._cards = sum([c._card for c in self._counter_sheets],[])
65
+ self.map_pieces()
66
+
67
+ def parse_dice_hand(self,elem):
68
+ return ZTDiceHand(elem)
69
+
70
+ def parse_map(self,elem):
71
+ m = ZTMap(elem)
72
+ m.read_image(self._zip)
73
+ # self._master[m._name] = m
74
+ return m
75
+
76
+ def parse_counter_sheet(self,elem):
77
+ s = ZTCounterSheet(elem)
78
+ s.read_image(self._zip)
79
+ s.make_pieces()
80
+ self._sheets_map[s._name] = s
81
+ return s
82
+
83
+ def parse_scenario(self,fn):
84
+ with self._zip.open(fn,'r') as inp:
85
+ return ZTScenario(inp)
86
+
87
+ def write_image(self,dir,name,image):
88
+ if image is None:
89
+ return
90
+
91
+ fn = dir / f'{name}.{image.format.lower()}'
92
+ print(f'Writing {fn}')
93
+ image.save(filename=fn)
94
+
95
+ def map_pieces(self):
96
+ with VerboseGuard(f'Mapping pieces to ID and back'):
97
+ # Cards and pieces are intermingled
98
+ tmp = sum([c._piece+c._card for c in self._counter_sheets],[])
99
+ self._piece_map = {
100
+ i: p for i,p in enumerate(tmp) }
101
+ self._piece_id = {
102
+ v: k for k,v in self._piece_map.items()}
103
+
104
+
105
+ def write_images(self):
106
+ from pathlib import Path
107
+
108
+ dir = Path('images')
109
+ dir.mkdir(0o755,parents=True,exist_ok=True)
110
+
111
+ for m in self._maps:
112
+ if not m._image:
113
+ print(f'Missing image for map {m._name}')
114
+ continue
115
+
116
+ self.write_image(dir,m._name,m._image._image)
117
+
118
+ for i,p in enumerate(self._pieces):
119
+ for img,nam in zip([p._front,p._back],
120
+ ['front','back']):
121
+
122
+ self.write_image(dir,f'{i:04d}_{nam}',img)
123
+
124
+ for i,p in enumerate(self._cards):
125
+ for img,nam in zip([p._front,p._back],
126
+ ['front','back']):
127
+
128
+ self.write_image(dir,f'c{i:04d}_{nam}',img)
129
+
130
+ for s in self._counter_sheets:
131
+ name = s._name
132
+ for fac,nam in zip([s._front,s._back],
133
+ ['front','back']):
134
+ if not fac:
135
+ continue
136
+
137
+ self.write_image(dir,f'{name}_{nam}',fac._image)
138
+
139
+
140
+ def __str__(self):
141
+ return (f'{self._name}'+'\n'+
142
+ f' Description: {self._desc}'+'\n'+
143
+ f' Copyright: {self._copy}'+'\n'+
144
+ f' Start: {self._start}'+'\n'+
145
+ f' Icon: {self._icon}'+
146
+ ('\n' if len(self._dice_hands)>0 else '')+
147
+ '\n'.join([str(d) for d in self._dice_hands])+
148
+ ('\n' if len(self._maps)>0 else '')+
149
+ '\n'.join([str(m) for m in self._maps])+
150
+ ('\n' if len(self._counter_sheets)>0 else '')+
151
+ '\n'.join([str(s) for s in self._counter_sheets]))
152
+ #
153
+ # EOF
154
+ #
@@ -0,0 +1,36 @@
1
+ ## BEGIN_IMPORTS
2
+ from base import DomInspect, ZTImage
3
+ from common import VerboseGuard
4
+ ## END_IMPORTS
5
+
6
+ # --------------------------------------------------------------------
7
+ class ZTMap(DomInspect):
8
+ def __init__(self,elem):
9
+ with VerboseGuard(f'Got a map'):
10
+ self._name = self._get_attr(elem,'name')
11
+ self._image = ZTImage(elem)
12
+
13
+ def read_image(self,zf):
14
+ with VerboseGuard(f'Reading map ({self._name}) image') as v:
15
+ self._image.read_image(zf)
16
+ sc = ZTImage.target_dpi / self._image._reso
17
+ v(f'Scale by {sc}={ZTImage.target_dpi}/{self._image._reso} '
18
+ f'from {self._image._image.width}x{self._image._image.height}')
19
+ self._image._image.resize(int(sc*self._image._image.width),
20
+ int(sc*self._image._image.height))
21
+ v(f'Scaled by {sc} to {self._image._image.width}x'
22
+ f'{self._image._image.height}')
23
+
24
+ @property
25
+ def filename(self):
26
+ return f'{self._name.replace(" ","_")}.{self._image._image.format.lower()}'
27
+
28
+ @property
29
+ def size(self):
30
+ return self._image._image.width,self._image._image.height
31
+
32
+ def __str__(self):
33
+ return f' Map: name={self._name}'+'\n'+str(self._image)
34
+ #
35
+ # EOF
36
+ #
@@ -0,0 +1,37 @@
1
+ # --------------------------------------------------------------------
2
+ class ZTPiece:
3
+ def __init__(self,front_image,back_image,x,y,terrain,card):
4
+ self._front = front_image
5
+ self._back = back_image
6
+ self._terrain = terrain
7
+ self._card = card
8
+ self._x = x
9
+ self._y = y
10
+
11
+ @property
12
+ def two_sides(self):
13
+ return (self._front is not None and
14
+ self._back is not None)
15
+
16
+ @property
17
+ def size(self):
18
+ return self.width,self.height
19
+
20
+ @property
21
+ def width(self):
22
+ return self._front.width
23
+
24
+ @property
25
+ def height(self):
26
+ return self._front.height
27
+
28
+
29
+ def __str__(self):
30
+ return (f' Piece: '+
31
+ f'{"card" if self._card else "piece"} '+
32
+ f'{"terrain" if self._terrain else "piece"} '+
33
+ f'front={self._front} back={self._back}')
34
+
35
+ #
36
+ # EOF
37
+ #
@@ -0,0 +1,208 @@
1
+ ## BEGIN_IMPORTS
2
+ from common import VerboseGuard
3
+ from base import DomInspect
4
+ ## END_IMPORTS
5
+
6
+ # --------------------------------------------------------------------
7
+ class ZTStack:
8
+ def __init__(self,x,y,ids,flp,rot):
9
+ self._x = x
10
+ self._y = y
11
+ self._ids = ids
12
+ self._flip = flp
13
+ self._rot = rot
14
+
15
+ def translate(self,dx,dy):
16
+ self._x += dx
17
+ self._y += dy
18
+
19
+ def scale(self,f):
20
+ self._x *= f
21
+ self._y *= f
22
+
23
+
24
+ # --------------------------------------------------------------------
25
+ class ZTLayout(DomInspect):
26
+ def __init__(self,elem):
27
+ self._name = self._get_attr(elem,'board')
28
+ self._left = float(self._get_attr(elem,'left', -1))
29
+ self._top = float(self._get_attr(elem,'top', -1))
30
+ self._right = float(self._get_attr(elem,'right', -1))
31
+ self._bottom = float(self._get_attr(elem,'bottom',-1))
32
+ self._visible = self._get_attr(elem,'visible','true')=='true'
33
+
34
+ self._stacks = [self.parse_stack(s)
35
+ for s in self._find_children(elem,'counter','stack')]
36
+
37
+ @property
38
+ def ulx(self):
39
+ return self._left
40
+
41
+ @property
42
+ def lrx(self):
43
+ return self._right
44
+
45
+ @property
46
+ def uly(self):
47
+ return self._top
48
+
49
+ @property
50
+ def lry(self):
51
+ return self._bottom
52
+
53
+ @property
54
+ def left(self):
55
+ return int(self._left)
56
+
57
+ @property
58
+ def top(self):
59
+ return int(self._top)
60
+
61
+ @property
62
+ def width(self):
63
+ return int(self._right - self._left+.5)
64
+
65
+ @property
66
+ def height(self):
67
+ return int(self._bottom - self._top+.5)
68
+
69
+ def parse_stack(self,elem):
70
+ x = float(self._get_attr(elem,'x',0))
71
+ y = float(self._get_attr(elem,'y',0))
72
+ # We ignore the `rot` and `Side` attributes for now
73
+ # More difficult to propagate to the states, which are handled
74
+ # in VSav. Could perhaps add a mapping from traits to states
75
+ # when the traits are flattened there.
76
+ ids = []
77
+ flp = []
78
+ rot = []
79
+ if elem.tagName == 'counter':
80
+ ids.append(int(self._get_attr(elem,'id',-1)))
81
+ flp.append(self._get_attr(elem,'side','')=='Back')
82
+ rot.append(int(self._get_attr(elem,'rot',0)))
83
+ else:
84
+ ids.extend([int(self._get_attr(c,'id',-1))
85
+ for c in self._find_children(elem,'counter')])
86
+ flp.extend([self._get_attr(c,'side','')=='Back'
87
+ for c in self._find_children(elem,'counter')])
88
+ rot.extend([int(self._get_attr(c,'rot',0))
89
+ for c in self._find_children(elem,'counter')])
90
+
91
+ return ZTStack(x,y,ids,flp,rot)
92
+
93
+ def translate(self,dx,dy):
94
+ self._left += dx
95
+ self._right += dx
96
+ self._top += dy
97
+ self._bottom += dy
98
+ for s in self._stacks:
99
+ s.translate(dx,dy)
100
+
101
+ def scale(self,f):
102
+ self._left *= f
103
+ self._right *= f
104
+ self._top *= f
105
+ self._bottom *= f
106
+ for s in self._stacks:
107
+ s.scale(f)
108
+
109
+ def __str__(self):
110
+ return f'Layout "{self._name}" ({len(self._stacks)}: {self.ulx},{self.uly},{self.lrx},{self.lry}'
111
+
112
+ # --------------------------------------------------------------------
113
+ class ZTScenario(DomInspect):
114
+ def __init__(self,file):
115
+ from xml.dom.minidom import parse
116
+ from pathlib import Path
117
+
118
+ with VerboseGuard(f'Got a scenario {file}') as v:
119
+ self._dom = parse(file)
120
+
121
+ p = Path(file if isinstance(file,str) else file.name)
122
+
123
+ self._file = p.stem
124
+ self._root = self._dom.firstChild
125
+ self._game = self._get_attr(self._root,'game-box')
126
+ self._name = self._get_attr(self._root,'scenario-name')
127
+ self._desc = self._get_attr(self._root,'scenario-description','')
128
+ self._copy = self._get_attr(self._root,'scenario-copyright','')
129
+
130
+ self._layouts = [self.parse_layout(elem)
131
+ for elem in
132
+ self._root.getElementsByTagName('layout')]
133
+
134
+ self.ulx = None
135
+ self.uly = None
136
+ self.lrx = None
137
+ self.lry = None
138
+
139
+ v(f'Bounding box: {self.bounding_box}')
140
+
141
+ def parse_layout(self,elem):
142
+ return ZTLayout(elem)
143
+
144
+ def translate(self,dx,dy):
145
+ with VerboseGuard(f'Translating scenario by {dx},{dy}'):
146
+ self.ulx = None
147
+ self.uly = None
148
+ self.lrx = None
149
+ self.lry = None
150
+
151
+ for l in self._layouts:
152
+ l.translate(dx,dy)
153
+
154
+ def scale(self,f):
155
+ with VerboseGuard(f'Scaling scenario by {f}'):
156
+ self.ulx = None
157
+ self.uly = None
158
+ self.lrx = None
159
+ self.lry = None
160
+
161
+ for l in self._layouts:
162
+ l.scale(f)
163
+
164
+ def on_map(self,name):
165
+ return any([l._name == name for l in self._layouts])
166
+
167
+ def map_layout(self,name):
168
+ return [l for l in self._layouts if l._name == name]
169
+
170
+ def calc_bounding_box(self,name=None):
171
+ layouts = self._layouts if name is None else self.map_layout(name)
172
+ ulx = int(min([l.ulx for l in layouts])-.5)
173
+ uly = int(min([l.uly for l in layouts])-.5)
174
+ lrx = int(max([l.lrx for l in layouts])+.5)
175
+ lry = int(max([l.lry for l in layouts])+.5)
176
+ return ulx,uly,lrx,lry
177
+
178
+ @property
179
+ def bounding_box(self):
180
+ '''Cache calculations'''
181
+ if self.ulx is None or \
182
+ self.uly is None or \
183
+ self.lrx is None or \
184
+ self.lry is None:
185
+ self.ulx = int(min([l.ulx for l in self._layouts])-.5)
186
+ self.uly = int(min([l.uly for l in self._layouts])-.5)
187
+ self.lrx = int(max([l.lrx for l in self._layouts])+.5)
188
+ self.lry = int(max([l.lry for l in self._layouts])+.5)
189
+
190
+ return self.ulx,self.uly,self.lrx,self.lry
191
+
192
+ def __str__(self):
193
+ return f'Scenario "{self._name}": {self._desc}'+'\n'+\
194
+ '\n'.join([str(l) for l in self._layouts])
195
+
196
+ @property
197
+ def width(self):
198
+ x1,_,x2,_ = self.bounding_box
199
+ return x2-x1
200
+ @property
201
+ def height(self):
202
+ _,y1,_,y2 = self.bounding_box
203
+ return y2-y1
204
+
205
+
206
+ #
207
+ # EOF
208
+ #
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env python
2
+ ## BEGIN_IMPORTS
3
+ from sys import path
4
+ path.append('..')
5
+
6
+ from gamebox import ZTGameBox
7
+ from exporter import ZTExporter
8
+ from common import Verbose
9
+ from base import ZTImage
10
+ ## END_IMPORTS
11
+
12
+ if __name__ == '__main__':
13
+ from argparse import ArgumentParser, FileType, \
14
+ RawDescriptionHelpFormatter
15
+ from pathlib import Path
16
+ from textwrap import wrap, dedent
17
+
18
+ w = lambda s : '\n\n'.join(['\n'.join(wrap(p))
19
+ for p in dedent(s).split('\n\n')])
20
+ e = '''
21
+ If the script fails with "cache resources exhausted",
22
+ try reducing the resolution (-r).
23
+
24
+ If the ZunTzu game box does not have selectable
25
+ boards, use the -a option to add all boards to
26
+ the generated VASSAL module.
27
+
28
+ Pass a Python script with the option -p to do
29
+ user post-processing with that script. Use the
30
+ pywargame VASSAL API to do all sorts of manipulations.
31
+ '''
32
+
33
+ ap = ArgumentParser(description='Read in a ZunTzu GameBox',
34
+ formatter_class= RawDescriptionHelpFormatter,
35
+ epilog=w(e))
36
+ ap.add_argument('input', type=FileType('rb'),
37
+ help='Input ZunTzu GameBox')
38
+ ap.add_argument('--output', '-o', type=str, nargs='?',
39
+ default='', help='Output VASSAL module')
40
+ ap.add_argument('-p','--patch',
41
+ help='A python script to patch generated module',
42
+ type=FileType('r'))
43
+ ap.add_argument('-V','--verbose',
44
+ help='Be verbose',
45
+ action='store_true')
46
+ ap.add_argument('-r','--resolution',help='Set target DPI',type=int,
47
+ choices=[75,150,300,600],default=150)
48
+ ap.add_argument('-a','--all-maps',action='store_true',
49
+ help='Generate all maps')
50
+ ap.add_argument('-1','--one-map',action='store_false',dest='all_maps',
51
+ help='All maps are different versions of main map')
52
+ ap.add_argument('-R','--n-rotations',type=int,
53
+ help='Number of rotations to allow. Set to 1 for '
54
+ 'arbitrary rotations',default=12)
55
+ ap.add_argument('-W','--vassal-version',
56
+ help='Vassal version number',
57
+ type=str,
58
+ default='3.7.0')
59
+ ap.add_argument('-S','--symbolic-dice',
60
+ help='Use symbolic dice',
61
+ action='store_true')
62
+ ap.add_argument('-T','--text-dice',
63
+ help='Use normal text dice',
64
+ dest='symbolic_dice',
65
+ action='store_false')
66
+ ap.add_argument('-v','--version',
67
+ help='Override version',
68
+ type=str,
69
+ default='0.0.1')
70
+ ap.set_defaults(symbolic_dice=True,
71
+ all_maps=False)
72
+
73
+
74
+ args = ap.parse_args()
75
+
76
+ Verbose().setVerbose(args.verbose)
77
+
78
+ ZTImage.target_dpi = args.resolution
79
+ output = args.output
80
+ patch = args.patch
81
+ if output == '':
82
+ p = Path(args.input.name)
83
+ output = p.with_suffix('.vmod')
84
+ if patch is not None:
85
+ tmp = patch.name
86
+ patch.close()
87
+ patch = tmp
88
+
89
+ gb = ZTGameBox(args.input)
90
+ # gb.write_images()
91
+
92
+ try:
93
+ exporter = ZTExporter(gb,
94
+ version=args.version,
95
+ vassalVersion=args.vassal_version,
96
+ allmaps=args.all_maps,
97
+ nrotations=args.n_rotations,
98
+ symbolic_dice=args.symbolic_dice)
99
+ exporter.run(output,patch)
100
+ except Exception as e:
101
+ from sys import stderr
102
+ from os import unlink
103
+
104
+ print(f'Failed to build {output}: {e}',file=stderr)
105
+
106
+ try:
107
+ unlink(vmodname)
108
+ except:
109
+ pass
110
+
111
+ raise e
112
+
113
+ #
114
+ # EOF
115
+ #