- 5 Biomes: Day, Night, Pool, Fog, Roof (25 Campaign levels) - Minigames: Wall-nut Bowling, I Zombie, Roguelike, Boss Rush & Dr. Zomboss - Systems: Zen Garden, Workshop Crafting, Almanac, Tree of Wisdom, Achievements - Backend: REST API + SQLite Accounts & Save Synchronization - Infrastructure: Nginx HTTPS & Docker deployment
88 lines
2.9 KiB
Python
88 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import zlib
|
|
import struct
|
|
import math
|
|
|
|
def make_png(w, h, get_pixel):
|
|
def chunk(tag, data):
|
|
return struct.pack('>I', len(data)) + tag + data + struct.pack('>I', zlib.crc32(tag + data) & 0xffffffff)
|
|
|
|
ihdr = struct.pack('>IIBBBBB', w, h, 8, 6, 0, 0, 0) # RGBA 8-bit
|
|
raw_rows = []
|
|
for y in range(h):
|
|
row = [0] # filter type 0
|
|
for x in range(w):
|
|
r, g, b, a = get_pixel(x, y, w, h)
|
|
row.extend([r, g, b, a])
|
|
raw_rows.append(bytes(row))
|
|
raw_data = b''.join(raw_rows)
|
|
idat = zlib.compress(raw_data, 9)
|
|
return b'\x89PNG\r\n\x1a\n' + chunk(b'IHDR', ihdr) + chunk(b'IDAT', idat) + chunk(b'IEND', b'')
|
|
|
|
def render_pvz_icon(x, y, w, h):
|
|
# Normalized coords (-1 to 1)
|
|
nx = (x - w / 2) / (w / 2)
|
|
ny = (y - h / 2) / (h / 2)
|
|
dist = math.hypot(nx, ny)
|
|
|
|
# Outer dark green circle border
|
|
if dist > 0.96:
|
|
return 0, 0, 0, 0
|
|
if dist > 0.90:
|
|
return 27, 94, 32, 255
|
|
|
|
# Background circle (lawn green gradient)
|
|
if dist <= 0.90:
|
|
# Sunflower petals or Peashooter head
|
|
# Let's draw stylized bright yellow sunflower with green peashooter center!
|
|
angle = math.atan2(ny, nx)
|
|
petal_r = 0.55 + 0.15 * math.sin(angle * 8)
|
|
|
|
# Petal check
|
|
if dist < petal_r and dist > 0.40:
|
|
return 255, 213, 79, 255 # Yellow sunflower petals
|
|
|
|
# Peashooter green head in center
|
|
center_dist = math.hypot(nx + 0.08, ny)
|
|
if center_dist < 0.35:
|
|
# Snout pointing right
|
|
snout = (nx > 0.05 and nx < 0.35 and abs(ny) < 0.12)
|
|
if snout:
|
|
return 76, 175, 80, 255
|
|
# Eye
|
|
eye_dist = math.hypot(nx - (-0.05), ny - (-0.12))
|
|
if eye_dist < 0.06:
|
|
return 255, 255, 255, 255
|
|
if eye_dist < 0.03:
|
|
return 0, 0, 0, 255
|
|
return 67, 160, 71, 255
|
|
|
|
# Green lawn background inside circle
|
|
grad = int(46 + (1.0 - dist) * 60)
|
|
return 27, min(255, grad + 80), 32, 255
|
|
|
|
def main():
|
|
game_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "game")
|
|
|
|
# Generate 192x192
|
|
p192 = make_png(192, 192, render_pvz_icon)
|
|
with open(os.path.join(game_dir, "icon-192.png"), "wb") as f:
|
|
f.write(p192)
|
|
print("Generated icon-192.png:", len(p192), "bytes")
|
|
|
|
# Generate 512x512
|
|
p512 = make_png(512, 512, render_pvz_icon)
|
|
with open(os.path.join(game_dir, "icon-512.png"), "wb") as f:
|
|
f.write(p512)
|
|
print("Generated icon-512.png:", len(p512), "bytes")
|
|
|
|
# Generate favicon.ico (valid 32x32 PNG inside or 32x32 favicon)
|
|
p32 = make_png(32, 32, render_pvz_icon)
|
|
with open(os.path.join(game_dir, "favicon.ico"), "wb") as f:
|
|
f.write(p32)
|
|
print("Generated favicon.ico:", len(p32), "bytes")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|