From af4f498c0b1ca713b08c32554fb1ba1efb47d0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Sat, 29 Feb 2020 18:07:14 +0100 Subject: [PATCH] Add map tool --- TODO.txt | 5 + assets/img2map.py | 261 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 assets/img2map.py diff --git a/TODO.txt b/TODO.txt index ede27ea..f708140 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,10 @@ general: +- Add blinking: + - In menu, the selected level number should blink to indicate it can be + changed. + - Near locked door the specific unlocking card should blink on the HUD bar. + - Add setting SFG_BLINK_PERIOD to control blinking speed. - try to remove the debug flag (-g1) from compiler and see if it decreases size - port to GB Meta - more level prop items diff --git a/assets/img2map.py b/assets/img2map.py new file mode 100644 index 0000000..1cd169c --- /dev/null +++ b/assets/img2map.py @@ -0,0 +1,261 @@ +# Python tool to convert an image to map for the Anarch game. The input image +# has to be in gif format. +# +# by drummyfish +# released under CC0 1.0. + +import sys +from PIL import Image + +elementTypes = [ + "NONE", + "BARREL", + "HEALTH", + "BULLETS", + "ROCKETS", + "PLASMA", + "TREE", + "FINISH", + "TELEPORT", + "TERMINAL", + "COLUMN", + "CARD0", + "CARD1", + "CARD2", + "LOCK0" + ] + +propertyTypes = [ + "ELEVATOR", + "SQUEEZER", + "DOOR" +] + +image = Image.open(sys.argv[1]) +pixels = image.load() + +palette = [] +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 + + palette.append(pixels[(x,y)]) + + paletteInverse[pixels[(x,y)]] = i + + x += 1 + +def getPixel(x,y): + return paletteInverse[pixels[(x,y)]] + +def loadTileDict(x,y): + result = [] + + for i in range(64): + texture = getPixel(x + i,y + 31) + + if texture > 6: + raise(Exception("Texture index can't be higher than 6.")) + + height = 0 + + for j in range(31): + if getPixel(x + i,y + 30 - j) == 7: + break + + height += 1 + + result.append((texture,height)) + + return result + +def defineName(n): + c = chr(ord("A") + n) + return c + c + +floorDict = loadTileDict(5,37) +ceilDict = loadTileDict(5,5) +floorColor = getPixel(41,122) +ceilColor = getPixel(41,118) +backgroundTex = getPixel(41,126) +doorTex = getPixel(41,130) +playerStart = [0,0,0] +textures = [] +elements = [] +defines = [] + +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 = getPixel(70 + x,5 + y) + + if n < 64: + levelMap[x][y] = (n,False) + else: + # tile with special property, create a define for it + + prop = n / 64 - 1 + tile = n % 64 + + defNum = -1 + + for i in range(len(defines)): + if defines[i] == (tile,prop): + defNum = i + break + + if defNum == -1: # not found: + defNum = len(defines) + defines.append((tile,prop)) + + levelMap[x][y] = (defNum,True) + +# load elements + +playerFound = False + +for y in range(64): + for x in range(64): + n = getPixel(x + 70, y + 70) + + if n < len(elementTypes): + elements.append((n,x,y)) + elif n >= 240: + if playerFound: + raise(Exception("Multiple player starting positions specified.")) + + playerStart = [x,y,(n - 240) * 16] + playerFound = True + +if not playerFound: + raise(Exception("Player starting position not specified.")) + +if len(elements) > 128: + raise(Exception("More than 128 level elements.")) + +for i in range(128 - len(elements)): + elements.append((0,0,0)) + +# load textures + +x = 41 +y = 114 + +for i in range(6): + textures.append(getPixel(x,y)) + x += 4 + +def numAlign(n): + return str(n) + "," + (" " if n < 10 else "") + +def mapXScale(): + r = " // " + + for i in range(64): + r += str(i).ljust(2) + " " + + return r + "\n" + +def printC(): + result = "" + result += " { // level\n" + result += " { // mapArray\n" + result += " #define o 0\n" + + for i in range(len(defines)): + result += " #define " + defineName(i) + " (" + str(defines[i][0]) + " | SFG_TILE_PROPERTY_" + propertyTypes[defines[i][1]] + ")\n" + + result += mapXScale() + + for y in range(64): + result += "/*" + str(y).ljust(2) + "*/ " + + for x in range(64): + item = levelMap[x][y] + + if not item[1]: + result += ("o " if item[0] == 0 else str(item[0]).ljust(2)) + else: + result += defineName(item[0]) + + result += "," if y < 63 or x < 63 else " " + + result += " /*" + str(y).ljust(2) + "*/ \n" + + result += mapXScale() + + for i in range(len(defines)): + result += " #undef " + defineName(i) + "\n" + + result += " #undef o\n" + result += " },\n" + result += " { // tileDictionary\n " + + for i in range(64): + result += "SFG_TD(" + str(floorDict[i][1]).rjust(2) + "," + str(ceilDict[i][1]).rjust(2) + "," + str(floorDict[i][0]) + "," + str(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 textures: + if first: + first = False + else: + s += "," + + s += str(t).ljust(2) + + result += " {" + s + "}, // textureIndices\n" + result += " " + numAlign(doorTex) + " // doorTextureIndex\n" + result += " " + numAlign(floorColor) + " // floorColor\n" + result += " " + numAlign(ceilColor) + " // ceilingColor\n" + result += " {" + str(playerStart[0]).ljust(2) + ", " + str(playerStart[1]).ljust(2) + ", " + str(playerStart[2]).ljust(3) + "}, // player start: x, y, direction\n" + result += " " + numAlign(backgroundTex) + " // backgroundImage\n" + result += " { // elements\n" + + even = True + + i = 0 + + for e in elements: + if even: + result += " " + + result += "{SFG_LEVEL_ELEMENT_" + 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) + +printC() +