Revert "Redraw wall/bush maze tiles with richer pixel-art detail"

The user asked to go back to the pre-commit assets. The original
BMP_{1..4}_*.png tiles have been restored. The generator script
introduced in that commit is also removed.
This commit is contained in:
2026-06-27 20:21:05 +02:00
parent 0f14ae3376
commit e76c6f665a
49 changed files with 0 additions and 401 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1014 B

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 955 B

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 993 B

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 B

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 991 B

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 959 B

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1004 B

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 959 B

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 947 B

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1013 B

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 956 B

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 950 B

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 986 B

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 986 B

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1019 B

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 941 B

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1012 B

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 B

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 970 B

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 967 B

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1011 B

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 957 B

After

Width:  |  Height:  |  Size: 208 B

-401
View File
@@ -1,401 +0,0 @@
#!/usr/bin/env python3
"""Regenerate the 32x32 wall/bush tile sprites for the maze with more detail.
Replaces the noisy checkerboard BMP_{theme}_{N,S,E,W,NE,NW,SE,SW,EN,ES,WN,WS}.png
tiles with hand-designed pixel art bush clusters, keeping the original
palette per theme (or a richer one for theme 1).
Each tile is 32x32. The wall/bush area is on a specific side(s) of the tile:
N = wall on the top side, passage below
S = wall on the bottom side, passage above
E = wall on the right side, passage left
W = wall on the left side, passage right
NE = wall on top + right (outer corner)
NW = wall on top + left
SE = wall on bottom + right
SW = wall on bottom + left
EN = inner corner: passage top-left, wall bottom-right (L-shape)
ES = inner corner: passage top-right, wall bottom-left
WN = inner corner: passage bottom-left, wall top-right
WS = inner corner: passage bottom-right, wall top-left
Run from repo root:
python3 tools/redraw_walls.py
"""
import os
import sys
from pathlib import Path
# Output directory
OUT_DIR = Path(__file__).resolve().parents[1] / "assets" / "Rat"
OUT_DIR.mkdir(parents=True, exist_ok=True)
SIZE = 32
TRANSPARENT = (128, 128, 128, 255) # engine treats this color as transparent
# Palette per theme. Each theme gets a 5-color bush palette:
# (deep_shadow, dark, mid, light, highlight)
THEME_PALETTES = {
# Theme 1: lush green bushes (the canonical "hedge maze" look).
1: {
"deep": (0, 70, 0, 255),
"dark": (0, 110, 0, 255),
"mid": (0, 160, 0, 255),
"light": (60, 220, 60, 255),
"highlight": (170, 255, 170, 255),
},
# Theme 2: yellow/golden dry brush.
2: {
"deep": (90, 90, 0, 255),
"dark": (130, 130, 0, 255),
"mid": (200, 200, 0, 255),
"light": (240, 240, 80, 255),
"highlight": (255, 255, 200, 255),
},
# Theme 3: white/silver snowy brush.
3: {
"deep": (140, 140, 140, 255),
"dark": (180, 180, 180, 255),
"mid": (220, 220, 220, 255),
"light": (245, 245, 245, 255),
"highlight": (255, 255, 255, 255),
},
# Theme 4: ashen/red lava brush.
4: {
"deep": (90, 0, 0, 255),
"dark": (150, 25, 25, 255),
"mid": (210, 50, 50, 255),
"light": (240, 110, 90, 255),
"highlight": (255, 200, 180, 255),
},
}
# ---------------------------------------------------------------------------
# Deterministic pseudo-random helpers.
# ---------------------------------------------------------------------------
def _hash(x: int, y: int, salt: int = 0) -> int:
"""Tiny integer hash in [0, 65536)."""
h = (x * 374761393 + y * 668265263 + salt * 2147483647) & 0xFFFFFFFF
h = (h ^ (h >> 13)) * 1274126177 & 0xFFFFFFFF
return h & 0xFFFF
def _chance(x: int, y: int, threshold: int, salt: int = 0) -> bool:
return _hash(x, y, salt) < threshold
def _hash_seed(x: int, y: int, salt: int) -> int:
"""Return a deterministic seed in [0, 8) used to pick a cluster variant."""
return _hash(x, y, salt) % 8
# ---------------------------------------------------------------------------
# Cluster patterns: small 3x3 / 4x4 / 5x5 stamps used to add visible "leaves"
# inside the bush body. Each cluster is a small relative offset (+dx, +dy) and
# a color choice.
# ---------------------------------------------------------------------------
# A cluster is (dx, dy, color_key). The cluster is placed at integer pixel
# positions; each pixel within a small radius is set to that color (overriding
# the base body color). This adds visible "leaf clusters" on top of the body.
def _leaf_cluster_positions(cx: int, cy: int, salt: int) -> list:
"""Return [(dx, dy, color_key), ...] relative to (cx, cy) for one leaf."""
# Choose a variant: 0-7
variant = _hash_seed(cx, cy, salt)
# Variants:
# 0: 3 leaves in a triangle
# 1: 4 leaves in a small plus
# 2: 5 leaves in a + shape
# 3: small cluster of 3
# 4: scattered 3
# 5: 4 leaves diagonal
# 6: single + 2 around
# 7: tight 5 cluster
clusters = {
0: [(0, 0, "highlight"), (-2, 1, "light"), (1, 2, "light")],
1: [(0, 0, "highlight"), (2, 0, "light"), (-2, 0, "light"), (0, 2, "light")],
2: [(0, 0, "highlight"), (2, 0, "light"), (-2, 0, "light"), (0, 2, "light"), (0, -2, "mid")],
3: [(0, 0, "light"), (-1, 1, "mid"), (1, -1, "mid")],
4: [(0, 0, "highlight"), (2, 2, "light"), (-2, -1, "light")],
5: [(0, 0, "highlight"), (2, 2, "light"), (-2, -2, "light"), (1, -1, "mid")],
6: [(0, 0, "highlight"), (-1, 0, "light"), (0, -1, "light")],
7: [(0, 0, "highlight"), (1, 0, "light"), (-1, 0, "light"), (0, 1, "light"), (0, -1, "light")],
}
return clusters[variant]
# ---------------------------------------------------------------------------
# Tile layout: where is the wall (muro di cespugli)?
# ---------------------------------------------------------------------------
def ideal_mask(shape: str) -> list:
"""Return a 32x32 list-of-lists mask of the IDEAL wall footprint (True = bush)."""
mask = [[False] * SIZE for _ in range(SIZE)]
if shape == "N":
for y in range(SIZE // 2):
for x in range(SIZE):
mask[y][x] = True
elif shape == "S":
for y in range(SIZE // 2, SIZE):
for x in range(SIZE):
mask[y][x] = True
elif shape == "E":
for y in range(SIZE):
for x in range(SIZE // 2, SIZE):
mask[y][x] = True
elif shape == "W":
for y in range(SIZE):
for x in range(SIZE // 2):
mask[y][x] = True
elif shape == "NE":
for y in range(SIZE // 2):
for x in range(SIZE):
mask[y][x] = True
for y in range(SIZE):
for x in range(SIZE // 2, SIZE):
mask[y][x] = True
elif shape == "NW":
for y in range(SIZE // 2):
for x in range(SIZE):
mask[y][x] = True
for y in range(SIZE):
for x in range(SIZE // 2):
mask[y][x] = True
elif shape == "SE":
for y in range(SIZE // 2, SIZE):
for x in range(SIZE):
mask[y][x] = True
for y in range(SIZE):
for x in range(SIZE // 2, SIZE):
mask[y][x] = True
elif shape == "SW":
for y in range(SIZE // 2, SIZE):
for x in range(SIZE):
mask[y][x] = True
for y in range(SIZE):
for x in range(SIZE // 2):
mask[y][x] = True
elif shape == "EN":
for y in range(SIZE // 2, SIZE):
for x in range(SIZE // 2, SIZE):
mask[y][x] = True
for x in range(SIZE // 2, SIZE):
mask[SIZE // 2][x] = True
for y in range(SIZE // 2, SIZE):
mask[y][SIZE // 2] = True
elif shape == "ES":
for y in range(SIZE // 2, SIZE):
for x in range(SIZE // 2):
mask[y][x] = True
for x in range(SIZE // 2):
mask[SIZE // 2][x] = True
for y in range(SIZE // 2, SIZE):
mask[y][SIZE // 2 - 1] = True
elif shape == "WN":
for y in range(SIZE // 2):
for x in range(SIZE // 2, SIZE):
mask[y][x] = True
for x in range(SIZE // 2, SIZE):
mask[SIZE // 2 - 1][x] = True
for y in range(SIZE // 2):
mask[y][SIZE // 2] = True
elif shape == "WS":
for y in range(SIZE // 2):
for x in range(SIZE // 2):
mask[y][x] = True
for x in range(SIZE // 2):
mask[SIZE // 2 - 1][x] = True
for y in range(SIZE // 2):
mask[y][SIZE // 2 - 1] = True
else:
raise ValueError(f"Unknown shape: {shape}")
return mask
def erode_boundary(mask: list, salt: int) -> list:
"""Make the wall/passage boundary irregular and natural."""
new_mask = [row[:] for row in mask]
for y in range(SIZE):
for x in range(SIZE):
is_wall = mask[y][x]
diffs = 0
for dy, dx in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
ny, nx = y + dy, x + dx
if not (0 <= ny < SIZE and 0 <= nx < SIZE) or mask[ny][nx] != is_wall:
diffs += 1
if diffs == 0:
continue
if is_wall:
# carve a notch out of the bush (more aggressive)
if _chance(x, y, 7500, salt):
new_mask[y][x] = False
else:
# let a leaf cluster stick out into the passage
if _chance(x, y, 5500, salt + 1):
near = False
for dy in range(-2, 3):
for dx in range(-2, 3):
ny, nx = y + dy, x + dx
if 0 <= ny < SIZE and 0 <= nx < SIZE and mask[ny][nx]:
near = True
break
if near:
break
if near:
new_mask[y][x] = True
return new_mask
def compute_depth(mask: list) -> list:
"""For each wall pixel, return its distance from the wall/passage boundary.
Used to determine which shade of green to use (deeper = darker).
"""
depth = [[0] * SIZE for _ in range(SIZE)]
# Boundary pixels have depth 1; interior grows with distance from boundary.
for y in range(SIZE):
for x in range(SIZE):
if not mask[y][x]:
continue
# find nearest passage pixel via BFS-lite (4-direction)
# Use a simple expansion: search outward until we find a False.
d = 1
found = False
while d < SIZE:
ring = False
for dy in range(-d, d + 1):
for dx in range(-d, d + 1):
if abs(dy) != d and abs(dx) != d:
continue
ny, nx = y + dy, x + dx
if not (0 <= ny < SIZE and 0 <= nx < SIZE):
ring = True
break
if not mask[ny][nx]:
ring = True
break
if ring:
break
if ring:
found = True
break
d += 1
depth[y][x] = d if found else SIZE
return depth
def fill_bush_detail(mask: list, depth: list, pal: dict, salt: int) -> list:
"""Assign palette colors to wall pixels, with leaf clusters overlaid."""
pixels = [[None] * SIZE for _ in range(SIZE)]
# 1) base layer: pick color by depth.
for y in range(SIZE):
for x in range(SIZE):
if not mask[y][x]:
pixels[y][x] = TRANSPARENT
continue
d = depth[y][x]
if d <= 1:
pixels[y][x] = pal["dark"]
elif d == 2:
pixels[y][x] = pal["dark"]
elif d == 3:
pixels[y][x] = pal["mid"]
elif d == 4:
pixels[y][x] = pal["mid"]
else:
pixels[y][x] = pal["deep"]
# 2) scattered mid/light/highlight "speckles" to break uniformity.
for y in range(SIZE):
for x in range(SIZE):
if not mask[y][x]:
continue
d = depth[y][x]
# A light speckle anywhere on the bush
if d <= 4 and _chance(x, y, 4500, salt + 11):
pixels[y][x] = pal["light"]
# Highlight speckle near the edge only
if d <= 2 and _chance(x, y, 3000, salt + 23):
pixels[y][x] = pal["highlight"]
# 3) Overlay leaf clusters at deterministic anchor points.
# Anchors are picked from a low-density grid so each tile gets a few clusters.
anchor_spacing = 6
for ay in range(2, SIZE - 2, anchor_spacing):
for ax in range(2, SIZE - 2, anchor_spacing):
if not mask[ay][ax]:
continue
# Some anchors are skipped for variety
if not _chance(ax, ay, 22000, salt + 31):
continue
leaves = _leaf_cluster_positions(ax, ay, salt + 41)
for dx, dy, color_key in leaves:
nx, ny = ax + dx, ay + dy
if 0 <= nx < SIZE and 0 <= ny < SIZE and mask[ny][nx]:
pixels[ny][nx] = pal[color_key]
# 4) Soft "rim" highlight along the wall/passage boundary on the
# passage-facing side (depth=1) — adds a sense of light catching the
# outer leaves.
for y in range(SIZE):
for x in range(SIZE):
if not mask[y][x]:
continue
if depth[y][x] == 1 and _chance(x, y, 5000, salt + 53):
pixels[y][x] = pal["light"]
return pixels
def render_tile(shape: str, theme_index: int) -> list:
pal = THEME_PALETTES[theme_index]
salt = (theme_index * 1000) + sum(ord(c) for c in shape)
base = ideal_mask(shape)
eroded = erode_boundary(base, salt)
depth = compute_depth(eroded)
pixels = fill_bush_detail(eroded, depth, pal, salt + 99)
return pixels
# ---------------------------------------------------------------------------
# PNG writer (PIL mode P matching original BMP_{theme}_{shape}.png format).
# ---------------------------------------------------------------------------
def save_png_mode_p(pixels: list, path: Path) -> None:
from PIL import Image
# Build a unique palette
used = {}
# Reserve index 0 for the transparent gray (engine convention)
used[TRANSPARENT] = 0
for y in range(SIZE):
for x in range(SIZE):
c = pixels[y][x]
if c not in used:
used[c] = len(used)
palette = [0] * (256 * 3)
for color, idx in used.items():
palette[idx * 3] = color[0]
palette[idx * 3 + 1] = color[1]
palette[idx * 3 + 2] = color[2]
pal_img = Image.new("P", (SIZE, SIZE))
pal_img.putpalette(palette)
for y in range(SIZE):
for x in range(SIZE):
pal_img.putpixel((x, y), used[pixels[y][x]])
pal_img.save(path, optimize=True)
SHAPES = ["N", "S", "E", "W",
"NE", "NW", "SE", "SW",
"EN", "ES", "WN", "WS"]
def main():
written = []
for theme_index in range(1, 5):
for shape in SHAPES:
pixels = render_tile(shape, theme_index)
path = OUT_DIR / f"BMP_{theme_index}_{shape}.png"
save_png_mode_p(pixels, path)
written.append(str(path.relative_to(OUT_DIR.parents[1])))
print(f"Wrote {len(written)} tile sprites.")
for w in written:
print(f" {w}")
if __name__ == "__main__":
main()