cartographer/table.lua
2020-03-08 10:34:20 -04:00

464 lines
15 KiB
Lua

local SIZE_SMALL = 20;
local SIZE_LARGE = 40;
local SCALE_SMALL = 1;
local SCALE_LARGE = 4;
local separator = [[
formspec_version[3]
box[0.1,%f;10.1,0.01;black]
]];
local function get_material_cost(size, detail)
local paper = 0;
local pigment = 0;
if size == SIZE_SMALL then
paper = paper + 4;
pigment = pigment + 5;
elseif size == SIZE_LARGE then
paper = paper + 16;
pigment = pigment + 20;
end
pigment = pigment + (detail * 5);
return {
paper = math.max(paper, 0),
pigment = math.max(pigment, 0),
};
end
local function get_full_material_cost(meta)
local cost = get_material_cost(meta:get_int("size") or SIZE_SMALL, meta:get_int("detail") or 0);
local stack = meta:get_inventory():get_stack("output", 1);
if stack:get_name() == "cartographer:map" then
local smeta = stack:get_meta();
local sub_cost = get_material_cost(smeta:get_int("cartographer:size") or SIZE_SMALL, (smeta:get_int("cartographer:detail") or 1) - 1);
cost.paper = math.max(cost.paper - sub_cost.paper, 0);
cost.pigment = math.max(cost.pigment - sub_cost.pigment, 0);
end
return cost;
end
local fs = {};
function fs.header(w, h, rank, tab)
local data = [[
formspec_version[3]
size[%f,%f]
]];
data = data:format(w, h);
if rank < 2 then
data = data .. "tabheader[0,0;tabs;Materials,Create Map;%d;false;false]";
data = data:format(tab);
else
data = data .. "tabheader[0,0;tabs;Materials,Create Map,Copy Map;%d;false;false]";
data = data:format(tab);
end
return data;
end
function fs.materials(x, y, rank, meta)
local paper = meta:get_int("paper");
local pigment = meta:get_int("pigment");
local data = [[
container[%f,%f]
formspec_version[3]
label[0,0.25;paper x %d]
label[3,0.25;Pigment x %d]
]];
data = data:format(x, y, paper, pigment);
return data .. "container_end[]";
end
function fs.cost(x, y, materials)
local data = "";
local i = 0;
for name,value in pairs(materials) do
data = data .. "label[" .. tostring(x) .. "," .. tostring(y + (i * 0.25)) .. ";" .. name .. " x " .. tostring(value) .. "]";
i = i + 1;
end
return data;
end
function fs.convert(x, y, pos)
local data = [[
container[%f,%f]
formspec_version[3]
list[nodemeta:%d,%d,%d;input;0,0;1,1;]
button[3.5,0.25;2,0.5;convert;Convert Materials]
]];
data = data:format(x, y, pos.x, pos.y, pos.z);
data = data .. fs.cost(1.25, 0.25, {
paper = 0,
Pigment = 0,
}) .. "container_end[]";
return data;
end
function fs.craft(x, y, pos, rank, meta)
local data = [[
container[%f, %f]
formspec_version[3]
list[nodemeta:%d,%d,%d;output;0,1;1,1;]
button[3.5,1.5;2,0.5;craft;Craft Map]
]] .. separator:format(0.75);
data = data:format(x, y, pos.x, pos.y, pos.z);
if rank > 1 then
local size = "s";
if meta:get_int("size") == SIZE_LARGE then
size = "l";
end
data = data .. [[
style[%s;bgcolor=blue]
button[0,0;0.5,0.5;s;S]
button[0.5,0;0.5,0.5;l;L]
]];
data = data:format(size);
end
if rank > 2 then
local scale = "1x";
if meta:get_int("scale") == SCALE_LARGE then
scale = "4x";
end
data = data .. [[
style[%s;bgcolor=blue]
button[3.5,0;0.5,0.5;1x;1x]
button[4.0,0;0.5,0.5;4x;4x]
]];
data = data:format(scale);
end
local detail = tostring(meta:get_int("detail") + 1);
data = data .. [[
style[%s;bgcolor=blue]
button[1.25,0;0.5,0.5;1;1]
button[1.75,0;0.5,0.5;2;2]
]];
if rank > 1 then
data = data .. "button[2.25,0;0.5,0.5;3;3]";
if rank > 2 then
data = data .. "button[2.75,0;0.5,0.5;4;4]";
end
end
data = data:format(detail) .. fs.cost(3.5, 1, get_full_material_cost(meta)) .. "container_end[]";
return data;
end
function fs.copy(x, y, pos)
local data = [[
container[%f,%f]
formspec_version[3]
list[nodemeta:%d,%d,%d;copy_input;0,0;1,1;]
list[nodemeta:%d,%d,%d;copy_output;0,1.25;1,1;]
button[3.5,0.25;2,0.5;copy;Copy Map]
]];
data = data:format(x, y, pos.x, pos.y, pos.z, pos.x, pos.y, pos.z);
data = data .. fs.cost(1.25, 0.25, {
paper = 0,
Pigment = 0,
}) .. "container_end[]";
return data;
end
function fs.inv(x, y)
local data = [[
container[%f, %f]
formspec_version[3]
list[current_player;main;0,0;8,4;]
container_end[]
]];
return data:format(x, y)
end
local player_tables = {};
local function table_formspec(player, tab)
local pos = player_tables[player];
local meta = minetest.get_meta(pos);
local rank = 1;
local name = minetest.get_node(pos).name;
if name == "cartographer:standard_table" then
rank = 2;
elseif name == "cartographer:advanced_table" then
rank = 3;
end
if tab == 1 then
minetest.show_formspec(player, "simple_table",
fs.header(10.25, 6.75, rank, tab) ..
fs.materials(0.25, 0, rank, meta) ..
separator:format(0.4) ..
fs.convert(0.25, 0.5, pos) ..
fs.inv(0.25, 1.75)
);
elseif tab == 2 then
minetest.show_formspec(player, "simple_table",
fs.header(10.25, 8.0, rank, tab) ..
fs.materials(0.25, 0, rank, meta) ..
separator:format(0.4) ..
fs.craft(0.25, 0.5, pos, rank, meta) ..
fs.inv(0.25, 3)
);
elseif tab == 3 then
minetest.show_formspec(player, "simple_table",
fs.header(10.25, 8.0, rank, tab) ..
fs.materials(0.25, 0, rank, meta) ..
separator:format(0.4) ..
fs.copy(0.25, 0.5, pos) ..
fs.inv(0.25, 3)
);
end
end
minetest.register_on_player_receive_fields(function(player, name, fields)
if name == "simple_table" then
minetest.chat_send_all(name..": ");
for k,v in pairs(fields) do
minetest.chat_send_all(tostring(k).." - "..tostring(v));
end
local meta = minetest.get_meta(player_tables[player:get_player_name()]);
if fields["convert"] ~= nil then
local inv = meta:get_inventory();
local stack = inv:get_stack("input", 1);
local paper = meta:get_int("paper");
local pigment = meta:get_int("pigment");
local item_name = stack:get_name();
local item_count = stack:get_count();
local found_match = false;
for name,mats in pairs(_cartographer.materials_by_name) do
if name == item_name then
paper = paper + ((mats.paper or 0) * item_count);
pigment = pigment + ((mats.pigment or 0) * item_count);
found_match = true;
break;
end
end
if not found_match then
for group,mats in pairs(_cartographer.materials_by_group) do
if minetest.get_item_group(item_name, group) ~= 0 then
paper = paper + ((mats.paper or 0) * item_count);
pigment = pigment + ((mats.pigment or 0) * item_count);
found_match = true;
break;
end
end
end
if found_match then
inv:set_stack("input", 1, ItemStack(nil));
end
meta:set_int("paper", paper);
meta:set_int("pigment", pigment);
table_formspec(player:get_player_name(), 1)
elseif fields["craft"] ~= nil then
local size = meta:get_int("size");
local detail = meta:get_int("detail");
local scale = meta:get_int("scale");
local paper = meta:get_int("paper");
local pigment = meta:get_int("pigment");
local inv = meta:get_inventory();
local stack = inv:get_stack("output", 1);
local cost = get_full_material_cost(meta);
if stack:is_empty() then
if paper >= cost.paper and pigment >= cost.pigment then
paper = paper - cost.paper;
pigment = pigment - cost.pigment;
meta:set_int("paper", paper);
meta:set_int("pigment", pigment);
inv:set_stack("output", 1, cartographer.create_map_item(size, 1 + detail, scale));
end
else
local smeta = stack:get_meta();
local old_size = smeta:get_int("cartographer:size");
local old_detail = smeta:get_int("cartographer:detail") - 1;
if old_detail <= detail and old_size <= size and not (old_detail == detail and old_size == size) and paper >= cost.paper and pigment >= cost.pigment then
paper = paper - cost.paper;
pigment = pigment - cost.pigment;
meta:set_int("paper", paper);
meta:set_int("pigment", pigment);
smeta:set_int("cartographer:detail", 1 + detail);
cartographer.resize_map_item(smeta, size);
local map = cartographer.get_map(smeta:get_int("cartographer:map_id"));
if map ~= nil then
map.detail = 1 + detail;
end
inv:set_stack("output", 1, stack);
end
end
table_formspec(player:get_player_name(), 2)
elseif fields["copy"] ~= nil then
local paper = meta:get_int("paper");
local pigment = meta:get_int("pigment");
local inv = meta:get_inventory();
local in_stack = inv:get_stack("copy_input", 1);
local out_stack = inv:get_stack("copy_output", 1);
if out_stack:is_empty() and in_stack:get_name() == "cartographer:map" then
local smeta = in_stack:get_meta();
local size = smeta:get_int("cartographer:size") or SIZE_SMALL;
local detail = smeta:get_int("cartographer:detail") or 1;
local cost = get_material_cost(size, detail - 1);
if paper >= cost.paper and pigment >= cost.pigment then
paper = paper - cost.paper;
pigment = pigment - cost.pigment;
meta:set_int("paper", paper);
meta:set_int("pigment", pigment);
inv:set_stack("copy_output", 1, cartographer.copy_map_item(in_stack));
end
end
table_formspec(player:get_player_name(), 3)
elseif fields["s"] ~= nil then
meta:set_int("size", SIZE_SMALL);
table_formspec(player:get_player_name(), 2)
elseif fields["l"] ~= nil then
meta:set_int("size", SIZE_LARGE);
table_formspec(player:get_player_name(), 2)
elseif fields["1"] ~= nil then
meta:set_int("detail", 0);
table_formspec(player:get_player_name(), 2)
elseif fields["2"] ~= nil then
meta:set_int("detail", 1);
table_formspec(player:get_player_name(), 2)
elseif fields["3"] ~= nil then
meta:set_int("detail", 2);
table_formspec(player:get_player_name(), 2)
elseif fields["4"] ~= nil then
meta:set_int("detail", 3);
table_formspec(player:get_player_name(), 2)
elseif fields["1x"] ~= nil then
meta:set_int("scale", SCALE_SMALL);
table_formspec(player:get_player_name(), 2)
elseif fields["4x"] ~= nil then
meta:set_int("scale", SCALE_LARGE);
table_formspec(player:get_player_name(), 2)
elseif fields["tabs"] ~= nil then
table_formspec(player:get_player_name(), tonumber(fields["tabs"]));
end
end
end);
local function setup_table_node(pos)
local meta = minetest.get_meta(pos);
meta:get_inventory():set_size("input", 1);
meta:get_inventory():set_size("output", 1);
meta:get_inventory():set_size("copy_input", 1);
meta:get_inventory():set_size("copy_output", 1);
meta:set_int("size", SIZE_SMALL);
meta:set_int("scale", SCALE_SMALL);
meta:set_int("detail", 0);
end
minetest.register_node("cartographer:simple_table", {
description = "Shabby Cartographer's Table",
drawtype = "mesh",
mesh = "cartographer_simple_table.obj",
tiles = { "cartographer_simple_table.png" },
paramtype2 = "facedir",
groups = {
choppy = 2,
oddly_breakable_by_hand = 2,
},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
player_tables[player:get_player_name()] = minetest.get_pointed_thing_position(pointed_thing);
table_formspec(player:get_player_name(), 1)
end,
after_place_node = setup_table_node,
});
minetest.register_node("cartographer:standard_table", {
description = "Simple Cartographer's Table",
drawtype = "mesh",
mesh = "cartographer_standard_table.obj",
tiles = { "cartographer_standard_table.png" },
paramtype2 = "facedir",
groups = {
choppy = 2,
oddly_breakable_by_hand = 2,
},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
player_tables[player:get_player_name()] = minetest.get_pointed_thing_position(pointed_thing);
table_formspec(player:get_player_name(), 1)
end,
after_place_node = setup_table_node,
});
minetest.register_node("cartographer:advanced_table", {
description = "Advanced Cartographer's Table",
tiles = { "cartographer_advanced_table.png" },
paramtype2 = "facedir",
groups = {
choppy = 2,
oddly_breakable_by_hand = 2,
},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
player_tables[player:get_player_name()] = minetest.get_pointed_thing_position(pointed_thing);
table_formspec(player:get_player_name(), 1)
end,
after_place_node = setup_table_node,
});
function cartographer.register_map_material_name(name, material, value)
if _cartographer.materials_by_name[name] == nil then
_cartographer.materials_by_name[name] = {
[material] = value or 1,
};
else
_cartographer.materials_by_name[name][material] = value;
end
end
function cartographer.register_map_material_group(name, material, value)
if _cartographer.materials_by_group[name] == nil then
_cartographer.materials_by_group[name] = {
[material] = value or 1,
};
else
_cartographer.materials_by_group[name][material] = value;
end
end