From 59c359a3a338ff29fda29e2d135b29de33f66073 Mon Sep 17 00:00:00 2001 From: Hugues Ross Date: Sun, 19 Apr 2020 18:23:28 -0400 Subject: [PATCH] 'Disable' table buttons when an action is invalid --- skin_api.lua | 3 ++ table.lua | 125 ++++++++++++++++++++++++++------------------------- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/skin_api.lua b/skin_api.lua index 22c4feb..c87ebcc 100644 --- a/skin_api.lua +++ b/skin_api.lua @@ -41,6 +41,7 @@ cartographer.skin = { }, button = { font_color = "#694a3a", + disabled_font_color = "#606060", texture = "cartographer_simple_table_button", selected_texture = "cartographer_simple_table_button_pressed", hovered_texture = "cartographer_simple_table_button_hovered", @@ -84,6 +85,7 @@ cartographer.skin = { }, button = { font_color = "#694a3a", + disabled_font_color = "#606060", texture = "cartographer_simple_table_button", selected_texture = "cartographer_simple_table_button_pressed", hovered_texture = "cartographer_simple_table_button_hovered", @@ -127,6 +129,7 @@ cartographer.skin = { }, button = { font_color = "#1f2533", + disabled_font_color = "#606060", texture = "cartographer_advanced_table_button", selected_texture = "cartographer_advanced_table_button_pressed", hovered_texture = "cartographer_advanced_table_button_hovered", diff --git a/table.lua b/table.lua index c15bd99..9ef39c5 100644 --- a/table.lua +++ b/table.lua @@ -48,21 +48,34 @@ end -- 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 +-- Returns a table with the material costs, and a boolean indicating if the +-- costs were positive or negative before clamping. 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); + local is_positive = true; + 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); + is_positive = cost.paper >= sub_cost.paper and cost.pigment >= sub_cost.pigment; cost.paper = math.max(cost.paper - sub_cost.paper, 0); cost.pigment = math.max(cost.pigment - sub_cost.pigment, 0); end - return cost; + return cost, is_positive; +end + +-- Check if the given table metadata has enough materials to cover the given +-- cost table. +-- cost: A table of material costs +-- meta: The metadata +-- +-- Returns true if the table's materials can cover the cost +local function can_afford(cost, meta) + return cost.paper + cost.pigment > 0 + and cost.paper <= meta:get_int("paper") + and cost.pigment <= meta:get_int("pigment"); end -- Get the material cost of the copy settings from the given table metadata @@ -123,6 +136,24 @@ end local fs = {}; +-- Draw a button, with support for enabled/disabled states +-- x: The x position of the button +-- y: The y position of the button +-- w: The width of the button +-- h: The height of the button +-- id: The element id +-- text: The text to display in the button +-- enabled: Whether or not the button is enabled +-- +-- Returns a formspec string +function fs.button(x, y, w, h, id, text, enabled) + if enabled then + return string.format("button[%f,%f;%f,%f;%s;%s]", x, y, w, h, id, text); + end + + return string.format("button[%f,%f;%f,%f;disabled_button;%s]", x, y, w, h, text); +end + -- Draw a 1px thick horizontal separator formspec element -- y: The y position of the separator -- skin: A 9-slice background skin table @@ -154,7 +185,8 @@ function fs.header(w, h, rank, tab, skin) data = data .. string.format("button[3.25,-0.425;1.5,0.55;tab3;Copy Map]", tab); end - return data .. string.format("style_type[button;border=false;bgimg=%s.png;bgimg_hovered=%s.png;bgimg_pressed=%s.png;bgimg_middle=%s;textcolor=%s]", skin.button.texture, skin.button.hovered_texture, skin.button.pressed_texture, tostring(skin.button.radius), skin.button.font_color); + return data .. string.format("style_type[button;border=false;bgimg=%s.png;bgimg_hovered=%s.png;bgimg_pressed=%s.png;bgimg_middle=%s;textcolor=%s]", skin.button.texture, skin.button.hovered_texture, skin.button.pressed_texture, tostring(skin.button.radius), skin.button.font_color) + .. string.format("style[disabled_button;bgimg=;bgimg_hovered=;bgimg_pressed=;textcolor=%s]", skin.button.disabled_font_color); end -- Draw material counters from a table's metadata @@ -205,13 +237,14 @@ end -- Returns a formspec string function fs.convert(x, y, pos, skin) local meta = minetest.get_meta(pos); + local value = cartographer.get_material_value(meta:get_inventory():get_stack("input", 1)); 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, cartographer.get_material_value(meta:get_inventory():get_stack("input", 1)), skin) + .. fs.button(1.25, 0.5, 2, 0.5, "convert", "Convert Materials", value.paper + value.pigment > 0) + .. fs.cost(1.25, 0.125, value, skin) .. "container_end[]"; end @@ -225,12 +258,13 @@ end -- -- Returns a formspec string function fs.craft(x, y, pos, rank, meta, skin) + local cost, is_positive = get_craft_material_cost(meta); local data = string.format("container[%f,%f]", x, y) .. "formspec_version[3]" .. 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_craft_material_cost(meta), skin); + .. fs.button(1.25, 1.25, 2, 0.5, "craft", "Craft Map", is_positive and can_afford(cost, meta)) + .. fs.cost(1.25, 0.875, cost, skin); if rank > 1 then local size = "s"; @@ -276,13 +310,14 @@ end -- Returns a formspec string function fs.copy(x, y, pos, skin) local meta = minetest.get_meta(pos); + local costs = get_copy_material_cost(meta); 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, get_copy_material_cost(meta), skin) + .. fs.button(1.25, 0.5, 2, 0.5, "copy", "Copy Map", can_afford(costs, meta)) + .. fs.cost(1.25, 0.125, costs, 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[]"; @@ -367,7 +402,6 @@ end -- fields: A table containing the input minetest.register_on_player_receive_fields(function(player, name, fields) if name == "simple_table" then - minetest.chat_send_all(name..": "); local meta = minetest.get_meta(player_tables[player:get_player_name()].pos); if fields["convert"] then @@ -385,35 +419,19 @@ minetest.register_on_player_receive_fields(function(player, name, fields) 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 cost, is_positive = get_craft_material_cost(meta); + if is_positive and can_afford(cost, meta) then + meta:set_int("paper", meta:get_int("paper") - cost.paper); + meta:set_int("pigment", meta:get_int("paper") - cost.pigment); - local inv = meta:get_inventory(); - local stack = inv:get_stack("output", 1); + local inv = meta:get_inventory(); + local stack = inv:get_stack("output", 1); - local cost = get_craft_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); - - cartographer.map_sound("cartographer_write", player); + if stack:is_empty() then 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); - + else + local smeta = stack:get_meta(); smeta:set_int("cartographer:detail", 1 + detail); cartographer.resize_map_item(smeta, size); @@ -421,34 +439,21 @@ minetest.register_on_player_receive_fields(function(player, name, fields) if map then map.detail = 1 + detail; end - cartographer.map_sound("cartographer_write", player); inv:set_stack("output", 1, stack); end + + cartographer.map_sound("cartographer_write", player); end elseif fields["copy"] then - local paper = meta:get_int("paper"); - local pigment = meta:get_int("pigment"); + local cost = get_copy_material_cost(meta); + if can_afford(cost, meta) then + meta:set_int("paper", meta:get_int("paper") - cost.paper); + meta:set_int("pigment", meta:get_int("paper") - cost.pigment); - local inv = meta:get_inventory(); - local in_stack = inv:get_stack("copy_input", 1); - local out_stack = inv:get_stack("copy_output", 1); + cartographer.map_sound("cartographer_write", player); - - 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); - - cartographer.map_sound("cartographer_write", player); - inv:set_stack("copy_output", 1, cartographer.copy_map_item(in_stack)); - end + local inv = meta:get_inventory(); + inv:set_stack("copy_output", 1, cartographer.copy_map_item(inv:get_stack("copy_input", 1))); end elseif fields["s"] then meta:set_int("size", SIZE_SMALL);