Skip to content
Star

Terrain, paths, water and caves tools

Generated from the battlemap-mcp server at a020c64. Your assistant gets these same names, descriptions and parameters from the server when it connects; the server is named battlemap, so a client may show a tool as battlemap:ping or similar.

set_terrain_slot

Assign a Terrain asset to a terrain slot index so it can be filled/painted with that slot.

ParameterTypeDefault
asset requiredstring
slotinteger0

fill_terrain

Flood-fill the whole current level with a terrain slot.

If asset is given, it is assigned to the slot first.

The usual first ground call is fill_terrain(asset=<base material>) on the default slot 0: that replaces the base under everything and leaves slots 1-3 free for roads, yards and worn edges painted on top with fill_region.

ParameterTypeDefault
slotinteger0
assetstring""

fill_region

Fill only a region with a terrain slot (e.g. floor a single room), in woxel coords.

Unlike fill_terrain (whole level), this paints inside a shape. Provide ONE of: rect: [x, y, w, h] axis-aligned rectangle, or points: [[x,y], ...] a polygon (>= 3 points).

asset: optional Terrain asset to assign to the slot first.

rate: paint strength 0..1 (1 = fully replace). Undoable via undo().

ParameterTypeDefault
rectnumber[] | nullnull
pointsnumber[][] | nullnull
slotinteger0
assetstring""
ratenumber1

paint_terrain

Paint a soft circular terrain brush of a slot at a woxel position.

radius: brush radius in woxels. rate: peak strength 0..1 at the center, with a smooth falloff to the rim so strokes blend. asset: optional Terrain asset to assign to the slot first (else set it with set_terrain_slot). Undoable. For a hard-edged region instead of a brush, use fill_region.

ParameterTypeDefault
slotinteger0
xnumber | nullnull
ynumber | nullnull
radiusnumber64
ratenumber1
assetstring""

paint_path

Paint a continuous terrain stroke (a road/trail) along a polyline in one call.

asset is a TERRAIN asset, not a Paths one — this paints ground, it does not lay a Paths element. Use draw_path for that.

points: a list of [x, y] woxel corners the path runs through (>= 2). The bridge rasterizes a uniform ribbon of constant width by measuring each pixel's distance to the nearest segment, so the route comes out smooth with clean edges — no gaps or double-painted overlaps. Prefer this over stamping many paint_terrain dabs for any line/road.

radius: half-width of the stroke in woxels. rate: peak strength 0..1 with a soft falloff to the edges so it blends. asset: optional Terrain asset to assign to the slot first (else set it with set_terrain_slot). Undoable.

ParameterTypeDefault
points requirednumber[][]
slotinteger0
radiusnumber96
ratenumber1
assetstring""

paint_material

Paint a MATERIAL patch along a brush stroke. Returns what it painted.

Materials are their own system — irregular patches of stone, earth, lava or moss with their own borders — and they are not terrain and not patterns. A Materials asset passed to place_pattern makes a PATTERN, not a material.

Choose between them deliberately: terrain ground that must BLEND into neighbouring ground pattern a tiled floor inside a building material a sculpted patch with its own edge, sitting on top of ground water actual water

points: the stroke, in woxels. One point is a single dab.

asset: a Materials path from list_assets(category='Materials').

size: brush radius in mesh CELLS, 1-20. A cell is typically one tile, so size 6 paints roughly twelve tiles across PER DAB. Start at 1-2 and look.

layer: which material layer to paint into. Materials on different layers stack rather than merge. Keep the default -400 unless you have checked an export: a stroke on -300 showed in the editor but not in an export.

smooth: smooth the patch's edge, versus following the material's own texture.

erase: remove this material along the stroke instead of adding it.

The response reports cell_size_woxels and covered_woxels so the brush size can be reasoned about on the ground. There is no "did it land" flag, because the engine offers no reliable one: verify a stroke by looking at it. Each call is one undo step.

ParameterTypeDefault
points requirednumber[][]
asset requiredstring
sizeinteger2
layerinteger-400
smoothbooleantrue
erasebooleanfalse

get_terrain

Read the terrain back: sample the painted terrain on a grid.

rect: [x, y, w, h] in woxels; omit for the whole map.

samples: grid resolution per side, 2-64 (16 = 256 points).

Returns a weights grid, row-major from the rect's top-left. Each point is [slot0, slot1, slot2, slot3], read directly from the splat image's RGBA channels and summing to ~1, and slots: the texture each of those four slots holds.

Slot 0 is the BASE: whatever slots 1-3 leave unclaimed shows slot 0's texture. So [1, 0, 0, 0] means "all slot 0" — and what that looks like depends entirely on slots[0]. On a new map every slot holds limestone, so it is ground nobody chose; after fill_terrain(asset=grass) it is grass. The weights cannot tell those apart, which is why slots is reported. paint_terrain(slot=0) is accepted by the engine but never raises slot 0's weight; fill_terrain(slot=0) replaces the base instead.

Slots 4-7 live in a second splat image, reported as weights2. All eight weights are one blend: painting any slot takes weight from the other seven. A slot 4-7 needs a texture (set_terrain_slot) before it is painted.

This is the only way to check terrain without a screenshot — use it to confirm a fill or paint landed where you meant, and to see what ground you inherited on a map you did not build.

render: also report how the GPU draws it (shader, bound textures, and at at = [x, y] the CPU and GPU weights), for ground that reads wrong.

ParameterTypeDefault
rectnumber[] | nullnull
samplesinteger16
renderbooleanfalse
atnumber[] | nullnull

set_terrain_blending

Choose how terrain slots blend into one another on this level.

