Update table material costs/values when items are placed/removed from them

This commit is contained in:
Hugues Ross 2020-04-19 15:30:18 -04:00
parent 05a831d643
commit 913cd03594
1 changed files with 141 additions and 88 deletions

229
table.lua
View File

@ -45,7 +45,11 @@ local function get_material_cost(size, detail)
};
end
local function get_full_material_cost(meta)
-- Get the material cost of the craft settings from the given table metadata
-- meta: The metadata to read
--
-- Returns a table with the material costs
local function get_craft_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);
@ -61,6 +65,62 @@ local function get_full_material_cost(meta)
return cost;
end
-- Get the material cost of the copy settings from the given table metadata
-- meta: The metadata to read
--
-- Returns a table with the material costs
local function get_copy_material_cost(meta)
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;
return get_material_cost(size, detail - 1);
end
return {
paper = 0,
pigment = 0,
};
end
-- Get the converted material value of the given itemstack
-- stack: The itemstack to convert
--
-- Returns a table with the material values
function cartographer.get_material_value(stack)
local item_name = stack:get_name();
local item_count = stack:get_count();
for name,mats in pairs(_cartographer.materials_by_name) do
if name == item_name then
return {
paper = (mats.paper or 0) * item_count,
pigment = (mats.pigment or 0) * item_count,
}
end
end
for group,mats in pairs(_cartographer.materials_by_group) do
if minetest.get_item_group(item_name, group) ~= 0 then
return {
paper = (mats.paper or 0) * item_count,
pigment = (mats.pigment or 0) * item_count,
}
end
end
return {
paper = 0,
pigment = 0,
};
end
local fs = {};
-- Draw a 1px thick horizontal separator formspec element
@ -144,12 +204,14 @@ end
--
-- Returns a formspec string
function fs.convert(x, y, pos, skin)
local meta = minetest.get_meta(pos);
return string.format("container[%f,%f]", x, y)
.. "formspec_version[3]"
.. inventory_bg(0, 0, 1, 1, skin.slot)
.. string.format("list[nodemeta:%d,%d,%d;input;0,0;1,1;]", pos.x, pos.y, pos.z)
.. "button[1.25,0.5;2,0.5;convert;Convert Materials]"
.. fs.cost(1.25, 0.125, { Paper = 0, Pigment = 0, }, skin)
.. fs.cost(1.25, 0.125, cartographer.get_material_value(meta:get_inventory():get_stack("input", 1)), skin)
.. "container_end[]";
end
@ -168,7 +230,7 @@ function fs.craft(x, y, pos, rank, meta, skin)
.. inventory_bg(0, 0.75, 1, 1, skin.slot)
.. string.format("list[nodemeta:%d,%d,%d;output;0,0.75;1,1;]", pos.x, pos.y, pos.z)
.. "button[1.25,1.25;2,0.5;craft;Craft Map]"
.. fs.cost(1.25, 0.875, get_full_material_cost(meta), skin);
.. fs.cost(1.25, 0.875, get_craft_material_cost(meta), skin);
if rank > 1 then
local size = "s";
@ -213,12 +275,14 @@ end
--
-- Returns a formspec string
function fs.copy(x, y, pos, skin)
local meta = minetest.get_meta(pos);
return string.format("container[%f,%f]", x, y)
.. "formspec_version[3]"
.. inventory_bg(0, 0, 1, 1, skin.slot)
.. string.format("list[nodemeta:%d,%d,%d;copy_input;0,0;1,1;]", pos.x, pos.y, pos.z)
.. "button[1.25,0.5;2,0.5;copy;Copy Map]"
.. fs.cost(1.25, 0.125, { Paper = 0, Pigment = 0, }, skin)
.. fs.cost(1.25, 0.125, get_copy_material_cost(meta), skin)
.. inventory_bg(8.75, 0, 1, 1, skin.slot)
.. string.format("list[nodemeta:%d,%d,%d;copy_output;8.75,0;1,1;]", pos.x, pos.y, pos.z)
.. "container_end[]";
@ -244,10 +308,10 @@ local player_tables = {};
-- The player must be recorded in player_tables in order to receive
-- a formspec.
--
-- player: A string containing the player's name
-- tab: Which tab of the interface to display
local function table_formspec(player, tab)
local pos = player_tables[player];
-- player: The player's name
local function table_formspec(player)
local data = player_tables[player];
local pos = data.pos;
if not pos then
return;
@ -266,27 +330,27 @@ local function table_formspec(player, tab)
skin = cartographer.skin.table_skins.advanced_table;
end
if tab == 1 then
if data.tab == 1 then
minetest.show_formspec(player, "simple_table",
fs.header(10.25, 7.375, rank, tab, skin) ..
fs.header(10.25, 7.375, rank, data.tab, skin) ..
fs.materials(0.25, 0.1875, meta, skin) ..
fs.separator(0.6875, skin.separator) ..
fs.convert(0.25, 0.875, pos, skin) ..
fs.separator(2.125, skin.separator) ..
fs.inv(0.25, 2.375, skin)
);
elseif tab == 2 then
elseif data.tab == 2 then
minetest.show_formspec(player, "simple_table",
fs.header(10.25, 8.0, rank, tab, skin) ..
fs.header(10.25, 8.0, rank, data.tab, skin) ..
fs.materials(0.25, 0.1875, meta, skin) ..
fs.separator(0.6875, skin.separator) ..
fs.craft(0.25, 0.875, pos, rank, meta, skin) ..
fs.separator(2.75, skin.separator) ..
fs.inv(0.25, 3, skin)
);
elseif tab == 3 then
elseif data.tab == 3 then
minetest.show_formspec(player, "simple_table",
fs.header(10.25, 7.375, rank, tab, skin) ..
fs.header(10.25, 7.375, rank, data.tab, skin) ..
fs.materials(0.25, 0.1875, meta, skin) ..
fs.separator(0.6875, skin.separator) ..
fs.copy(0.25, 0.875, pos, skin) ..
@ -304,52 +368,20 @@ 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()].pos);
local meta = minetest.get_meta(player_tables[player:get_player_name()]);
if fields["convert"] ~= nil then
if fields["convert"] 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 value = cartographer.get_material_value(stack);
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
if value.paper + value.pigment > 0 then
meta:set_int("paper", meta:get_int("paper") + value.paper);
meta:set_int("pigment", meta:get_int("pigment") + value.pigment);
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
elseif fields["craft"] then
local size = meta:get_int("size");
local detail = meta:get_int("detail");
local scale = meta:get_int("scale");
@ -360,7 +392,7 @@ minetest.register_on_player_receive_fields(function(player, name, fields)
local inv = meta:get_inventory();
local stack = inv:get_stack("output", 1);
local cost = get_full_material_cost(meta);
local cost = get_craft_material_cost(meta);
if stack:is_empty() then
if paper >= cost.paper and pigment >= cost.pigment then
@ -386,16 +418,14 @@ minetest.register_on_player_receive_fields(function(player, name, fields)
cartographer.resize_map_item(smeta, size);
local map = cartographer.get_map(smeta:get_int("cartographer:map_id"));
if map ~= nil then
if map then
map.detail = 1 + detail;
end
cartographer.map_sound("cartographer_write", player);
inv:set_stack("output", 1, stack);
end
end
table_formspec(player:get_player_name(), 2)
elseif fields["copy"] ~= nil then
elseif fields["copy"] then
local paper = meta:get_int("paper");
local pigment = meta:get_int("pigment");
@ -420,41 +450,35 @@ minetest.register_on_player_receive_fields(function(player, name, fields)
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
elseif fields["s"] then
meta:set_int("size", SIZE_SMALL);
table_formspec(player:get_player_name(), 2)
elseif fields["l"] ~= nil then
elseif fields["l"] then
meta:set_int("size", SIZE_LARGE);
table_formspec(player:get_player_name(), 2)
elseif fields["1"] ~= nil then
elseif fields["1"] then
meta:set_int("detail", 0);
table_formspec(player:get_player_name(), 2)
elseif fields["2"] ~= nil then
elseif fields["2"] then
meta:set_int("detail", 1);
table_formspec(player:get_player_name(), 2)
elseif fields["3"] ~= nil then
elseif fields["3"] then
meta:set_int("detail", 2);
table_formspec(player:get_player_name(), 2)
elseif fields["4"] ~= nil then
elseif fields["4"] then
meta:set_int("detail", 3);
table_formspec(player:get_player_name(), 2)
elseif fields["1x"] ~= nil then
elseif fields["1x"] then
meta:set_int("scale", SCALE_SMALL);
table_formspec(player:get_player_name(), 2)
elseif fields["4x"] ~= nil then
elseif fields["4x"] then
meta:set_int("scale", SCALE_LARGE);
table_formspec(player:get_player_name(), 2)
elseif fields["tab1"] ~= nil then
elseif fields["tab1"] then
player_tables[player:get_player_name()].tab = 1;
cartographer.map_sound("cartographer_turn_page", player);
table_formspec(player:get_player_name(), 1);
elseif fields["tab2"] ~= nil then
elseif fields["tab2"] then
player_tables[player:get_player_name()].tab = 2;
cartographer.map_sound("cartographer_turn_page", player);
table_formspec(player:get_player_name(), 2);
elseif fields["tab3"] ~= nil then
elseif fields["tab3"] then
player_tables[player:get_player_name()].tab = 3;
cartographer.map_sound("cartographer_turn_page", player);
table_formspec(player:get_player_name(), 3);
end
if not fields["quit"] then
table_formspec(player:get_player_name());
end
end
end);
@ -507,6 +531,20 @@ local function table_can_move(_, _, _, to_list, _, count, _)
return count;
end
-- Called when a change occurs in a table's inventory
-- pos: The node's position
-- listname: The name of the changed inventory list
local function table_on_items_changed(pos, listname, _, _, _)
for player, data in pairs(player_tables) do
if vector.equals(pos, data.pos) and (
(data.tab == 1 and listname == "input")
or (data.tab == 2 and listname == "output")
or (data.tab == 3 and listname == "copy_input")) then
table_formspec(player);
end
end
end
minetest.register_node("cartographer:simple_table", {
description = "Shabby Cartographer's Table",
drawtype = "mesh",
@ -530,16 +568,21 @@ minetest.register_node("cartographer:simple_table", {
},
},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
player_tables[player:get_player_name()] = minetest.get_pointed_thing_position(pointed_thing);
player_tables[player:get_player_name()] = {
pos = minetest.get_pointed_thing_position(pointed_thing),
tab = 1,
};
cartographer.map_sound("cartographer_open_map", player);
table_formspec(player:get_player_name(), 1)
table_formspec(player:get_player_name())
end,
after_place_node = setup_table_node,
allow_metadata_inventory_move = table_can_move,
allow_metadata_inventory_put = table_can_put,
on_metadata_inventory_put = table_on_items_changed,
on_metadata_inventory_take = table_on_items_changed,
});
minetest.register_node("cartographer:standard_table", {
@ -565,16 +608,21 @@ minetest.register_node("cartographer:standard_table", {
},
},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
player_tables[player:get_player_name()] = minetest.get_pointed_thing_position(pointed_thing);
player_tables[player:get_player_name()] = {
pos = minetest.get_pointed_thing_position(pointed_thing),
tab = 1,
};
cartographer.map_sound("cartographer_open_map", player);
table_formspec(player:get_player_name(), 1)
table_formspec(player:get_player_name())
end,
after_place_node = setup_table_node,
allow_metadata_inventory_move = table_can_move,
allow_metadata_inventory_put = table_can_put,
on_metadata_inventory_put = table_on_items_changed,
on_metadata_inventory_take = table_on_items_changed,
});
minetest.register_node("cartographer:advanced_table", {
@ -600,16 +648,21 @@ minetest.register_node("cartographer:advanced_table", {
},
},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
player_tables[player:get_player_name()] = minetest.get_pointed_thing_position(pointed_thing);
player_tables[player:get_player_name()] = {
pos = minetest.get_pointed_thing_position(pointed_thing),
tab = 1,
};
cartographer.map_sound("cartographer_open_map", player);
table_formspec(player:get_player_name(), 1)
table_formspec(player:get_player_name())
end,
after_place_node = setup_table_node,
allow_metadata_inventory_move = table_can_move,
allow_metadata_inventory_put = table_can_put,
on_metadata_inventory_put = table_on_items_changed,
on_metadata_inventory_take = table_on_items_changed,
});
function cartographer.register_map_material_name(name, material, value)