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,111 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . archive import Archive
|
4
|
+
## END_IMPORT
|
5
|
+
|
6
|
+
def num_version(major,minor):
|
7
|
+
return major * 256 + minor
|
8
|
+
|
9
|
+
def readVector(ar,cls):
|
10
|
+
with VerboseGuard('Reading vector') as g:
|
11
|
+
if Features().size_size == 8:
|
12
|
+
n = ar.size()
|
13
|
+
else:
|
14
|
+
n = ar.word()
|
15
|
+
if n == 0xFFFF:
|
16
|
+
n = ar.dword()
|
17
|
+
if n == 0xFFFFFFFF:
|
18
|
+
n = ar.int(64)
|
19
|
+
g(f'{n} elements')
|
20
|
+
return [cls(ar) for _ in range(n)]
|
21
|
+
|
22
|
+
# ====================================================================
|
23
|
+
class GBXHeader:
|
24
|
+
BOX = 'GBOX'
|
25
|
+
SCENARIO = 'GSCN'
|
26
|
+
def __init__(self,ar,expect=BOX):
|
27
|
+
'''GBXHeader of file
|
28
|
+
|
29
|
+
4 bytes format ID
|
30
|
+
4x1 byte format and program version
|
31
|
+
|
32
|
+
8 bytes in total
|
33
|
+
'''
|
34
|
+
with VerboseGuard('Reading header') as g:
|
35
|
+
sig = ar.chr(len(expect))
|
36
|
+
assert sig == expect, f'Not a {expect} file: {sig}'
|
37
|
+
|
38
|
+
self._major = ar.byte()
|
39
|
+
self._minor = ar.byte()
|
40
|
+
self._programMajor = ar.byte()
|
41
|
+
self._programMinor = ar.byte()
|
42
|
+
self._vers = num_version(self._major,self._minor)
|
43
|
+
g(f'Version {self._major}.{self._minor}')
|
44
|
+
|
45
|
+
assert self._vers >= num_version(3,0),\
|
46
|
+
f'{self._major}.{self._minor} format not supported'
|
47
|
+
|
48
|
+
if self._vers >= num_version(4,0):
|
49
|
+
g(f'Detected version 4.0 or newer, setting some features')
|
50
|
+
Features().id_size = 4
|
51
|
+
Features().size_size = 8
|
52
|
+
Features().sub_size = 8
|
53
|
+
Features().square_cells = True
|
54
|
+
Features().rotate_unit = True
|
55
|
+
Features().piece_100 = True
|
56
|
+
Features().private_board = True
|
57
|
+
Features().roll_state = True
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
def __str__(self):
|
64
|
+
return ('Header:\n'
|
65
|
+
f' Format major version: {self._major}\n'
|
66
|
+
f' Format minor version: {self._minor}\n'
|
67
|
+
f' Program major version: {self._programMajor}\n'
|
68
|
+
f' Program minor version: {self._programMinor}\n')
|
69
|
+
|
70
|
+
|
71
|
+
# --------------------------------------------------------------------
|
72
|
+
class GBXStrings:
|
73
|
+
def __init__(self,ar):
|
74
|
+
'''Map IDs to strings'''
|
75
|
+
with VerboseGuard(f'Reading string mappings'):
|
76
|
+
strMapN = ar.size()
|
77
|
+
|
78
|
+
self._id2str = {}
|
79
|
+
for _ in range(strMapN):
|
80
|
+
key = ar.dword()
|
81
|
+
val = ar.str()
|
82
|
+
|
83
|
+
self._id2str[key] = val
|
84
|
+
|
85
|
+
def __str__(self):
|
86
|
+
return ('Strings:\n'+
|
87
|
+
'\n'.join([f' {key:8x}: {val}'
|
88
|
+
for key,val in self._id2str.items()]))
|
89
|
+
|
90
|
+
# --------------------------------------------------------------------
|
91
|
+
class GSNStrings:
|
92
|
+
def __init__(self,ar):
|
93
|
+
'''Map IDs to strings'''
|
94
|
+
with VerboseGuard(f'Reading string mappings'):
|
95
|
+
strMapN = ar.size()
|
96
|
+
|
97
|
+
self._id2str = {}
|
98
|
+
for _ in range(strMapN):
|
99
|
+
key = ar.size()
|
100
|
+
val = ar.str()
|
101
|
+
|
102
|
+
self._id2str[key] = val
|
103
|
+
|
104
|
+
def __str__(self):
|
105
|
+
return ('Strings:\n'+
|
106
|
+
'\n'.join([f' {key:8x}: {val}'
|
107
|
+
for key,val in self._id2str.items()]))
|
108
|
+
|
109
|
+
#
|
110
|
+
# EOF
|
111
|
+
#
|
@@ -0,0 +1,76 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
## END_IMPORT
|
4
|
+
|
5
|
+
# ====================================================================
|
6
|
+
class GBXImage:
|
7
|
+
def __init__(self,ar,transparent=None,save=None):
|
8
|
+
'''A DIB image stored in GameBox'''
|
9
|
+
with VerboseGuard('Reading an image') as g:
|
10
|
+
size = ar.dword()
|
11
|
+
|
12
|
+
if size & 0x80000000: # Compressed
|
13
|
+
from zlib import decompress
|
14
|
+
g(f'Read compressed image')
|
15
|
+
|
16
|
+
size &= 0x80000000 # Remove flag
|
17
|
+
compSize = ar.dword() # Compressed size
|
18
|
+
compressed = ar.read(compSize) # Compressed
|
19
|
+
buffer = decompress(compressed,bufsize=size)
|
20
|
+
#assert len(buffer) == size, \
|
21
|
+
# f'Failed to decompress to expected {size}, ' \
|
22
|
+
# f'got {len(buffer)}'
|
23
|
+
|
24
|
+
else:
|
25
|
+
buffer = ar.read(size)
|
26
|
+
|
27
|
+
from PIL import Image as PILImage
|
28
|
+
from io import BytesIO
|
29
|
+
from numpy import asarray, where, uint8
|
30
|
+
|
31
|
+
img = PILImage.open(BytesIO(buffer)).convert('RGBA')
|
32
|
+
|
33
|
+
# If transparancy is defined, clean up the image
|
34
|
+
if transparent is None:
|
35
|
+
self._img = img
|
36
|
+
else:
|
37
|
+
g(f'Making #{transparent:06x} transparent')
|
38
|
+
dat = asarray(img)
|
39
|
+
tr = (transparent >> 16) & 0xFF
|
40
|
+
tg = (transparent >> 8) & 0xFF
|
41
|
+
tb = (transparent >> 0) & 0xFF
|
42
|
+
dat2 = dat.copy()
|
43
|
+
dat2[:,:,3] = (255*(dat[:,:,:3]!=[tb,tg,tr]).any(axis=2))\
|
44
|
+
.astype(uint8)
|
45
|
+
|
46
|
+
#if (dat[:,:,3] == dat2[:,:,3]).all():
|
47
|
+
# print(f'Transparency operation seemed to have no effect '
|
48
|
+
# f'for image')
|
49
|
+
|
50
|
+
self._img = PILImage.fromarray(dat2)
|
51
|
+
|
52
|
+
if save is None:
|
53
|
+
return
|
54
|
+
|
55
|
+
self._img.save(save)
|
56
|
+
|
57
|
+
@classmethod
|
58
|
+
def b64encode(cls,img):
|
59
|
+
'''Encode image as a base64 data URL'''
|
60
|
+
from io import BytesIO
|
61
|
+
from base64 import b64encode
|
62
|
+
|
63
|
+
if img is None:
|
64
|
+
return None
|
65
|
+
|
66
|
+
buffered = BytesIO()
|
67
|
+
img.save(buffered,format='PNG')
|
68
|
+
data = b64encode(buffered.getvalue())
|
69
|
+
if not isinstance(data,str):
|
70
|
+
data = data.decode()
|
71
|
+
|
72
|
+
return 'data:image/png;base64,'+data
|
73
|
+
|
74
|
+
#
|
75
|
+
# EOF
|
76
|
+
#
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
#
|
3
|
+
# CyberBoard GitHub page:
|
4
|
+
#
|
5
|
+
# https://github.com/CyberBoardPBEM/cbwindows
|
6
|
+
#
|
7
|
+
|
8
|
+
# ====================================================================
|
9
|
+
if __name__ == '__main__':
|
10
|
+
from argparse import ArgumentParser, FileType
|
11
|
+
from pathlib import Path
|
12
|
+
## BEGIN_IMPORT
|
13
|
+
from gamebox import GameBox
|
14
|
+
from extractor import Extractor
|
15
|
+
from common import Verbose
|
16
|
+
## END_IMPORT
|
17
|
+
|
18
|
+
ap = ArgumentParser(description='Read the file')
|
19
|
+
ap.add_argument('input', type=str, help='The file')
|
20
|
+
ap.add_argument('output',type=str, nargs='?',help='Output',default='')
|
21
|
+
ap.add_argument('-V','--verbose',
|
22
|
+
help='Be verbose',
|
23
|
+
action='store_true')
|
24
|
+
ap.add_argument('-D','--dump',type=str,nargs='*',default='',
|
25
|
+
help='Dump content')
|
26
|
+
|
27
|
+
args = ap.parse_args()
|
28
|
+
Verbose().setVerbose(args.verbose)
|
29
|
+
|
30
|
+
gbx = GameBox.fromFile(args.input)
|
31
|
+
rat = Extractor(gbx)
|
32
|
+
|
33
|
+
out = args.output
|
34
|
+
if out == '':
|
35
|
+
p = Path(args.input)
|
36
|
+
out = p.stem+'.zip'
|
37
|
+
|
38
|
+
rat.save(out)
|
39
|
+
|
40
|
+
if 'save' in args.dump:
|
41
|
+
print(rat)
|
42
|
+
if 'gbx' in args.dump:
|
43
|
+
print(gbx)
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . base import CbManager
|
4
|
+
## END_IMPORT
|
5
|
+
|
6
|
+
# ====================================================================
|
7
|
+
class GBXMarkDef:
|
8
|
+
def __init__(self,ar):
|
9
|
+
'''Definition of a mark'''
|
10
|
+
with VerboseGuard(f'Reading mark definition'):
|
11
|
+
self._id = ar.iden()
|
12
|
+
self._flags = ar.word()
|
13
|
+
|
14
|
+
def __str__(self):
|
15
|
+
return f'Mark: {self._id:04x},{self._flags:04x}'
|
16
|
+
|
17
|
+
# --------------------------------------------------------------------
|
18
|
+
class GBXMarkSet:
|
19
|
+
def __init__(self,ar):
|
20
|
+
'''Set of marks'''
|
21
|
+
with VerboseGuard(f'Reading mark set'):
|
22
|
+
self._name = ar.str()
|
23
|
+
self._viz = ar.word()
|
24
|
+
n = ar.sub_size()
|
25
|
+
self._marks = [ar.iden() for _ in range(n)]
|
26
|
+
|
27
|
+
def __len__(self):
|
28
|
+
return len(self._marks)
|
29
|
+
|
30
|
+
def __str__(self):
|
31
|
+
return (f'{self._name}: '+','.join([str(p) for p in self._marks]))
|
32
|
+
|
33
|
+
# --------------------------------------------------------------------
|
34
|
+
class GBXMarkManager:
|
35
|
+
def __init__(self,ar):
|
36
|
+
'''Manager of marks'''
|
37
|
+
with VerboseGuard(f'Reading mark manager'):
|
38
|
+
self._reserved = [ar.word() for _ in range(4)]
|
39
|
+
n = ar.iden()
|
40
|
+
self._marks = [GBXMarkDef(ar) for _ in range(n)]
|
41
|
+
n = ar.sub_size()
|
42
|
+
self._sets = [GBXMarkSet(ar) for _ in range(n)]
|
43
|
+
|
44
|
+
def __len__(self):
|
45
|
+
return len(self._sets)
|
46
|
+
|
47
|
+
def toDict(self,tileManager,strings):
|
48
|
+
from math import log10, ceil
|
49
|
+
with VerboseGuard(f'Creating dict from mark manager'):
|
50
|
+
setDigits = int(ceil(log10(len(self)+.5)))
|
51
|
+
markDigits = 1
|
52
|
+
for markSet in self._sets:
|
53
|
+
markDigits = max(markDigits,
|
54
|
+
int(ceil(log10(len(markSet)+.5))))
|
55
|
+
|
56
|
+
marksMap = {}
|
57
|
+
setList = []
|
58
|
+
ret = {'map': marksMap,
|
59
|
+
'sets': setList }
|
60
|
+
|
61
|
+
for ips, markSet in enumerate(self._sets):
|
62
|
+
with VerboseGuard(f'Creating dict mark set {markSet._name}'):
|
63
|
+
setPrefix = f'mark_{ips:0{setDigits}d}'
|
64
|
+
idList = []
|
65
|
+
setDict = { 'description': markSet._name.strip(),
|
66
|
+
'marks': idList }
|
67
|
+
setList.append(setDict)
|
68
|
+
|
69
|
+
for ipc, markID in enumerate(markSet._marks):
|
70
|
+
markPrefix = f'{setPrefix}_{ipc:0{markDigits}d}'
|
71
|
+
markDef = self._marks[markID]
|
72
|
+
tmpStr = strings._id2str.get(markID|0xF0000000,'')
|
73
|
+
markDesc = tmpStr.replace('\r','').replace('\n',', ')
|
74
|
+
markDict = {}
|
75
|
+
if markDesc != '':
|
76
|
+
markDict['description'] = markDesc
|
77
|
+
marksMap[markID] = markDict
|
78
|
+
idList .append(markID)
|
79
|
+
|
80
|
+
img = tileManager.image(markDef._id)
|
81
|
+
|
82
|
+
if img is None:
|
83
|
+
continue
|
84
|
+
|
85
|
+
sav = f'{markPrefix}.png'
|
86
|
+
markDict.update({'image': img,
|
87
|
+
'filename': sav })
|
88
|
+
|
89
|
+
return ret
|
90
|
+
|
91
|
+
def __str__(self):
|
92
|
+
return ('Mark manager:\n'
|
93
|
+
+f'Reserved: {self._reserved}\n'
|
94
|
+
+f'# marks: {len(self._marks)}\n '
|
95
|
+
+'\n '.join([str(p) for p in self._marks])+'\n'
|
96
|
+
+f'# mark sets: {len(self._sets)}\n '
|
97
|
+
+'\n '.join([str(p) for p in self._sets])
|
98
|
+
)
|
99
|
+
|
100
|
+
#
|
101
|
+
# EOF
|
102
|
+
#
|
@@ -0,0 +1,36 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . head import num_version, readVector
|
4
|
+
## END_IMPORT
|
5
|
+
|
6
|
+
class GSNPalette:
|
7
|
+
def __init__(self,ar):
|
8
|
+
with VerboseGuard('Reading palette'):
|
9
|
+
self._visible = ar.word()
|
10
|
+
self._comboIndex = ar.dword()
|
11
|
+
self._topIndex = ar.dword()
|
12
|
+
|
13
|
+
class GSNTrayPalette(GSNPalette):
|
14
|
+
def __init__(self,ar,vers,iden):
|
15
|
+
with VerboseGuard(f'Reading scenario tray palette {iden}'):
|
16
|
+
super(GSNTrayPalette,self).__init__(ar)
|
17
|
+
self._iden = iden
|
18
|
+
self._listSel = readVector(ar,lambda ar : ar.dword())
|
19
|
+
|
20
|
+
def __str__(self):
|
21
|
+
return f'GSNTrayPalette: {self._comboIndex} '\
|
22
|
+
f'{self._topIndex} {self._listSel}\n'
|
23
|
+
|
24
|
+
class GSNMarkPalette(GSNPalette):
|
25
|
+
def __init__(self,ar,vers):
|
26
|
+
with VerboseGuard(f'Reading scenario mark palette'):
|
27
|
+
super(GSNMarkPalette,self).__init__(ar)
|
28
|
+
self._listSel = ar.dword()
|
29
|
+
def __str__(self):
|
30
|
+
return f'GSNMarkPalette: {self._comboIndex} '\
|
31
|
+
f'{self._topIndex} {self._listSel}\n'
|
32
|
+
|
33
|
+
#
|
34
|
+
# EOF
|
35
|
+
#
|
36
|
+
|
@@ -0,0 +1,169 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
from . head import num_version
|
4
|
+
## END_IMPORT
|
5
|
+
# ====================================================================
|
6
|
+
class GBXPieceDef:
|
7
|
+
def __init__(self,ar):
|
8
|
+
'''Definition of a piece
|
9
|
+
|
10
|
+
FRONT and BACK are tile IDs
|
11
|
+
|
12
|
+
FLAGS is ...
|
13
|
+
'''
|
14
|
+
with VerboseGuard(f'Reading piece definition'):
|
15
|
+
if Features().piece_100:
|
16
|
+
n = ar.size()
|
17
|
+
self._ids = [ar.iden() for _ in range(n)]
|
18
|
+
else:
|
19
|
+
self._ids = [ar.word(),ar.word()]
|
20
|
+
self._flags = ar.word()
|
21
|
+
|
22
|
+
|
23
|
+
@property
|
24
|
+
def _front(self):
|
25
|
+
return self._ids[0]
|
26
|
+
|
27
|
+
@property
|
28
|
+
def _back(self):
|
29
|
+
return self._ids[1] if len(self._ids) > 1 else 0
|
30
|
+
|
31
|
+
def __str__(self):
|
32
|
+
return f'Piece: {self._front:04x},{self._back:04x},{self._flags:04x}'
|
33
|
+
|
34
|
+
# --------------------------------------------------------------------
|
35
|
+
class GBXPieceSet:
|
36
|
+
def __init__(self,ar):
|
37
|
+
'''Set of pieces'''
|
38
|
+
with VerboseGuard(f'Reading piece set'):
|
39
|
+
self._name = ar.str()
|
40
|
+
n = ar.sub_size()
|
41
|
+
self._pieces = [ar.iden() for _ in range(n)]
|
42
|
+
|
43
|
+
def __len__(self):
|
44
|
+
return len(self._pieces)
|
45
|
+
|
46
|
+
def __str__(self):
|
47
|
+
return (f'{self._name}: '+','.join([str(p) for p in self._pieces]))
|
48
|
+
|
49
|
+
# --------------------------------------------------------------------
|
50
|
+
class GBXPieceManager:
|
51
|
+
def __init__(self,ar):
|
52
|
+
'''Manager of pieces'''
|
53
|
+
with VerboseGuard(f'Reading piece manager') as g:
|
54
|
+
self._reserved = [ar.word() for _ in range(4)]
|
55
|
+
g(f'Reserved are {self._reserved}')
|
56
|
+
n = ar.iden();
|
57
|
+
g(f'Will read {n} pieces')
|
58
|
+
self._pieces = [GBXPieceDef(ar) for _ in range(n)]
|
59
|
+
n = ar.sub_size()
|
60
|
+
g(f'Will read {n} sets')
|
61
|
+
self._sets = [GBXPieceSet(ar) for _ in range(n)]
|
62
|
+
|
63
|
+
def __len__(self):
|
64
|
+
return len(self._sets)
|
65
|
+
|
66
|
+
def toDict(self,tileManager,strings):
|
67
|
+
from math import log10, ceil
|
68
|
+
with VerboseGuard(f'Creating dict from piece manager') as gg:
|
69
|
+
gg(f'Has {len(self._sets)} and {len(self._pieces)} pieces')
|
70
|
+
setDigits = int(ceil(log10(len(self)+.5)))
|
71
|
+
pieceDigits = 1
|
72
|
+
for pieceSet in self._sets:
|
73
|
+
pieceDigits = max(pieceDigits,
|
74
|
+
int(ceil(log10(len(pieceSet)+.5))))
|
75
|
+
|
76
|
+
cnt = 0
|
77
|
+
piecesMap = {}
|
78
|
+
setList = []
|
79
|
+
ret = {'map': piecesMap,
|
80
|
+
'sets': setList }
|
81
|
+
|
82
|
+
for ips, pieceSet in enumerate(self._sets):
|
83
|
+
with VerboseGuard(f'Creating dict from piece set '
|
84
|
+
f'{pieceSet._name}') as g:
|
85
|
+
setPrefix = f'piece_{ips:0{setDigits}d}'
|
86
|
+
idList = []
|
87
|
+
setDict = { 'description': pieceSet._name.strip(),
|
88
|
+
'pieces': idList }
|
89
|
+
setList.append(setDict)
|
90
|
+
|
91
|
+
for ipc, pieceID in enumerate(pieceSet._pieces):
|
92
|
+
|
93
|
+
piecePrefix = f'{setPrefix}_{ipc:0{pieceDigits}d}'
|
94
|
+
pieceDef = self._pieces[pieceID]
|
95
|
+
tmpStr = strings._id2str.get(pieceID,'')
|
96
|
+
pieceDesc = tmpStr.replace('\r','').replace('\n',', ').replace('/','\\/')
|
97
|
+
pieceDict = {}
|
98
|
+
if pieceDesc != '':
|
99
|
+
pieceDict['description'] = pieceDesc
|
100
|
+
cnt += 1
|
101
|
+
# pieceList.append(pieceDict)
|
102
|
+
idList .append(pieceID)
|
103
|
+
|
104
|
+
# print(f'{pd} => "{tr}"')
|
105
|
+
for tileId,which in zip([pieceDef._front,
|
106
|
+
pieceDef._back],
|
107
|
+
['front',
|
108
|
+
'back']):
|
109
|
+
img = tileManager.image(tileId)
|
110
|
+
|
111
|
+
if img is None:
|
112
|
+
continue
|
113
|
+
|
114
|
+
sav = f'{piecePrefix}_{which}.png'
|
115
|
+
setname = pieceSet._name.strip()\
|
116
|
+
.replace('\n',' ')\
|
117
|
+
.replace('\r',' ')\
|
118
|
+
.replace('/','\\/')
|
119
|
+
gg(f'Set name, escaped: "{setname}"')
|
120
|
+
pieceDict[which] = {
|
121
|
+
'image': img,
|
122
|
+
'filename': sav,
|
123
|
+
'set': setname }
|
124
|
+
piecesMap[pieceID] = pieceDict
|
125
|
+
g(f'{pieceID}: {pieceDict}')
|
126
|
+
|
127
|
+
gg(f'{list(piecesMap.keys())}')
|
128
|
+
return ret
|
129
|
+
|
130
|
+
|
131
|
+
def __str__(self):
|
132
|
+
return ('Piece manager:\n'
|
133
|
+
+f'Reserved: {self._reserved}\n'
|
134
|
+
+f'# pieces: {len(self._pieces)}\n '
|
135
|
+
+'\n '.join([str(p) for p in self._pieces])+'\n'
|
136
|
+
+f'# piece sets: {len(self._sets)}\n '
|
137
|
+
+'\n '.join([str(p) for p in self._sets])
|
138
|
+
)
|
139
|
+
|
140
|
+
# --------------------------------------------------------------------
|
141
|
+
class GSNPieceEntry:
|
142
|
+
def __init__(self,ar,vers,i):
|
143
|
+
'''Manager of pieces'''
|
144
|
+
with VerboseGuard(f'Reading piece # {i:3d} ({vers//256}.{vers%256})'):
|
145
|
+
self._side = ar.byte()
|
146
|
+
self._facing = ar.word()
|
147
|
+
self._owner = ar.word() if vers < num_version(3,10) else ar.dword()
|
148
|
+
|
149
|
+
def __str__(self):
|
150
|
+
return f'Piece: {self._side}, {self._facing:3d}, {self._owner:08x}'
|
151
|
+
|
152
|
+
# --------------------------------------------------------------------
|
153
|
+
class GSNPieceTable:
|
154
|
+
def __init__(self,ar,vers):
|
155
|
+
'''Manager of pieces'''
|
156
|
+
with VerboseGuard(f'Reading piece table'):
|
157
|
+
self._reserved = [ar.word() for _ in range(4)]
|
158
|
+
n = ar.word()#sub_size()
|
159
|
+
if Features().piece_100:
|
160
|
+
dummy = ar.word();
|
161
|
+
self._pieces = [GSNPieceEntry(ar,vers,i) for i in range(n)]
|
162
|
+
|
163
|
+
def __str__(self):
|
164
|
+
pl = '\n '.join([str(s) for s in self._pieces])
|
165
|
+
return (f'Piece table: {self._reserved} {len(self._pieces)}'
|
166
|
+
f'\n {pl}\n')
|
167
|
+
#
|
168
|
+
# EOF
|
169
|
+
#
|
@@ -0,0 +1,36 @@
|
|
1
|
+
## BEGIN_IMPORT
|
2
|
+
from common import VerboseGuard
|
3
|
+
## END_IMPORT
|
4
|
+
|
5
|
+
class GSNPlayerManager:
|
6
|
+
def __init__(self,ar):
|
7
|
+
with VerboseGuard(f'Reading players mappings'):
|
8
|
+
self._enable = ar.byte()
|
9
|
+
self._players = []
|
10
|
+
if self._enable:
|
11
|
+
n = ar.sub_size()
|
12
|
+
self._players = [GSNPlayer(ar) for _ in range(n)]
|
13
|
+
|
14
|
+
def toDict(self):
|
15
|
+
return [p._name for p in self._players]
|
16
|
+
|
17
|
+
def __str__(self):
|
18
|
+
pl = '\n '.join([str(s) for s in self._players])
|
19
|
+
return ('Players:\n'
|
20
|
+
f' Enabled: {self._enable}\n'
|
21
|
+
f' # players: {len(self._players)}\n {pl}\n')
|
22
|
+
|
23
|
+
class GSNPlayer:
|
24
|
+
def __init__(self,ar):
|
25
|
+
with VerboseGuard(f'Reading player'):
|
26
|
+
self._key = ar.dword()
|
27
|
+
self._name = ar.str()
|
28
|
+
|
29
|
+
|
30
|
+
def __str__(self):
|
31
|
+
return f'Player: {self._name} (0x{self._key:08x})'
|
32
|
+
|
33
|
+
#
|
34
|
+
# EOF
|
35
|
+
#
|
36
|
+
|