264 lines
8.0 KiB
Lua
264 lines
8.0 KiB
Lua
function cartographer.create_map(x, z, w, h, filled, detail, scale)
|
|
local id = _cartographer.next_map_id;
|
|
|
|
local map = {
|
|
id = id,
|
|
x = x,
|
|
z = z,
|
|
w = w,
|
|
h = h,
|
|
detail = detail,
|
|
scale = scale,
|
|
fill = {},
|
|
markers = {},
|
|
};
|
|
|
|
_cartographer.maps[id] = map;
|
|
if filled then
|
|
cartographer.fill(map, x, z, w, h);
|
|
end
|
|
|
|
_cartographer.next_map_id = _cartographer.next_map_id + 1;
|
|
|
|
return id;
|
|
end
|
|
|
|
function cartographer.get_map(id)
|
|
return _cartographer.maps[id];
|
|
end
|
|
|
|
function cartographer.resize_map(id, w, h)
|
|
local map = cartographer.get_map(id);
|
|
if map ~= nil and w >= map.w and h >= map.h then
|
|
map.w = w;
|
|
map.h = h;
|
|
end
|
|
end
|
|
|
|
function cartographer.fill(map, x, z, w, h)
|
|
if map == nil then
|
|
return;
|
|
end
|
|
|
|
for i = math.max(x, map.x),math.min(x + w - 1, map.x + map.w),1 do
|
|
for j = math.max(z, map.z),math.min(z + h - 1, map.z + map.h),1 do
|
|
map.fill[(i - map.x) + ((j - map.z) * map.w)] = map.detail;
|
|
end
|
|
end
|
|
end
|
|
|
|
function cartographer.set_marker(map, x, z, marker)
|
|
if map == nil or x < map.x or x > map.x + map.w or z < map.z or z > map.z + map.h then
|
|
return;
|
|
end
|
|
|
|
if not map.markers[x] then
|
|
map.markers[x] = {
|
|
[z] = marker,
|
|
};
|
|
else
|
|
map.markers[x][z] = marker;
|
|
end
|
|
end
|
|
|
|
function cartographer.get_marker(map, x, z)
|
|
if map == nil or x < map.x or x > map.x + map.w or z < map.z or z > map.z + map.h or not map.markers[x] then
|
|
return nil;
|
|
end
|
|
|
|
return map.markers[x][z];
|
|
end
|
|
|
|
-- Fill in the local area of a map around a position
|
|
-- id: A map ID
|
|
-- x: The x position, in world coordinates
|
|
-- z: The z position, in world coordinates
|
|
function cartographer.fill_local(id, x, z)
|
|
local map = cartographer.get_map(id);
|
|
|
|
x, z = cartographer.to_map_coordinates(map, x, z);
|
|
|
|
-- TODO: Adjust size to match map scale
|
|
if map and x >= map.x - 2 and x <= map.x + map.w + 1 and z >= map.z - 2 and z <= map.z + map.h + 1 then
|
|
cartographer.fill(map, x - 2, z - 2, 5, 5);
|
|
end
|
|
end
|
|
|
|
-- Convert a position in world coordinates to the given map's coordinate system
|
|
-- map: The map to use as reference, or nil to use the default size (map scale of 1)
|
|
-- x: The x position, in world coordinates
|
|
-- z: The z position, in world coordinates
|
|
--
|
|
-- Returns The converted x and z coordinates
|
|
function cartographer.to_map_coordinates(map, x, z)
|
|
if not map or map.scale == 0 then
|
|
return tochunk(x), tochunk(z);
|
|
end
|
|
|
|
return math.floor(tochunk(x) / map.scale + 0.5), math.floor(tochunk(z) / map.scale + 0.5);
|
|
end
|
|
|
|
-- Periodically-called function to fill in maps and queue chunks for manual
|
|
-- scanning
|
|
local function fill_loop()
|
|
-- Fill in all player-held maps
|
|
for _,p in ipairs(minetest.get_connected_players()) do
|
|
local inventory = p:get_inventory();
|
|
local pos = p:get_pos();
|
|
if pos.y > -10 then
|
|
for i = 1,inventory:get_size("main") do
|
|
local stack = inventory:get_stack("main", i);
|
|
|
|
if stack:get_name() == "cartographer:map" then
|
|
cartographer.fill_local(stack:get_meta():get_int("cartographer:map_id"), pos.x, pos.z);
|
|
end
|
|
end
|
|
for i = -2,2 do
|
|
for j = -2,2 do
|
|
local adjusted_pos = {
|
|
x = pos.x + fromchunk(i),
|
|
y = pos.y,
|
|
z = pos.z + fromchunk(j),
|
|
}
|
|
cartographer.queue_region(adjusted_pos);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for _ = 1,10 do
|
|
cartographer.scan_regions();
|
|
end
|
|
minetest.after(5, fill_loop);
|
|
end
|
|
minetest.after(5, fill_loop);
|
|
|
|
-- Register a biome with textures to display
|
|
-- name: A string containing the biome name
|
|
-- textures: A table of texture names.
|
|
-- These should correspond with detail levels,
|
|
-- any detail level past the length of the table will return the last texture
|
|
-- (Optional) min_height: The minimum Y position where this biome data should be used
|
|
-- (Optional) max_height: The maximum Y position where this biome data should be used
|
|
function cartographer.register_biome(name, textures, min_height, max_height)
|
|
_cartographer.biome_lookup[#_cartographer.biome_lookup + 1] = {
|
|
name = name,
|
|
textures = textures,
|
|
min_height = min_height,
|
|
max_height = max_height,
|
|
};
|
|
end
|
|
|
|
-- Format marker ids to allow their use as formspec element ids.
|
|
-- We're mostly concerned with guarding against the : character because it is
|
|
-- common for ids and has an alternate meaning in formspecs.
|
|
-- id: The id to format
|
|
--
|
|
-- Returns the formatted id
|
|
local function format_marker_id(id)
|
|
return id:gsub(":", "_");
|
|
end
|
|
|
|
-- Find the marker data for a given id
|
|
-- id: The id to search for
|
|
--
|
|
-- Returns the marker data, or nil if not found
|
|
function cartographer.get_marker_data(id)
|
|
if not id then
|
|
return nil;
|
|
end
|
|
|
|
id = format_marker_id(id);
|
|
for _,marker in pairs(_cartographer.marker_lookup) do
|
|
if marker.id == id then
|
|
return marker;
|
|
end
|
|
end
|
|
|
|
return nil;
|
|
end
|
|
|
|
-- Register a marker with textures to display
|
|
-- id: A string containing the id of the marker
|
|
-- name: A string containing the displayedname of the marker
|
|
-- textures: A table of texture names.
|
|
-- These should correspond with detail levels,
|
|
-- any detail level past the length of the table will return the last texture
|
|
function cartographer.register_marker(id, name, textures)
|
|
if not id then
|
|
return nil;
|
|
end
|
|
|
|
id = format_marker_id(id);
|
|
local existing_marker = cartographer.get_marker_data(id);
|
|
if existing_marker then
|
|
existing_marker.name = name;
|
|
existing_marker.textures = textures;
|
|
else
|
|
_cartographer.marker_lookup[#_cartographer.marker_lookup+1] = {
|
|
id = id,
|
|
name = name,
|
|
textures = textures,
|
|
};
|
|
end
|
|
end
|
|
|
|
function cartographer.is_filled(map, x, z)
|
|
if map == nil then
|
|
return false;
|
|
end
|
|
|
|
-- minetest.chat_send_all(tostring(x).. ", " .. tostring(z) .. "(" .. tostring(x + (z * map.w)) .."): " .. tostring(map.fill[x + (z * map.w)]));
|
|
return map.fill[(x - map.x) + ((z - map.z) * map.w)] ~= nil;
|
|
end
|
|
|
|
-- Get an entry from a list for a given detail level
|
|
-- textures: An array of textures
|
|
-- detail: The detail level
|
|
--
|
|
-- Returns the entry at detail, or the last entry if detail is out-of-bounds
|
|
function cartographer.detail_texture(textures, detail)
|
|
return textures[math.min(detail, #textures)];
|
|
end
|
|
|
|
-- Get the texture name (minus index/extension) for the given biome, height, and detail level.
|
|
-- name: A string containing the biome name
|
|
-- height: A number representing the Y position of the biome
|
|
-- detail: The detail level
|
|
-- Returns a string with a texture name, or nil if no matching biome entry was found.
|
|
function cartographer.get_biome_texture(name, height, detail)
|
|
for _,biome in ipairs(_cartographer.biome_lookup) do
|
|
if biome.name == name and (not biome.min_height or height >= biome.min_height) and (not biome.max_height or height <= biome.max_height) then
|
|
return cartographer.detail_texture(biome.textures, detail);
|
|
end
|
|
end
|
|
|
|
return nil;
|
|
end
|
|
|
|
-- Get the texture name (minus extension) for the given marker and detail level.
|
|
-- id: A string containing the marker id
|
|
-- detail: The detail level
|
|
-- Returns a string with a texture name, or nil if no matching marker was found.
|
|
function cartographer.get_marker_texture(id, detail)
|
|
if not id then
|
|
return nil;
|
|
end
|
|
|
|
id = format_marker_id(id);
|
|
local marker = cartographer.get_marker_data(id);
|
|
|
|
if marker then
|
|
return marker.textures[math.min(detail, #marker.textures)];
|
|
end
|
|
|
|
return nil;
|
|
end
|
|
|
|
-- Play a feedback sound localized on the given player
|
|
-- sound: The sound to play
|
|
-- player: The player who triggered the sound
|
|
function cartographer.map_sound(sound, player)
|
|
minetest.sound_play(sound, { pos=player:get_pos(), max_hear_distance=5 }, true);
|
|
end
|