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,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
+