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
@@ -0,0 +1,240 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
## END_IMPORT
|
4
|
+
|
5
|
+
# ====================================================================
|
6
|
+
class CbExtractor:
|
7
|
+
def __init__(self):
|
8
|
+
pass
|
9
|
+
|
10
|
+
def save(self,filename):
|
11
|
+
from zipfile import ZipFile
|
12
|
+
from copy import deepcopy
|
13
|
+
|
14
|
+
with VerboseGuard(f'Saving to {filename}') as g:
|
15
|
+
with ZipFile(filename,'w') as zfile:
|
16
|
+
self._save(zfile)
|
17
|
+
|
18
|
+
def saveImages(self,d,zfile):
|
19
|
+
with VerboseGuard(f'Saving images') as g:
|
20
|
+
for serial, board in d['boards'].items():
|
21
|
+
g(f'Saving board: {board}')
|
22
|
+
self.saveSVG(board,zfile)
|
23
|
+
|
24
|
+
for piece in d['pieces']['map'].values():
|
25
|
+
g(f'Saving piece: {piece}')
|
26
|
+
for which in ['front','back']:
|
27
|
+
if which not in piece:
|
28
|
+
continue
|
29
|
+
|
30
|
+
side = piece[which]
|
31
|
+
self.savePNG(side,zfile)
|
32
|
+
piece[which] = side['filename']
|
33
|
+
|
34
|
+
for mark in d['marks']['map'].values():
|
35
|
+
g(f'Saving marks: {mark}')
|
36
|
+
self.savePNG(mark,zfile)
|
37
|
+
|
38
|
+
for tile in d['tiles'].values():
|
39
|
+
g(f'Saving tile: {tile}')
|
40
|
+
self.savePNG(tile,zfile)
|
41
|
+
|
42
|
+
del d['tiles']
|
43
|
+
|
44
|
+
|
45
|
+
def saveSVG(self,d,zfile,removeImage=True):
|
46
|
+
from io import StringIO
|
47
|
+
|
48
|
+
with VerboseGuard(f'Saving SVG') as g:
|
49
|
+
filename = d['filename']
|
50
|
+
image = d['image']
|
51
|
+
|
52
|
+
# stream = StringIO()
|
53
|
+
# image.write(stream,pretty=True)
|
54
|
+
g(f'Saving SVG: {image}')
|
55
|
+
zfile.writestr(filename,image)#stream.getvalue())
|
56
|
+
|
57
|
+
if removeImage:
|
58
|
+
del d['image']
|
59
|
+
|
60
|
+
def savePNG(self,d,zfile,removeImage=True):
|
61
|
+
with VerboseGuard(f'Saving PNG') as g:
|
62
|
+
filename = d['filename']
|
63
|
+
img = d['image']
|
64
|
+
|
65
|
+
with zfile.open(filename,'w') as file:
|
66
|
+
g(f'Save {img}')
|
67
|
+
img.save(file,format='PNG')
|
68
|
+
|
69
|
+
if removeImage:
|
70
|
+
del d['image']
|
71
|
+
|
72
|
+
def _save(self,zfile):
|
73
|
+
pass
|
74
|
+
|
75
|
+
|
76
|
+
# ====================================================================
|
77
|
+
class GBXExtractor(CbExtractor):
|
78
|
+
def __init__(self,gbx):
|
79
|
+
'''Turns gambox into a more sensible structure'''
|
80
|
+
super(GBXExtractor,self).__init__()
|
81
|
+
|
82
|
+
with VerboseGuard(f'Extract gamebox {gbx._info._title}') as g:
|
83
|
+
self._d = {
|
84
|
+
'title': gbx._info._title,
|
85
|
+
'author': gbx._info._author,
|
86
|
+
'description': gbx._info._description.replace('\r',''),
|
87
|
+
'major': gbx._info._majorRevs,
|
88
|
+
'minor': gbx._info._minorRevs,
|
89
|
+
'version': f'{gbx._info._majorRevs}.{gbx._info._minorRevs}'
|
90
|
+
}
|
91
|
+
|
92
|
+
self._d['pieces'] = gbx._pieceManager.toDict(gbx._tileManager,
|
93
|
+
gbx._strings)
|
94
|
+
self._d['marks'] = gbx._markManager.toDict(gbx._tileManager,
|
95
|
+
gbx._strings)
|
96
|
+
self._d['boards'] = gbx._boardManager.toDict(gbx._tileManager,
|
97
|
+
gbx._markManager,
|
98
|
+
gbx._strings)
|
99
|
+
self._d['tiles'] = gbx._tileManager._toStore
|
100
|
+
|
101
|
+
g(f'Done rationalizing {gbx._info._title}')
|
102
|
+
|
103
|
+
|
104
|
+
def _save(self,zfile):
|
105
|
+
from pprint import pprint
|
106
|
+
from io import StringIO
|
107
|
+
from json import dumps
|
108
|
+
from copy import deepcopy
|
109
|
+
|
110
|
+
with VerboseGuard(f'Saving {self._d["title"]} to {zfile.filename}')as g:
|
111
|
+
d = deepcopy(self._d)
|
112
|
+
|
113
|
+
self.saveImages(d,zfile)
|
114
|
+
|
115
|
+
zfile.writestr('info.json',dumps(d,indent=2))
|
116
|
+
|
117
|
+
g(f'Done saving')
|
118
|
+
|
119
|
+
def fromZipfile(self,zipfile,d):
|
120
|
+
pass
|
121
|
+
|
122
|
+
def __str__(self):
|
123
|
+
from pprint import pformat
|
124
|
+
|
125
|
+
return pformat(self._d,depth=2)
|
126
|
+
|
127
|
+
# ====================================================================
|
128
|
+
class GSNExtractor(CbExtractor):
|
129
|
+
def __init__(self,gsn,zipfile=None):
|
130
|
+
'''Turns gambox into a more sensible structure'''
|
131
|
+
super(GSNExtractor,self).__init__()
|
132
|
+
|
133
|
+
if zipfile is not None:
|
134
|
+
self.fromZipfile(zipfile)
|
135
|
+
return
|
136
|
+
|
137
|
+
with VerboseGuard(f'Extract scenario {gsn._info._title}') as g:
|
138
|
+
gbxextractor = GBXExtractor(gsn._gbx)
|
139
|
+
self._d = {
|
140
|
+
'title': gsn._info._title,
|
141
|
+
'author': gsn._info._author,
|
142
|
+
'description': gsn._info._description.replace('\r',''),
|
143
|
+
'major': gsn._info._majorRevs,
|
144
|
+
'minor': gsn._info._minorRevs,
|
145
|
+
'version': f'{gsn._info._majorRevs}.{gsn._info._minorRevs}',
|
146
|
+
'gamebox': gbxextractor._d}
|
147
|
+
self._d['players'] = gsn._playerManager.toDict()
|
148
|
+
self._d['trays'] = gsn._trayManager.toDict()
|
149
|
+
self._d['boards'] = gsn._boards.toDict(gsn._gbx._boardManager)
|
150
|
+
|
151
|
+
|
152
|
+
def _save(self,zfile):
|
153
|
+
from pprint import pprint
|
154
|
+
from io import StringIO
|
155
|
+
from json import dumps
|
156
|
+
from copy import deepcopy
|
157
|
+
|
158
|
+
with VerboseGuard(f'Saving {self._d["title"]} to {zfile.filename}')as g:
|
159
|
+
d = deepcopy(self._d)
|
160
|
+
|
161
|
+
self.saveImages(d['gamebox'],zfile)
|
162
|
+
|
163
|
+
zfile.writestr('info.json',dumps(d,indent=2))
|
164
|
+
|
165
|
+
g(f'Done saving')
|
166
|
+
|
167
|
+
def fromZipfile(self,zipfile):
|
168
|
+
from json import loads
|
169
|
+
from PIL import Image as PILImage
|
170
|
+
from io import BytesIO
|
171
|
+
from wand.image import Image as WandImage
|
172
|
+
with VerboseGuard(f'Reading module from zip file') as v:
|
173
|
+
self._d = loads(zipfile.read('info.json').decode())
|
174
|
+
|
175
|
+
newMap = {}
|
176
|
+
for pieceSID,piece in self._d['gamebox']['pieces']['map'].items():
|
177
|
+
pieceID = int(pieceSID)
|
178
|
+
if pieceID in newMap:
|
179
|
+
continue
|
180
|
+
for which in ['front', 'back']:
|
181
|
+
if which not in piece:
|
182
|
+
continue
|
183
|
+
|
184
|
+
|
185
|
+
fn = piece[which]
|
186
|
+
v(f'Read image {fn}')
|
187
|
+
bts = BytesIO(zipfile.read(fn))
|
188
|
+
img = PILImage.open(bts)
|
189
|
+
piece[which] = {'filename': fn,
|
190
|
+
'image': img,
|
191
|
+
'size': img.size}
|
192
|
+
|
193
|
+
newMap[pieceID] = piece
|
194
|
+
|
195
|
+
del self._d['gamebox']['pieces']['map']
|
196
|
+
self._d['gamebox']['pieces']['map'] = newMap
|
197
|
+
|
198
|
+
newMap = {}
|
199
|
+
for markSID,mark in self._d['gamebox']['marks']['map'].items():
|
200
|
+
markID = int(markSID)
|
201
|
+
if markID in newMap:
|
202
|
+
continue
|
203
|
+
fn = mark['filename']
|
204
|
+
v(f'Read image {fn}')
|
205
|
+
bts = BytesIO(zipfile.read(fn))
|
206
|
+
img = PILImage.open(bts)
|
207
|
+
dsc = mark.get('description',None)
|
208
|
+
mark['image'] = img
|
209
|
+
mark['size'] = img.size
|
210
|
+
newMap[markID] = mark
|
211
|
+
|
212
|
+
del self._d['gamebox']['marks']['map']
|
213
|
+
self._d['gamebox']['marks']['map'] = newMap
|
214
|
+
|
215
|
+
newMap = {}
|
216
|
+
for boardSID,board in self._d['gamebox']['boards'].items():
|
217
|
+
boardID = int(boardSID)
|
218
|
+
if boardID in newMap:
|
219
|
+
continue
|
220
|
+
filename = board['filename']
|
221
|
+
v(f'Read file {filename}')
|
222
|
+
content = zipfile.read(filename)
|
223
|
+
img = WandImage(blob=content)
|
224
|
+
board['image'] = content.decode()
|
225
|
+
board['size'] = img.size
|
226
|
+
newMap[boardID] = board
|
227
|
+
|
228
|
+
# del self._d['gamebox']['boards']
|
229
|
+
# self._d['gamebox']['boards'] = newMap
|
230
|
+
|
231
|
+
# print(self)
|
232
|
+
|
233
|
+
def __str__(self):
|
234
|
+
from pprint import pformat
|
235
|
+
|
236
|
+
return pformat(self._d)#,depth=5)
|
237
|
+
|
238
|
+
#
|
239
|
+
# EOF
|
240
|
+
#
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# --------------------------------------------------------------------
|
2
|
+
## BEGIN_IMPORT
|
3
|
+
from common.singleton import Singleton
|
4
|
+
## END_IMPORT
|
5
|
+
|
6
|
+
class Features(metaclass=Singleton):
|
7
|
+
def __init__(self):
|
8
|
+
self.bmp_zlib = False # wxBMPHandler + Zlib
|
9
|
+
self.id_size = 2 # Size of IDs in bytes (1, 2 or 4)
|
10
|
+
self.size_size = 4 # Size of sizes in bytes (4 or 8)
|
11
|
+
self.sub_size = 2 # Size of sub-sizes in bytes (4 or 8)
|
12
|
+
self.square_cells = False # Geomorphic boards, square cells
|
13
|
+
self.rotate_unit = False # Geomorphic boards, rotated unit board
|
14
|
+
self.piece_100 = False # Pieces w/<= 100 sides
|
15
|
+
self.private_board = False #
|
16
|
+
self.roll_state = False # serialize roll state
|
17
|
+
self.little_endian = True
|
@@ -0,0 +1,81 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . head import *
|
4
|
+
from . tile import GBXTileManager
|
5
|
+
from . piece import GBXPieceManager
|
6
|
+
from . mark import GBXMarkManager
|
7
|
+
from . board import GBXBoardManager
|
8
|
+
from . archive import Archive
|
9
|
+
from . features import Features
|
10
|
+
## END_IMPORT
|
11
|
+
|
12
|
+
# --------------------------------------------------------------------
|
13
|
+
class GBXInfo:
|
14
|
+
def __init__(self,ar):
|
15
|
+
'''GameBox information'''
|
16
|
+
with VerboseGuard('Reading information') as g:
|
17
|
+
self._bitsPerPixel = ar.word() # 2 -> 2
|
18
|
+
self._majorRevs = ar.dword() # 4 -> 6
|
19
|
+
self._minorRevs = ar.dword() # 4 -> 10
|
20
|
+
self._gameID = ar.dword() # 4 -> 14
|
21
|
+
self._boxID = ar.read(16) # 16 -> 30
|
22
|
+
self._author = ar.str() # X -> 30+X
|
23
|
+
self._title = ar.str() # Y -> 30+X+Y
|
24
|
+
self._description = ar.str() # Z -> 30+X+Y+Z
|
25
|
+
self._password = ar.read(16) # 16 -> 46+X+Y+Z
|
26
|
+
self._stickyDraw = ar.word() # 2 -> 48+X+Y+Z
|
27
|
+
self._compression = ar.word() # 2 -> 50+X+Y+Z
|
28
|
+
self._reserved = [ar.word() for _ in range(4)] # 4x2 -> 58+X+Y+Z
|
29
|
+
g(f'GameBox is {self._title} by {self._author} (password: {self._password})')
|
30
|
+
|
31
|
+
def __str__(self):
|
32
|
+
return ('Information:\n'
|
33
|
+
f' Bits/pixel: {self._bitsPerPixel}\n'
|
34
|
+
f' Major revision: {self._majorRevs}\n'
|
35
|
+
f' Minor revision: {self._minorRevs}\n'
|
36
|
+
f' Game ID: {self._gameID}\n'
|
37
|
+
f' Box ID: {self._boxID}\n'
|
38
|
+
f' Author: {self._author}\n'
|
39
|
+
f' Title: {self._title}\n'
|
40
|
+
f' Description: {self._description}\n'
|
41
|
+
f' Password: {self._password}\n'
|
42
|
+
f' Sticky Draw tools: {self._stickyDraw}\n'
|
43
|
+
f' Compression level: {self._compression}\n'
|
44
|
+
f' Reserved: {self._reserved}')
|
45
|
+
|
46
|
+
|
47
|
+
# ====================================================================
|
48
|
+
class GameBox:
|
49
|
+
def __init__(self,ar):
|
50
|
+
'''Container of game'''
|
51
|
+
with VerboseGuard(f'Reading gamebox'):
|
52
|
+
self._header = GBXHeader(ar,GBXHeader.BOX)
|
53
|
+
self._info = GBXInfo(ar)
|
54
|
+
self._strings = GBXStrings(ar)
|
55
|
+
self._tileManager = GBXTileManager(ar)
|
56
|
+
self._boardManager = GBXBoardManager(ar)
|
57
|
+
self._pieceManager = GBXPieceManager(ar)
|
58
|
+
self._markManager = GBXMarkManager(ar)
|
59
|
+
|
60
|
+
# print(self._strings)
|
61
|
+
# print(self._markManager)
|
62
|
+
|
63
|
+
def __str__(self):
|
64
|
+
return (str(self._header)+
|
65
|
+
str(self._info)+
|
66
|
+
str(self._strings)+
|
67
|
+
str(self._tileManager)+
|
68
|
+
str(self._boardManager)+
|
69
|
+
str(self._pieceManager)+
|
70
|
+
str(self._markManager))
|
71
|
+
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
def fromFile(cls,filename):
|
75
|
+
with VerboseGuard(f'Read gamebox from {filename}'):
|
76
|
+
with Archive(filename,'rb') as ar:
|
77
|
+
return GameBox(ar)
|
78
|
+
|
79
|
+
#
|
80
|
+
# EOF
|
81
|
+
#
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
## BEGIN_IMPORTS
|
3
|
+
from exporter import GBXExporter
|
4
|
+
from common import Verbose
|
5
|
+
from gamebox import GameBox
|
6
|
+
from extractor import GBXExtractor
|
7
|
+
## END_IMPORTS
|
8
|
+
|
9
|
+
# ====================================================================
|
10
|
+
if __name__ == '__main__':
|
11
|
+
from argparse import ArgumentParser, FileType
|
12
|
+
|
13
|
+
ap = ArgumentParser(description='Create draft VASSAL module')
|
14
|
+
ap.add_argument('gbxfile',
|
15
|
+
help='The GBX file to data from',
|
16
|
+
type=FileType('r'))
|
17
|
+
ap.add_argument('-p','--patch',
|
18
|
+
help='A python script to patch generated module',
|
19
|
+
type=FileType('r'))
|
20
|
+
ap.add_argument('-o','--output',
|
21
|
+
help='Output file to write module to',
|
22
|
+
type=FileType('w'),
|
23
|
+
default='Draft.vmod')
|
24
|
+
ap.add_argument('-r','--rules',
|
25
|
+
help='Rules PDF file',
|
26
|
+
type=FileType('r'))
|
27
|
+
ap.add_argument('-T','--tutorial',
|
28
|
+
help='Tutorial (v)log file',
|
29
|
+
type=FileType('r'))
|
30
|
+
ap.add_argument('-W','--vassal-version',
|
31
|
+
help='Vassal version number',
|
32
|
+
type=str,
|
33
|
+
default='3.6.7')
|
34
|
+
ap.add_argument('-V','--verbose',
|
35
|
+
help='Be verbose',
|
36
|
+
action='store_true')
|
37
|
+
ap.add_argument('-G','--visible-grids',
|
38
|
+
action='store_true',
|
39
|
+
help='Make grids visible in the module')
|
40
|
+
|
41
|
+
|
42
|
+
args = ap.parse_args()
|
43
|
+
|
44
|
+
gbxname = args.gbxfile.name
|
45
|
+
vmodname = args.output.name
|
46
|
+
rulesname = args.rules.name if args.rules is not None else None
|
47
|
+
tutname = args.tutorial.name if args.tutorial is not None else None
|
48
|
+
args.output.close()
|
49
|
+
args.gbxfile.close()
|
50
|
+
|
51
|
+
patchname = args.patch.name if args.patch is not None else None
|
52
|
+
if args.patch is not None:
|
53
|
+
args.patch.close()
|
54
|
+
|
55
|
+
Verbose().setVerbose(args.verbose)
|
56
|
+
|
57
|
+
try:
|
58
|
+
gamebox = GameBox.fromFile(gbxname)
|
59
|
+
extractor = GBXExtractor(gamebox)
|
60
|
+
exporter = GBXExporter(extractor._d,
|
61
|
+
rules = rulesname,
|
62
|
+
tutorial = tutname,
|
63
|
+
visible = args.visible_grids,
|
64
|
+
vassalVersion = args.vassal_version)
|
65
|
+
exporter.run(vmodname,patchname)
|
66
|
+
except Exception as e:
|
67
|
+
from sys import stderr
|
68
|
+
print(f'Failed to build {vmodname}: {e}',file=stderr)
|
69
|
+
from os import unlink
|
70
|
+
try:
|
71
|
+
unlink(vmodname)
|
72
|
+
except:
|
73
|
+
pass
|
74
|
+
|
75
|
+
raise e
|
76
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
#
|
3
|
+
# CyberBoard GitHub page:
|
4
|
+
#
|
5
|
+
# https://github.com/CyberBoardPBEM/cbwindows
|
6
|
+
#
|
7
|
+
#
|
8
|
+
|
9
|
+
|
10
|
+
# ====================================================================
|
11
|
+
if __name__ == '__main__':
|
12
|
+
from argparse import ArgumentParser, FileType
|
13
|
+
from pathlib import Path
|
14
|
+
## BEGIN_IMPORT
|
15
|
+
from gamebox import GameBox
|
16
|
+
from extractor import GBXExtractor
|
17
|
+
from common import Verbose
|
18
|
+
## END_IMPORT
|
19
|
+
|
20
|
+
ap = ArgumentParser(description='Extract information from a '
|
21
|
+
'CyberBoard GameBox file and store in ZIP archive',
|
22
|
+
epilog='Default output file name is input file name '
|
23
|
+
'with .gbx replaced by .zip')
|
24
|
+
ap.add_argument('input', type=str, help='The file')
|
25
|
+
ap.add_argument('output',type=str, nargs='?',help='Output',default='')
|
26
|
+
ap.add_argument('-V','--verbose',
|
27
|
+
help='Be verbose',
|
28
|
+
action='store_true')
|
29
|
+
ap.add_argument('-D','--dump',type=str,nargs='*',default='',
|
30
|
+
help='Dump content')
|
31
|
+
ap.add_argument('-S','--size-bytes',type=int,choices=[4,8],
|
32
|
+
default=4, help='The size of size counts')
|
33
|
+
ap.add_argument('-I','--id-bytes',type=int,choices=[2,4],
|
34
|
+
default=2, help='The size of identifiers')
|
35
|
+
ap.add_argument('-P','--password',action='store_true',
|
36
|
+
help='Show password')
|
37
|
+
|
38
|
+
args = ap.parse_args()
|
39
|
+
Verbose().setVerbose(args.verbose)
|
40
|
+
|
41
|
+
Features().size_size = args.size_bytes
|
42
|
+
Features().id_size = args.id_bytes
|
43
|
+
|
44
|
+
gbx = GameBox.fromFile(args.input)
|
45
|
+
if args.password:
|
46
|
+
print(f'Password is "{gbx._info._password.decode()}"')
|
47
|
+
|
48
|
+
rat = GBXExtractor(gbx)
|
49
|
+
|
50
|
+
out = args.output
|
51
|
+
if out == '':
|
52
|
+
p = Path(args.input)
|
53
|
+
out = p.stem+'.zip'
|
54
|
+
|
55
|
+
rat.save(out)
|
56
|
+
|
57
|
+
if 'save' in args.dump:
|
58
|
+
print(rat)
|
59
|
+
if 'gbx' in args.dump:
|
60
|
+
print(gbx)
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
|
@@ -0,0 +1,147 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
## BEGIN_IMPORTS
|
3
|
+
from sys import path
|
4
|
+
path.append('..')
|
5
|
+
from exporter import GSNExporter
|
6
|
+
from common import Verbose
|
7
|
+
from scenario import Scenario
|
8
|
+
from extractor import GSNExtractor
|
9
|
+
from head import GBXHeader
|
10
|
+
## END_IMPORTS
|
11
|
+
|
12
|
+
# ====================================================================
|
13
|
+
if __name__ == '__main__':
|
14
|
+
from argparse import ArgumentParser, FileType, \
|
15
|
+
RawDescriptionHelpFormatter
|
16
|
+
from textwrap import wrap, dedent
|
17
|
+
from pathlib import Path
|
18
|
+
|
19
|
+
w = lambda s : '\n\n'.join(['\n'.join(wrap(p))
|
20
|
+
for p in dedent(s).split('\n\n')])
|
21
|
+
e = '''
|
22
|
+
The script can only handle CyberBoard game boxes and scenarios
|
23
|
+
from version 3 and up. Use CBDesign.exe and CBPlay.exe to
|
24
|
+
upgrade any pre-version 3 '.gbx' and '.gsn' files, respectively.
|
25
|
+
|
26
|
+
You can override the game box files searched for by passing
|
27
|
+
that game box file name to the option '--gamebox'.
|
28
|
+
|
29
|
+
If the script finds the wrong main map, try passing the name
|
30
|
+
of the main board as argument to the option '--main-board'.
|
31
|
+
|
32
|
+
If the script adds boards (maps) to the 'Charts' menu,
|
33
|
+
rather than as maps, pass a regular expression to match
|
34
|
+
these board names, as argument to the option '--map-regex'.
|
35
|
+
|
36
|
+
Pass a Python script with the option -p to do
|
37
|
+
user post-processing with that script. Use the
|
38
|
+
pywargame VASSAL API to do all sorts of manipulations.
|
39
|
+
'''
|
40
|
+
|
41
|
+
ap = ArgumentParser(description='Create draft VASSAL module',
|
42
|
+
formatter_class= RawDescriptionHelpFormatter,
|
43
|
+
epilog=w(e))
|
44
|
+
ap.add_argument('gsnfile',
|
45
|
+
help='The GSN file to data from',
|
46
|
+
type=FileType('rb'))
|
47
|
+
ap.add_argument('-p','--patch',
|
48
|
+
help='A python script to patch generated module',
|
49
|
+
type=FileType('r'))
|
50
|
+
ap.add_argument('-o','--output',
|
51
|
+
help='Output file to write module to',
|
52
|
+
type=str,
|
53
|
+
default='')
|
54
|
+
ap.add_argument('-t','--title',
|
55
|
+
help='Override title',
|
56
|
+
type=str,
|
57
|
+
default=None)
|
58
|
+
ap.add_argument('-v','--version',
|
59
|
+
help='Override version',
|
60
|
+
type=str,
|
61
|
+
default=None)
|
62
|
+
ap.add_argument('-r','--rules',
|
63
|
+
help='Rules PDF file',
|
64
|
+
type=FileType('r'))
|
65
|
+
ap.add_argument('-T','--tutorial',
|
66
|
+
help='Tutorial (v)log file',
|
67
|
+
type=FileType('r'))
|
68
|
+
ap.add_argument('-W','--vassal-version',
|
69
|
+
help='Vassal version number',
|
70
|
+
type=str,
|
71
|
+
default='3.7.0')
|
72
|
+
ap.add_argument('-V','--verbose',
|
73
|
+
help='Be verbose',
|
74
|
+
action='store_true')
|
75
|
+
ap.add_argument('-G','--visible-grids',
|
76
|
+
action='store_true',
|
77
|
+
help='Make grids visible in the module')
|
78
|
+
ap.add_argument('-X','--gamebox',
|
79
|
+
type=str,
|
80
|
+
default=None,
|
81
|
+
help='Override gamebox (.gbx) file')
|
82
|
+
ap.add_argument('-M','--main-board',
|
83
|
+
type=str,
|
84
|
+
default=None,
|
85
|
+
help='Set the main board')
|
86
|
+
ap.add_argument('-R','--map-regex',
|
87
|
+
type=str,
|
88
|
+
default=None,
|
89
|
+
help='Regular expression to match additional maps')
|
90
|
+
ap.add_argument('-S','--scenario',
|
91
|
+
action='store_true',
|
92
|
+
help='Make scenario rather than at-start placements')
|
93
|
+
|
94
|
+
|
95
|
+
args = ap.parse_args()
|
96
|
+
|
97
|
+
gsnname = args.gsnfile.name
|
98
|
+
zipfile = None
|
99
|
+
vmodname = args.output
|
100
|
+
rulesname = args.rules.name if args.rules is not None else None
|
101
|
+
tutname = args.tutorial.name if args.tutorial is not None else None
|
102
|
+
# Read first 4 bytes from input to see if we're dealing with a GSN file
|
103
|
+
magic = args.gsnfile.read(4)
|
104
|
+
args.gsnfile.close()
|
105
|
+
if magic != GBXHeader.SCENARIO.encode():
|
106
|
+
if magic[:2] == 'PK'.encode():
|
107
|
+
from zipfile import ZipFile
|
108
|
+
zipfile = ZipFile(gsnname,'r')
|
109
|
+
# args.output.close()
|
110
|
+
|
111
|
+
if vmodname == '':
|
112
|
+
p = Path(gsnname)
|
113
|
+
vmodname = p.stem+'.vmod'
|
114
|
+
|
115
|
+
patchname = args.patch.name if args.patch is not None else None
|
116
|
+
if args.patch is not None:
|
117
|
+
args.patch.close()
|
118
|
+
|
119
|
+
Verbose().setVerbose(args.verbose)
|
120
|
+
|
121
|
+
try:
|
122
|
+
scenario = None
|
123
|
+
if zipfile is None:
|
124
|
+
scenario = Scenario.fromFile(gsnname,args.gamebox)
|
125
|
+
extractor = GSNExtractor(scenario,zipfile)
|
126
|
+
exporter = GSNExporter(extractor._d,
|
127
|
+
title = args.title,
|
128
|
+
version = args.version,
|
129
|
+
rules = rulesname,
|
130
|
+
tutorial = tutname,
|
131
|
+
visible = args.visible_grids,
|
132
|
+
main_board = args.main_board,
|
133
|
+
map_regex = args.map_regex,
|
134
|
+
vassalVersion = args.vassal_version,
|
135
|
+
do_scenario = args.scenario)
|
136
|
+
exporter.run(vmodname,patchname)
|
137
|
+
except Exception as e:
|
138
|
+
from sys import stderr
|
139
|
+
print(f'Failed to build {vmodname}: {e}',file=stderr)
|
140
|
+
from os import unlink
|
141
|
+
try:
|
142
|
+
unlink(vmodname)
|
143
|
+
except:
|
144
|
+
pass
|
145
|
+
|
146
|
+
raise e
|
147
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
#
|
3
|
+
# CyberBoard GitHub page:
|
4
|
+
#
|
5
|
+
# https://github.com/CyberBoardPBEM/cbwindows
|
6
|
+
#
|
7
|
+
#
|
8
|
+
|
9
|
+
|
10
|
+
# ====================================================================
|
11
|
+
if __name__ == '__main__':
|
12
|
+
from argparse import ArgumentParser, FileType
|
13
|
+
from pathlib import Path
|
14
|
+
## BEGIN_IMPORT
|
15
|
+
from scenario import Scenario
|
16
|
+
from extractor import GSNExtractor
|
17
|
+
from common import Verbose
|
18
|
+
## END_IMPORT
|
19
|
+
|
20
|
+
ap = ArgumentParser(description='Extract information from a '
|
21
|
+
'CyberBoard Scenario file and store in ZIP archive',
|
22
|
+
epilog='Default output file name is input file name '
|
23
|
+
'with .gsn replaced by .zip')
|
24
|
+
ap.add_argument('input', type=str, help='The file')
|
25
|
+
ap.add_argument('output',type=str, nargs='?',help='Output',default='')
|
26
|
+
ap.add_argument('-V','--verbose',
|
27
|
+
help='Be verbose',
|
28
|
+
action='store_true')
|
29
|
+
ap.add_argument('-D','--dump',type=str,nargs='*',default='',
|
30
|
+
help='Dump content')
|
31
|
+
ap.add_argument('-X','--gamebox',
|
32
|
+
type=str,
|
33
|
+
default=None,
|
34
|
+
help='Override gamebox (.gbx) file')
|
35
|
+
|
36
|
+
args = ap.parse_args()
|
37
|
+
Verbose().setVerbose(args.verbose)
|
38
|
+
|
39
|
+
gsn = Scenario.fromFile(args.input,args.gamebox)
|
40
|
+
rat = GSNExtractor(gsn)
|
41
|
+
|
42
|
+
out = args.output
|
43
|
+
if out == '':
|
44
|
+
p = Path(args.input)
|
45
|
+
out = p.stem+'.zip'
|
46
|
+
rat.save(out)
|
47
|
+
|
48
|
+
if 'save' in args.dump:
|
49
|
+
print(rat)
|
50
|
+
if 'gsn' in args.dump:
|
51
|
+
print(gsn)
|
52
|
+
|
53
|
+
#
|
54
|
+
# EOF
|
55
|
+
#
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|