anarchmap.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. # Converts an Anarch map image to usable data.
  2. #
  3. # by drummyfish, edits by pixelbath
  4. # released under CC0 1.0.
  5. from PIL import Image
  6. import math
  7. class AnarchMap:
  8. def __init__(self, image_path):
  9. self.elementTypes = [
  10. "NONE",
  11. "BARREL",
  12. "HEALTH",
  13. "BULLETS",
  14. "ROCKETS",
  15. "PLASMA",
  16. "TREE",
  17. "FINISH",
  18. "TELEPORTER",
  19. "TERMINAL",
  20. "COLUMN",
  21. "RUIN",
  22. "LAMP",
  23. "CARD0",
  24. "CARD1",
  25. "CARD2",
  26. "LOCK0",
  27. "LOCK1",
  28. "LOCK2",
  29. "BLOCKER",
  30. "",
  31. "",
  32. "",
  33. "",
  34. "",
  35. "",
  36. "",
  37. "",
  38. "",
  39. "",
  40. "",
  41. "",
  42. "MONSTER_SPIDER",
  43. "MONSTER_DESTROYER",
  44. "MONSTER_WARRIOR",
  45. "MONSTER_PLASMABOT",
  46. "MONSTER_ENDER",
  47. "MONSTER_TURRET",
  48. "MONSTER_EXPLODER"
  49. ]
  50. self.propertyTypes = [
  51. "ELEVATOR",
  52. "SQUEEZER",
  53. "DOOR"
  54. ]
  55. with Image.open(image_path) as image:
  56. self.pixel_data = image.load()
  57. self.palette = []
  58. self.paletteInverse = [0 for i in range(256)]
  59. x = 5
  60. y = 69
  61. i = 0
  62. # load the palette/sca
  63. for i in range(256):
  64. if i % 64 == 0:
  65. x = 5
  66. y += 1
  67. self.palette.append(self.pixel_data[(x,y)])
  68. self.paletteInverse[self.pixel_data[(x,y)]] = i
  69. x += 1
  70. self.floorDict = self.load_tile_dict(5,37)
  71. self.ceilDict = self.load_tile_dict(5,5)
  72. self.floorColor = self.get_pixel(41,122)
  73. self.ceilColor = self.get_pixel(41,118)
  74. self.backgroundTex = self.get_pixel(41,126)
  75. self.doorTex = self.get_pixel(41,130)
  76. self.playerStart = [0,0,0]
  77. self.textures = []
  78. self.elements = []
  79. self.defines = []
  80. self.levelMap = [[(0,False) for i in range(64)] for j in range(64)]
  81. # load the map
  82. for y in range(64):
  83. for x in range(64):
  84. n = self.get_pixel(70 + x, 5 + y)
  85. if n < 64:
  86. self.levelMap[63 - x][y] = (n,False)
  87. else:
  88. # tile with special property, create a define for it
  89. prop = math.floor(n / 64) - 1
  90. tile = n % 64
  91. defNum = -1
  92. for i in range(len(self.defines)):
  93. if self.defines[i] == (tile, prop):
  94. defNum = i
  95. break
  96. if defNum == -1: # not found:
  97. defNum = len(self.defines)
  98. self.defines.append((tile,prop))
  99. self.levelMap[63 - x][y] = (defNum,True)
  100. # load elements
  101. playerFound = False
  102. for y in range(64):
  103. for x in range(64):
  104. n = self.get_pixel(x + 70, y + 70)
  105. if n < len(self.elementTypes):
  106. self.elements.append((n,63 - x,y))
  107. elif n >= 240:
  108. if playerFound:
  109. raise(Exception("Multiple player starting positions specified."))
  110. playerStart = [63 - x,y,(n - 240) * 16]
  111. playerFound = True
  112. if not playerFound:
  113. raise(Exception("Player starting position not specified."))
  114. if len(self.elements) > 128:
  115. raise(Exception("More than 128 level elements."))
  116. for i in range(128 - len(self.elements)):
  117. self.elements.append((0,0,0))
  118. # load textures
  119. x = 41
  120. y = 114
  121. for i in range(7):
  122. self.textures.append(self.get_pixel(x, y))
  123. x += 4
  124. def get_pixel(self, x, y):
  125. return self.paletteInverse[self.pixel_data[(x, y)]]
  126. def load_tile_dict(self, x, y):
  127. result = []
  128. for i in range(64):
  129. texture = self.get_pixel(x + i, y + 31)
  130. if texture > 7:
  131. raise(Exception("Texture index can't be higher than 7."))
  132. height = 0
  133. for j in range(31):
  134. if self.get_pixel(x + i, y + 30 - j) == 7:
  135. break
  136. height += 1
  137. result.append((texture,height))
  138. return result
  139. def defineName(self, n):
  140. c = chr(ord("A") + n)
  141. return c + c
  142. def numAlign(self, n):
  143. return str(n) + "," + (" " if n < 10 else "")
  144. def mapXScale(self):
  145. r = " // "
  146. for i in range(64):
  147. r += str(i).ljust(2) + " "
  148. return r + "\n"
  149. def printC(self):
  150. result = ""
  151. result += " { // level\n"
  152. result += " { // mapArray\n"
  153. result += " #define o 0\n"
  154. for i in range(len(self.defines)):
  155. result += " #define " + self.defineName(i) + " (" + str(self.defines[i][0]) + " | SFG_TILE_PROPERTY_" + self.propertyTypes[self.defines[i][1]] + ")\n"
  156. result += self.mapXScale()
  157. for y in range(64):
  158. result += "/*" + str(y).ljust(2) + "*/ "
  159. for x in range(64):
  160. item = self.levelMap[x][y]
  161. if not item[1]:
  162. result += ("o " if item[0] == 0 else str(item[0]).ljust(2))
  163. else:
  164. result += self.defineName(item[0])
  165. result += "," if y < 63 or x < 63 else " "
  166. result += " /*" + str(y).ljust(2) + "*/ \n"
  167. result += self.mapXScale()
  168. for i in range(len(self.defines)):
  169. result += " #undef " + self.defineName(i) + "\n"
  170. result += " #undef o\n"
  171. result += " },\n"
  172. result += " { // tileDictionary\n "
  173. for i in range(64):
  174. result += "SFG_TD(" + str(self.floorDict[i][1]).rjust(2) + "," + str(self.ceilDict[i][1]).rjust(2) + "," + str(self.floorDict[i][0]) + "," + str(self.ceilDict[i][0]) + ")"
  175. result += "," if i != 63 else " "
  176. if (i + 1) % 4 == 0:
  177. result += " // " + str(i - 3) + " \n "
  178. result += "}, // tileDictionary\n"
  179. s = ""
  180. first = True
  181. for t in self.textures:
  182. if first:
  183. first = False
  184. else:
  185. s += ","
  186. s += str(t).ljust(2)
  187. result += " {" + s + "}, // textureIndices\n"
  188. result += " " + self.numAlign(self.doorTex) + " // doorTextureIndex\n"
  189. result += " " + self.numAlign(self.floorColor) + " // floorColor\n"
  190. result += " " + self.numAlign(self.ceilColor) + " // ceilingColor\n"
  191. result += " {" + str(self.playerStart[0]).ljust(2) + ", " + str(self.playerStart[1]).ljust(2) + ", " + str(self.playerStart[2]).ljust(3) + "}, // player start: x, y, direction\n"
  192. result += " " + self.numAlign(self.backgroundTex) + " // backgroundImage\n"
  193. result += " { // elements\n"
  194. even = True
  195. i = 0
  196. for e in self.elements:
  197. if even:
  198. result += " "
  199. result += "{SFG_LEVEL_ELEMENT_" + self.elementTypes[e[0]] + ", {" + str(e[1]) + "," + str(e[2]) + "}}"
  200. if i < 127:
  201. result += ","
  202. if not even:
  203. result += "\n"
  204. even = not even
  205. i += 1
  206. result += " }, // elements\n"
  207. result += " } // level\n"
  208. print(result)