# Converts an Anarch map image to usable data. # # by drummyfish, edits by pixelbath # released under CC0 1.0. from PIL import Image import math class AnarchMap: def __init__(self, image_path): self.elementTypes = [ "NONE", "BARREL", "HEALTH", "BULLETS", "ROCKETS", "PLASMA", "TREE", "FINISH", "TELEPORTER", "TERMINAL", "COLUMN", "RUIN", "LAMP", "CARD0", "CARD1", "CARD2", "LOCK0", "LOCK1", "LOCK2", "BLOCKER", "", "", "", "", "", "", "", "", "", "", "", "", "MONSTER_SPIDER", "MONSTER_DESTROYER", "MONSTER_WARRIOR", "MONSTER_PLASMABOT", "MONSTER_ENDER", "MONSTER_TURRET", "MONSTER_EXPLODER" ] self.propertyTypes = [ "ELEVATOR", "SQUEEZER", "DOOR" ] with Image.open(image_path) as image: self.pixel_data = image.load() self.palette = [] self.paletteInverse = [0 for i in range(256)] x = 5 y = 69 i = 0 # load the palette/sca for i in range(256): if i % 64 == 0: x = 5 y += 1 self.palette.append(self.pixel_data[(x,y)]) self.paletteInverse[self.pixel_data[(x,y)]] = i x += 1 self.floorDict = self.load_tile_dict(5,37) self.ceilDict = self.load_tile_dict(5,5) self.floorColor = self.get_pixel(41,122) self.ceilColor = self.get_pixel(41,118) self.backgroundTex = self.get_pixel(41,126) self.doorTex = self.get_pixel(41,130) self.playerStart = [0,0,0] self.textures = [] self.elements = [] self.defines = [] self.levelMap = [[(0,False) for i in range(64)] for j in range(64)] # load the map for y in range(64): for x in range(64): n = self.get_pixel(70 + x, 5 + y) if n < 64: self.levelMap[63 - x][y] = (n,False) else: # tile with special property, create a define for it prop = math.floor(n / 64) - 1 tile = n % 64 defNum = -1 for i in range(len(self.defines)): if self.defines[i] == (tile, prop): defNum = i break if defNum == -1: # not found: defNum = len(self.defines) self.defines.append((tile,prop)) self.levelMap[63 - x][y] = (defNum,True) # load elements playerFound = False for y in range(64): for x in range(64): n = self.get_pixel(x + 70, y + 70) if n < len(self.elementTypes): self.elements.append((n,63 - x,y)) elif n >= 240: if playerFound: raise(Exception("Multiple player starting positions specified.")) playerStart = [63 - x,y,(n - 240) * 16] playerFound = True if not playerFound: raise(Exception("Player starting position not specified.")) if len(self.elements) > 128: raise(Exception("More than 128 level elements.")) for i in range(128 - len(self.elements)): self.elements.append((0,0,0)) # load textures x = 41 y = 114 for i in range(7): self.textures.append(self.get_pixel(x, y)) x += 4 def get_pixel(self, x, y): return self.paletteInverse[self.pixel_data[(x, y)]] def load_tile_dict(self, x, y): result = [] for i in range(64): texture = self.get_pixel(x + i, y + 31) if texture > 7: raise(Exception("Texture index can't be higher than 7.")) height = 0 for j in range(31): if self.get_pixel(x + i, y + 30 - j) == 7: break height += 1 result.append((texture,height)) return result def defineName(self, n): c = chr(ord("A") + n) return c + c def numAlign(self, n): return str(n) + "," + (" " if n < 10 else "") def mapXScale(self): r = " // " for i in range(64): r += str(i).ljust(2) + " " return r + "\n" def printC(self): result = "" result += " { // level\n" result += " { // mapArray\n" result += " #define o 0\n" for i in range(len(self.defines)): result += " #define " + self.defineName(i) + " (" + str(self.defines[i][0]) + " | SFG_TILE_PROPERTY_" + self.propertyTypes[self.defines[i][1]] + ")\n" result += self.mapXScale() for y in range(64): result += "/*" + str(y).ljust(2) + "*/ " for x in range(64): item = self.levelMap[x][y] if not item[1]: result += ("o " if item[0] == 0 else str(item[0]).ljust(2)) else: result += self.defineName(item[0]) result += "," if y < 63 or x < 63 else " " result += " /*" + str(y).ljust(2) + "*/ \n" result += self.mapXScale() for i in range(len(self.defines)): result += " #undef " + self.defineName(i) + "\n" result += " #undef o\n" result += " },\n" result += " { // tileDictionary\n " for i in range(64): 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]) + ")" result += "," if i != 63 else " " if (i + 1) % 4 == 0: result += " // " + str(i - 3) + " \n " result += "}, // tileDictionary\n" s = "" first = True for t in self.textures: if first: first = False else: s += "," s += str(t).ljust(2) result += " {" + s + "}, // textureIndices\n" result += " " + self.numAlign(self.doorTex) + " // doorTextureIndex\n" result += " " + self.numAlign(self.floorColor) + " // floorColor\n" result += " " + self.numAlign(self.ceilColor) + " // ceilingColor\n" 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" result += " " + self.numAlign(self.backgroundTex) + " // backgroundImage\n" result += " { // elements\n" even = True i = 0 for e in self.elements: if even: result += " " result += "{SFG_LEVEL_ELEMENT_" + self.elementTypes[e[0]] + ", {" + str(e[1]) + "," + str(e[2]) + "}}" if i < 127: result += "," if not even: result += "\n" even = not even i += 1 result += " }, // elements\n" result += " } // level\n" print(result)