mom-save-edit.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. #!/usr/bin/env python3
  2. import sys
  3. from struct import unpack
  4. from PySide6.QtCore import (
  5. QMargins,
  6. QSettings,
  7. QSize,
  8. Qt,
  9. )
  10. from PySide6.QtGui import (
  11. QBrush,
  12. QColor,
  13. QPen,
  14. )
  15. from PySide6.QtWidgets import (
  16. QApplication,
  17. QGraphicsRectItem,
  18. QGraphicsScene,
  19. QGraphicsView,
  20. QGridLayout,
  21. QLabel,
  22. QMainWindow,
  23. QMessageBox,
  24. QPushButton,
  25. QSizePolicy,
  26. QToolBar,
  27. QWidget,
  28. )
  29. num_wizards = 6
  30. num_heroes = 35
  31. num_nodes = 30
  32. num_items = 132
  33. num_encounters = 102
  34. num_cities = 100
  35. num_units = 1009
  36. num_events = 50
  37. map_width = 60
  38. map_height = 40
  39. savefile = 'SAVE5.GAM'
  40. tile_size = 20
  41. terrain_colors = {
  42. 'Ocean': (20, 20, 80),
  43. 'Shore': (40, 40, 120),
  44. 'Lake': (60, 60, 160),
  45. 'River': (60, 60, 160),
  46. 'Desert': (210, 200, 100),
  47. 'Swamp': (40, 10, 40),
  48. 'Grassland': (40, 120, 40),
  49. 'Forest': (20, 80, 20),
  50. 'Hills': (80, 120, 80),
  51. 'Mountain': (80, 80, 80),
  52. 'Tundra': (180, 180, 180),
  53. 'Node': (10, 10, 10),
  54. }
  55. terrain_hex_lookup = {
  56. 0x000: 'Ocean',
  57. 0x012: 'Lake',
  58. 0x0a2: 'Grassland',
  59. 0x0a3: 'Forest',
  60. 0x0a4: 'Mountain',
  61. 0x0a5: 'Desert',
  62. 0x0a6: 'Swamp',
  63. 0x0a7: 'Tundra',
  64. 0x0a8: 'Node', #sorcery
  65. 0x0a9: 'Node', #nature
  66. 0x0aa: 'Node', #chaos
  67. 0x0ab: 'Hills',
  68. 0x0ac: 'Grassland',
  69. 0x0ad: 'Grassland',
  70. 0x0ae: 'Desert',
  71. 0x0af: 'Desert',
  72. 0x0b0: 'Desert',
  73. 0x0b1: 'Swamp',
  74. 0x0b2: 'Swamp',
  75. 0x0b3: 'Node', #volcano
  76. 0x0b4: 'Grassland',
  77. 0x0b5: 'Tundra',
  78. 0x0b6: 'Tundra',
  79. 0x0b7: 'Forest',
  80. 0x0b8: 'Forest',
  81. 0x0c5: 'Lake',
  82. 0x0c6: 'Lake',
  83. 0x0c7: 'Lake',
  84. 0x0c8: 'Lake',
  85. 0x1d4: 'River',
  86. 0x1d5: 'River',
  87. 0x1d6: 'River',
  88. 0x1d7: 'River',
  89. 0x1d8: 'River',
  90. 0x259: 'Ocean',
  91. 0x26a: 'Tundra',
  92. }
  93. terrain_hex_ranges = {
  94. (0x002, 0x0a1): 'Shore',
  95. (0x0b9, 0x0c4): 'River',
  96. (0x0c9, 0x0e8): 'Shore',
  97. (0x0e9, 0x102): 'River',
  98. (0x103, 0x112): 'Mountain',
  99. (0x113, 0x123): 'Hills',
  100. (0x124, 0x1c3): 'Desert',
  101. (0x1c4, 0x1d3): 'Shore',
  102. (0x1d9, 0x258): 'Shore',
  103. (0x25a, 0x2ff): 'Tundra',
  104. }
  105. missed_hexes = []
  106. def map_square_color(terrain_hex):
  107. color = (250, 60, 60)
  108. terrain = ''
  109. if terrain_hex in terrain_hex_lookup:
  110. terrain = terrain_hex_lookup[terrain_hex]
  111. else:
  112. for (r, t) in terrain_hex_ranges.items():
  113. if r[0] <= terrain_hex <= r[1]:
  114. terrain = t
  115. if terrain in terrain_colors:
  116. color = terrain_colors[terrain]
  117. else:
  118. missed_hexes.append(terrain_hex)
  119. return color
  120. def map_square_terrain(terrain_hex):
  121. terrain = ''
  122. if terrain_hex in terrain_hex_lookup:
  123. terrain = terrain_hex_lookup[terrain_hex]
  124. else:
  125. for (r, t) in terrain_hex_ranges.items():
  126. if r[0] <= terrain_hex <= r[1]:
  127. terrain = t
  128. return terrain
  129. class MapTile(QGraphicsRectItem):
  130. def __init__(self, x, y, tile_hex):
  131. super().__init__(0, 0, tile_size, tile_size)
  132. self.x = x
  133. self.y = y
  134. self.tile_hex = tile_hex
  135. self.terrain = map_square_terrain(tile_hex)
  136. self.color = (250, 60, 60)
  137. if self.terrain in terrain_colors:
  138. self.color = terrain_colors[self.terrain]
  139. brush = QBrush(QColor(self.color[0], self.color[1], self.color[2]))
  140. self.setBrush(brush)
  141. self.setPos(tile_size * self.x, tile_size * self.y)
  142. self.setHandlesChildEvents(True)
  143. def mousePressEvent(self, mousevent):
  144. print("clicked a %s at (%s, %s)" % (self.terrain, self.x, self.y))
  145. class MainWindow(QMainWindow):
  146. def __init__(self):
  147. super().__init__()
  148. self.data = {}
  149. self.setWindowTitle("MOM Save Editor")
  150. mapGridLayout = QGridLayout()
  151. mapGridLayout.setSpacing(0)
  152. mapGridLayout.setHorizontalSpacing(0)
  153. mapGridLayout.setVerticalSpacing(0)
  154. mapGridLayout.setContentsMargins(QMargins(0,0,0,0))
  155. self.setCentralWidget(QWidget())
  156. self.addToolBar(QToolBar())
  157. self.centralWidget().setLayout(mapGridLayout)
  158. self.main_scene = QGraphicsScene(0, 0, 1200, 800)
  159. self.mirror_scene = QGraphicsScene(0, 0, 1200, 800)
  160. self.mapView = QGraphicsView(self.main_scene)
  161. # self.mapView.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)
  162. self.current_map = "Arcanus"
  163. self.button = QPushButton("Switch to Myrror")
  164. self.button.clicked.connect(self.the_button_was_clicked)
  165. self.setMinimumSize(QSize(150,150))
  166. mapGridLayout.addWidget(self.mapView)
  167. mapGridLayout.addWidget(self.button)
  168. # for x in range(map_height):
  169. # for y in range(map_width):
  170. # print(map_square_string(mirror_terrain[y][x]), end='')
  171. # print()
  172. def plot_map(self, main_data, mirror_data):
  173. for y in range(map_height):
  174. for x in range(map_width):
  175. atile = MapTile(x, y, main_data[x][y])
  176. mtile = MapTile(x, y, mirror_data[x][y])
  177. self.main_scene.addItem(atile)
  178. self.mirror_scene.addItem(mtile)
  179. self.mapView.show()
  180. def the_button_was_clicked(self):
  181. print("button clicked")
  182. if self.current_map == "Arcanus":
  183. self.button.setText("Switch to Arcanus")
  184. self.current_map = "Myrror"
  185. self.mapView.setScene(self.mirror_scene)
  186. self.mapView.show()
  187. else:
  188. self.button.setText("Switch to Myrror")
  189. self.current_map = "Arcanus"
  190. self.mapView.setScene(self.main_scene)
  191. self.mapView.show()
  192. if __name__ == '__main__':
  193. with open(savefile, 'rb') as sf:
  194. hero_stats = []
  195. for w in range(num_wizards):
  196. for h in range(num_heroes):
  197. hero_stats.append(sf.read(12))
  198. gamedata = sf.read(16)
  199. wizard_data = []
  200. for w in range(num_wizards):
  201. wizard_data.append(sf.read(1224))
  202. main_terrain = [ [ 0 for h in range(map_height) ]
  203. for w in range(map_width) ]
  204. for h in range(map_height):
  205. for w in range(map_width):
  206. main_terrain[w][h] = unpack("<H", sf.read(2))[0]
  207. mirror_terrain = [ [ 0 for h in range(map_height) ]
  208. for w in range(map_width) ]
  209. for h in range(map_height):
  210. for w in range(map_width):
  211. mirror_terrain[w][h] = unpack("<H", sf.read(2))[0]
  212. unused = sf.read(192*2)
  213. landmass_main = [ [ 0 for h in range(map_height) ]
  214. for w in range(map_width) ]
  215. for h in range(map_height):
  216. for w in range(map_width):
  217. landmass_main[w][h] = sf.read(1)
  218. landmass_mirror = [ [ 0 for h in range(map_height) ]
  219. for w in range(map_width) ]
  220. for h in range(map_height):
  221. for w in range(map_width):
  222. landmass_mirror[w][h] = sf.read(1)
  223. nodes = []
  224. for n in range(num_nodes):
  225. nodes.append(sf.read(48))
  226. fortresses = []
  227. for f in range(num_wizards):
  228. fortresses.append(sf.read(4))
  229. towers = []
  230. for t in range(num_wizards):
  231. towers.append(sf.read(4))
  232. encounter_zones = []
  233. for e in range(num_encounters):
  234. encounter_zones.append(sf.read(24))
  235. items = []
  236. for i in range(num_items):
  237. items.append(sf.read(50))
  238. queued_items = sf.read(50 * 4)
  239. merchant_item = sf.read(50)
  240. forging_item = sf.read(50)
  241. cities = []
  242. for c in range(num_cities):
  243. cities.append(sf.read(114))
  244. units = []
  245. for u in range(num_units):
  246. units.append(sf.read(32))
  247. minerals_main = [ [ 0 for h in range(map_height) ]
  248. for w in range(map_width) ]
  249. for h in range(map_height):
  250. for w in range(map_width):
  251. minerals_main[w][h] = sf.read(1)
  252. minerals_mirror = [ [ 0 for h in range(map_height) ]
  253. for w in range(map_width) ]
  254. for h in range(map_height):
  255. for w in range(map_width):
  256. minerals_mirror[w][h] = sf.read(1)
  257. explored_main = [ [ 0 for h in range(map_height) ]
  258. for w in range(map_width) ]
  259. for h in range(map_height):
  260. for w in range(map_width):
  261. explored_main[w][h] = sf.read(1)
  262. explored_mirror = [ [ 0 for h in range(map_height) ]
  263. for w in range(map_width) ]
  264. for h in range(map_height):
  265. for w in range(map_width):
  266. explored_mirror[w][h] = sf.read(1)
  267. for i in range(12):
  268. for h in range(map_height):
  269. for w in range(map_width):
  270. throwaway = sf.read(1)
  271. events = []
  272. for e in range(num_events):
  273. events.append(sf.read(2))
  274. flags_main = [ [ 0 for h in range(map_height) ]
  275. for w in range(map_width) ]
  276. for h in range(map_height):
  277. for w in range(map_width):
  278. flags_main[w][h] = sf.read(1)
  279. flags_mirror = [ [ 0 for h in range(map_height) ]
  280. for w in range(map_width) ]
  281. for h in range(map_height):
  282. for w in range(map_width):
  283. flags_mirror[w][h] = sf.read(1)
  284. grand_vizer = sf.read(2)
  285. items_in_game = sf.read(250)
  286. hero_names = []
  287. for h in range(num_heroes):
  288. hero_names.append(sf.read(16))
  289. for x in sorted(missed_hexes):
  290. print(x)
  291. app = QApplication(sys.argv)
  292. window = MainWindow()
  293. window.data['main_terrain'] = main_terrain
  294. window.data['mirror_terrain'] = mirror_terrain
  295. window.show()
  296. window.plot_map(main_terrain, mirror_terrain)
  297. app.exec()
  298. #####################################
  299. # with open(savefile, 'rb') as sf:
  300. # hero_stats = []
  301. # for w in range(num_wizards):
  302. # for h in range(num_heroes):
  303. # hero_stats.append(sf.read(12))
  304. # gamedata = sf.read(16)
  305. # wizard_data = []
  306. # for w in range(num_wizards):
  307. # wizard_data.append(sf.read(1224))
  308. # main_terrain = [ [ 0 for h in range(map_height) ]
  309. # for w in range(map_width) ]
  310. # for h in range(map_height):
  311. # for w in range(map_width):
  312. # main_terrain[w][h] = unpack("<H", sf.read(2))[0]
  313. # mirror_terrain = [ [ 0 for h in range(map_height) ]
  314. # for w in range(map_width) ]
  315. # for h in range(map_height):
  316. # for w in range(map_width):
  317. # mirror_terrain[w][h] = unpack("<H", sf.read(2))[0]
  318. # unused = sf.read(192*2)
  319. # landmass_main = [ [ 0 for h in range(map_height) ]
  320. # for w in range(map_width) ]
  321. # for h in range(map_height):
  322. # for w in range(map_width):
  323. # landmass_main[w][h] = sf.read(1)
  324. # landmass_mirror = [ [ 0 for h in range(map_height) ]
  325. # for w in range(map_width) ]
  326. # for h in range(map_height):
  327. # for w in range(map_width):
  328. # landmass_mirror[w][h] = sf.read(1)
  329. # nodes = []
  330. # for n in range(num_nodes):
  331. # nodes.append(sf.read(48))
  332. # fortresses = []
  333. # for f in range(num_wizards):
  334. # fortresses.append(sf.read(4))
  335. # towers = []
  336. # for t in range(num_wizards):
  337. # towers.append(sf.read(4))
  338. # encounter_zones = []
  339. # for e in range(num_encounters):
  340. # encounter_zones.append(sf.read(24))
  341. # items = []
  342. # for i in range(num_items):
  343. # items.append(sf.read(50))
  344. # queued_items = sf.read(50 * 4)
  345. # merchant_item = sf.read(50)
  346. # forging_item = sf.read(50)
  347. # cities = []
  348. # for c in range(num_cities):
  349. # cities.append(sf.read(114))
  350. # units = []
  351. # for u in range(num_units):
  352. # units.append(sf.read(36))
  353. # minerals_main = [ [ 0 for h in range(map_height) ]
  354. # for w in range(map_width) ]
  355. # for h in range(map_height):
  356. # for w in range(map_width):
  357. # minerals_main[w][h] = sf.read(1)
  358. # minerals_mirror = [ [ 0 for h in range(map_height) ]
  359. # for w in range(map_width) ]
  360. # for h in range(map_height):
  361. # for w in range(map_width):
  362. # minerals_mirror[w][h] = sf.read(1)
  363. # explored_main = [ [ 0 for h in range(map_height) ]
  364. # for w in range(map_width) ]
  365. # for h in range(map_height):
  366. # for w in range(map_width):
  367. # explored_main[w][h] = sf.read(1)
  368. # explored_mirror = [ [ 0 for h in range(map_height) ]
  369. # for w in range(map_width) ]
  370. # for h in range(map_height):
  371. # for w in range(map_width):
  372. # explored_mirror[w][h] = sf.read(1)
  373. # for i in range(12):
  374. # for h in range(map_height):
  375. # for w in range(map_width):
  376. # throwaway = sf.read(1)
  377. # events = []
  378. # for e in range(num_events):
  379. # events.append(sf.read(2))
  380. # flags_main = [ [ 0 for h in range(map_height) ]
  381. # for w in range(map_width) ]
  382. # for h in range(map_height):
  383. # for w in range(map_width):
  384. # flags_main[w][h] = sf.read(1)
  385. # flags_mirror = [ [ 0 for h in range(map_height) ]
  386. # for w in range(map_width) ]
  387. # for h in range(map_height):
  388. # for w in range(map_width):
  389. # flags_mirror[w][h] = sf.read(1)
  390. # grand_vizer = sf.read(2)
  391. # items_in_game = sf.read(250)
  392. # hero_names = []
  393. # for h in range(num_heroes):
  394. # hero_names.append(sf.read(16))