161 lines
4.4 KiB
Python
161 lines
4.4 KiB
Python
# Copyright (c) 2026 Dominic Masters
|
|
#
|
|
# This software is released under the MIT License.
|
|
# https://opensource.org/licenses/MIT
|
|
|
|
"""
|
|
Generates chunk 0_0_0.dcf with a small hill in the centre.
|
|
|
|
Hill layout (tile coordinates, 0-based):
|
|
y=5: . . . . . . N N . . . . . . . . RAMP_NORTH (south slope)
|
|
y=6: . . . . . E H H W . . . . . . . Hill top (H), RAMP_EAST/WEST
|
|
y=7: . . . . . E H H W . . . . . . .
|
|
y=8: . . . . . . S S . . . . . . . . RAMP_SOUTH (north slope)
|
|
x=6 x=7
|
|
"""
|
|
|
|
import struct, os
|
|
|
|
# Must match src/dusk/rpg/overworld/chunk.h and tile.h
|
|
CHUNK_WIDTH = 16
|
|
CHUNK_HEIGHT = 16
|
|
CHUNK_DEPTH = 32
|
|
CHUNK_W_F = float(CHUNK_WIDTH)
|
|
|
|
TILE_NULL = 0
|
|
TILE_GROUND = 1
|
|
TILE_RAMP_NORTH = 2
|
|
TILE_RAMP_SOUTH = 3
|
|
TILE_RAMP_EAST = 4
|
|
TILE_RAMP_WEST = 5
|
|
|
|
TILE_SIZE = 4 # sizeof(tile_t) = sizeof(int)
|
|
VERT_SIZE = 20 # sizeof(meshvertex_t): uv[2] + pos[3] floats
|
|
FILE_VER = 2
|
|
|
|
# Hill geometry parameters
|
|
HILL_X = frozenset({6, 7})
|
|
HILL_Y = frozenset({6, 7})
|
|
HILL_H = 1.0
|
|
|
|
|
|
def tile_idx(cx, cy, cz):
|
|
return cz * CHUNK_WIDTH * CHUNK_HEIGHT + cy * CHUNK_WIDTH + cx
|
|
|
|
|
|
def make_vert(u, v, px, py, pz):
|
|
return struct.pack('<5f', u, v, px, py, pz)
|
|
|
|
|
|
def quad_verts(cx, cy, z_sw, z_se, z_ne, z_nw):
|
|
"""
|
|
Build 6 vertices (2 triangles) for a tile quad.
|
|
Heights at each corner: SW=south-west, SE=south-east,
|
|
NE=north-east, NW=north-west.
|
|
UV formula (verified against existing DCF data):
|
|
u = (cy + within_x) / CHUNK_WIDTH where within_x in {0,1}
|
|
v = (cx + within_y) / CHUNK_HEIGHT where within_y in {0,1}
|
|
"""
|
|
u0 = cy / CHUNK_W_F
|
|
u1 = (cy + 1) / CHUNK_W_F
|
|
v0 = cx / CHUNK_W_F
|
|
v1 = (cx + 1) / CHUNK_W_F
|
|
x0, x1 = float(cx), float(cx + 1)
|
|
y0, y1 = float(cy), float(cy + 1)
|
|
|
|
SW = make_vert(u0, v0, x0, y0, float(z_sw))
|
|
SE = make_vert(u1, v0, x1, y0, float(z_se))
|
|
NE = make_vert(u1, v1, x1, y1, float(z_ne))
|
|
NW = make_vert(u0, v1, x0, y1, float(z_nw))
|
|
|
|
return SW + SE + NE + SW + NE + NW
|
|
|
|
|
|
def flat(cx, cy, z):
|
|
return quad_verts(cx, cy, z, z, z, z)
|
|
|
|
|
|
def ramp_north(cx, cy):
|
|
return quad_verts(cx, cy, 0, 0, HILL_H, HILL_H)
|
|
|
|
|
|
def ramp_south(cx, cy):
|
|
return quad_verts(cx, cy, HILL_H, HILL_H, 0, 0)
|
|
|
|
|
|
def ramp_east(cx, cy):
|
|
return quad_verts(cx, cy, 0, HILL_H, HILL_H, 0)
|
|
|
|
|
|
def ramp_west(cx, cy):
|
|
return quad_verts(cx, cy, HILL_H, 0, 0, HILL_H)
|
|
|
|
|
|
def generate():
|
|
tiles = [TILE_GROUND] * (CHUNK_WIDTH * CHUNK_HEIGHT * CHUNK_DEPTH)
|
|
|
|
ramps_n = frozenset((cx, 5) for cx in HILL_X)
|
|
ramps_s = frozenset((cx, 8) for cx in HILL_X)
|
|
ramps_e = frozenset((5, cy) for cy in HILL_Y)
|
|
ramps_w = frozenset((8, cy) for cy in HILL_Y)
|
|
|
|
for cx, cy in ramps_n:
|
|
tiles[tile_idx(cx, cy, 0)] = TILE_RAMP_NORTH
|
|
for cx, cy in ramps_s:
|
|
tiles[tile_idx(cx, cy, 0)] = TILE_RAMP_SOUTH
|
|
for cx, cy in ramps_e:
|
|
tiles[tile_idx(cx, cy, 0)] = TILE_RAMP_EAST
|
|
for cx, cy in ramps_w:
|
|
tiles[tile_idx(cx, cy, 0)] = TILE_RAMP_WEST
|
|
|
|
for cx in HILL_X:
|
|
for cy in HILL_Y:
|
|
tiles[tile_idx(cx, cy, 1)] = TILE_GROUND
|
|
|
|
verts = bytearray()
|
|
|
|
for cx in range(CHUNK_WIDTH):
|
|
for cy in range(CHUNK_HEIGHT):
|
|
pos = (cx, cy)
|
|
if cx in HILL_X and cy in HILL_Y:
|
|
continue
|
|
if pos in ramps_n:
|
|
verts += ramp_north(cx, cy)
|
|
elif pos in ramps_s:
|
|
verts += ramp_south(cx, cy)
|
|
elif pos in ramps_e:
|
|
verts += ramp_east(cx, cy)
|
|
elif pos in ramps_w:
|
|
verts += ramp_west(cx, cy)
|
|
else:
|
|
verts += flat(cx, cy, 0)
|
|
|
|
for cx in sorted(HILL_X):
|
|
for cy in sorted(HILL_Y):
|
|
verts += flat(cx, cy, HILL_H)
|
|
|
|
vert_count = len(verts) // VERT_SIZE
|
|
tile_bytes = struct.pack(f'<{len(tiles)}i', *tiles)
|
|
|
|
buf = bytearray()
|
|
buf += b'DCF\x00'
|
|
buf += struct.pack('<I', FILE_VER)
|
|
buf += tile_bytes
|
|
buf += struct.pack('<B', 1)
|
|
buf += struct.pack('<I', vert_count)
|
|
buf += verts
|
|
|
|
return buf, vert_count
|
|
|
|
|
|
if __name__ == '__main__':
|
|
out = os.path.join(
|
|
os.path.dirname(__file__), '..', '..', '..', 'assets', 'chunks',
|
|
'0_0_0.dcf'
|
|
)
|
|
out = os.path.normpath(out)
|
|
buf, vert_count = generate()
|
|
with open(out, 'wb') as f:
|
|
f.write(buf)
|
|
print(f'Wrote {out}: {vert_count} vertices, {len(buf)} bytes')
|