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 0000000000..abf93e2918 Binary files /dev/null and b/tiled/tileset/logic/layer/bg_checkered.png differ diff --git a/tiled/tileset/logic/layer/text/armed.png b/tiled/tileset/logic/layer/text/armed.png new file mode 100644 index 0000000000..4483ac31e2 Binary files /dev/null and b/tiled/tileset/logic/layer/text/armed.png differ diff --git a/tiled/tileset/logic/layer/text/axe.png b/tiled/tileset/logic/layer/text/axe.png new file mode 100644 index 0000000000..9ff4d362cc Binary files /dev/null and b/tiled/tileset/logic/layer/text/axe.png differ diff --git a/tiled/tileset/logic/layer/text/b.png b/tiled/tileset/logic/layer/text/b.png new file mode 100644 index 0000000000..a0d7c76c3d Binary files /dev/null and b/tiled/tileset/logic/layer/text/b.png differ diff --git a/tiled/tileset/logic/layer/text/baby.png b/tiled/tileset/logic/layer/text/baby.png new file mode 100644 index 0000000000..46e2338ce1 Binary files /dev/null and b/tiled/tileset/logic/layer/text/baby.png differ diff --git a/tiled/tileset/logic/layer/text/bad.png b/tiled/tileset/logic/layer/text/bad.png new file mode 100644 index 0000000000..a5cf101029 Binary files /dev/null and b/tiled/tileset/logic/layer/text/bad.png differ diff --git a/tiled/tileset/logic/layer/text/black.png b/tiled/tileset/logic/layer/text/black.png new file mode 100644 index 0000000000..521ede8242 Binary files /dev/null and b/tiled/tileset/logic/layer/text/black.png differ diff --git a/tiled/tileset/logic/layer/text/bull.png b/tiled/tileset/logic/layer/text/bull.png new file mode 100644 index 0000000000..f8be3e5fef Binary files /dev/null and b/tiled/tileset/logic/layer/text/bull.png differ diff --git a/tiled/tileset/logic/layer/text/caiman.png b/tiled/tileset/logic/layer/text/caiman.png new file mode 100644 index 0000000000..35395da849 Binary files /dev/null and b/tiled/tileset/logic/layer/text/caiman.png differ diff --git a/tiled/tileset/logic/layer/text/cave.png b/tiled/tileset/logic/layer/text/cave.png new file mode 100644 index 0000000000..ff70aa018c Binary files /dev/null and b/tiled/tileset/logic/layer/text/cave.png differ diff --git a/tiled/tileset/logic/layer/text/dark.png b/tiled/tileset/logic/layer/text/dark.png new file mode 100644 index 0000000000..731770a9d4 Binary files /dev/null and b/tiled/tileset/logic/layer/text/dark.png differ diff --git a/tiled/tileset/logic/layer/text/durin.png b/tiled/tileset/logic/layer/text/durin.png new file mode 100644 index 0000000000..40859a2053 Binary files /dev/null and b/tiled/tileset/logic/layer/text/durin.png differ diff --git a/tiled/tileset/logic/layer/text/gasha.png b/tiled/tileset/logic/layer/text/gasha.png new file mode 100644 index 0000000000..120e794891 Binary files /dev/null and b/tiled/tileset/logic/layer/text/gasha.png differ diff --git a/tiled/tileset/logic/layer/text/giant.png b/tiled/tileset/logic/layer/text/giant.png new file mode 100644 index 0000000000..2585655afe Binary files /dev/null and b/tiled/tileset/logic/layer/text/giant.png differ diff --git a/tiled/tileset/logic/layer/text/high.png b/tiled/tileset/logic/layer/text/high.png new file mode 100644 index 0000000000..3ba413729d Binary files /dev/null and b/tiled/tileset/logic/layer/text/high.png differ diff --git a/tiled/tileset/logic/layer/text/king.png b/tiled/tileset/logic/layer/text/king.png new file mode 100644 index 0000000000..6de3b1fdcf Binary files /dev/null and b/tiled/tileset/logic/layer/text/king.png differ diff --git a/tiled/tileset/logic/layer/text/mammoth.png b/tiled/tileset/logic/layer/text/mammoth.png new file mode 100644 index 0000000000..2f115b9aff Binary files /dev/null and b/tiled/tileset/logic/layer/text/mammoth.png differ diff --git a/tiled/tileset/logic/layer/text/mountain.png b/tiled/tileset/logic/layer/text/mountain.png new file mode 100644 index 0000000000..012fbe4381 Binary files /dev/null and b/tiled/tileset/logic/layer/text/mountain.png differ diff --git a/tiled/tileset/logic/layer/text/nuggetcutter.png b/tiled/tileset/logic/layer/text/nuggetcutter.png new file mode 100644 index 0000000000..33a19cb6e3 Binary files /dev/null and b/tiled/tileset/logic/layer/text/nuggetcutter.png differ diff --git a/tiled/tileset/logic/layer/text/s.png b/tiled/tileset/logic/layer/text/s.png new file mode 100644 index 0000000000..506f7f9171 Binary files /dev/null and b/tiled/tileset/logic/layer/text/s.png differ diff --git a/tiled/tileset/logic/layer/text/unknown.png b/tiled/tileset/logic/layer/text/unknown.png new file mode 100644 index 0000000000..304b284a18 Binary files /dev/null and b/tiled/tileset/logic/layer/text/unknown.png differ diff --git a/tiled/tileset/logic/layer/text/w.png b/tiled/tileset/logic/layer/text/w.png new file mode 100644 index 0000000000..ab20f8b456 Binary files /dev/null and b/tiled/tileset/logic/layer/text/w.png differ