-- Arguments -- map_data: The cartographer map data table local map_data = ...; -- Constants local TILE_SIZE = 0.25; local TILE_OFFSET = 0.24; -- Slightly smaller than TILE_SIZE. We overlap tiles slightly to minimize seams -- NoiseParams table for tile variations local MAP_NOISE = { offset = 0, scale = 1, spread = {x = 2, y = 2, z = 2}, seed = tonumber(minetest.get_mapgen_setting("seed")), octaves = 2, persist = 0.63, lacunarity = 2.0, flags = "defaults, absvalue", }; -- Get the variant of the tile at a given position -- x: The X position of the tile (in map coordinates) -- z: The Z position of the tile (in map coordinates) -- noise: A 2d lookup table of perlin noise. Must contain the position [x + 1][y + 1] -- -- Returns a number from 1 to 4 local function get_variant(x, z, noise) return math.floor(math.min(noise[x + 1][z + 1] * 3, 3)) + 1; end local map_formspec_prefix = [[ formspec_version[3] size[%f,%f] real_coordinates[true] style_type[image_button;border=false] ]]; local tile = "image[%f,%f;%f,%f;%s]"; local player_marker = "animated_image[%f,%f;%f,%f;;%s;%d;%d]"; -- Generate formspec markup for an unknown biome tile -- x: The x position of the tile -- y: The y position of the tile -- detail: The detail level -- variant: The tile variant -- -- Returns a formspec string local function unknown_biome_tile(x, y, detail, variant) return string.format("image[%f,%f;%f,%f;%s.%s.png]", x, y, TILE_SIZE, TILE_SIZE, cartographer.detail_texture(cartographer.skin.unknown_biome_textures, detail), variant); end -- Generate formspec markup for a given map -- x: The X position of the map (in map coordinates) -- y: The Z position of the map (in map coordinates) -- w: The width of the map (in map coordinates) -- h: The height of the map (in map coordinates) -- player_x: The X position of the player marker (in map coordinates) -- player_y: The Y position of the player marker (in map coordinates) -- detail: The detail level -- map_scale: Integer scaling factor for displaying a zoomed-out map -- height_mode: If true, displaces tiles by their height -- (Optional) is_visible: Callback to determine if a tile should be drawn -- (Optional) get_marker: Callback to get the marker for any given tile -- (Optional) user: userdata passed to the is_visible/get_marker callbacks -- -- Returns a formspec string local function generate_map(x, y, w, h, player_x, player_y, detail, map_scale, height_mode, is_visible, get_marker, user) local str = ""; local noise = PerlinNoiseMap(MAP_NOISE, { x=w + 1, y=h + 1, z=1}):get_2d_map({ x=x, y=y}); for i = x,x + w,1 do local fx = (i - x) * TILE_OFFSET; local column = map_data.generated[i * map_scale]; for j = y + h,y,-1 do local fy = (y + h - j) * TILE_OFFSET; if column == nil or column[j * map_scale] == nil or (is_visible and not is_visible(user, i, j)) then str = str .. unknown_biome_tile(fx, fy, detail, get_variant(i - x, j - y, noise)); else local name = minetest.get_biome_name(column[j * map_scale].biome); local height = column[j * map_scale].height; local biome = cartographer.get_biome_texture(name, math.floor(height + 0.5), detail); if biome then local depth = math.min(math.max(math.floor(height / 8), -8), 0) * -1 height = math.max(math.min(math.floor(height / (math.max(map_scale * 0.5, 1) + 4)), 8), 0) local mod = ""; if height > 0 then mod = "^[colorize:white:"..tostring(height * 10) height = height * 0.05; if height_mode then str = str .. tile:format(fx, fy - height + TILE_OFFSET, TILE_SIZE, height + 0.01, cartographer.detail_texture(cartographer.skin.cliff_textures, detail) .. ".png"); else height = 0; end elseif depth > 0 then mod = "^[colorize:#1f1f34:"..tostring(depth * 10) end str = str..tile:format(fx, fy - height, TILE_SIZE, TILE_SIZE, biome .. "." .. tostring(get_variant(i - x, j - y, noise)) .. ".png" .. mod) if get_marker then local marker = cartographer.get_marker_texture(get_marker(user, i, j), detail); if marker then str = str..tile:format(fx, fy - height, TILE_SIZE, TILE_SIZE, marker .. ".png") end end if i == player_x and j == player_y then local player_icon = cartographer.detail_texture(cartographer.skin.player_icons, detail); str = str .. player_marker:format(fx, fy - height, TILE_SIZE, TILE_SIZE, player_icon.texture .. ".png", player_icon.frame_count, player_icon.frame_duration); end else str = str .. unknown_biome_tile(fx, fy, detail, get_variant(i - x, j - y, noise)); end end end end return str; end -- Get the formspec for a given map segment -- x: The X position of the map, in map coordinates -- y: The Y position of the map, in map coordinates -- w: The width of the map, in map coordinates -- h: The height of the map, in map coordinates -- detail: The detail level of the map -- scale: Integer scaling factor for displaying a zoomed-out map -- height_mode: If true, displaces tiles by their height -- -- Returns a formspec string, the width of the formspec, and the height of the -- formspec function cartographer.get_map_formspec(x, y, w, h, detail, scale, height_mode) local formspec_width = (w + 1) * TILE_OFFSET + 0.01; local formspec_height = (h + 1) * TILE_OFFSET + 0.01; return map_formspec_prefix:format(formspec_width, formspec_height)..generate_map(x - (w * 0.5), y - (h * 0.5), w, h, x, y, detail, scale, height_mode), formspec_width, formspec_height; end -- Get the formspec for a given map table -- map: The map to use -- x: The X position of the player marker, in map coordinates -- y: The Y position of the player marker, in map coordinates -- height_mode: If true, displaces tiles by their height -- -- Returns a formspec string, the width of the formspec, and the height of the -- formspec function cartographer.get_map_formspec_map(map, x, y, height_mode) local formspec_width = (map.w + 1) * TILE_OFFSET + 0.01; local formspec_height = (map.h + 1) * TILE_OFFSET + 0.01; return map_formspec_prefix:format(formspec_width, formspec_height)..generate_map(map.x, map.z, map.w, map.h, x, y, map.detail, map.scale, height_mode, cartographer.is_filled, cartographer.get_marker, map), formspec_width, formspec_height; end