A minetest mod for mapmaking
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
7.9KB

  1. -- Arguments
  2. -- map_data: The cartographer map data table
  3. -- gui: The GUI API
  4. -- skin: The GUI skin
  5. -- util: API for uncategorized utility methods
  6. -- biomes: The biome API
  7. -- markers: The marker API
  8. local map_data, gui, skin, util, biomes, markers = ...;
  9. -- Constants
  10. local TILE_SIZE = 0.25;
  11. local TILE_OFFSET = 0.24; -- Slightly smaller than TILE_SIZE. We overlap tiles slightly to minimize seams
  12. -- NoiseParams table for tile variations
  13. local MAP_NOISE = {
  14. offset = 0,
  15. scale = 1,
  16. spread = {x = 2, y = 2, z = 2},
  17. seed = tonumber(minetest.get_mapgen_setting("seed")),
  18. octaves = 2,
  19. persist = 0.63,
  20. lacunarity = 2.0,
  21. flags = "defaults, absvalue",
  22. };
  23. local function map_is_filled(map, x, y)
  24. return map:is_filled(x, y);
  25. end
  26. local function map_get_marker(map, x, y)
  27. return map:get_marker(x, y);
  28. end
  29. -- Get the variant of the tile at a given position
  30. --
  31. -- prefix: The part of the tile texture name before the variant
  32. -- x: The X position of the tile (in map coordinates)
  33. -- z: The Z position of the tile (in map coordinates)
  34. -- noise: A 2d lookup table of perlin noise. Must contain the position [x + 1][y + 1]
  35. --
  36. -- Returns a string in the format 'prefix.variant.png', where variant is a number from 1 to 4
  37. local function get_variant(prefix, x, z, noise)
  38. return string.format("%s.%d.png", prefix, math.floor(math.min(noise[x + 1][z + 1] * 3, 3)) + 1);
  39. end
  40. -- Generate formspec markup for a given map
  41. --
  42. -- x: The X position of the map (in relative map coordinates)
  43. -- y: The Z position of the map (in relative map coordinates)
  44. -- w: The width of the map (in map coordinates)
  45. -- h: The height of the map (in map coordinates)
  46. -- player_x: The X position of the player marker (in map coordinates)
  47. -- player_y: The Y position of the player marker (in map coordinates)
  48. -- detail: The detail level
  49. -- map_scale: Integer scaling factor for displaying a zoomed-out map
  50. -- height_mode: If true, displaces tiles by their height
  51. -- (Optional) is_visible: Callback to determine if a tile should be drawn
  52. -- (Optional) get_marker: Callback to get the marker for any given tile
  53. --
  54. -- Additional arguments are provided to is_visible / get_marker
  55. --
  56. -- Returns a formspec string
  57. local function generate_map(x, y, w, h, player_x, player_y, detail, map_scale, height_mode, is_visible, get_marker, ...)
  58. local str = "";
  59. local noise = PerlinNoiseMap(MAP_NOISE, { x=w + 1, y=h + 1, z=1}):get_2d_map({ x=x, y=y});
  60. for i = 0,w,1 do
  61. local world_i = x + (i * map_scale);
  62. local fx = i * TILE_OFFSET;
  63. local column = map_data.generated[world_i];
  64. for j = h,0,-1 do
  65. local world_j = y + (j * map_scale);
  66. local fy = (h - j) * TILE_OFFSET;
  67. if column == nil or column[world_j] == nil or (is_visible and not is_visible(..., x + i, y + j)) then
  68. local unknown_tex = util.get_clamped(skin.unknown_biome_textures, detail);
  69. str = str .. gui.image {
  70. x = fx,
  71. y = fy,
  72. w = TILE_SIZE,
  73. h = TILE_SIZE,
  74. image = get_variant(unknown_tex, i, j, noise),
  75. };
  76. else
  77. local name = minetest.get_biome_name(column[world_j].biome);
  78. local height = column[world_j].height;
  79. local biome = biomes.get_texture(name, math.floor(height + 0.5), detail);
  80. if biome then
  81. local depth = math.min(math.max(math.floor(height / 8), -8), 0) * -1
  82. height = math.max(math.min(math.floor(height / (math.max(map_scale * 0.5, 1) + 4)), 8), 0)
  83. local mod = "";
  84. if height > 0 then
  85. mod = "^[colorize:white:"..tostring(height * 10)
  86. height = height * 0.05;
  87. if height_mode then
  88. str = str .. gui.image {
  89. x = fx,
  90. y = fy - height + TILE_OFFSET,
  91. w = TILE_SIZE,
  92. h = height + 0.01,
  93. image = util.get_clamped(skin.cliff_textures, detail) .. ".png",
  94. };
  95. else
  96. height = 0;
  97. end
  98. elseif depth > 0 then
  99. mod = "^[colorize:#1f1f34:"..tostring(depth * 10)
  100. end
  101. str = str .. gui.image {
  102. x = fx,
  103. y = fy - height,
  104. w = TILE_SIZE,
  105. h = TILE_SIZE,
  106. image = get_variant(biome, i, j, noise) .. mod,
  107. };
  108. if get_marker then
  109. local marker = markers.get_texture(get_marker(..., i, j), detail);
  110. if marker then
  111. str = str .. gui.image {
  112. x = fx,
  113. y = fy - height,
  114. w = TILE_SIZE,
  115. h = TILE_SIZE,
  116. image = marker .. ".png",
  117. };
  118. end
  119. end
  120. if i == player_x and j == player_y then
  121. local player_icon = util.get_clamped(skin.player_icons, detail);
  122. str = str .. gui.animated_image {
  123. x = fx,
  124. y = fy - height,
  125. w = TILE_SIZE,
  126. h = TILE_SIZE,
  127. animation = player_icon,
  128. };
  129. end
  130. else
  131. local unknown_tex = util.get_clamped(skin.unknown_biome_textures, detail);
  132. str = str .. gui.image {
  133. x = fx,
  134. y = fy,
  135. w = TILE_SIZE,
  136. h = TILE_SIZE,
  137. image = get_variant(unknown_tex, i, j, noise),
  138. };
  139. end
  140. end
  141. end
  142. end
  143. return str;
  144. end
  145. local map_formspec = {};
  146. -- Get the formspec for a given map segment
  147. --
  148. -- x: The X position of the map, in map coordinates
  149. -- y: The Y position of the map, in map coordinates
  150. -- w: The width of the map, in map coordinates
  151. -- h: The height of the map, in map coordinates
  152. -- detail: The detail level of the map
  153. -- scale: Integer scaling factor for displaying a zoomed-out map
  154. -- height_mode: If true, displaces tiles by their height
  155. --
  156. -- Returns a formspec string, the width of the formspec, and the height of the
  157. -- formspec
  158. function map_formspec.from_coords(x, y, w, h, detail, scale, height_mode)
  159. local formspec_width = (w + 1) * TILE_OFFSET + 0.01;
  160. local formspec_height = (h + 1) * TILE_OFFSET + 0.01;
  161. return gui.formspec {
  162. w = formspec_width,
  163. h = formspec_height,
  164. generate_map(x - (w * 0.5), y - (h * 0.5), w, h, w * 0.5, h * 0.5, detail, scale, height_mode),
  165. }, formspec_width, formspec_height;
  166. end
  167. -- Get the formspec for a given map table
  168. --
  169. -- map: The map to use
  170. -- x: The X position of the player marker, in relative map coordinates
  171. -- y: The Y position of the player marker, in relative map coordinates
  172. -- height_mode: If true, displaces tiles by their height
  173. --
  174. -- Returns a formspec string, the width of the formspec, and the height of the
  175. -- formspec
  176. function map_formspec.from_map(map, x, y, height_mode)
  177. local formspec_width = (map.w + 1) * TILE_OFFSET + 0.01;
  178. local formspec_height = (map.h + 1) * TILE_OFFSET + 0.01;
  179. return gui.formspec {
  180. w = formspec_width,
  181. h = formspec_height,
  182. generate_map(map.x, map.z, map.w, map.h,
  183. x, y, map.detail, map.scale, height_mode, map_is_filled, map_get_marker, map),
  184. }, formspec_width, formspec_height;
  185. end
  186. return map_formspec;