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, }, selection_box = { type = "fixed", fixed = { {-0.5, -0.5, -0.375, 0.5, 0.6875, 0.375}, }, }, collision_box = { type = "fixed", fixed = { {-0.5, -0.5, -0.375, 0.5, 0.6875, 0.375}, }, }, 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, }, selection_box = { type = "fixed", fixed = { {-0.5, -0.5, -0.375, 0.5, 0.6875, 0.375}, }, }, collision_box = { type = "fixed", fixed = { {-0.5, -0.5, -0.375, 0.5, 0.6875, 0.375}, }, }, 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", drawtype = "mesh", mesh = "cartographer_advanced_table.obj", tiles = { "cartographer_advanced_table.png" }, paramtype2 = "facedir", groups = { choppy = 2, oddly_breakable_by_hand = 2, }, selection_box = { type = "fixed", fixed = { {-0.5, -0.5, -0.375, 0.5, 0.6875, 0.375}, }, }, collision_box = { type = "fixed", fixed = { {-0.5, -0.5, -0.375, 0.5, 0.6875, 0.375}, }, }, 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