-- The list of players looking at maps, and the map IDs that they're looking at local player_maps = {}; -- Show a map to a player from the ID -- id: The map ID -- player_x: The X position (in world coordinates) -- player_z: The Z position (in world coordinates) -- player_name: The name of the player to show to -- (Optional) marker_page: The current page that the marker editor is on local function show_map_id_formspec(id, player_x, player_z, player_name, marker_page) cartographer.fill_local(id, player_x, player_z); player_maps[player_name] = { id = id, page = marker_page or 1, }; local map = cartographer.get_map(id); player_x, player_z = cartographer.to_map_coordinates(map, player_x, player_z) local formspec, formspec_width, formspec_height = cartographer.get_map_formspec_map(data, map, player_x, player_z); if #_cartographer.marker_lookup > 0 then formspec = formspec .. string.format("style_type[button,image_button,label;noclip=true] container[%f,0.5]", formspec_width - 0.01) .. _cartographer.generate_marker_formspec(cartographer.get_marker(map, player_x, player_z), map.detail, marker_page or 1, cartographer.skin.marker_bg, cartographer.skin.marker_button) .. "container_end[]"; end minetest.show_formspec(player_name, "cartographer:map", formspec); end -- Create a map from metadata, and assign the ID to the metadata -- meta: A metadata object containing the map ID -- player_x: The X position (in map coordinates) -- player_z: The Z position (in map coordinates) local function map_from_meta(meta, player_x, player_z) local size = meta:get_int("cartographer:size") or 10; local detail = meta:get_int("cartographer:detail") or 1; local scale = meta:get_int("cartographer:scale") or 1; local total_size = size * scale; local map_x = math.floor((player_x + 10)/total_size) * total_size - 10 local map_y = math.floor((player_z + 10)/total_size) * total_size - 10; local id = cartographer.create_map(map_x, map_y, size, size, false, detail, scale); meta:set_int("cartographer:map_id", id); meta:set_string("description", "Map #" .. tostring(id) .. "\n[" .. tostring(fromchunk(map_x)) .. "," .. tostring(fromchunk(map_y)) .. "] - [" .. tostring(fromchunk(map_x + total_size)) .. "," .. tostring(fromchunk(map_y + total_size)) .. "]") return id; end -- Show a map to a player from metadata, creating it if possible -- meta: A metadata object containing the map ID -- player: The player to show the map to local function show_map_meta(meta, player) local pos = player:get_pos(); local player_x = tochunk(pos.x); local player_z = tochunk(pos.z); local id = meta:get_int("cartographer:map_id"); if id == 0 then id = map_from_meta(meta, player_x, player_z); end show_map_id_formspec(id, pos.x, pos.z, player:get_player_name()); end -- Called when a player sends input to the server from a formspec -- This callback handles player input in the map formspec, for editing markers -- player: The player who sent the input -- name: The formspec name -- fields: A table containing the input minetest.register_on_player_receive_fields(function(player, name, fields) if name == "cartographer:map" then local data = player_maps[player:get_player_name()]; local map = cartographer.get_map(data.id); if not map then return; end for k,v in pairs(fields) do local marker = k:match("marker%-(.+)"); local pos = player:get_pos(); if marker or k == "clear_marker" then local player_x, player_z = cartographer.to_map_coordinates(map, pos.x, pos.z); cartographer.set_marker(map, player_x, player_z, marker); cartographer.map_sound("cartographer_write", player); show_map_id_formspec(map.id, pos.x, pos.z, player:get_player_name(), data.page); elseif k == "prev_button" then show_map_id_formspec(map.id, pos.x, pos.z, player:get_player_name(), data.page - 1); elseif k == "next_button" then show_map_id_formspec(map.id, pos.x, pos.z, player:get_player_name(), data.page + 1); elseif k == "quit" then player_maps[player:get_player_name()] = nil; end end end end); -- The map item/node minetest.register_node("cartographer:map", { description = "Map", inventory_image = "cartographer_map.png", tiles = { "cartographer_map.png" }, drawtype = "signlike", paramtype = "light", paramtype2 = "wallmounted", stack_max = 1, sunlight_propagates = true, walkable = false, selection_box = { type = "fixed", fixed = { {-0.5, -0.5, -0.5, 0.5, -7 / 16, 0.5}, }, }, -- Called when this node is placed in the world. Copies map data from the -- item to the node. -- pos: The position of the node -- placer: The object that placed this node (can be nil) -- stack: The itemstack that was placed -- pointed_thing: The current pointed thing after_place_node = function(pos, placer, stack, pointed_thing) local meta = stack:get_meta():to_table(); local node_meta = minetest.get_meta(pos); node_meta:from_table(meta); -- Consume the item after placing return false; end, -- Called when a player right-clicks this node. Display's the map's -- content, creating it if it doesn't exist. -- pos: The position of the node -- player: The player that right-clicked the node on_rightclick = function(pos, _, player) cartographer.map_sound("cartographer_open_map", player); show_map_meta(minetest.get_meta(pos), player); end, -- Called when a player uses this item. Displays the map's content, -- creating it if it doesn't exist. -- stack: The itemstack -- player: The player that used the item on_use = function(stack, player) cartographer.map_sound("cartographer_open_map", player); show_map_meta(stack:get_meta(), player); end, }); function cartographer.create_map_item(size, detail, scale) local map = ItemStack("cartographer:map"); local meta = map:get_meta(); meta:set_int("cartographer:size", size); meta:set_int("cartographer:detail", detail); meta:set_int("cartographer:scale", scale); meta:set_string("description", "Empty Map\nUse to set the initial location"); return map; end -- Create a copy of the given map -- stack: An itemstack containing a map -- -- Returns an itemstack with the copied map function cartographer.copy_map_item(stack) local meta = stack:get_meta(); local size = meta:get_int("cartographer:size"); local detail = meta:get_int("cartographer:detail"); local scale = meta:get_int("cartographer:scale"); local copy = cartographer.create_map_item(size, detail, scale); local copy_meta = copy:get_meta(); local id = meta:get_int("cartographer:map_id"); local new_id = 0; if id > 0 then local src = cartographer.get_map(id); new_id = cartographer.create_map(src.x, src.z, src.w, src.h, false, src.detail, src.scale); local dest = cartographer.get_map(new_id); for k,v in pairs(src.fill) do dest.fill[k] = v; end for k,v in pairs(src.markers) do dest.markers[k] = v; end copy_meta:set_int("cartographer:map_id", new_id); copy_meta:set_string("description", "Map #" .. tostring(new_id) .. "\n[" .. tostring(fromchunk(dest.x)) .. "," .. tostring(fromchunk(dest.z)) .. "] - [" .. tostring(fromchunk(dest.x + dest.w)) .. "," .. tostring(fromchunk(dest.z + dest.h)) .. "]") end return copy; end function cartographer.resize_map_item(meta, size) local old_size = meta:get_int("cartographer:size"); if old_size >= size then return; end meta:set_int("cartographer:size", size); local id = meta:get_int("cartographer:map_id"); if id > 0 then local map = cartographer.get_map(id); cartographer.resize_map(id, size, size); meta:set_string("description", "Map #" .. tostring(id) .. "\n[" .. tostring(fromchunk(map.x)) .. "," .. tostring(fromchunk(map.z)) .. "] - [" .. tostring(fromchunk(map.x + map.w)) .. "," .. tostring(fromchunk(map.z + map.h)) .. "]") end end