From 06ec89c134754f641e8affb4fb6d8ac863fec005 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 5 Mar 2023 23:33:23 -0800 Subject: [PATCH] Add text option to logic tiles script --- build.xml | 1 + tiled/tileset/logic/generatetiles.py | 126 +++++++++++++----- tiled/tileset/logic/layer/bg_checkered.png | Bin 0 -> 103 bytes tiled/tileset/logic/layer/text/armed.png | Bin 0 -> 163 bytes tiled/tileset/logic/layer/text/axe.png | Bin 0 -> 144 bytes tiled/tileset/logic/layer/text/b.png | Bin 0 -> 131 bytes tiled/tileset/logic/layer/text/baby.png | Bin 0 -> 167 bytes tiled/tileset/logic/layer/text/bad.png | Bin 0 -> 154 bytes tiled/tileset/logic/layer/text/black.png | Bin 0 -> 160 bytes tiled/tileset/logic/layer/text/bull.png | Bin 0 -> 138 bytes tiled/tileset/logic/layer/text/caiman.png | Bin 0 -> 170 bytes tiled/tileset/logic/layer/text/cave.png | Bin 0 -> 156 bytes tiled/tileset/logic/layer/text/dark.png | Bin 0 -> 155 bytes tiled/tileset/logic/layer/text/durin.png | Bin 0 -> 156 bytes tiled/tileset/logic/layer/text/gasha.png | Bin 0 -> 174 bytes tiled/tileset/logic/layer/text/giant.png | Bin 0 -> 164 bytes tiled/tileset/logic/layer/text/high.png | Bin 0 -> 156 bytes tiled/tileset/logic/layer/text/king.png | Bin 0 -> 154 bytes tiled/tileset/logic/layer/text/mammoth.png | Bin 0 -> 179 bytes tiled/tileset/logic/layer/text/mountain.png | Bin 0 -> 138 bytes .../tileset/logic/layer/text/nuggetcutter.png | Bin 0 -> 154 bytes tiled/tileset/logic/layer/text/s.png | Bin 0 -> 124 bytes tiled/tileset/logic/layer/text/unknown.png | Bin 0 -> 157 bytes tiled/tileset/logic/layer/text/w.png | Bin 0 -> 134 bytes 24 files changed, 95 insertions(+), 32 deletions(-) create mode 100644 tiled/tileset/logic/layer/bg_checkered.png create mode 100644 tiled/tileset/logic/layer/text/armed.png create mode 100644 tiled/tileset/logic/layer/text/axe.png create mode 100644 tiled/tileset/logic/layer/text/b.png create mode 100644 tiled/tileset/logic/layer/text/baby.png create mode 100644 tiled/tileset/logic/layer/text/bad.png create mode 100644 tiled/tileset/logic/layer/text/black.png create mode 100644 tiled/tileset/logic/layer/text/bull.png create mode 100644 tiled/tileset/logic/layer/text/caiman.png create mode 100644 tiled/tileset/logic/layer/text/cave.png create mode 100644 tiled/tileset/logic/layer/text/dark.png create mode 100644 tiled/tileset/logic/layer/text/durin.png create mode 100644 tiled/tileset/logic/layer/text/gasha.png create mode 100644 tiled/tileset/logic/layer/text/giant.png create mode 100644 tiled/tileset/logic/layer/text/high.png create mode 100644 tiled/tileset/logic/layer/text/king.png create mode 100644 tiled/tileset/logic/layer/text/mammoth.png create mode 100644 tiled/tileset/logic/layer/text/mountain.png create mode 100644 tiled/tileset/logic/layer/text/nuggetcutter.png create mode 100644 tiled/tileset/logic/layer/text/s.png create mode 100644 tiled/tileset/logic/layer/text/unknown.png create mode 100644 tiled/tileset/logic/layer/text/w.png diff --git a/build.xml b/build.xml index 4e89ccdec2..16cc86deaf 100644 --- a/build.xml +++ b/build.xml @@ -804,6 +804,7 @@ + diff --git a/tiled/tileset/logic/generatetiles.py b/tiled/tileset/logic/generatetiles.py index fc24a5c578..cad47ceac7 100755 --- a/tiled/tileset/logic/generatetiles.py +++ b/tiled/tileset/logic/generatetiles.py @@ -41,9 +41,32 @@ tile_nouse = Image.open(_file_nouse) if os.path.isfile(_file_nouse) else Image.n tile_bg = Image.new("RGB", (32, 32)) # draw white background image with black border ImageDraw.Draw(tile_bg).rectangle(((0, 0), (31, 31)), (255, 255, 255), (0, 0, 0)) +_file_bg_checkered = os.path.normpath(os.path.join(dir_logic, "layer/bg_checkered.png")) +tile_bg_checkered = Image.open(_file_bg_checkered).convert("RGB") if os.path.isfile(_file_bg_checkered) else tile_bg.copy() tilesPerRow = 8 +warn_count = 0 +err_count = 0 + +def message(mtype, text=None): + global warn_count, err_count + + if text == None: + text = mtype + mtype = "info" + + mtype = mtype.lower() + if mtype == "warn": + text = "WARNING: " + text + warn_count += 1 + elif mtype == "error": + text = "ERROR: " + text + err_count += 1 + + print(text) + + ## Reads config text. # # @param filepath @@ -73,10 +96,10 @@ if os.path.isfile(file_creature_conf): key = line[0:idx].strip() value = line[idx+1:].strip() if not key: - print("WARNING: empty key in creatures.conf") + message("warn", "empty key in creatures.conf") continue if not value: - print("WARNING: empty value for \"{}\" in creatures.conf".format(key)) + message("warn", "empty value for \"{}\" in creatures.conf".format(key)) continue conf = {} @@ -116,12 +139,11 @@ if os.path.isfile(file_creature_conf): # Root path of sprite images tree. # @param defs # Entities or items definitions. -# @param itemType -# `True` for items, `False` for creatures. +# @param flags # @return # Generated tileset image. -def buildTileSet(tiles, spriteDir, defs, itemType=True): - global tile_unused, tile_nouse, tile_bg, tilesPerRow, creature_conf +def buildTileSet(tiles, spriteDir, defs, flags=()): + global tile_unused, tile_nouse, tile_bg, tile_bg_checkered, tilesPerRow, creature_conf, dir_logic tileRows = [] currentRow = [] @@ -136,6 +158,10 @@ def buildTileSet(tiles, spriteDir, defs, itemType=True): if not tileRows: return None + bgTile = tile_bg + if "checkered" in flags: + bgTile = tile_bg_checkered + # create base image with pink background tileSetImage = Image.new("RGB", (len(tileRows[0]) * 32, len(tileRows) * 32), (255, 0, 255)) tileIdx = -1 @@ -146,33 +172,37 @@ def buildTileSet(tiles, spriteDir, defs, itemType=True): tileIdx += 1 offsetX = col * 32 tileId = tileRows[row][col] - tileImage = tile_bg.copy() + tileImage = bgTile.copy() + text = None if tileId in tiles: name = tiles[tileIdx] - refit = not itemType + refit = "creature_type" in flags sprite = None if name == "_nouse": refit = False sprite = tile_nouse.copy().convert("RGBA") + elif name == "_unknown": + refit = False + text = "unknown" else: spritePath = os.path.normpath(os.path.join(spriteDir, defs[name]["image"])) sprite = Image.open(spritePath).convert("RGBA") if refit: conf = {"flags": []} if name not in creature_conf else creature_conf[name] - noscale = "noscale" in conf["flags"] + nofit = "nofit" in conf["flags"] nopad = "nopad" in conf["flags"] - alignX = "left" if "alignX" not in conf else conf["alignX"] - alignY = "center" if "alignY" not in conf else conf["alignY"] - # TODO: add text - text = None if "text" not in conf else conf["text"] + alignX = "center" if "alignX" not in conf else conf["alignX"] + alignY = "top" if "alignY" not in conf else conf["alignY"] + if "text" in conf: + text = conf["text"] if "downscale" in conf: dfactor = 1 try: dfactor = int(conf["downscale"]) except ValueError: - print("ERROR: downscale factor for \"{}\" must be an integer") + message("error", "invalid tile ID: \"{}\"".format(value)) newWidth = math.floor(sprite.width / dfactor) newHeight = math.floor(sprite.height / dfactor) sprite = sprite.resize((newWidth, newHeight), Image.BICUBIC) @@ -185,7 +215,7 @@ def buildTileSet(tiles, spriteDir, defs, itemType=True): if "sliceY" in conf: sliceY = int(conf["sliceY"]) except ValueError: - print("ERROR: \"slice\" parameter must be an integer") + message("error", "\"slice\" parameter must be an integer") sliceW = math.floor(sprite.width / 3) sliceH = math.floor(sprite.height / 4) @@ -194,7 +224,8 @@ def buildTileSet(tiles, spriteDir, defs, itemType=True): sprite = sprite.crop((sliceX, sliceY, sliceX + sliceW, sliceY + sliceH)) # trim transparent pixels - sprite = sprite.crop(sprite.getbbox()) + if "notrim" not in conf["flags"]: + sprite = sprite.crop(sprite.getbbox()) # make square if sprite.width != sprite.height: @@ -217,7 +248,7 @@ def buildTileSet(tiles, spriteDir, defs, itemType=True): # scale down to 30x30 to fit inside border if sprite.width > 30: - if not noscale: + if not nofit: sprite = sprite.resize((30, 30), Image.BICUBIC) else: adjustX = math.floor((sprite.width - 30) / 2) @@ -238,18 +269,27 @@ def buildTileSet(tiles, spriteDir, defs, itemType=True): if sprite.height < 32: sprite = ImageOps.pad(sprite, (sprite.width, 32)) - # remove semi-transparent pixels - # ~ alpha = sprite.getchannel("A").point(lambda p: p > 128 and 255) - channels = sprite.split() - if len(channels) > 3: - alpha = channels[3].point(lambda p: p > 128 and 255) - sprite.putalpha(alpha) + if sprite: + # remove semi-transparent pixels + # ~ alpha = sprite.getchannel("A").point(lambda p: p > 128 and 255) + channels = sprite.split() + if len(channels) > 3: + alpha = channels[3].point(lambda p: p > 128 and 255) + sprite.putalpha(alpha) - tileImage.paste(sprite, None, sprite) - sprite.close() + tileImage.paste(sprite, None, sprite) + sprite.close() else: tileImage = tile_unused.copy() + if text: + _file_text = os.path.normpath(os.path.join(dir_logic, "layer/text/{}.png".format(text))) + if not os.path.isfile(_file_text): + message("warn", "text image not found: {}".format(_file_text)) + else: + tile_text = Image.open(_file_text).convert("RGBA") + tileImage.paste(tile_text, None, tile_text) + tileSetImage.paste(tileImage, (offsetX, offsetY)) tileImage.close() @@ -263,7 +303,7 @@ def buildTileSet(tiles, spriteDir, defs, itemType=True): # Image data to be exported. def writeTileSet(filepath, image): # convert to indexed color & save - image.convert("P").save(filepath) + image.convert("RGB").save(filepath) image.close() @@ -330,7 +370,7 @@ for xml in os.listdir(dir_config_item): raise ValueError tileId = int(vtmp[1]) except ValueError: - print("WARNING: invalid tile ID: \"{}\"".format(value)) + message("warn", "invalid tile ID: \"{}\"".format(value)) if spritePath.endswith(".png") and tileId > -1: itemData["image"] = spritePath @@ -368,17 +408,26 @@ def buildCreatureTiles(tileSet, creatures): print(" " + creatureName) tiles[creatures[creatureName]["tileid"]] = creatureName + flags = [] group_name = tileSet.split(".png")[0] if group_name in creature_conf["groups"]: gconf = creature_conf["groups"][group_name] + flags = gconf["flags"] if "nouse" in gconf: try: for nid in gconf["nouse"].split(","): tiles[int(nid)] = "_nouse" except ValueError: - print("ERROR: \"nouse\" value must be colon-separated list of integers") + message("error", "\"nouse\" value must be a list of integers") + if "unknown" in gconf: + try: + for nid in gconf["unknown"].split(","): + tiles[int(nid)] = "_unknown" + except ValueError: + message("error", "\"unknown\" value must be a list of integers") - tileSetImage = buildTileSet(tiles, dir_sprite_creature, creatures, False) + flags.append("creature_type") + tileSetImage = buildTileSet(tiles, dir_sprite_creature, creatures, tuple(flags)) if not tileSetImage: return writeTileSet(os.path.join(dir_target_creature, tileSet), tileSetImage) @@ -390,10 +439,13 @@ for xml in os.listdir(dir_config_creature): creatureName = None tileSet = None creatureData = {} + conf = {} for line in lines: line = line.strip() if not creatureName and line.startswith(" -1: creatureData["image"] = spritePath @@ -438,6 +494,7 @@ for xml in os.listdir(dir_config_creature): creatureName = None tileSet = None creatureData = {} + conf = {} continue for tileSet in creature_tilesets: @@ -447,3 +504,8 @@ for tileSet in creature_tilesets: tile_unused.close() tile_nouse.close() tile_bg.close() +tile_bg_checkered.close() + +print() +print("{} warnings".format(warn_count)) +print("{} errors".format(err_count)) diff --git a/tiled/tileset/logic/layer/bg_checkered.png b/tiled/tileset/logic/layer/bg_checkered.png new file mode 100644 index 0000000000000000000000000000000000000000..abf93e2918bac6150fff5ffc77bdabe1a3a12f19 GIT binary patch literal 103 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;*aCb)T!Hle|NocXoPQU{lJRtL x4B@z*oWQ`CoSdx8Hs3h?oCAkJ`Gcbl3=B?ICT1VCKLJ@l6I}gV);T3K0RZ~J93%h$ literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/armed.png b/tiled/tileset/logic/layer/text/armed.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ac31e2e02c385512062b8dc1011f7a4a3f65 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0D`p|Nk?ryRQ%rWHFWm z`2{mLJiCzw9p<Q!r665jk_h%QyBVLsE;YA2+k1#O6bX!WtznD=lwr kl3d-8<=`dpaMuL}hVtz^x7`2B8i5S?;;d;w!i;$uNmcaNSV{dn=HAp00i_ I>zopr07acI)&Kwi literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/bad.png b/tiled/tileset/logic/layer/text/bad.png new file mode 100644 index 0000000000000000000000000000000000000000..a5cf10102963d47c4424d33513d8a913d7b5915e GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^S0D`nj12$(GpL$g-w9%u z1o;IsI6S+N2ISayx;TbNTux4qn3TZE+$=U@V{@Y;|Ct+CrMB^%xv~Gxb^DGJm$N!f utb4wHVbAWT0j8h#J6>5cOKKa}dRGPq2hp8-SXOs|Z18mTb6Mw<&;$U*OEKpF literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/black.png b/tiled/tileset/logic/layer/text/black.png new file mode 100644 index 0000000000000000000000000000000000000000..521ede824218a29d20d50a2694f6bed22df22e82 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0D`p|Nk?ryRQ%rWHFWm z`2{mLJiCzw2?@-GLCVg~hn*UF)|^^UAnZXBo)=b&JV2~{3qM}_S>f)=x(UP!{f#J?Yq1&8CJ-9&@dAj8V5NaR_IxC!eqq>pE*5iHlzx; et;o*ci0fw1SLS)-SuT7SWT>aBpUXO@geCxa2PMY< literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/caiman.png b/tiled/tileset/logic/layer/text/caiman.png new file mode 100644 index 0000000000000000000000000000000000000000..35395da84976f65e2bd745c1795ba9c0f8fc0651 GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^S0D`nj12$(GpL$g-w9%u z1o;IsI6S+N2ITm7x;TbNTux4qc%;B`OoMUq8pVYR7cPqAmN>Hi+Vuau_5Yh3&CK@f zvH5bBk1g`zuTP&U1eCv3RaRpZ4_Z1i;X Kb6Mw<&;$VDNj8`O literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/cave.png b/tiled/tileset/logic/layer/text/cave.png new file mode 100644 index 0000000000000000000000000000000000000000..ff70aa018c8f7a6b463323205149476036197eba GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0D`p|Nk?ryRQ%rWHFWm z`2{mLJiCzw>3o vD!dv(TtUXUsVO&vCak+~A>f*T&M`&?ujK+;bN0kd0a@bd>gTe~DWM4fK>sWt literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/dark.png b/tiled/tileset/logic/layer/text/dark.png new file mode 100644 index 0000000000000000000000000000000000000000..731770a9d4122b0cdeb7b9d389135b366832d254 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0D`p|Nk?ryRQ%rWHFWm z`2{mLJiCzwyN6ae@b<@gXPYVA%$fL_)0SfddwdCla{lN^!X`I=J1qGVVzP{XZ#kf*h{GxZ2NO`D~q-8zXa)r|&Ht_T`ztgiAOxSst400J5>~~3;o-=#8 P0%WbHtDnm{r-UW|_`@>_ literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/giant.png b/tiled/tileset/logic/layer/text/giant.png new file mode 100644 index 0000000000000000000000000000000000000000..2585655afe67ac24ab52d47f3a029c18a11d8e50 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0K&6$ngI^!{q&(??LR6 zAirP+hi5m^fE-Ux7sn8Z%gG56UJX|nPbCy5B=9hBwlEzOQE<+Qys{?KyMgEAmJ2gi z1|R5IF>|Hxfu4|#jvJfS%v_mZy3!$5QDLH{K{Io~4GxC8Z-x4AsK?I)S?B5M=d#Wz Gp$Pz;8Z(*z literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/high.png b/tiled/tileset/logic/layer/text/high.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba413729d8b9c9bc29da71d92670487b73007d0 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^S0D`nj12$(GpL$g-w9%u z1o;IsI6S+N2ISazx;TbNTux4qxYTgfu;D7>k%aO+2lx_O+;sU_jsNZY_fPyxN9}f7 uG4aP=%MF@MO|r8!j(GeP57@j_jDeHENmMkXUan*g$PQ0eKbLh*2~7ZuoGnZM literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/king.png b/tiled/tileset/logic/layer/text/king.png new file mode 100644 index 0000000000000000000000000000000000000000..6de3b1fdcfb17fb80b63f6479ebc4917f7d75de6 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0D`p|Nk?ryRQ%rWHFWm z`2{mLJiCzwxPbF}qCNMDMh6?H$wex|@W$<+Mb6Mw<&;$T-peJ_# literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/mammoth.png b/tiled/tileset/logic/layer/text/mammoth.png new file mode 100644 index 0000000000000000000000000000000000000000..2f115b9aff8356ca75ea424e64836809f4cb0cc8 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0D`p|Nk?ryRQ%rWHFWm z`2{mLJiCzw}n~ UBW=e+S)d&Zp00i_>zopr0PNf|q5uE@ literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/mountain.png b/tiled/tileset/logic/layer/text/mountain.png new file mode 100644 index 0000000000000000000000000000000000000000..012fbe43812e49ed6ef0437ce20b1dbbc34da432 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^S0D`nj12$(GpL$g-w9%u z1o;IsI6S+N2IS~?x;TbNTux4qFl)$UoWa!_^_A(&iv53ov(E^O+xw2S=Ocsj6Lz2L cTsdt_3>$rgqJ*CQwE~&w>FVdQ&MBb@07%CsX8-^I literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/nuggetcutter.png b/tiled/tileset/logic/layer/text/nuggetcutter.png new file mode 100644 index 0000000000000000000000000000000000000000..33a19cb6e3b8821a7042ff0d5c12cbf9d03c3ec1 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^S0D`nj12$(GpL$g-w9%u z1o;IsI6S+N2ISayx;TbNTux4qxYTg3=D%fo6I5$@(2`;sALL+jFIt&I|E5*MyaU`tNB yamB|Vc~#1TkPYh?0*^5mBsZx%W)Ttm#mMk3me(eH{flg%X$+pOelF{r5}E*k8!box literal 0 HcmV?d00001 diff --git a/tiled/tileset/logic/layer/text/w.png b/tiled/tileset/logic/layer/text/w.png new file mode 100644 index 0000000000000000000000000000000000000000..ab20f8b456abe48434c5f763629f5a05dcfcb928 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0D`p|Nk?ryRQ%rWHFWm z`2{mLJiCzwxvX