#!/usr/bin/env python3 """Build original vector site symbols, review PNGs and the game's single atlas. Requires rsvg-convert and Pillow. Runtime texture import is done in Workbench. """ from pathlib import Path import io import subprocess from PIL import Image, ImageDraw, ImageFont ROOT = Path(__file__).resolve().parents[1] OUT = ROOT / 'art/map-markers' RUNTIME = ROOT / 'addons/core/UI/Textures/ERR' VIOLET = '#B277F0' # All symbols use a 64-unit grid and a generous quiet border for small map sizes. SYMBOLS = [ ('unknown', 'Unknown location', 'mark-question', ''), ('radio', 'Radio station', 'radio', ''), ('extraction', 'Extraction pickup', 'helicopters', ''), ('camp', 'Camp / outpost', 'building', ''), ('supplies', 'Supply depot', 'supplies', ''), ('mortar', 'Mortar position', 'artilleryFireMission', ''), ('hospital', 'Field hospital', 'medical', ''), ('prison', 'Prison', 'prison', ''), ('roadblock', 'Roadblock', 'roadblock', ''), ('factory', 'Industrial site', 'factory', ''), ('minefield', 'Minefield', 'minefield', ''), ('crash', 'Aircraft wreck', 'crash', ''), ] def svg(symbol): return f'{symbol}\n' def main(): OUT.mkdir(parents=True, exist_ok=True) RUNTIME.mkdir(parents=True, exist_ok=True) atlas = Image.new('RGBA', (512, 512)) sheet = Image.new('RGB', (1200, 1050), '#f2f0f5') draw = ImageDraw.Draw(sheet) font_path = '/usr/share/fonts/TTF/DejaVuSans.ttf' title = ImageFont.truetype(font_path, 32) label = ImageFont.truetype(font_path, 19) note = ImageFont.truetype(font_path, 16) draw.text((40, 26), 'CO10 ESCAPE / MAP MARKERS', font=title, fill='#21152f') draw.text((40, 74), 'Violet circles · black symbols · transparent outside · actual 36 px samples below', font=note, fill='#544662') definitions = [] for i, (name, caption, image_name, symbol) in enumerate(SYMBOLS): source = OUT / (name + '.svg') source.write_text(svg(symbol)) png = subprocess.check_output(['rsvg-convert', str(source)]) (OUT / (name + '.png')).write_bytes(png) icon = Image.open(io.BytesIO(png)).convert('RGBA') x, y = i % 4 * 128, i // 4 * 128 atlas.alpha_composite(icon.resize((128, 128), Image.Resampling.LANCZOS), (x, y)) definitions.append(f' ImageSetDefClass "{image_name}" {{\n Pos {x} {y}\n Size 128 128\n Flags 0 0\n }}') sx, sy = 40 + i % 4 * 290, 135 + i // 4 * 295 sheet.paste(icon.resize((160, 160), Image.Resampling.LANCZOS), (sx + 50, sy), icon.resize((160, 160), Image.Resampling.LANCZOS)) draw.text((sx + 130, sy + 178), caption, font=label, fill='#21152f', anchor='mt') small = icon.resize((36, 36), Image.Resampling.LANCZOS) for j, bg in enumerate(('#d5d3b2', '#303b32')): px = sx + 82 + j * 55 draw.rectangle((px-4, sy+215, px+39, sy+258), fill=bg) sheet.paste(small, (px, sy + 219), small) atlas.save(RUNTIME / 'SiteMarkers.png') sheet.save(OUT / 'preview.png') (RUNTIME / 'SiteMarkers.imageset').write_text('ImageSetClass {\n RefSize 512 512\n Textures {\n ImageSetTextureClass {\n screenSize FHD\n size 512 512\n path "{ADEE022D9F06C05A}UI/Textures/ERR/SiteMarkers.edds"\n }\n }\n Images {\n' + '\n'.join(definitions) + '\n }\n}\n') print(OUT / 'preview.png') if __name__ == '__main__': main()