enabled: True for smooth blending (slots fade into each other), False for textured (the blend follows the material's own texture, giving a grainier, more natural seam).

This is a per-level setting that affects every terrain edge already painted, not just the next one, so choose it before painting rather than after.

get_terrain reports the current value as smooth_blending.

ParameterTypeDefault
enabled requiredboolean

repair_terrain

Rebuild a level's terrain splat when the engine dropped it. Destructive.

Only needed on a map whose terrain has already been lost. Symptom: every terrain call answers "the terrain splat image is empty", and Dungeondraft's log carries Expected data size of N bytes in Image::create() at load.

That happens when a map was resized while its terrain was not. The splat keeps the pixel dimensions it was created with, the mismatch is silent until the map is next opened, and Godot then refuses the image and drops every painted stroke — while the save that produced it reported success. set_map_size now resizes the rasters with the map, so new maps do not reach this state; this repairs one that already did.

It does not recover anything. The painted terrain is gone before this runs; all it restores is a usable surface to paint on, so the terrain has to be laid down again afterwards. Nothing else on the map is touched.

force: blank a splat that is already usable. This throws away working terrain, so it is off by default.

ParameterTypeDefault
forcebooleanfalse

draw_path

Draw a path/road/river through a list of [x, y] woxel points. Returns the new element id.

asset: a Paths asset path from list_assets(category='Paths').

smoothness: optional curve smoothing. width: optional width scale multiplier.

A wall-textured path looks like a wall but carries no line of sight into a VTT export. Where vision matters, run a real draw_wall along it too.

End treatments, which are what make a path read as part of the world rather than a strip laid on top of it:

fade_in / fade_out: the path's opacity fades at its start / end. Use where a trail should disappear into undergrowth or run off the map edge, instead of stopping at a hard rectangular cut. grow / shrink: the path's WIDTH tapers at its start / end. A stream that narrows upstream, a track that widens as it approaches a gate.

Set these per path, here: changing the PathTool's own options beforehand does not affect what this draws.

snap: 'none', 'grid' or 'auto'; see get_snap_settings.

ParameterTypeDefault
points requirednumber[][]
asset requiredstring
layerinteger0
sortinginteger0
smoothnessnumber | nullnull
widthnumber | nullnull
fade_inbooleanfalse
fade_outbooleanfalse
growbooleanfalse
shrinkbooleanfalse
snapstring""

add_water

Add a body of water — a pond, pool, river bend, moat, or flooded room.

rect: [x, y, w, h] in woxels, or points: [[x,y], ...] for a shoreline.

invert: erase water inside the outline instead of adding it. Water is a layer, not an object — there is nothing to select and delete — so this is how you take a pond back or cut an island out of one.

Water is a polygon layer, not a brush stroke: you give it a closed outline and the whole enclosed area becomes water. Give exactly one of:

rect: [x, y, w, h] in woxels, for a rectangular pool.

points: [[x, y], ...] with at least 3 points, for an irregular shape — a pond, a river bend, a cave lake. The outline closes automatically.

Call it repeatedly to build up several separate bodies of water. When the level's existing water shares one style (set_water_style), new water takes it too and the response says matched_level_style.

ParameterTypeDefault
rectnumber[] | nullnull
pointsnumber[][] | nullnull
invertbooleanfalse

set_water_style

Style this level's water: what KIND of water it is. Returns the result.

Geometry first (add_water), then this. A muddy river, a clear shallow, a peat swamp and a deep cold pool are the same mesh with different colour.

Per LEVEL: every body of water on this level is restyled, and water drawn later on a level whose bodies share one style takes that style too. The response reads the style back off the water bodies, which are what the map saves; bodies is how many there are, and mixed_styles means they differ.

ParameterTypeDefault
deep_colorstring""
shallow_colorstring""
blend_distancenumber | nullnull
borderboolean | nullnull

dig_cave

Carve a cave along a path with the Cave Brush (the dig/blast tool).

Dungeondraft caves are a separate layer: you dig open floor out of solid rock, and DD auto-generates the rocky wall border + debris around the opening.

points: a list of [x, y] woxel points the cave runs through (>= 1). A single point digs one circular chamber; multiple points dig a connected tunnel (rasterized as a constant-width ribbon, like paint_path). radius: half-width in woxels (default 256 = ~1 tile). dig: True carves open cave; False fills it back to rock. ground_color / wall_color: optional cave floor/wall tints ("#rrggbb" or [r,g,b]). texture: optional Caves floor asset (see list_assets(category="Caves")). The mesh rebuilds automatically.

ParameterTypeDefault
points requirednumber[][]
radiusnumber256
digbooleantrue
ground_colorstring""
wall_colorstring""
texturestring""

get_cave

Read the selected level's cave floor/entrance cell counts and actual colours.

Entrances are a separate blast mask that removes rocky borders; they do not carve floor. Counts describe bitmap cells, not distinct rooms or openings.

No parameters.

set_cave_entrance

Open or restore a circular section of cave border, as one undoable edit.

Place the centre at an existing cave edge in woxels. radius is the half-width (0 < radius <= 2048), rounded to cave cells. open=False removes the blast mask, restoring the border; neither mode digs or fills cave floor. Dig the approach first with dig_cave, then inspect a screenshot of the mouth. The edit belongs to the selected level. Undo requires that same level and unchanged bitmap dimensions. Returns the actual number of changed cells.

ParameterTypeDefault
x requirednumber
y requirednumber
radiusnumber256
openbooleantrue

clear_caves

Wipe the entire cave layer back to solid rock.

Removes all carved caves at once (the whole cave system), rebuilding the mesh. Undoable like dig_cave. Use this instead of filling regions back with dig_cave(dig=False) when you want to reset all caves.

No parameters.