Expand moon01.lvl from 200 to 1000 tiles using a Python generator script. The level features 27 gap sections with floating one-way platforms at varying heights, progressing from easy (8-tile gaps) to challenging (22-tile gaps with tiny platforms). 20 asteroids spread across the level. Increase tilemap line buffer from 1024 to 16384 bytes to support wide levels.
201 lines
6.9 KiB
Python
201 lines
6.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate the 1000-tile-wide moon level.
|
|
|
|
Layout philosophy:
|
|
- Start with a flat landing zone (spacecraft intro)
|
|
- Alternate between ground sections and wide chasms with floating platforms
|
|
- Chasms get progressively wider / platforms more sparse as the level goes on
|
|
- Moon gravity (300) gives ~20 tiles of full-jump horizontal range
|
|
- Gaps are 8-18 tiles wide; platforms are 3-5 tiles wide at varying heights
|
|
- Ground depth: rows 19-22 (surface at 19, bedrock fills below)
|
|
- Total: 1000 x 23 tiles
|
|
"""
|
|
|
|
import random
|
|
|
|
WIDTH = 1000
|
|
HEIGHT = 23
|
|
GROUND_ROW = 19 # top of ground surface
|
|
SURFACE_ROWS = 3 # rows of ground below surface (19, 20, 21, 22 = index 19-22)
|
|
|
|
random.seed(42) # reproducible
|
|
|
|
# Tile IDs:
|
|
# 0 = air
|
|
# 1 = solid surface
|
|
# 2 = solid surface variant (decorative, still solid)
|
|
# 3 = solid surface variant (decorative, still solid)
|
|
# 4 = one-way platform
|
|
|
|
def make_empty_grid():
|
|
return [[0] * WIDTH for _ in range(HEIGHT)]
|
|
|
|
def place_ground(grid, col_start, col_end, row=GROUND_ROW):
|
|
"""Fill ground from col_start to col_end (exclusive), from row down to bottom."""
|
|
for r in range(row, HEIGHT):
|
|
for c in range(col_start, min(col_end, WIDTH)):
|
|
if r == row:
|
|
grid[r][c] = 1
|
|
elif r == row + 1:
|
|
# second row: sprinkle variant tiles
|
|
grid[r][c] = 2 if random.random() < 0.12 else 1
|
|
else:
|
|
# deep rows: more variant
|
|
grid[r][c] = 3 if random.random() < 0.1 else 1
|
|
|
|
def place_platform(grid, col_start, length, row):
|
|
"""Place a one-way platform."""
|
|
for c in range(col_start, min(col_start + length, WIDTH)):
|
|
grid[row][c] = 4
|
|
|
|
def generate_level():
|
|
grid = make_empty_grid()
|
|
entities = []
|
|
|
|
# === Section 1: Landing zone (cols 0-30) ===
|
|
place_ground(grid, 0, 30)
|
|
entities.append(("spacecraft", 1, 14))
|
|
|
|
# === Generate sections with gaps ===
|
|
col = 30
|
|
section = 0
|
|
|
|
# Define gap/ground section patterns
|
|
# (ground_len, gap_len, platform_configs)
|
|
# platform_configs: list of (offset_into_gap, length, row)
|
|
sections = [
|
|
# Easy warmup: small gaps, generous platforms
|
|
(15, 8, [(2, 4, 16)]),
|
|
(12, 10, [(3, 3, 14)]),
|
|
(14, 10, [(2, 3, 17), (6, 3, 15)]),
|
|
|
|
# Getting harder: wider gaps
|
|
(10, 14, [(3, 3, 15), (9, 3, 13)]),
|
|
(12, 12, [(4, 4, 16)]),
|
|
(8, 16, [(3, 3, 14), (8, 3, 17), (12, 3, 12)]),
|
|
|
|
# Big chasms with platform chains
|
|
(10, 18, [(2, 3, 16), (7, 3, 13), (13, 3, 16)]),
|
|
(6, 14, [(3, 4, 15), (9, 3, 12)]),
|
|
(12, 16, [(2, 3, 17), (7, 3, 14), (12, 3, 17)]),
|
|
|
|
# Mid-level: varied terrain
|
|
(20, 10, [(3, 3, 16)]),
|
|
(8, 18, [(2, 3, 15), (8, 4, 12), (14, 3, 16)]),
|
|
(15, 8, [(2, 3, 14)]),
|
|
(6, 16, [(3, 3, 16), (9, 3, 13), (13, 3, 16)]),
|
|
|
|
# Hard section: wide gaps, small platforms
|
|
(8, 18, [(3, 3, 14), (9, 3, 17), (14, 2, 12)]),
|
|
(10, 14, [(3, 3, 13), (8, 3, 16)]),
|
|
(6, 18, [(2, 2, 16), (6, 3, 12), (11, 2, 16), (15, 2, 13)]),
|
|
(12, 16, [(4, 3, 14), (10, 3, 17)]),
|
|
|
|
# Staircase sections — platforms ascending/descending
|
|
(10, 20, [(2, 3, 17), (6, 3, 15), (10, 3, 13), (14, 3, 11), (17, 3, 14)]),
|
|
(8, 16, [(2, 3, 11), (6, 3, 13), (10, 3, 15), (13, 3, 17)]),
|
|
|
|
# Very hard: sparse platforms over huge gaps
|
|
(15, 18, [(4, 3, 14), (11, 2, 12)]),
|
|
(6, 20, [(3, 3, 15), (8, 2, 12), (13, 3, 16), (17, 2, 13)]),
|
|
(10, 16, [(3, 2, 13), (8, 3, 16), (13, 2, 11)]),
|
|
|
|
# Climax: super wide with tiny platforms
|
|
(8, 22, [(3, 2, 15), (8, 2, 12), (13, 2, 16), (18, 2, 13)]),
|
|
(6, 18, [(3, 3, 14), (9, 2, 11), (14, 3, 16)]),
|
|
(10, 20, [(2, 2, 16), (7, 3, 13), (12, 2, 10), (16, 3, 16)]),
|
|
|
|
# Victory approach
|
|
(12, 14, [(3, 3, 15), (9, 3, 13)]),
|
|
(8, 10, [(3, 4, 16)]),
|
|
]
|
|
|
|
for ground_len, gap_len, platforms in sections:
|
|
if col + ground_len + gap_len > WIDTH - 30:
|
|
break
|
|
|
|
# Place ground section
|
|
place_ground(grid, col, col + ground_len)
|
|
col += ground_len
|
|
|
|
# Place platforms in the gap
|
|
for p_offset, p_len, p_row in platforms:
|
|
place_platform(grid, col + p_offset, p_len, p_row)
|
|
|
|
col += gap_len
|
|
section += 1
|
|
|
|
# Fill remaining with ground to the exit
|
|
end_ground_start = col
|
|
place_ground(grid, end_ground_start, WIDTH)
|
|
|
|
# === Asteroids: spread across the level, ~1 per 50 tiles in gap areas ===
|
|
asteroid_cols = list(range(60, WIDTH - 40, 45))
|
|
random.shuffle(asteroid_cols)
|
|
asteroid_cols = sorted(asteroid_cols[:20]) # pick ~20, spread out
|
|
for ac in asteroid_cols:
|
|
ar = random.randint(0, 3)
|
|
entities.append(("asteroid", ac, ar))
|
|
|
|
# === Exit zone near the end ===
|
|
exit_col = WIDTH - 4
|
|
exit_row = GROUND_ROW - 2
|
|
|
|
return grid, entities, exit_col, exit_row
|
|
|
|
def write_level(filename):
|
|
grid, entities, exit_col, exit_row = generate_level()
|
|
|
|
lines = []
|
|
lines.append("# Moon Surface - Landing")
|
|
lines.append("# ======================")
|
|
lines.append("# Extended moon level: wide chasms with floating platforms.")
|
|
lines.append("# Pure jump-and-run intro with asteroid hazards. No gun.")
|
|
lines.append("")
|
|
lines.append("TILESET assets/tiles/moon_tileset.png")
|
|
lines.append(f"SIZE {WIDTH} {HEIGHT}")
|
|
lines.append("SPAWN 3 18")
|
|
lines.append("GRAVITY 300")
|
|
lines.append("BG_COLOR 5 5 15")
|
|
lines.append("PARALLAX_STYLE 4")
|
|
lines.append("MUSIC assets/sounds/algardalgar.ogg")
|
|
lines.append("PLAYER_UNARMED")
|
|
lines.append("")
|
|
|
|
# Entities
|
|
for etype, ex, ey in entities:
|
|
lines.append(f"ENTITY {etype} {ex} {ey}")
|
|
lines.append("")
|
|
|
|
# Exit
|
|
lines.append(f"EXIT {exit_col} {exit_row} 2 3 assets/levels/level01.lvl")
|
|
lines.append("")
|
|
|
|
# Tile definitions
|
|
lines.append("# Tile definitions")
|
|
lines.append("TILEDEF 1 0 0 1")
|
|
lines.append("TILEDEF 2 1 0 1")
|
|
lines.append("TILEDEF 3 2 0 1")
|
|
lines.append("TILEDEF 4 0 1 2")
|
|
lines.append("")
|
|
|
|
# Collision layer
|
|
lines.append("LAYER collision")
|
|
for row in grid:
|
|
lines.append(" ".join(str(t) for t in row))
|
|
|
|
with open(filename, "w") as f:
|
|
f.write("\n".join(lines) + "\n")
|
|
|
|
# Print stats
|
|
gap_tiles = sum(1 for r in range(HEIGHT) for c in range(WIDTH)
|
|
if grid[GROUND_ROW][c] == 0 and grid[r][c] == 0)
|
|
plat_count = sum(1 for r in range(HEIGHT) for c in range(WIDTH) if grid[r][c] == 4)
|
|
print(f"Generated {filename}: {WIDTH}x{HEIGHT} tiles")
|
|
print(f" Entities: {len(entities)}")
|
|
print(f" Platforms: {plat_count} tiles")
|
|
print(f" Ground surface gaps: {sum(1 for c in range(WIDTH) if grid[GROUND_ROW][c] == 0)} columns")
|
|
|
|
if __name__ == "__main__":
|
|
write_level("assets/levels/moon01.lvl")
|