"""Deterministic sci-fi/body-horror environment, prop and inventory icon sources.""" from __future__ import annotations from pathlib import Path import random from PIL import Image, ImageDraw ROOT = Path(__file__).resolve().parents[1] WORLD = ROOT / "assets/sources/world" ICONS = ROOT / "assets/sources/items" MANIFEST = ROOT / "assets/manifests/static.generated.yaml" INK = (13, 17, 22, 255) STEEL = (61, 72, 79, 255) EDGE = (27, 34, 39, 255) LIGHT = (103, 119, 121, 255) FLESH = (91, 32, 42, 255) VEIN = (159, 48, 55, 255) SICK = (121, 145, 78, 255) def save(image: Image.Image, root: Path, name: str) -> Path: root.mkdir(parents=True, exist_ok=True) path = root / f"{name}.png" image.save(path) return path def floor(name: str, mode: str, seed: int) -> None: rng = random.Random(seed) im = Image.new("RGBA", (32, 16)); d = ImageDraw.Draw(im) poly = [(15, 0), (31, 8), (15, 15), (0, 8)] d.polygon(poly, fill=(49, 58, 63, 255), outline=EDGE) for _ in range(30): x, y = rng.randrange(32), rng.randrange(16) if im.getpixel((x, y))[3]: q = rng.randrange(-10, 9); c = im.getpixel((x, y)) im.putpixel((x, y), tuple(max(0, min(255, c[i]+q)) for i in range(3))+(255,)) if mode == "clean": d.line([(7, 4), (23, 12)], fill=(75, 87, 91, 255)); d.point((15, 3), fill=LIGHT) d.point((5, 8), fill=LIGHT); d.point((25, 8), fill=LIGHT) elif mode == "cracked": d.line([(18, 2), (15, 6), (18, 8), (12, 13)], fill=(12, 15, 18, 255), width=1) d.line([(15, 6), (10, 7)], fill=(12, 15, 18, 255)) elif mode == "grate": d.polygon([(10, 5), (16, 2), (23, 6), (16, 11)], fill=(20, 27, 30, 255), outline=(91, 104, 104, 255)) for x in range(11, 22, 3): d.line([(x, 4), (x-1, 9)], fill=(74, 91, 89, 255)) else: d.ellipse((6, 4, 25, 13), fill=(62, 27, 35, 255), outline=FLESH) for _ in range(8): x = rng.randrange(8, 24); y = rng.randrange(5, 12) d.line([(16, 8), (x, y)], fill=VEIN) d.ellipse((13, 6, 18, 10), fill=(137, 50, 57, 255)) save(im, WORLD, name) def wall(name: str, infested: bool) -> None: im = Image.new("RGBA", (32, 32)); d = ImageDraw.Draw(im) d.polygon([(15, 0), (31, 8), (15, 16), (0, 8)], fill=(72, 82, 85, 255), outline=EDGE) d.polygon([(0, 8), (15, 16), (15, 31), (0, 23)], fill=(35, 43, 48, 255), outline=INK) d.polygon([(15, 16), (31, 8), (31, 23), (15, 31)], fill=(48, 57, 61, 255), outline=INK) d.line([(4, 10), (4, 21), (12, 25)], fill=(80, 92, 92, 255)) d.line([(27, 11), (27, 20), (19, 25)], fill=(27, 34, 38, 255)) for p in ((5, 11), (12, 15), (26, 12), (19, 16)): d.rectangle((p[0],p[1],p[0]+1,p[1]+1), fill=LIGHT) if infested: d.ellipse((7, 7, 24, 27), fill=(70, 27, 35, 235), outline=FLESH) d.ellipse((11, 11, 20, 22), fill=(111, 36, 44, 255), outline=VEIN) d.ellipse((14, 14, 17, 18), fill=(32, 14, 19, 255)) for end in ((2,9),(29,9),(4,25),(27,25)): d.line([(15,17), end], fill=VEIN, width=1) save(im, WORLD, name) def prop(name: str, kind: str) -> None: sizes = {"crate": (24,22), "barrel": (18,25), "locker": (18,32)} w,h=sizes[kind]; im=Image.new("RGBA",(w,h)); d=ImageDraw.Draw(im) if kind == "crate": d.polygon([(1,6),(11,1),(22,6),(12,11)],fill=(82,78,64,255),outline=INK) d.polygon([(1,6),(12,11),(12,21),(1,16)],fill=(48,48,43,255),outline=INK) d.polygon([(12,11),(22,6),(22,16),(12,21)],fill=(61,59,50,255),outline=INK) d.line([(3,7),(10,10),(10,18),(3,15),(3,7)],fill=(112,105,78,255)) elif kind == "barrel": d.ellipse((2,1,15,7),fill=(77,82,77,255),outline=INK) d.rectangle((2,4,15,20),fill=(50,59,57,255),outline=INK) d.ellipse((2,17,15,24),fill=(42,48,47,255),outline=INK) d.line([(2,9),(15,9)],fill=LIGHT); d.line([(2,17),(15,17)],fill=INK) d.polygon([(6,10),(10,8),(12,12),(9,16),(5,14)],fill=SICK) else: d.polygon([(2,5),(9,1),(16,5),(9,9)],fill=(75,82,84,255),outline=INK) d.polygon([(2,5),(9,9),(9,31),(2,27)],fill=(38,46,50,255),outline=INK) d.polygon([(9,9),(16,5),(16,27),(9,31)],fill=(52,61,64,255),outline=INK) d.line([(11,11),(11,27)],fill=INK); d.point((13,18),fill=(180,61,56,255)) save(im,WORLD,"prop_"+name) def icon(name: str) -> None: im=Image.new("RGBA",(24,24)); d=ImageDraw.Draw(im) d.rounded_rectangle((1,1,22,22),3,fill=(20,25,30,230),outline=(72,84,88,255)) metal=(151,165,166,255); dark=(45,52,55,255); red=(164,48,54,255) if name in {"rifle","smg","shotgun","pistol","magnum"}: length={"pistol":11,"magnum":12,"smg":15,"shotgun":18,"rifle":18}[name] d.rectangle((3,9,3+length,12),fill=metal); d.rectangle((7,12,10,17),fill=dark) if name=="shotgun": d.line((4,14,19,14),fill=(113,77,50,255),width=2) elif name == "bow": d.arc((4,3,18,21),270,90,fill=metal,width=2); d.line((11,4,11,20),fill=(104,124,103,255)) elif name in {"saber","knife","cleaver"}: end=(18,4) if name!="knife" else (15,7); d.line((6,18,*end),fill=metal,width=3) d.line((4,19,9,16),fill=(118,76,43,255),width=2) elif name in {"jacket","vest","plate","shroud"}: col={"jacket":(75,83,77,255),"vest":(82,91,91,255),"plate":(115,122,119,255),"shroud":(56,49,63,255)}[name] d.polygon([(7,5),(4,9),(6,20),(18,20),(20,9),(17,5),(14,8),(10,8)],fill=col,outline=INK) elif name in {"bandage","stimpack"}: d.rectangle((7,4,16,20),fill=(178,188,175,255),outline=INK) d.rectangle((9,10,14,14),fill=red); d.line((11,8,11,16),fill=(220,220,205,255)) else: colors={"lantern":(224,184,72,255),"charm":(142,69,101,255),"spurs":(143,151,151,255)} d.ellipse((6,5,18,18),fill=colors[name],outline=INK); d.ellipse((10,9,14,13),fill=(235,221,159,255)) save(im,ICONS,"item_icon_"+name) def manifest() -> None: entries=[] for name in ("floor_clean","floor_cracked","floor_grate","floor_biomass","wall_industrial","wall_infested", "prop_crate","prop_barrel","prop_locker"): pivot = '"15,8"' if name.startswith("floor") else ("\"15,31\"" if name.startswith("wall") else "bottom_center") entries += [f"{name}:", " backend: import", f" source: ../sources/world/{name}.png", f" pivot: {pivot}", f" tags: [environment, {'floor' if name.startswith('floor') else 'prop' if name.startswith('prop') else 'wall'}]", ""] names=("rifle","pistol","shotgun","smg","magnum","bow","saber","knife","cleaver","jacket","vest","plate", "shroud","lantern","charm","spurs","bandage","stimpack") for name in names: aid="item_icon_"+name; entries += [f"{aid}:"," backend: import",f" source: ../sources/items/{aid}.png"," pivot: center"," tags: [ui, item]",""] MANIFEST.write_text("\n".join(["version: 1","defaults:"," dirs: 1"," fps: 1",""]+entries),encoding="utf-8",newline="\n") def main() -> None: for i,mode in enumerate(("clean","cracked","grate","biomass")): floor("floor_"+mode,mode,100+i) wall("wall_industrial",False); wall("wall_infested",True) for kind in ("crate","barrel","locker"): prop(kind,kind) for name in ("rifle","pistol","shotgun","smg","magnum","bow","saber","knife","cleaver","jacket","vest","plate", "shroud","lantern","charm","spurs","bandage","stimpack"): icon(name) manifest(); print("generated 27 static assets and assets/manifests/static.generated.yaml") if __name__ == "__main__": main()