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,283 @@
1
+ ## BEGIN_IMPORT
2
+ from common import VerboseGuard
3
+ from common import Verbose
4
+ from . features import Features
5
+ ## END_IMPORT
6
+
7
+
8
+
9
+ class BaseArchive:
10
+ WORD_SIZE = 2
11
+
12
+ def __init__(self,filename,mode='rb'):
13
+ '''Read data from a MFT CArchive stored on disk
14
+
15
+ Works as a context manager
16
+ '''
17
+ with VerboseGuard(f'Opening archive {filename}'):
18
+ self._filename = filename
19
+ self._file = open(filename,mode)
20
+ self._i = 0
21
+ self.vmsg = lambda *args : Verbose().message(*args)
22
+ #self.vmsg = lambda *args : None
23
+
24
+ def __enter__(self):
25
+ '''Enter context'''
26
+ return self
27
+
28
+ def __exit__(self,*args,**kwargs):
29
+ '''Exit context'''
30
+ self._file.close()
31
+
32
+ def tell(self):
33
+ pass
34
+
35
+ def read(self,n):
36
+ '''Read n bytes from archive'''
37
+ pass
38
+
39
+ def chr(self,n):
40
+ '''Read n characters from archive'''
41
+ b = self.read(n)
42
+ try:
43
+ c = b.decode()
44
+ self.vmsg(f'char->{c}')
45
+ return c
46
+ except:
47
+ print(f'Failed at {b} ({self._file.tell()})')
48
+ raise
49
+
50
+ def int(self,n):
51
+ '''Read an (unsigned) integer from archive'''
52
+ b = self.read(n)
53
+ i = int.from_bytes(b,'little' if Features().little_endian else 'big')
54
+ self.vmsg(f'int->{i}')
55
+ return i
56
+
57
+ def byte(self):
58
+ '''Read a byte from archive'''
59
+ return self.int(1)
60
+
61
+ def word(self):
62
+ '''Read a word (16bit integer) from archive'''
63
+ w = self.int(BaseArchive.WORD_SIZE)
64
+ self.vmsg(f'word->{w}')
65
+ return w;
66
+
67
+
68
+ def dword(self):
69
+ '''Read a double word (32bit integer) from archive'''
70
+ d = self.int(2*BaseArchive.WORD_SIZE)
71
+ self.vmsg(f'dword->{d}')
72
+ return d
73
+
74
+ def size(self):
75
+ '''Read a size'''
76
+ s = self.int(Features().size_size)
77
+ self.vmsg(f'size->{s}')
78
+ return s
79
+
80
+ def sub_size(self):
81
+ '''Read a size'''
82
+ s = self.int(Features().sub_size)
83
+ self.vmsg(f'sub->{s}')
84
+ return s
85
+
86
+ def count(self):
87
+ '''Read a count'''
88
+ if Features().size_size == 4:
89
+ return self.word()
90
+
91
+ c = self.word()
92
+ if c != 0xFFFF:
93
+ return c
94
+
95
+ c = self.dword()
96
+ if c != 0xFFFFFFFF:
97
+ return c
98
+
99
+ return int(8)
100
+
101
+ def iden(self):
102
+ '''Read an identifier'''
103
+ i = self.int(Features().id_size)
104
+ self.vmsg(f'id->{i}')
105
+ return i
106
+
107
+ def _strlen(self):
108
+ '''Read length of following string from archive'''
109
+ # See https://github.com/pixelspark/corespark/blob/master/Libraries/atlmfc/src/mfc/arccore.cpp
110
+
111
+ s = 1
112
+ l = self.byte()
113
+
114
+ if l < 0xFF: # Small ASCII string
115
+ self.vmsg(f'slen->{l},{s}')
116
+ return l, s
117
+
118
+ l = self.word()
119
+ if l == 0xFFFE: # Unicode - try again
120
+ s = 2
121
+ l = self.byte()
122
+
123
+ if l < 0xFF: # Small unicode
124
+ self.vmsg(f'slen->{l},{s}')
125
+ return l, s
126
+
127
+
128
+ l = self.word() # Large unicode string
129
+
130
+ if l < 0xFFFF: # Not super long
131
+ self.vmsg(f'slen->{l},{s}')
132
+ return l, s
133
+
134
+ l = self.dword()
135
+
136
+ if l < 0xFFFFFFFF: # Not hyper long
137
+ self.vmsg(f'slen->{l},{s}')
138
+ return l, s
139
+
140
+
141
+ self.vmsg(f'slen->{8},fixed')
142
+ return self.int(8)
143
+
144
+ def str(self):
145
+ '''Read a string from the archive'''
146
+ # See https://github.com/pixelspark/corespark/blob/master/Libraries/atlmfc/src/mfc/arccore.cpp
147
+ l, s = self._strlen()
148
+ # print(f'Read string of length {l}*{s} at {self.tell()}')
149
+ ret = [self.read(s) for i in range(l)]
150
+ try:
151
+ ret = [c.decode() for c in ret]
152
+ except:
153
+ ret = ['']
154
+ self.vmsg(f'str->"{"".join(ret)}"')
155
+ return ''.join(ret)
156
+
157
+ @property
158
+ def filename(self):
159
+ return self._filename
160
+
161
+ @property
162
+ def path(self):
163
+ from pathlib import Path
164
+ return Path(self._filename)
165
+
166
+ # ====================================================================
167
+ class UnbufferedArchive(BaseArchive):
168
+ def __init__(self,filename,mode='rb'):
169
+ '''Read data from a MFT CArchive stored on dist
170
+
171
+ Works as a context manager
172
+ '''
173
+ super(UnbufferedArchive,self).__init__(filename,mode='rb')
174
+
175
+ def read(self,n):
176
+ '''Read n bytes from archive - directly from file'''
177
+ b = self._file.read(n)
178
+ self.vmsg(f'read->{list(b)}')
179
+ # print(f'{self._i:6d} -> {b}')
180
+ self._i += n
181
+ return b
182
+
183
+ def tell(self):
184
+ return self._file.tell()
185
+
186
+ # ====================================================================
187
+ class BufferedArchive(BaseArchive):
188
+ def __init__(self,filename,mode='rb'):
189
+ '''Read data from a MFT CArchive stored on dist
190
+
191
+ Works as a context manager
192
+ '''
193
+ super(BufferedArchive,self).__init__(filename,mode='rb')
194
+ self._size = 4096
195
+ self._max = self._size
196
+ self._current = self._max
197
+ self._buffer = []
198
+
199
+ def read(self,n):
200
+ with VerboseGuard(f'Read {n} bytes') as g:
201
+ '''Read n bytes from archive - buffered
202
+
203
+ This emulates the behaviour of MFC CArchive::Read
204
+ '''
205
+
206
+ nmax = n
207
+ ntmp = min(nmax, self._max - self._current)
208
+ b = self._buffer[self._current:self._current+ntmp]
209
+ g(f'Take {ntmp} bytes from buffer -> {b}')
210
+ self._current += ntmp
211
+ nmax -= ntmp
212
+
213
+ if nmax != 0:
214
+ g(f'Need to read at least {nmax} from file')
215
+ assert self._current == self._max,\
216
+ f'Something is wrong! {self._current} != ' \
217
+ f'{self._max} (1)'
218
+
219
+ g(f'Missing {nmax} bytes -> ({nmax % self._size})')
220
+ ntmp = nmax - (nmax % self._size)
221
+ nread = 0
222
+ nleft = ntmp
223
+ nbytes = 0
224
+ while True:
225
+ tmpbuf = self._file.read(nleft)
226
+ nbytes = len(tmpbuf)
227
+ nread += nbytes
228
+ nleft -= nbytes
229
+ b += tmpbuf
230
+ g(f'Read {nleft} -> {tmpbuf}')
231
+
232
+ if nbytes <= 0 or nleft <= 0:
233
+ break
234
+
235
+ nmax -= nread
236
+
237
+ if nmax > 0 and nread == ntmp:
238
+ # Last read chunk into buffer and copy
239
+ assert self._current == self._max,\
240
+ f'Something is wrong! {self._current} != ' \
241
+ f'{self._max} (2)'
242
+
243
+ assert nmax < self._size, \
244
+ f'Something is wrong {nmax} >= {self._size}'
245
+
246
+ nlastleft = max(nmax,self._size)
247
+ nlastbytes = 0
248
+ nread = 0
249
+ self._buffer = []
250
+ while True:
251
+ tmpbuf = self._file.read(nlastleft)
252
+ nlastbytes = len(tmpbuf)
253
+ nread += nlastbytes
254
+ nlastleft -= nlastbytes
255
+ self._buffer += tmpbuf
256
+
257
+ if (nlastbytes <= 0) or \
258
+ (nlastleft <= 0) or \
259
+ nread >= ntmp:
260
+ break
261
+
262
+ self._current = 0
263
+ self._max = nread
264
+
265
+ ntmp = min(nmax, self._max - self._current)
266
+ b += self._buffer[self._current:
267
+ self._current+ntmp]
268
+ self._current += ntmp
269
+ nmax -= ntmp
270
+
271
+ g(b)
272
+ return b''.join(b)
273
+
274
+ def tell(self):
275
+ return self._file.tell()
276
+
277
+
278
+ Archive = UnbufferedArchive
279
+ # Archive = BufferedArchive
280
+
281
+ #
282
+ # EOF
283
+ #
@@ -0,0 +1,63 @@
1
+ ## BEGIN_IMPORT
2
+ from common import VerboseGuard
3
+ ## END_IMPORT
4
+
5
+ # --------------------------------------------------------------------
6
+ class CbFont:
7
+ def __init__(self,ar):
8
+ '''Shared structure that holds font information'''
9
+ # Fonts
10
+ with VerboseGuard('Reading font definition'):
11
+ self._size = ar.word()
12
+ self._flags = ar.word()
13
+ self._family = ar.word()
14
+ self._name = ar.str()
15
+
16
+ def isBold(self):
17
+ return self._flags & 0x1
18
+
19
+ def isItalic(self):
20
+ return self._flags & 0x2
21
+
22
+ def isUnderline(self):
23
+ return self._flags & 0x4
24
+
25
+ def __str__(self):
26
+ return (f'Font:{self._name} ({self._family}) @ '
27
+ f'{self._size} ({self._flags:08x})')
28
+
29
+ # --------------------------------------------------------------------
30
+ class CbManager:
31
+ def __init__(self,ar):
32
+ '''Base class for some managers'''
33
+ with VerboseGuard('Reading general manager'):
34
+ self._foreground = ar.dword()
35
+ self._background = ar.dword()
36
+ self._linewidth = ar.word()
37
+ self._font = CbFont(ar)
38
+ self._reserved = [ar.word() for _ in range(4)]
39
+
40
+ def _readNsub(self,ar,sub_size):
41
+ return ar.int(sub_size)
42
+
43
+ def _readSub(self,ar,cls,sub_size=None):
44
+ if sub_size is None:
45
+ sub_size = Features().sub_size
46
+ with VerboseGuard(f'Reading sub {cls} of manager ({sub_size})'):
47
+ n = self._readNsub(ar,sub_size)
48
+ return [cls(ar) for _ in range(n)]
49
+
50
+ def _strSub(self,title,subs):
51
+ subl = '\n '.join([str(s) for s in subs])
52
+ return f' # {title}: {len(subs)}\n {subl}'
53
+
54
+ def __str__(self):
55
+ return (f' Foreground: {self._foreground:08x}\n'
56
+ f' Background: {self._background:08x}\n'
57
+ f' Linewidth: {self._linewidth}\n'
58
+ f' Font: {self._font}\n'
59
+ f' Reserved: {self._reserved}\n')
60
+
61
+ #
62
+ # EOF
63
+ #