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,462 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . draw import GBXDrawList
|
4
|
+
from . cell import GBXCell, GBXCellGeometry
|
5
|
+
from . base import CbManager, CbFont
|
6
|
+
from . head import num_version
|
7
|
+
## END_IMPORT
|
8
|
+
|
9
|
+
# --------------------------------------------------------------------
|
10
|
+
class GBXBoardCalculator:
|
11
|
+
def __init__(self,board):
|
12
|
+
self._geometry = board._full
|
13
|
+
self._nRows = board._nRows
|
14
|
+
self._nCols = board._nCols
|
15
|
+
self._rowOffset = board._rowOffset
|
16
|
+
self._colOffset = board._colOffset
|
17
|
+
self._rowInvert = board._rowInvert
|
18
|
+
self._colInvert = board._colInvert
|
19
|
+
|
20
|
+
def __call__(self,x,y):
|
21
|
+
# Shift depending on grid type and stagger
|
22
|
+
row, col = self._geometry.inverse(x,y)
|
23
|
+
if self._rowInvert:
|
24
|
+
row = self._nRows - row - 1
|
25
|
+
if self._colInvert:
|
26
|
+
col = self._nCols - col - 1
|
27
|
+
|
28
|
+
return row+self._rowOffset, col+self._colOffset
|
29
|
+
|
30
|
+
# --------------------------------------------------------------------
|
31
|
+
class GBXBoard:
|
32
|
+
def __init__(self,ar):
|
33
|
+
'''A board'''
|
34
|
+
with VerboseGuard(f'Reading board') as g:
|
35
|
+
self._serial = ar.iden()
|
36
|
+
self._visible = ar.word()
|
37
|
+
self._snap = ar.word()
|
38
|
+
self._xSnap = ar.dword()
|
39
|
+
self._ySnap = ar.dword()
|
40
|
+
self._xSnapOffset = ar.dword()
|
41
|
+
self._ySnapOffset = ar.dword()
|
42
|
+
self._maxLayer = ar.word()
|
43
|
+
self._background = ar.dword()
|
44
|
+
self._name = ar.str()
|
45
|
+
hasDraw = ar.word()
|
46
|
+
self._baseDraw = GBXDrawList(ar) if hasDraw else None
|
47
|
+
|
48
|
+
self._showCellBorder = ar.word()
|
49
|
+
self._topCellBorder = ar.word()
|
50
|
+
self._reserved = [ar.word() for _ in range(4)]
|
51
|
+
self._reserved2 = None
|
52
|
+
self._rowOffset = 0
|
53
|
+
self._colOffset = 0
|
54
|
+
self._rowInvert = False
|
55
|
+
self._colInvert = False
|
56
|
+
self._nRows = 0
|
57
|
+
self._nCols = 0
|
58
|
+
self._transparent = False
|
59
|
+
self._numbers = 0
|
60
|
+
self._trackCell = False
|
61
|
+
self._frameColor = 0xFF000000
|
62
|
+
self._full = None
|
63
|
+
self._half = None
|
64
|
+
self._small = None
|
65
|
+
self._map = []
|
66
|
+
self._topDraw = None
|
67
|
+
|
68
|
+
hasArray = ar.word()
|
69
|
+
if hasArray != 0:
|
70
|
+
self._reserved2 = [ar.word() for _ in range(4)]
|
71
|
+
self._rowOffset = ar.word()
|
72
|
+
self._colOffset = ar.word()
|
73
|
+
self._rowInvert = ar.word()
|
74
|
+
self._colInvert = ar.word()
|
75
|
+
self._nRows = ar.int(Features().sub_size)
|
76
|
+
self._nCols = ar.int(Features().sub_size)
|
77
|
+
self._transparent = ar.word()
|
78
|
+
self._numbers = ar.word()
|
79
|
+
self._trackCell = ar.word()
|
80
|
+
self._frameColor = ar.dword()
|
81
|
+
|
82
|
+
self._full = GBXCellGeometry(ar)
|
83
|
+
self._half = GBXCellGeometry(ar)
|
84
|
+
self._small = GBXCellGeometry(ar)
|
85
|
+
|
86
|
+
self._map = [[GBXCell(ar,row,col) for col in range(self._nCols)]
|
87
|
+
for row in range(self._nRows)]
|
88
|
+
|
89
|
+
hasDraw = ar.word()
|
90
|
+
self._topDraw = GBXDrawList(ar) if hasDraw else None
|
91
|
+
g(f'Board background read: {self._background:06x}, frame color: {self._frameColor:06x}')
|
92
|
+
|
93
|
+
def toDict(self,tileManager,markManager,strings,no,boardDigits,
|
94
|
+
alsoMap=True):
|
95
|
+
from io import StringIO
|
96
|
+
|
97
|
+
with VerboseGuard(f'Making dict of board {self._name}') as g:
|
98
|
+
sav = f'board_{no:0{boardDigits}d}.svg'
|
99
|
+
g(f'File to save in: {sav}')
|
100
|
+
dct = {'name': self._name,
|
101
|
+
'serial': self._serial,
|
102
|
+
'visible': self._visible,
|
103
|
+
'snap': {
|
104
|
+
'enable': self._snap,
|
105
|
+
'x': {
|
106
|
+
'distance': self._xSnap,
|
107
|
+
'offset': self._xSnapOffset
|
108
|
+
},
|
109
|
+
'y': {
|
110
|
+
'distance': self._ySnap,
|
111
|
+
'offset': self._ySnapOffset
|
112
|
+
}
|
113
|
+
},
|
114
|
+
'max layer': self._maxLayer,
|
115
|
+
'cell border': {
|
116
|
+
'visible': self._showCellBorder,
|
117
|
+
'on top layer': self._topCellBorder,
|
118
|
+
},
|
119
|
+
'rows': {
|
120
|
+
'size': self._nRows,
|
121
|
+
'offset': self._rowOffset,
|
122
|
+
'inverted': self._rowInvert
|
123
|
+
},
|
124
|
+
'columns': {
|
125
|
+
'size': self._nCols,
|
126
|
+
'offset': self._colOffset,
|
127
|
+
'inverted': self._colInvert
|
128
|
+
},
|
129
|
+
'cells': {
|
130
|
+
'transparent': self._transparent,
|
131
|
+
'foreground': self._frameColor,
|
132
|
+
},
|
133
|
+
'numbering': {
|
134
|
+
'order': 'V' if self._numbers % 2 == 0 else 'H',
|
135
|
+
'padding': self._numbers in [2,3],
|
136
|
+
'first': 'A' if self._numbers in [4,5] else 'N'
|
137
|
+
}
|
138
|
+
}
|
139
|
+
if self._full is not None:
|
140
|
+
dct['cells']['geometry'] = self._full.toDict()
|
141
|
+
if alsoMap and self._map is not None:
|
142
|
+
dct['cells']['list'] = [[c.toDict(tileManager,self._full)
|
143
|
+
for c in row]
|
144
|
+
for row in self._map]
|
145
|
+
|
146
|
+
|
147
|
+
sav = f'board_{no:0{boardDigits}d}.svg'
|
148
|
+
img = self.drawing(sav,
|
149
|
+
tileManager=tileManager,
|
150
|
+
markManager=markManager)
|
151
|
+
# img.save(pretty=True)
|
152
|
+
|
153
|
+
stream = StringIO()
|
154
|
+
img.write(stream,pretty=True)
|
155
|
+
|
156
|
+
dct['filename'] = sav
|
157
|
+
dct['image'] = stream.getvalue()#img.tostring()
|
158
|
+
dct['size'] = self._full.boardSize(self._nRows,self._nCols)
|
159
|
+
|
160
|
+
return dct
|
161
|
+
|
162
|
+
def drawing(self,sav,tileManager,markManager,*args,**kwargs):
|
163
|
+
from svgwrite import Drawing
|
164
|
+
from svgwrite.base import Title
|
165
|
+
with VerboseGuard(f'Making SVG of board {self._name}') as g:
|
166
|
+
size = self._full.boardSize(self._nRows,self._nCols)
|
167
|
+
dwg = Drawing(filename=sav,size=size)
|
168
|
+
frame, defMap, patMap = self.defs(dwg,tileManager,markManager)
|
169
|
+
|
170
|
+
# Draw background
|
171
|
+
g(f'Board background: {self._background:06x} {GBXDraw.hex(self._background)}')
|
172
|
+
dwg.add(Title(self._name))
|
173
|
+
dwg.add(dwg.rect(id='background',
|
174
|
+
insert=(0,0),
|
175
|
+
size=size,
|
176
|
+
fill=GBXDraw.hex(self._background)
|
177
|
+
#f'#{self._background:06x}')
|
178
|
+
))
|
179
|
+
# GBXDraw.hex(self._background)
|
180
|
+
|
181
|
+
g('Drawing base layer')
|
182
|
+
bse = self.base (dwg, 0, defMap)
|
183
|
+
g('Drawing cells')
|
184
|
+
grd = self.cells(dwg, frame, patMap)
|
185
|
+
if self._showCellBorder and not self._topCellBorder:
|
186
|
+
self.borders(dwg,frame)
|
187
|
+
g('Drawing top layer')
|
188
|
+
top1 = self.top (dwg, 1, defMap)
|
189
|
+
if self._showCellBorder and self._topCellBorder:
|
190
|
+
self.borders(dwg,frame)
|
191
|
+
top2 = self.top (dwg, 2, defMap)
|
192
|
+
|
193
|
+
return dwg
|
194
|
+
|
195
|
+
def defs(self,dwg,tileManager,markManager):
|
196
|
+
defMap = {}
|
197
|
+
patMap = {}
|
198
|
+
frame = self._full.svgDef(dwg)
|
199
|
+
defMap['cell'] = frame
|
200
|
+
|
201
|
+
# Get defininitions from base layer
|
202
|
+
if self._baseDraw:
|
203
|
+
self._baseDraw.svgDefs(dwg,
|
204
|
+
tileManager,
|
205
|
+
markManager,
|
206
|
+
defMap)
|
207
|
+
# Get definitions from cell layer
|
208
|
+
for row in self._map:
|
209
|
+
for cell in row:
|
210
|
+
cell.svgDef(dwg,tileManager,patMap)
|
211
|
+
|
212
|
+
# Get definitions from top layer
|
213
|
+
if self._topDraw:
|
214
|
+
self._topDraw.svgDefs(dwg,
|
215
|
+
tileManager,
|
216
|
+
markManager,
|
217
|
+
defMap)
|
218
|
+
|
219
|
+
return frame, defMap, patMap
|
220
|
+
|
221
|
+
def base(self,dwg,passNo,defMap):
|
222
|
+
bse = dwg.add(dwg.g(id=f'base_{passNo:02d}'))
|
223
|
+
if self._baseDraw:
|
224
|
+
self._baseDraw.svg(dwg,bse,passNo,defMap)
|
225
|
+
|
226
|
+
return bse
|
227
|
+
|
228
|
+
def cells(self,dwg,frame,patMap):
|
229
|
+
grd = dwg.add(dwg.g(id='grid'))
|
230
|
+
for row in self._map:
|
231
|
+
for cell in row:
|
232
|
+
cell.svg(dwg,grd,frame,self._full,patMap)
|
233
|
+
|
234
|
+
return grd
|
235
|
+
|
236
|
+
def borders(self,dwg,frame):
|
237
|
+
brd = dwg.add(dwg.g(id='borders'))
|
238
|
+
for row in self._map:
|
239
|
+
for cell in row:
|
240
|
+
cell.svgFrame(dwg,brd,frame,self._full,self._frameColor)
|
241
|
+
|
242
|
+
return brd
|
243
|
+
|
244
|
+
def top(self,dwg,passNo,defMap):
|
245
|
+
top = dwg.add(dwg.g(id=f'top_{passNo:02d}'))
|
246
|
+
if self._topDraw:
|
247
|
+
self._topDraw.svg (dwg,top,passNo,defMap)
|
248
|
+
|
249
|
+
return top
|
250
|
+
|
251
|
+
def __str__(self):
|
252
|
+
return (f'GBXBoard: {self._name}\n'
|
253
|
+
f' serial: {self._serial}\n'
|
254
|
+
f' visible: {self._visible}\n'
|
255
|
+
f' snap: {self._snap}\n'
|
256
|
+
f' xSnap: {self._xSnap}\n'
|
257
|
+
f' ySnap: {self._ySnap}\n'
|
258
|
+
f' xSnapOffset: {self._xSnapOffset}\n'
|
259
|
+
f' ySnapOffset: {self._ySnapOffset}\n'
|
260
|
+
f' maxLayer: {self._maxLayer}\n'
|
261
|
+
f' background: {self._background:08x}\n'
|
262
|
+
f' Base draws: {self._baseDraw}\n'
|
263
|
+
f' Show cell border: {self._showCellBorder}\n'
|
264
|
+
f' Top cell border: {self._topCellBorder}\n'
|
265
|
+
f' Reserved: {self._reserved}\n'
|
266
|
+
f' Reserved2: {self._reserved}\n'
|
267
|
+
f' Row offset: {self._rowOffset}\n'
|
268
|
+
f' Column offset: {self._colOffset}\n'
|
269
|
+
f' Row invert: {self._rowInvert}\n'
|
270
|
+
f' Colunn invert: {self._colInvert}\n'
|
271
|
+
f' # Rows: {self._nRows}\n'
|
272
|
+
f' # Cols: {self._nCols}\n'
|
273
|
+
f' Transparent: {self._transparent}\n'
|
274
|
+
f' Numbers: {self._numbers}\n'
|
275
|
+
f' Track cells: {self._trackCell}\n'
|
276
|
+
f' Frame color: {self._frameColor:08x}\n'
|
277
|
+
f' Full geometry: {self._full}\n'
|
278
|
+
f' Half geometry: {self._half}\n'
|
279
|
+
f' Small geometry: {self._small}\n'
|
280
|
+
f' Top draws: {self._topDraw}'
|
281
|
+
)
|
282
|
+
|
283
|
+
|
284
|
+
|
285
|
+
|
286
|
+
# --------------------------------------------------------------------
|
287
|
+
class GBXBoardManager(CbManager):
|
288
|
+
def __init__(self,ar):
|
289
|
+
'''Manager of boards'''
|
290
|
+
with VerboseGuard(f'Reading board manager'):
|
291
|
+
self._nextSerial = ar.iden()
|
292
|
+
super(GBXBoardManager,self).__init__(ar)
|
293
|
+
# print(Features().id_size)
|
294
|
+
self._boards = self._readSub(ar,GBXBoard)
|
295
|
+
|
296
|
+
def __len__(self):
|
297
|
+
return len(self._boards)
|
298
|
+
|
299
|
+
def bySerial(self,serial):
|
300
|
+
for b in self._boards:
|
301
|
+
if b._serial == serial:
|
302
|
+
return b
|
303
|
+
|
304
|
+
return None
|
305
|
+
|
306
|
+
def toDict(self,tileManager,markManager,strings):
|
307
|
+
from math import log10, ceil
|
308
|
+
with VerboseGuard(f'Making dict board manager'):
|
309
|
+
boardDigits = int(ceil(log10(len(self)+.5)))
|
310
|
+
|
311
|
+
return {b._serial:
|
312
|
+
b.toDict(tileManager,markManager,strings,no,boardDigits)
|
313
|
+
for no, b in enumerate(self._boards)}
|
314
|
+
|
315
|
+
def __str__(self):
|
316
|
+
return ('GBXBoard manager:\n'
|
317
|
+
+ f' Next serial: {self._nextSerial:08x}\n'
|
318
|
+
+ super(GBXBoardManager,self).__str__()
|
319
|
+
+ self._strSub('boards',self._boards))
|
320
|
+
|
321
|
+
# --------------------------------------------------------------------
|
322
|
+
class GSNGeomorphicElement:
|
323
|
+
def __init__(self,ar):
|
324
|
+
with VerboseGuard('Reading geomorphic element'):
|
325
|
+
self._serial = ar.word()
|
326
|
+
|
327
|
+
def __str__(self):
|
328
|
+
return f'GSNGeomorphicElement: {self._serial}'
|
329
|
+
|
330
|
+
# --------------------------------------------------------------------
|
331
|
+
class GSNGeomorphicBoard:
|
332
|
+
def __init__(self,ar):
|
333
|
+
with VerboseGuard('Reading geomorphic board'):
|
334
|
+
self._name = ar.str()
|
335
|
+
self._nRows = ar.word()
|
336
|
+
self._nCols = ar.word()
|
337
|
+
n = ar.word()
|
338
|
+
self._elements = [GSNGeomorphicElement(ar) for _ in range(n)]
|
339
|
+
|
340
|
+
def __str__(self):
|
341
|
+
pl = '\n '.join([str(s) for s in self._elements])
|
342
|
+
return (f'GeomorphicBoard: {self._name}\n'
|
343
|
+
f' Size: {self._nRows}x{self._nCols}\n'
|
344
|
+
f' Elements:\n {pl}\n')
|
345
|
+
|
346
|
+
# --------------------------------------------------------------------
|
347
|
+
class GSNBoard:
|
348
|
+
def __init__(self,ar,vers):
|
349
|
+
with VerboseGuard(f'Reading scenario board {vers//256}.{vers%256}'):
|
350
|
+
hasGeo = ar.byte()
|
351
|
+
self._geo = GSNGeomorphicBoard(ar) if hasGeo else None
|
352
|
+
self._serial = ar.iden()
|
353
|
+
self._snap = ar.word()
|
354
|
+
self._xSnap = ar.dword()
|
355
|
+
self._ySnap = ar.dword()
|
356
|
+
self._xSnapOffset = ar.dword()
|
357
|
+
self._ySnapOffset = ar.dword()
|
358
|
+
self._xStagger = ar.word()
|
359
|
+
self._yStagger = ar.word()
|
360
|
+
self._piecesVisible = ar.word()
|
361
|
+
self._blockBeneath = ar.word()
|
362
|
+
self._rotate180 = ar.word()
|
363
|
+
self._showTiny = ar.word()
|
364
|
+
self._indicatorsVisible= ar.word()
|
365
|
+
self._cellBorders = ar.word()
|
366
|
+
self._smallCellBorders = ar.word()
|
367
|
+
self._enforceLocks = ar.word()
|
368
|
+
self._plotLineColor = ar.dword()
|
369
|
+
self._plotLineWidth = ar.word()
|
370
|
+
self._lineColor = ar.dword()
|
371
|
+
self._lineWidth = ar.word()
|
372
|
+
self._textColor = ar.dword()
|
373
|
+
self._textBoxColor = ar.dword()
|
374
|
+
self._font = CbFont(ar)
|
375
|
+
self._gridCenters = ar.word()
|
376
|
+
self._snapMove = ar.word()
|
377
|
+
self._indactorsTop = ar.word()
|
378
|
+
self._openOnLoad = ar.word()
|
379
|
+
self._prevPlotMode = ar.word()
|
380
|
+
self._prevPlotX = ar.word()
|
381
|
+
self._prevPlotY = ar.word()
|
382
|
+
self._ownerMask = (ar.word() if vers < num_version(3,10) else
|
383
|
+
ar.dword())
|
384
|
+
self._restrictToOwner = ar.word()
|
385
|
+
self._pieces = GBXDrawList(ar)
|
386
|
+
self._indicators = GBXDrawList(ar)
|
387
|
+
|
388
|
+
|
389
|
+
def toDict(self,boardManager):
|
390
|
+
board = (None if boardManager is None else
|
391
|
+
boardManager.bySerial(self._serial))
|
392
|
+
geom = None if board is None else board._full
|
393
|
+
calc = None if geom is None else GBXBoardCalculator(board)
|
394
|
+
|
395
|
+
return {
|
396
|
+
'onload': self._openOnLoad != 0,
|
397
|
+
'snap': {
|
398
|
+
'enable': self._snap,
|
399
|
+
'onmove': self._snapMove != 0,
|
400
|
+
'gridCenter': self._gridCenters != 0,
|
401
|
+
'x': {
|
402
|
+
'distance': self._xSnap,
|
403
|
+
'offset': self._xSnapOffset
|
404
|
+
},
|
405
|
+
'y': {
|
406
|
+
'distance': self._ySnap,
|
407
|
+
'offset': self._ySnapOffset
|
408
|
+
}
|
409
|
+
},
|
410
|
+
'moves': {
|
411
|
+
'color': self._plotLineColor,
|
412
|
+
'width': self._plotLineWidth
|
413
|
+
},
|
414
|
+
'stacking': [self._xStagger, self._yStagger],
|
415
|
+
'owner': self._ownerMask,
|
416
|
+
'restrict': self._restrictToOwner != 0,
|
417
|
+
'grid': {
|
418
|
+
'show': self._cellBorders != 0,
|
419
|
+
'color': self._lineColor,
|
420
|
+
'width': self._lineWidth
|
421
|
+
},
|
422
|
+
'pieces': self._pieces.toDict(calc),
|
423
|
+
'indicators': self._indicators.toDict(calc)
|
424
|
+
}
|
425
|
+
|
426
|
+
def __str__(self):
|
427
|
+
return (f'ScenarioBoard: {self._serial}'
|
428
|
+
f' Geomorphic: {"None" if self._geo is None else self._geo}\n'
|
429
|
+
f' Font: {self._font}\n'
|
430
|
+
f' Pieces:\n{str(self._pieces)}\n'
|
431
|
+
f' Indicators:\n{str(self._indicators)}')
|
432
|
+
|
433
|
+
# --------------------------------------------------------------------
|
434
|
+
class GSNBoardManager:
|
435
|
+
def __init__(self,ar,vers):
|
436
|
+
with VerboseGuard(f'Reading scenario board manager') as g:
|
437
|
+
self._nextGeoSerial = ar.iden()
|
438
|
+
self._reserved = [ar.word() for _ in range(3)]
|
439
|
+
n = ar.sub_size()
|
440
|
+
g(f'Got {n} boards to read')
|
441
|
+
self._boards = [GSNBoard(ar,vers) for _ in range(n)]
|
442
|
+
|
443
|
+
def toDict(self,boardManager):
|
444
|
+
hasStart = False
|
445
|
+
for b in self._boards:
|
446
|
+
if b._openOnLoad:
|
447
|
+
hasStart = True
|
448
|
+
|
449
|
+
# Make sure at least one map is loaded
|
450
|
+
if not hasStart and len(self._boards) > 0:
|
451
|
+
self._boards[0]._openOnLoad = True
|
452
|
+
|
453
|
+
return {b._serial: b.toDict(boardManager) for b in self._boards }
|
454
|
+
|
455
|
+
def __str__(self):
|
456
|
+
pl = '\n '.join([str(s) for s in self._boards])
|
457
|
+
return f'GSNBoardManager: {self._nextGeoSerial}\n {pl}\n'
|
458
|
+
|
459
|
+
#
|
460
|
+
# EOF
|
461
|
+
#
|
462
|
+
|
@@ -0,0 +1,200 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . image import GBXImage
|
4
|
+
from . draw import GBXDraw
|
5
|
+
## END_IMPORT
|
6
|
+
|
7
|
+
# ====================================================================
|
8
|
+
class GBXCellGeometry:
|
9
|
+
RECTANGLE = 0
|
10
|
+
HORIZONTAL_BRICK = 1
|
11
|
+
VERTICAL_BRICK = 2
|
12
|
+
HEXAGON = 3
|
13
|
+
SIDEWAYS_HEXAGON = 4
|
14
|
+
STAGGER_OUT = 0
|
15
|
+
STAGGER_IN = 1
|
16
|
+
TYPES = {
|
17
|
+
RECTANGLE : 'rectangle',
|
18
|
+
HORIZONTAL_BRICK: 'horizontal brick',
|
19
|
+
VERTICAL_BRICK : 'vertical brick',
|
20
|
+
HEXAGON : 'hexagon',
|
21
|
+
SIDEWAYS_HEXAGON: 'sideways hexagon'
|
22
|
+
}
|
23
|
+
STAGGERS = {
|
24
|
+
STAGGER_OUT: 'out',
|
25
|
+
STAGGER_IN: 'in'
|
26
|
+
}
|
27
|
+
|
28
|
+
def __init__(self,ar):
|
29
|
+
'''The geometry of cells'''
|
30
|
+
with VerboseGuard('Reading cell geometry'):
|
31
|
+
from numpy import max
|
32
|
+
|
33
|
+
self._type = ar.word()
|
34
|
+
self._stagger = ar.word()
|
35
|
+
self._left = ar.word()
|
36
|
+
self._top = ar.word()
|
37
|
+
self._right = ar.word()
|
38
|
+
self._bottom = ar.word()
|
39
|
+
n = 7 if self._type > 2 else 5
|
40
|
+
self._points = [[ar.word(),ar.word()] for _ in range(n)]
|
41
|
+
size = max(self._points,axis=0)
|
42
|
+
self._dx = int(size[0])
|
43
|
+
self._dy = int(size[1])
|
44
|
+
self._size = [self._dx,self._dy]
|
45
|
+
|
46
|
+
if self._type == self.HEXAGON:
|
47
|
+
self._dx = int(0.75 * self._dx)
|
48
|
+
elif self._type == self.SIDEWAYS_HEXAGON:
|
49
|
+
self._dy = int(0.75 * self._dy)
|
50
|
+
|
51
|
+
def toDict(self):
|
52
|
+
from numpy import max
|
53
|
+
return {'shape': self.TYPES.get(self._type,''),
|
54
|
+
'stagger': self.STAGGERS.get(self._stagger,''),
|
55
|
+
'size': self._size,
|
56
|
+
'bounding box (ltrb)':
|
57
|
+
(self._left, self._top, self._right, self._bottom),
|
58
|
+
'points': self._points }
|
59
|
+
|
60
|
+
def svgDef(self,dwg):
|
61
|
+
with VerboseGuard('Defining SVG cell geometry'):
|
62
|
+
if self._type in [0,1,2]:
|
63
|
+
return dwg.defs.add(dwg.rect(id='cell',
|
64
|
+
size=(self._right-self._left,
|
65
|
+
self._bottom-self._top)))
|
66
|
+
|
67
|
+
return dwg.defs.add(dwg.polygon(self._points,id='cell'))
|
68
|
+
|
69
|
+
def translate(self,row,col,center=False):
|
70
|
+
x = col * self._dx
|
71
|
+
y = row * self._dy
|
72
|
+
if self._type == self.RECTANGLE: # No offset for rectangles
|
73
|
+
return x,y
|
74
|
+
if self._type in [self.HORIZONTAL_BRICK,self.SIDEWAYS_HEXAGON]:
|
75
|
+
x += self._dx//2 if (row % 2) != self._stagger else 0
|
76
|
+
if self._type in [self.VERTICAL_BRICK,self.HEXAGON]:
|
77
|
+
y += self._dy//2 if (col % 2) != self._stagger else 0
|
78
|
+
if center:
|
79
|
+
x += self._size[0]//2
|
80
|
+
y += self._size[1]//2
|
81
|
+
return x,y
|
82
|
+
|
83
|
+
def inverse(self,x,y):
|
84
|
+
col = x / self._dx
|
85
|
+
row = y / self._dy
|
86
|
+
if self._type in [self.HORIZONTAL_BRICK,self.SIDEWAYS_HEXAGON]:
|
87
|
+
col -= .5 if (int(row) % 2) != self._stagger else 0
|
88
|
+
if self._type in [self.VERTICAL_BRICK,self.HEXAGON]:
|
89
|
+
row -= .5 if (int(col) % 2) != self._stagger else 0
|
90
|
+
|
91
|
+
# CyberBoard start at 1
|
92
|
+
return int(row)+1, int(col)+1
|
93
|
+
|
94
|
+
|
95
|
+
def boardSize(self,nrows,ncols):
|
96
|
+
w = ncols * self._dx
|
97
|
+
h = nrows * self._dy
|
98
|
+
|
99
|
+
if self._type in [2,3]:
|
100
|
+
h += self._dy // 2
|
101
|
+
if self._type in [1,4]:
|
102
|
+
w += self._dx // 2
|
103
|
+
if self._type == 3:
|
104
|
+
w += self._dx // 3
|
105
|
+
if self._type == 4:
|
106
|
+
h += self._dy // 3
|
107
|
+
|
108
|
+
return w+1,h+1
|
109
|
+
|
110
|
+
def __str__(self):
|
111
|
+
return (f'type: {self.TYPES.get(self._type,"")} '
|
112
|
+
+ f'stagger: {self.STAGGERS.get(self._stagger,"")} '
|
113
|
+
+ f'({self._left},{self._top})x({self._right},{self._bottom}) '
|
114
|
+
+ f': [{self._points}]')
|
115
|
+
|
116
|
+
|
117
|
+
# --------------------------------------------------------------------
|
118
|
+
class GBXCell:
|
119
|
+
def __init__(self,ar,row,column):
|
120
|
+
'''A single cell'''
|
121
|
+
with VerboseGuard(f'Reading cell row={row} column={column}'):
|
122
|
+
self._row = row
|
123
|
+
self._column = column
|
124
|
+
if Features().id_size == 4:
|
125
|
+
self._is_tile = ar.byte();
|
126
|
+
self._tile = ar.dword()
|
127
|
+
if Features().id_size != 4:
|
128
|
+
self._is_tile = (self._tile >> 16) == 0xFFFF;
|
129
|
+
if self._is_tile:
|
130
|
+
self._tile = self._tile & 0xFFFF
|
131
|
+
|
132
|
+
def tileID(self):
|
133
|
+
if not self._is_tile:
|
134
|
+
return None
|
135
|
+
return self._tile
|
136
|
+
|
137
|
+
def color(self):
|
138
|
+
if self._is_tile:
|
139
|
+
return None
|
140
|
+
return GBXDraw.hex(self._tile)
|
141
|
+
|
142
|
+
def toDict(self,tileManager,calc=None):
|
143
|
+
d = {'row': self._row,
|
144
|
+
'column': self._column}
|
145
|
+
if not self._is_tile:
|
146
|
+
d['color'] = GBXDraw.hex(self._tile)
|
147
|
+
else:
|
148
|
+
d['tile'] = tileManager.store(self._tile)
|
149
|
+
if calc is not None:
|
150
|
+
d['pixel'] = calc.translate(self._row,self._column,True)
|
151
|
+
return d
|
152
|
+
|
153
|
+
|
154
|
+
def svgDef(self,dwg,tileManager,ptm):
|
155
|
+
tileID = self.tileID()
|
156
|
+
if tileID is None:
|
157
|
+
return
|
158
|
+
|
159
|
+
if tileID in ptm: # Have it
|
160
|
+
return
|
161
|
+
|
162
|
+
with VerboseGuard(f'Defining SVG pattern'):
|
163
|
+
img = tileManager.image(tileID)
|
164
|
+
data = GBXImage.b64encode(img)
|
165
|
+
if data is None:
|
166
|
+
return
|
167
|
+
|
168
|
+
iden = f'terrain_{tileID:04x}'
|
169
|
+
pat = dwg.defs.add(dwg.pattern(id=iden,
|
170
|
+
size=(img.width,img.height)))
|
171
|
+
pat.add(dwg.image(href=(data)))
|
172
|
+
ptm[tileID] = pat
|
173
|
+
|
174
|
+
def svg(self,dwg,g,cell,geom,ptm):
|
175
|
+
tileID = self.tileID()
|
176
|
+
if tileID is not None:
|
177
|
+
fill = ptm[tileID].get_paint_server()
|
178
|
+
else:
|
179
|
+
fill = self.color()
|
180
|
+
|
181
|
+
trans = geom.translate(self._row,self._column)
|
182
|
+
iden = f'cell_bg_{self._column:03d}{self._row:03d}'
|
183
|
+
g.add(dwg.use(cell,insert=trans,fill=fill,id=iden))
|
184
|
+
|
185
|
+
def svgFrame(self,dwg,g,cell,geom,color):
|
186
|
+
trans = geom.translate(self._row,self._column)
|
187
|
+
iden = f'cell_fg_{self._column:03d}{self._row:03d}'
|
188
|
+
g.add(dwg.use(cell,
|
189
|
+
insert=trans,
|
190
|
+
stroke=GBXDraw.hex(color),
|
191
|
+
fill='none',
|
192
|
+
id=iden))
|
193
|
+
|
194
|
+
|
195
|
+
def __str__(self):
|
196
|
+
return f'({self._row:02d},{self._column:02d}): {self._tile:08x}'
|
197
|
+
|
198
|
+
#
|
199
|
+
# EOF
|
200
|
+
#
|