cartographer/items.lua

309 lines
11 KiB
Lua
Raw Normal View History

local chunk, gui, skin = ...
-- 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
2020-04-21 13:36:48 +02:00
-- height_mode: Whether or not to display the map in height mode
-- (Optional) marker_page: The current page that the marker editor is on
2020-04-21 13:36:48 +02:00
local function show_map_id_formspec(id, player_x, player_z, player_name, height_mode, marker_page)
cartographer.fill_local(id, player_x, player_z);
player_maps[player_name] = {
id = id,
page = marker_page or 1,
2020-04-21 13:36:48 +02:00
height_mode = height_mode,
};
local map = cartographer.get_map(id);
player_x, player_z = cartographer.to_map_coordinates(map, player_x, player_z)
2020-06-02 00:00:53 +02:00
local formspec, formspec_width, _ = cartographer.get_map_formspec_map(map, player_x, player_z, height_mode);
if #_cartographer.marker_lookup > 0 then
local height_button_texture;
2020-04-21 13:36:48 +02:00
if height_mode then
height_button_texture = skin.height_button_texture .. ".png";
2020-04-21 13:36:48 +02:00
else
height_button_texture = skin.flat_button_texture .. ".png";
2020-04-21 13:36:48 +02:00
end
local data = {
gui.style_type {
selector = "button,image_button,label",
properties = {
noclip = true,
}
},
gui.container {
x = formspec_width - 0.01,
y = 1,
bg = skin.marker_bg,
_cartographer.generate_marker_formspec(cartographer.get_marker(map, player_x, player_z), map.detail, marker_page or 1, skin.marker_bg, skin.marker_button),
},
gui.container {
x = formspec_width - 0.01,
y = 0.125,
w = 0.75,
h = 0.75,
bg = skin.marker_bg,
gui.image_button {
x = 0.125,
y = 0.125,
w = 0.5,
h = 0.5,
id = "height_button",
image = height_button_texture,
tooltip = "Toggle height view",
}
},
};
formspec = formspec .. table.concat(data);
end
minetest.show_formspec(player_name, "cartographer:map", formspec);
end
-- Get the description text for a map ID and dimensions
-- id: The map ID
-- from_x: The x coordinate of the top-left corner of the map, in world coordinates
-- from_z: The z coordinate of the top-left corner of the map, in world coordinates
-- w: The width, in world coordinates
-- h: The height, in world coordinates
local function map_description(id, from_x, from_z, w, h)
return string.format("Map #%d\n[%d,%d] - [%d,%d]",
id,
chunk.from(from_x), chunk.from(from_z),
chunk.from(from_x + w), chunk.from(from_z + h));
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_description(id, map_x, map_y, total_size, 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 = chunk.to(pos.x);
local player_z = chunk.to(pos.z);
local id = meta:get_int("cartographer:map_id");
if id == 0 then
id = map_from_meta(meta, player_x, player_z);
end
2020-04-21 13:36:48 +02:00
show_map_id_formspec(id, pos.x, pos.z, player:get_player_name(), true);
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()];
2020-04-21 13:36:48 +02:00
if not data then
return;
end
local map = cartographer.get_map(data.id);
if not map then
return;
end
2020-06-02 00:00:53 +02:00
for k,_ 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
2020-04-21 13:36:48 +02:00
show_map_id_formspec(map.id, pos.x, pos.z, player:get_player_name(), data.height_mode, data.page - 1);
elseif k == "next_button" then
2020-04-21 13:36:48 +02:00
show_map_id_formspec(map.id, pos.x, pos.z, player:get_player_name(), data.height_mode, data.page + 1);
elseif k == "height_button" then
show_map_id_formspec(map.id, pos.x, pos.z, player:get_player_name(), not data.height_mode, data.page);
elseif k == "quit" then
player_maps[player:get_player_name()] = nil;
end
end
end
end);
-- The map item/node
2020-02-16 18:55:07 +01:00
minetest.register_node("cartographer:map", {
description = "Map",
inventory_image = "cartographer_map.png",
wield_image = "cartographer_map.png",
tiles = { "cartographer_map.png" },
2020-02-16 18:55:07 +01:00
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},
},
},
2020-02-16 18:55:07 +01:00
groups = {
attached_node = 1,
dig_immediate = 3,
},
-- Called when this node is placed in the world. Copies map data from the
-- item to the node.
-- pos: The position of the node
-- stack: The itemstack that was placed
2020-06-02 00:00:53 +02:00
after_place_node = function(pos, _, stack, _)
2020-02-16 18:55:07 +01:00
local meta = stack:get_meta():to_table();
local node_meta = minetest.get_meta(pos);
2020-02-16 18:55:07 +01:00
node_meta:from_table(meta);
-- Consume the item after placing
return false;
2020-02-16 18:55:07 +01:00
end,
-- Called when this node is dug. Turns the node into an item.
-- pos: The position of the node
on_dig = function(pos, _, _)
local node_meta = minetest.get_meta(pos):to_table();
local item = ItemStack("cartographer:map");
item:get_meta():from_table(node_meta);
if minetest.add_item(pos, item) then
minetest.remove_node(pos);
end
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,
2020-02-16 18:55:07 +01:00
-- 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);
return stack;
end,
-- Called when a node is about to be turned into an item. Copies all
-- metadata into any items matching this node's name.
-- oldnode: The old node's data
-- oldmeta: A table containing the old node's metadata
-- drops: A table containing the new items
preserve_metadata = function(_, oldnode, oldmeta, drops)
for _,item in ipairs(drops) do
if item:get_name() == oldnode.name then
item:get_meta():from_table({fields=oldmeta});
end
end
2020-02-16 18:55:07 +01:00
end,
});
function cartographer.create_map_item(size, detail, scale)
2020-02-16 18:55:07 +01:00
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);
2020-02-16 18:55:07 +01:00
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
2020-06-02 00:00:53 +02:00
--
-- Returns an itemstack with the copied map
2020-02-16 18:55:07 +01:00
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");
2020-02-16 18:55:07 +01:00
local copy = cartographer.create_map_item(size, detail, scale);
2020-02-16 18:55:07 +01:00
local copy_meta = copy:get_meta();
local id = meta:get_int("cartographer:map_id");
if id > 0 then
local src = cartographer.get_map(id);
2020-06-02 00:00:53 +02:00
local new_id = cartographer.create_map(src.x, src.z, src.w, src.h, false, src.detail, src.scale);
2020-02-16 18:55:07 +01:00
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
2020-02-16 18:55:07 +01:00
copy_meta:set_int("cartographer:map_id", new_id);
copy_meta:set_string("description", map_description(new_id,
dest.x, dest.z,
dest.w, dest.h));
2020-02-16 18:55:07 +01:00
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);
copy_meta:set_string("description", map_description(id,
chunk.from(map.x), chunk.from(map.z),
chunk.from(map.w), chunk.from(map.h)));
2020-02-16 18:55:07 +01:00
end
end