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,115 @@
1
+ ## BEGIN_IMPORT
2
+ from common import VerboseGuard
3
+ from . head import *
4
+ from . player import GSNPlayerManager
5
+ from . windows import GSNWindows
6
+ from . palette import GSNTrayPalette
7
+ from . palette import GSNMarkPalette
8
+ from . board import GSNBoardManager
9
+ from . tray import GSNTrayManager
10
+ from . piece import GSNPieceTable
11
+ from . gamebox import GameBox
12
+ ## END_IMPORT
13
+
14
+ class GSNInfo:
15
+ def __init__(self,ar):
16
+ '''Scenario information'''
17
+ self._disableOwnerTips = ar.word()
18
+ self._reserved = [ar.word() for _ in range(3)]
19
+ self._gameID = ar.dword() # 4 -> 14
20
+ self._majorRevs = ar.dword() # 4 -> 6
21
+ self._minorRevs = ar.dword() # 4 -> 10
22
+ self._gbxFilename = ar.str()
23
+ self._scenarioID = ar.dword()
24
+ self._title = ar.str() # Y -> 30+X+Y
25
+ self._author = ar.str() # X -> 30+X
26
+ self._description = ar.str() # Z -> 30+X+Y+Z
27
+ self._keepBackup = ar.word()
28
+ self._keepHistory = ar.word()
29
+ self._verifyState = ar.word()
30
+ self._verifySave = ar.word()
31
+ self._showObjectTip = ar.word()
32
+
33
+ def __str__(self):
34
+ return ('Information:\n'
35
+ f' Disable owner tips: {self._disableOwnerTips}\n'
36
+ f' Reserved: {self._reserved}\n'
37
+ f' Game ID: {self._gameID}\n'
38
+ f' Major revision: {self._majorRevs}\n'
39
+ f' Minor revision: {self._minorRevs}\n'
40
+ f' Game box filename: {self._gbxFilename}\n'
41
+ f' Scenario ID: {self._scenarioID}\n'
42
+ f' Title: {self._title}\n'
43
+ f' Author: {self._author}\n'
44
+ f' Description: {self._description}\n'
45
+ f' Keep backup: {self._keepBackup}\n'
46
+ f' Keep history: {self._keepHistory}\n'
47
+ f' Verify state: {self._verifyState}\n'
48
+ f' Verify save: {self._verifySave}\n'
49
+ f' Show object tips: {self._showObjectTip}\n')
50
+
51
+ # ====================================================================
52
+ class Scenario:
53
+ def __init__(self,ar,gbxfilename=None):
54
+ '''Container of game'''
55
+ with VerboseGuard(f'Reading scenario'):
56
+ self._header = GBXHeader (ar,GBXHeader.SCENARIO)
57
+ self._info = GSNInfo (ar)
58
+ self._strings = GSNStrings (ar)
59
+ self._playerManager = GSNPlayerManager(ar)
60
+ self._windows = GSNWindows (ar)
61
+ self._trayA = GSNTrayPalette (ar,self._header._vers,'A')
62
+ self._trayB = GSNTrayPalette (ar,self._header._vers,'B')
63
+ self._mark = GSNMarkPalette (ar,self._header._vers)
64
+ self._boards = GSNBoardManager (ar,self._header._vers)
65
+ self._trayManager = GSNTrayManager (ar,self._header._vers)
66
+ self._pieceTable = GSNPieceTable (ar,self._header._vers)
67
+ # Possibly override GBX file name
68
+ if gbxfilename is not None and gbxfilename != '':
69
+ self._info._gbxFilename = gbxfilename
70
+
71
+ self.readGameBox(ar)
72
+
73
+ def readGameBox(self,ar):
74
+ from pathlib import Path
75
+ with VerboseGuard(f'Read game box file {self._info._gbxFilename}') as v:
76
+ gbxname = self._info._gbxFilename
77
+ gbxpath = Path(gbxname)
78
+
79
+ if not gbxpath.exists():
80
+ v(f'GameBox file {gbxpath} does not exist')
81
+ if '\\' in gbxname:
82
+ gbxname = gbxname.replace('\\','/')
83
+ gbxpath = Path(gbxname)
84
+ gbxpath = ar.path.parent / Path(gbxpath.name)
85
+ if not gbxpath.exists():
86
+ raise RuntimeError(f'GameBox file {gbxpath} cannot be found')
87
+
88
+ self._gbx = GameBox.fromFile(str(gbxpath))
89
+
90
+ if self._gbx._info._gameID != self._info._gameID:
91
+ raise RuntimeError(f'Game IDs from GBX and GSN does not match: '
92
+ f'{self._gbx._info._gameID} versus '
93
+ f'{self._header._gameID}')
94
+
95
+ def __str__(self):
96
+ return (str(self._header)+
97
+ str(self._info)+
98
+ str(self._strings)+
99
+ str(self._playerManager)+
100
+ str(self._windows)+
101
+ str(self._trayA)+
102
+ str(self._trayB)+
103
+ str(self._mark)+
104
+ str(self._boards)+
105
+ str(self._trayManager)+
106
+ str(self._pieceTable)+
107
+ str(self._gbx)+
108
+ ''
109
+ )
110
+
111
+
112
+ @classmethod
113
+ def fromFile(cls,filename,gbxfile=None):
114
+ with Archive(filename,'rb') as ar:
115
+ return Scenario(ar,gbxfile)
@@ -0,0 +1,156 @@
1
+ class Geometry:
2
+ RECTANGLE = 0
3
+ HORIZONTAL_BRICK = 1
4
+ VERTICAL_BRICK = 2
5
+ HEXAGON = 3
6
+ SIDEWAYS_HEXAGON = 4
7
+ STAGGER_OUT = 0
8
+ STAGGER_IN = 1
9
+ TYPES = {
10
+ RECTANGLE : 'rectangle',
11
+ HORIZONTAL_BRICK: 'horizontal brick',
12
+ VERTICAL_BRICK : 'vertical brick',
13
+ HEXAGON : 'hexagon',
14
+ SIDEWAYS_HEXAGON: 'sideways hexagon'
15
+ }
16
+ STAGGERS = {
17
+ STAGGER_OUT: 'out',
18
+ STAGGER_IN: 'in'
19
+ }
20
+ SKETCHES = {
21
+ RECTANGLE : r'''
22
+ |---|---|
23
+ |---|---|''',
24
+ HORIZONTAL_BRICK: r'''
25
+ |---|---|
26
+ |---|''',
27
+ VERTICAL_BRICK : r'''
28
+ |--| |
29
+ | |--|
30
+ |--| |''',
31
+ HEXAGON : r''' _
32
+ / \
33
+ \_/''' ,
34
+ SIDEWAYS_HEXAGON: r'''/\
35
+ ||
36
+ \/'''
37
+ }
38
+
39
+ def __init__(self,nrows,ncols,tpe,stagger,w,h):
40
+ self._nrows = nrows
41
+ self._ncols = ncols
42
+ self._type = tpe
43
+ self._stagger = stagger
44
+ self._width = w
45
+ self._height = h
46
+ self._dx = w
47
+ self._dy = h
48
+
49
+ if self._type == self.HEXAGON:
50
+ self._dx = int(0.75 * self._dx)
51
+ elif self._type == self.SIDEWAYS_HEXAGON:
52
+ self._dy = int(0.75 * self._dy)
53
+
54
+ def toPixel(self,row,col):
55
+ x = col * self._dx
56
+ y = row * self._dy
57
+ if self._type == self.RECTANGLE: # No offset for rectangles
58
+ return x,y
59
+ elif self._type in [self.HORIZONTAL_BRICK,self.SIDEWAYS_HEXAGON]:
60
+ x += self._dx//2 if (row % 2) != self._stagger else 0
61
+ elif self._type in [self.VERTICAL_BRICK,self.HEXAGON]:
62
+ y += self._dy//2 if (col % 2) != self._stagger else 0
63
+ return x,y
64
+
65
+ def toGrid(self,x,y):
66
+ col = x / self._dx
67
+ row = y / self._dy
68
+ if self._type in [self.HORIZONTAL_BRICK,self.SIDEWAYS_HEXAGON]:
69
+ col -= .5 if (int(row) % 2) != self._stagger else 0
70
+ if self._type in [self.VERTICAL_BRICK,self.HEXAGON]:
71
+ row -= .5 if (int(col) % 2) != self._stagger else 0
72
+
73
+ return int(row), int(col)
74
+
75
+ def boardSize(self,nrows,ncols):
76
+ w = ncols * self._dx
77
+ h = nrows * self._dy
78
+
79
+ if self._type in [2,3]:
80
+ h += self._dy // 2
81
+ if self._type in [1,4]:
82
+ w += self._dx // 2
83
+ if self._type == 3:
84
+ w += self._dx // 3
85
+ if self._type == 4:
86
+ h += self._dy // 3
87
+
88
+ return w+1,h+1
89
+
90
+ def test(self,stepX=None,stepY=None):
91
+ from numpy import linspace
92
+
93
+ width, height = self.boardSize(self._nrows,self._ncols)
94
+ print(f'Test: {self._type},{self._stagger}')
95
+ print(f'{self._width}x{self._height} ({self._dx},{self._dy})')
96
+ print(f' {self.TYPES[self._type]} {self.STAGGERS[self._stagger]}')
97
+ print(self.SKETCHES[self._type])
98
+
99
+ for row in range(self._nrows):
100
+ for col in range(self._ncols):
101
+ x, y = self.toPixel(row,col)
102
+ cx, cy = x + self._width // 2, y + self._height // 2
103
+ r, c = self.toGrid(cx,cy)
104
+ print(f'== {row:3d},{col:3d} -> {cx:6d},{cy:6d} -> {r:3d},{c:3d}')
105
+ assert r == row, f'Rows (from {row} to {r}) inconsistent'
106
+ assert c == col, f'Columns (from {col} to {c}) inconsistent'
107
+
108
+ if row >= 3 or col >= 3:
109
+ continue
110
+ for dx in linspace(-self._width/4,self._width/4,5):
111
+ idx = int(dx)
112
+ for dy in linspace(-self._height/4,self._height/4,5):
113
+ idy = int(dy)
114
+ xx = cx + idx
115
+ yy = cy + idy
116
+ r, c = self.toGrid(xx,yy)
117
+ if r != row or c != col:
118
+ print(f'{row:3d},{col:3d} -> {cx:6d}+{idx:3d}={xx:6d},{cy:6d}+{idy:3d}={yy:6d} -> {r:3d},{c:3d}')
119
+
120
+
121
+
122
+
123
+ def testit(tpe,stagger):
124
+ w = 100
125
+ h = 100
126
+ if tpe == 3:
127
+ w = 80
128
+ h = 68
129
+ elif tpe == 4:
130
+ w = 68
131
+ h = 80
132
+
133
+ geo = Geometry(5,5,tpe,stagger,w,h)
134
+ geo.test()
135
+
136
+
137
+ def testall():
138
+ for t in [Geometry.RECTANGLE,
139
+ Geometry.HORIZONTAL_BRICK,
140
+ Geometry.VERTICAL_BRICK,
141
+ Geometry.HEXAGON,
142
+ Geometry.SIDEWAYS_HEXAGON]:
143
+ for s in [Geometry.STAGGER_IN,
144
+ Geometry.STAGGER_OUT]:
145
+ testit(t,s)
146
+
147
+
148
+
149
+ testall()
150
+
151
+
152
+
153
+
154
+
155
+
156
+
@@ -0,0 +1,121 @@
1
+ ## BEGIN_IMPORT
2
+ from common import VerboseGuard
3
+ from . image import GBXImage
4
+ from . base import CbManager
5
+ ## END_IMPORT
6
+
7
+ # ====================================================================
8
+ class GBXTileLocation:
9
+ def __init__(self,ar):
10
+ '''Where a tile can be found'''
11
+ with VerboseGuard('Reading tile location') as g:
12
+ self._sheet = (ar.word() if not Features().size_size == 8 else
13
+ ar.size())
14
+ self._offset = ar.word()
15
+ g(f'Tile location at sheet={self._sheet} offset={self._offset}')
16
+ if self._sheet == 65535: self._sheet = -1
17
+
18
+ def __str__(self):
19
+ return f'{self._sheet:3d} @ {self._offset:6d}'
20
+
21
+
22
+ # --------------------------------------------------------------------
23
+ class GBXTileDefinition:
24
+ def __init__(self,ar):
25
+ '''The definition of a tile'''
26
+ with VerboseGuard('Reading tile definition'):
27
+ self._full = GBXTileLocation(ar)
28
+ self._half = GBXTileLocation(ar)
29
+ self._fill = ar.dword()
30
+
31
+ def __str__(self):
32
+ return f'Full: {self._full}, Half: {self._half}, Fill: {self._fill:08x}'
33
+
34
+
35
+ # --------------------------------------------------------------------
36
+ class GBXTileSet:
37
+ def __init__(self,ar):
38
+ '''A set of tiles'''
39
+ with VerboseGuard('Reading tile set'):
40
+ self._name = ar.str()
41
+ n = ar.word() if Features().size_size != 8 else ar.size()
42
+ self._ids = [ar.iden()
43
+ for _ in range(n)]
44
+
45
+ def __str__(self):
46
+ return (self._name + ':' + ','.join([str(i) for i in self._ids]))
47
+
48
+
49
+ # --------------------------------------------------------------------
50
+ class GBXTileSheet:
51
+ def __init__(self,ar,transparent):
52
+ '''A single image that has multiple tile images in it
53
+
54
+ X,Y are the tile sizes
55
+ '''
56
+ with VerboseGuard('Reading tile sheet'):
57
+ self._x = ar.word()
58
+ self._y = ar.word()
59
+ hasBM = ar.word()
60
+ self._img = GBXImage(ar,transparent) if hasBM else None
61
+
62
+ def sub(self,off):
63
+ if self._img is None:
64
+ return None
65
+
66
+ return self._img._img.crop((0,off,self._x,off+self._y))
67
+
68
+ def __str__(self):
69
+ bm = str(self._img) if self._img is not None else 'None'
70
+ return (f'c=({self._x:4d},{self._y:4d}) bitmap={bm}')
71
+
72
+
73
+ # --------------------------------------------------------------------
74
+ class GBXTileManager(CbManager):
75
+ def __init__(self,ar):
76
+ '''Tile manager (including tiles)'''
77
+ with VerboseGuard('Reading tile manager'):
78
+ self._transparent = ar.dword()
79
+ super(GBXTileManager,self).__init__(ar)
80
+
81
+ ts = lambda ar : GBXTileSheet(ar, self._transparent)
82
+ self._tiledefs = self._readSub(ar,GBXTileDefinition,
83
+ Features().id_size)
84
+ self._tilesets = self._readSub(ar,GBXTileSet)
85
+ self._tilesheets = self._readSub(ar,ts)
86
+ self._toStore = {} # Used in boards, not elsewhere
87
+
88
+ def image(self,tileID):
89
+ if tileID is None:
90
+ return None
91
+ if tileID == 0xFFFF:
92
+ return None
93
+
94
+ tileDef = self._tiledefs[tileID]
95
+ tileSht = self._tilesheets[tileDef._full._sheet]
96
+ img = tileSht.sub(tileDef._full._offset)
97
+ return img
98
+
99
+ def store(self,tileID):
100
+ filename = self._toStore.get(tileID,{}).get('filename',None)
101
+ if filename is None:
102
+ filename = f'tile_{tileID:04d}.png'
103
+ self._toStore[tileID] = {
104
+ 'filename': filename,
105
+ 'image' : self.image(tileID)
106
+ }
107
+
108
+ return filename
109
+
110
+
111
+ def __str__(self):
112
+ return ('Tile manager:\n'
113
+ + f' Transparent: {self._transparent:08x}\n'
114
+ + super(GBXTileManager,self).__str__()
115
+ + self._strSub('tiles',self._tiledefs) + '\n'
116
+ + self._strSub('tile sets',self._tilesets) + '\n'
117
+ + self._strSub('tile sheets',self._tilesheets))
118
+
119
+ #
120
+ # EOF
121
+ #
@@ -0,0 +1,68 @@
1
+ ## BEGIN_IMPORT
2
+ from common import VerboseGuard
3
+ from . head import num_version, readVector
4
+ ## END_IMPORT
5
+
6
+ class GSNTraySet:
7
+ def __init__(self,ar,vers):
8
+ with VerboseGuard(f'Reading tray set') as g:
9
+ self._name = ar.str()
10
+ g(f'Tray set: {self._name}')
11
+ self._random = (ar.word() if Features().piece_100 else 0)
12
+ self._visibleFlags = ar.dword()
13
+ self._ownerMask = (ar.word() if vers < num_version(3,10) else
14
+ ar.dword())
15
+ self._restrict = ar.word()
16
+ self._pieces = readVector(ar,lambda ar: ar.iden())
17
+
18
+ def __len__(self):
19
+ return len(self._pieces)
20
+
21
+ def toDict(self):
22
+ viz = self._visibleFlags & ~0xFFFF8000
23
+ # print(f'{self._visibleFlags:08x} -> {viz}')
24
+ vizStr = {0: 'all',
25
+ 1: 'owner',
26
+ 2: 'generic',
27
+ 3: 'none'}.get(viz,'')
28
+ return {'name': self._name,
29
+ 'visible': vizStr,
30
+ 'owner': self._ownerMask,
31
+ 'restrict': self._restrict,
32
+ 'pieces': self._pieces }
33
+
34
+ def __str__(self):
35
+ return (f'Tray set: {self._name} '
36
+ f'[visible={self._visibleFlags},'
37
+ f'ownerMask={self._ownerMask},'
38
+ f'resrict={self._restrict}] '
39
+ f'({len(self)}): {self._pieces}')
40
+
41
+
42
+ class GSNTrayManager:
43
+ def __init__(self,ar,vers,iden=''):
44
+ with VerboseGuard(f'Reading tray {iden} manager @ {ar.tell()}') as g:
45
+ self._iden = iden
46
+ self._reserved = [ar.word() for _ in range(4)]
47
+ g(f'{self._reserved}')
48
+ self._dummy = (ar.byte() if vers >= num_version(4,0) else 0)
49
+ self._sets = readVector(ar, lambda ar : GSNTraySet(ar,vers))
50
+
51
+ def __len__(self):
52
+ return len(self._sets)
53
+
54
+ def toDict(self):
55
+ return [s.toDict() for s in self._sets]
56
+
57
+ def __str__(self):
58
+ pl = '\n '.join([str(s) for s in self._sets])
59
+ return f'TrayManager: {self._iden} ({len(self)})\n {pl}\n'
60
+
61
+
62
+ #
63
+ # EOF
64
+ #
65
+
66
+
67
+
68
+
@@ -0,0 +1,41 @@
1
+ ## BEGIN_IMPORT
2
+ from common import VerboseGuard
3
+ ## END_IMPORT
4
+
5
+ class GSNWindow:
6
+ def __init__(self,ar):
7
+ with VerboseGuard('Reading window state') as g:
8
+ self._code = ar.word()
9
+ self._user = ar.word()
10
+ self._board = ar.iden()
11
+ self._state = [ar.dword() for _ in range(10)]
12
+ n = ar.size()
13
+ g(f'Read {self._code} {self._user} {self._board} {self._state}')
14
+ g(f'Reading {n} bytes at {ar.tell()}')
15
+ self._buffer = ar.read(n)
16
+
17
+ def __str__(self):
18
+ return (f'code={self._code:04x} '
19
+ f'user={self._user:04x} '
20
+ f'board={self._board:04x} '
21
+ f'buffer={len(self._buffer)}')
22
+
23
+ class GSNWindows:
24
+ def __init__(self,ar):
25
+ with VerboseGuard(f'Reading window states') as g:
26
+ self._savePositions = ar.word()
27
+ self._enable = ar.byte()
28
+ n = ar.size() if self._enable else 0
29
+ g(f'Save position: {self._savePositions}, '
30
+ f'enable {self._enable} '
31
+ f'n={n}')
32
+ self._states = [GSNWindow(ar) for _ in range(n)]
33
+
34
+ def __str__(self):
35
+ pl = '\n '.join([str(s) for s in self._states])
36
+ return f'Windows states ({len(self._states)})\n {pl}\n'
37
+
38
+
39
+ #
40
+ # EOF
41
+ #
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env python
2
+ ## BEGIN_IMPORT
3
+ from gamebox import GBXInfo
4
+ from head import GBXHeader
5
+ from archive import Archive
6
+ ## END_IMPORT
7
+
8
+ nullpwd = b'\xee\n\xcbg\xbc\xdb\x92\x1a\x0c\xd2\xf1y\x83*\x96\xc9'
9
+
10
+ def zeropwd(filename):
11
+ from pathlib import Path
12
+
13
+ pos = None
14
+ with Archive(filename,'rb') as ar:
15
+ header = GBXHeader(ar,GBXHeader.BOX)
16
+ box = GBXInfo(ar)
17
+
18
+
19
+ pos = ar.tell() - 4*2 - 2 - 2 - 16
20
+
21
+ with open(filename,'rb') as file:
22
+ cnt = file.read()
23
+ old = cnt[pos:pos+16]
24
+
25
+ lcnt = list(cnt)
26
+ lcnt[pos:pos+16] = list(nullpwd)
27
+ ncnt = bytes(lcnt)
28
+
29
+ on = Path(filename)
30
+ on = on.with_stem(on.stem + '-new')
31
+ with open(on,'wb') as file:
32
+ file.write(ncnt)
33
+
34
+
35
+ if __name__ == '__main__':
36
+ from argparse import ArgumentParser, FileType
37
+ ap = ArgumentParser(description='Disable password in gamebox')
38
+ ap.add_argument('input', type=str, help='The file')
39
+
40
+ args = ap.parse_args()
41
+
42
+ zeropwd(args.input)
43
+
44
+
45
+