diff --git a/api.txt b/api.txt index b461e43..675ef71 100644 --- a/api.txt +++ b/api.txt @@ -303,6 +303,7 @@ The arguments for the above "list" Formspec Element would be represented as such * lua_inv.dynamic_list(inv_location, listname, x, y, w, h, start_index) - Like a list[], except it's a grid of buttons to form a lua_inv-compatible UI. * lua_inv.stack_mode_selector(x, y) - Meant to be paired with dynamic_list to offer more options for moving around ItemStacks. * lua_inv.drop_item_button(x, y) - Provides a way for formspecs with dynamic lists to drop items onto the ground. +* lua_inv.active_indicator(x, y, w, y, base_img, cover_img, var)- Like an image[], except var% of cover_img will be drawn over base_img. @@ -400,5 +401,8 @@ lua_inv.get_detached_inventory(name) - Returns a detached inventory indexed by t [Misc. Functions] -* lua_inv.update_hotbar(player) - Update the player's hotbar visuals in the event of a change. Automatically called for most use cases. +* lua_inv.change_involves_list(change, listname) - If the change table has an involved stack in the given listname, return the stack. +* lua_inv.set_list_take_only(inv, change, listname) - Use in an allow_change callback to prevent players from placing items in the given listname. * lua_inv.tiles_to_cube_textures({tiles}) - Converts a table of tiles from an object's properties into a table of textures for an entity. +* lua_inv.update_hotbar(player) - Update the player's hotbar visuals in the event of a change. Automatically called for most use cases. + diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..740c2ff --- /dev/null +++ b/changelog.txt @@ -0,0 +1,15 @@ +1.0.1: + -Added the active_indicator[] element, which can draw a percent-based part of an image over another image, using a defined meta field. + -Added support for the /give command + -Added support for default furnaces + -In Dynamic Lists, non-cubic nodes will now display in their proper form using the item_image[] element. + + -Fixed the hotbar's functionality on mobile. Tapping each slot now switches the wield index properly. + -Fixed the "Press this or ESC to continue" window on mobile. Pressing the button now properly opens the inventory, rather than closing the form. + -Added a workaround for mobile users being unable to place blocks. The Aux button can now place blocks as well. + -To help with aiming the Aux button, a crosshair is now shown on mobile, as the regular one is permanently disabled by the Android Client. + -Mobile's Aux key and extra crosshair can both be disabled in the settings. + -Test items can now be disabled in the settings. + -The hotbar HUD should now scale properly across different screen resolutions. + -The game will no longer crash when you use an unknown item. + -Right-clicking while holding a worn tool will no longer magically repair it. diff --git a/dynamic_formspecs/dynamic_formspec.lua b/dynamic_formspecs/dynamic_formspec.lua index 8ca1218..304be0f 100644 --- a/dynamic_formspecs/dynamic_formspec.lua +++ b/dynamic_formspecs/dynamic_formspec.lua @@ -56,6 +56,8 @@ function lua_inv.dynamic_formspec(input_elems) end, form = function(self, player, formname, fields) + self.meta:set_string("formname", formname) + local formspec = "" for i = 1, self:size() do @@ -85,8 +87,9 @@ function lua_inv.dynamic_formspec(input_elems) end function lua_inv.get_df_meta(player) - if lua_inv.open_formspecs[player:get_player_name()] then - return lua_inv.open_formspecs[player:get_player_name()].meta, lua_inv.open_formspecs[player:get_player_name()].temp_meta + local open = lua_inv.open_formspecs[player:get_player_name()] + if open then + return open.meta, open.temp_meta end end diff --git a/dynamic_formspecs/survival_inventory.lua b/dynamic_formspecs/survival_inventory.lua index 0920d55..0c4e227 100644 --- a/dynamic_formspecs/survival_inventory.lua +++ b/dynamic_formspecs/survival_inventory.lua @@ -55,20 +55,7 @@ function lua_inv.survival_inventory.ref(player) return lua_inv.inventory(player:get_player_name(), --Allow Change function(inv, change) - if change.type == "swap" and ((change.stack1.parent.list == "craftpreview" and change.stack2:is_empty()) or - (change.stack2.parent.list == "craftpreview" and change.stack1:is_empty())) then - return true - end - - if change.type == "swap" and (change.stack1.parent.list == "craftpreview" or change.stack2.parent.list == "craftpreview") then - return false - end - - if change.type == "set" and change.stack.parent.list == "craftpreview" and (change.key ~= "count" or change.val ~= 0) then - return false - end - - return true + return lua_inv.set_list_take_only(inv, change, "craftpreview") end, nil, diff --git a/formspec_elements/active_indicator.lua b/formspec_elements/active_indicator.lua new file mode 100644 index 0000000..fbff48b --- /dev/null +++ b/formspec_elements/active_indicator.lua @@ -0,0 +1,32 @@ +function lua_inv.active_indicator(in_x, in_y, in_w, in_h, in_base_img, in_cover_img, in_var) + return lua_inv.formspec_element( + "fuel_indicator", + + { + {in_x, in_y}, + {in_w, in_h}, + in_base_img, + in_cover_img, + in_var, + }, + + function(self, player, formname, fields) + local meta, temp_meta = lua_inv.get_df_meta(player) + + if not meta then + minetest.log("warning", "Warning: Attempt to form a closed formspec.") + return "" + end + + local pos = self.args[1] + local size = self.args[2] + local base_img = self.args[3] + local cover_img = self.args[4] + local var = self.args[5] + + local variable = meta:get_float(var) + + return "image["..pos[1]..","..pos[2]..";"..size[1]..","..size[2]..";"..base_img.."^[lowpart:"..(variable)..":"..cover_img.."]" + end + ) +end diff --git a/formspec_elements/dynamic_list.lua b/formspec_elements/dynamic_list.lua index 325278e..6564975 100644 --- a/formspec_elements/dynamic_list.lua +++ b/formspec_elements/dynamic_list.lua @@ -187,13 +187,15 @@ function lua_inv.dynamic_list(in_inv_location, in_listname, in_x, in_y, in_w, in str = str.."image_button["..(pos[1] + x - 1)..','..(pos[2] + y - 1)..";1,1;;"..slotname..";]" - if not stack:is_empty() then + if stack and not stack:is_empty() then str = str.."tooltip["..slotname..';'..stack:get_description()..']' local anim = stack:get_animation() if anim then str = str.."animated_image["..(pos[1] + x - 1)..','..(pos[2] + y - 1)..";1,1;"..stack:get_name()..";" ..stack:get_inventory_image()..";"..anim.frames..";"..anim.speed..";]" + elseif not stack:get_inventory_image(true) then + str = str.."item_image["..(pos[1] + x - 1)..','..(pos[2] + y - 1)..";1,1;"..stack:get_name().."]" else str = str.."image["..(pos[1] + x - 1)..','..(pos[2] + y - 1)..";1,1;"..stack:get_inventory_image()..']' end diff --git a/hotbar.lua b/hotbar.lua index c15c2b8..7d8f9df 100644 --- a/hotbar.lua +++ b/hotbar.lua @@ -21,6 +21,11 @@ local hotbar_data = {} local default_ratio = minetest.settings:get("screen_w") / minetest.settings:get("screen_h") +local function default_pos(i) + --0.348 + .0435 * (i - 1), 0.9625 + return 0.30555 + .05555 * (i - 1), -32 +end + function lua_inv.update_hotbar(player) local pname = player:get_player_name() @@ -68,15 +73,17 @@ function lua_inv.update_hotbar(player) end if not hotbar_data[pname]["hotbar_slot_"..i] then + local x, y = default_pos(i) + hotbar_data[pname]["hotbar_slot_"..i] = player:hud_add({ hud_elem_type = "image", text = img, scale = {x = -4, y = -4 * hotbar_data[pname].aspect_ratio}, - position = {x = 0.348 + .0435 * (i - 1), y = 0.9625}, + position = {x = 0.5, y = 1}, direction = 1, alignment = {x = 0, y = 0}, - offset = {x = 0, y = 0}, + offset = {x = x * 1000 - 500, y = y}, z_index = 1 }) @@ -86,10 +93,10 @@ function lua_inv.update_hotbar(player) number = "0xFFFFFF", scale = {x = -4, y = -4 * hotbar_data[pname].aspect_ratio}, - position = {x = 0.363 + .0435 * (i - 1), y = 0.9825}, + position = {x = 0.5, y = 1}, direction = 1, alignment = {x = 0, y = 0}, - offset = {x = 0, y = 0}, + offset = {x = (x + 0.015) * 1000 - 500, y = y + 16}, z_index = 1 }) @@ -98,10 +105,10 @@ function lua_inv.update_hotbar(player) text = wear_img, scale = {x = -4, y = -4 * hotbar_data[pname].aspect_ratio}, - position = {x = 0.348 + .0435 * (i - 1), y = 0.9625}, + position = {x = 0.5, y = 1}, direction = 1, alignment = {x = 0, y = 0}, - offset = {x = 0, y = 0}, + offset = {x = x * 1000 - 500, y = y}, z_index = 1 }) else @@ -114,6 +121,7 @@ end minetest.register_on_joinplayer(function(player, last_login) local pname = player:get_player_name() + local x, y = default_pos(1) hotbar_data[pname] = { wield_index = player:get_wield_index(), @@ -121,17 +129,17 @@ minetest.register_on_joinplayer(function(player, last_login) animation = {} } - player:hud_set_flags({hotbar = false}) + minetest.after(0.25, player.hud_set_flags, player, {hotbar = false}) player:hud_add({ hud_elem_type = "image", text = "lua_inv_hotbar.png", scale = {x = 0.75, y = 0.75}, - position = {x = 0.5, y = 0.9625}, + position = {x = 0.5, y = 1}, direction = 1, alignment = {x = 0, y = 0}, - offset = {x = 0, y = 0}, + offset = {x = 0, y = y}, z_index = 0 }) @@ -140,10 +148,10 @@ minetest.register_on_joinplayer(function(player, last_login) text = "lua_inv_selected.png", scale = {x = 3.25, y = 3.25}, - position = {x = 0.348, y = 0.9625}, + position = {x = 0.5, y = 1}, direction = 1, alignment = {x = 0, y = 0}, - offset = {x = 0, y = 0}, + offset = {x = x * 1000 - 500, y = y}, z_index = 2 }) @@ -183,11 +191,9 @@ minetest.register_globalstep(function(dtime) if hotbar_data[pname].wield_index ~= player:get_wield_index() then hotbar_data[pname].wield_index = player:get_wield_index() + local x, y = default_pos(hotbar_data[pname].wield_index) - player:hud_change(hotbar_data[pname].hotbar_wield_index, "position", { - x = 0.348 + .0435 * (player:get_wield_index() - 1), - y = 0.9625 - }) + player:hud_change(hotbar_data[pname].hotbar_wield_index, "offset", {x = x * 1000 - 500, y = y}) lua_inv.update_held_item_data(player) end diff --git a/init.lua b/init.lua index dccda91..8979c98 100644 --- a/init.lua +++ b/init.lua @@ -36,6 +36,7 @@ dofile(mp.."formspec_elements/formspec_element.lua") dofile(mp.."formspec_elements/dynamic_list.lua") dofile(mp.."formspec_elements/stack_mode_selector.lua") dofile(mp.."formspec_elements/drop_item_button.lua") +dofile(mp.."formspec_elements/active_indicator.lua") dofile(mp.."dynamic_formspecs/manager.lua") dofile(mp.."dynamic_formspecs/dynamic_formspec.lua") diff --git a/inventories/player_inventory.lua b/inventories/player_inventory.lua index e6e923e..e3c5766 100644 --- a/inventories/player_inventory.lua +++ b/inventories/player_inventory.lua @@ -84,9 +84,23 @@ minetest.register_on_joinplayer(function(player) player_inventory.form = lua_inv.survival_inventory.form(player) lua_inv.player_inventory[player:get_player_name()] = player_inventory - player:set_inventory_formspec("size[8,8]button_exit[1,1;6,6;continue;Please hit ESC to continue.]") + player:set_inventory_formspec("size[8,8]button[1,1;6,6;continue;Please this or hit ESC to continue.]") lua_inv.update_held_item_data(player) + + if minetest.settings:get_bool("lua_inv_mobile_support", true) then + player:hud_add({ + hud_elem_type = "image", + text = "lua_inv_crosshair.png", + + scale = {x = 1, y = 1}, + position = {x = 0.5, y = 0.5}, + direction = 1, + alignment = {x = 0, y = 0}, + offset = {x = 0, y = 0}, + z_index = 1 + }) + end end) function lua_inv.get_player_wielded_item(player) @@ -140,7 +154,7 @@ local function get_pointed_thing(player, tool) --Get the tool's definition, to check its digparams and range local def = tool:get_definition() --Create a ray between the player's eyes and where they're looking, limited by their tool's range - local ray = Raycast(pos, vector.add(pos, vector.multiply(player:get_look_dir(), def.range or minetest.registered_items[""].range or 4))) + local ray = Raycast(pos, vector.add(pos, vector.multiply(player:get_look_dir(), (def and def.range) or minetest.registered_items[""].range or 4))) --Return the first pointable thing found that isn't the player calling this for pt in ray do @@ -182,7 +196,7 @@ controls.register_on_press(function(player, control) lua_inv.set_player_wielded_item(player, itemstack) end - if control == "place" then + if control == "place" or (minetest.settings:get_bool("lua_inv_mobile_support", true) and control == "aux1") then local itemstack = lua_inv.get_player_wielded_item(player) if itemstack:is_empty() then return end @@ -201,7 +215,7 @@ controls.register_on_press(function(player, control) if pointed_thing.type == "node" then itemstack = lua_inv.itemstack_to_userdata(itemstack) - local output = (def.on_place or minetest.item_place_node)(itemstack, player, pointed_thing) + local output = (def.on_place or minetest.item_place)(itemstack, player, pointed_thing) if output then itemstack = output @@ -220,7 +234,7 @@ controls.register_on_press(function(player, control) end if itemstack then - lua_inv.set_player_wielded_item(player, lua_inv.itemstack_from_userdata(itemstack)) + lua_inv.set_player_wielded_item(player, itemstack) end end end) diff --git a/itemstack.lua b/itemstack.lua index 147cab1..ad70149 100644 --- a/itemstack.lua +++ b/itemstack.lua @@ -215,16 +215,19 @@ local static = { minetest.registered_items["unknown"].description end, - get_inventory_image = function(self) + get_inventory_image = function(self, nil_if_tiles) if not self:is_known() then return "unknown_item.png" end - local image = self:get_meta():get("inventory_image") or self:get_definition().inventory_image - local tiles = self:get_definition().tiles + local def = self:get_definition() + local image = self:get_meta():get("inventory_image") or def.inventory_image + local tiles = def.tiles if (not image or image == "") then if tiles then + if nil_if_tiles then return end + local t2 = tileToString(tiles[3]) or tileToString(tiles[2]) or tileToString(tiles[1]) local t3 = tileToString(tiles[6]) or t2 image = minetest.inventorycube(tileToString(tiles[1]), t3, t2) @@ -431,6 +434,9 @@ local static = { } function lua_inv.itemstack(input_name, input_count, input_wear, input_meta, input_parent) + input_name = (not input_count or input_count > 0) and input_name + input_count = input_name and input_name ~= "" and input_count + local itemstack = { name = input_name or "", count = input_count or (input_name and 1) or 0, @@ -508,6 +514,8 @@ end function lua_inv.itemstack_from_string(str) local splits = str:split("return", false, 1) + if not splits[1] then return lua_inv.itemstack() end + local stats = splits[1]:split(' ') local meta = nil @@ -520,10 +528,14 @@ function lua_inv.itemstack_from_string(str) end function lua_inv.itemstack_from_userdata(itemstack) + if type(itemstack) ~= "userdata" then return itemstack end + return lua_inv.itemstack(itemstack:get_name(), itemstack:get_count(), itemstack:get_wear() / 655.35, itemstack:get_meta():to_table().fields) end function lua_inv.itemstack_to_userdata(itemstack) + if type(itemstack) ~= "table" then return itemstack end + local stack = ItemStack({ name = itemstack:get_name(), count = itemstack:get_count(), diff --git a/misc.lua b/misc.lua index 6282cc6..6350710 100644 --- a/misc.lua +++ b/misc.lua @@ -17,6 +17,31 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA --]] +function lua_inv.change_involves_list(change, listname) + if change.stack and change.stack.parent.list == listname then return change.stack end + if change.stack1 and change.stack1.parent.list == listname then return change.stack2 end + if change.stack2 and change.stack2.parent.list == listname then return change.stack1 end +end + +function lua_inv.set_list_take_only(inv, change, listname) + if change.type == "swap" and ((change.stack1.parent.list == listname and change.stack2:is_empty()) or + (change.stack2.parent.list == listname and change.stack1:is_empty())) then + return true + end + + if change.type == "swap" and (change.stack1.parent.list == listname or change.stack2.parent.list == listname) then + return false + end + + if change.type == "set" and change.stack.parent.list == listname and (change.key ~= "count" or change.val ~= 0) then + return false + end + + return true +end + + + minetest.register_chatcommand("is", { description = "Get the item string of the item that you are holding.", @@ -28,67 +53,99 @@ minetest.register_chatcommand("is", { end }) -minetest.register_craftitem("lua_inv:die", { - description = "Roll the die!", - inventory_image = "lua_inv_die_1.png", +local function give_item(name, param) + if not minetest.get_player_by_name(name):get_pos() then return end - _lua_inv_on_use = function(itemstack, user, pointed_thing) - local meta = itemstack:get_meta() - local side = math.random(6) + local playername, itemname = param:match("^([^ ]+) +(.+)$") - minetest.chat_send_player(user:get_player_name(), "You got a "..side.."!") - - meta:set_string("inventory_image", "lua_inv_die_"..side..".png") + local player = minetest.get_player_by_name(playername or "") + local itemstack = lua_inv.itemstack_from_string(itemname or "") + if not player or not player:get_pos() or itemstack:is_empty() or not itemstack:is_known() or itemstack:get_name() == "ignore" then + return false, "The provided player or itemstack is invalid." end -}) -local torch_def = { - description = "Animated Torch", - inventory_image = "lua_inv_torch_animated.png", + itemstack = lua_inv.player_inventory[name].inv:add_item("main", itemstack) - _lua_inv_animation = function(self, frame) - return {frames = 16, speed = 250, frame_template = "lua_inv_torch_%d.png"} + if not itemstack:is_empty() then + return false, "That player's inventory was too full. Could not give all of the requested stack." end -} -if minetest.get_modpath("default") then - minetest.override_item("default:torch", torch_def) - minetest.register_alias("lua_inv:torch", "default:torch") -else - minetest.register_craftitem("lua_inv:torch", torch_def) + return true, "Successfully given." end -minetest.register_craftitem("lua_inv:pick", { - description = "Stackable Pickaxe", - inventory_image = "lua_inv_stackwear_pick.png", - - tool_capabilities = { - full_punch_interval = 1.2, - max_drop_level=0, - groupcaps={ - cracky = {times={[3]=0.60}, uses=2, maxlevel=1}, - }, - damage_groups = {fleshy=2}, - }, - - sound = {breaks = "default_tool_breaks"}, - groups = {pickaxe = 1} +minetest.override_chatcommand("give", { + func = give_item }) -minetest.register_chatcommand("testitems", { - description = "Gain a set of test lua_inv test items.", - - privs = {debug = true}, - +minetest.override_chatcommand("giveme", { func = function(name, param) - local player = minetest.get_player_by_name(name) - if not player:get_pos() then return end - - local inv = lua_inv.player_inventory[name].inv - - inv:add_item("main", lua_inv.itemstack("lua_inv:die")) - inv:add_item("main", lua_inv.itemstack("lua_inv:torch")) - inv:add_item("main", lua_inv.itemstack("lua_inv:pick", 66, 75)) - inv:add_item("main", lua_inv.itemstack("lua_inv:pick", 75, 33)) + return give_item(name, name.." "..(param or "")) end }) + +if minetest.settings:get_bool("lua_inv_test_items") then + minetest.register_craftitem("lua_inv:die", { + description = "Roll the die!", + inventory_image = "lua_inv_die_1.png", + + _lua_inv_on_use = function(itemstack, user, pointed_thing) + local meta = itemstack:get_meta() + local side = math.random(6) + + minetest.chat_send_player(user:get_player_name(), "You got a "..side.."!") + + meta:set_string("inventory_image", "lua_inv_die_"..side..".png") + end + }) + + local torch_def = { + description = "Animated Torch", + inventory_image = "lua_inv_torch_animated.png", + + _lua_inv_animation = function(self, frame) + return {frames = 16, speed = 250, frame_template = "lua_inv_torch_%d.png"} + end + } + + if minetest.get_modpath("default") then + minetest.override_item("default:torch", torch_def) + minetest.register_alias("lua_inv:torch", "default:torch") + else + minetest.register_craftitem("lua_inv:torch", torch_def) + end + + minetest.register_craftitem("lua_inv:pick", { + description = "Stackable Pickaxe", + inventory_image = "lua_inv_stackwear_pick.png", + + tool_capabilities = { + full_punch_interval = 1.2, + max_drop_level=0, + groupcaps={ + cracky = {times={[3]=0.60}, uses=2, maxlevel=1}, + }, + damage_groups = {fleshy=2}, + }, + + sound = {breaks = "default_tool_breaks"}, + groups = {pickaxe = 1} + }) + + minetest.register_chatcommand("testitems", { + description = "Gain a set of test lua_inv test items.", + + privs = {debug = true}, + + func = function(name, param) + local player = minetest.get_player_by_name(name) + if not player:get_pos() then return end + + local inv = lua_inv.player_inventory[name].inv + + inv:add_item("main", lua_inv.itemstack("lua_inv:die")) + inv:add_item("main", lua_inv.itemstack("lua_inv:torch")) + inv:add_item("main", lua_inv.itemstack("lua_inv:pick", 66, 75)) + inv:add_item("main", lua_inv.itemstack("lua_inv:pick", 75, 33)) + end + }) +end diff --git a/optional_depends/default.lua b/optional_depends/default.lua index 23ff684..a8c6ef3 100644 --- a/optional_depends/default.lua +++ b/optional_depends/default.lua @@ -17,6 +17,12 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA --]] +local function can_dig_container(pos, player) + local inv = lua_inv.fetch_node_inventory(pos, true) + + return inv and inv:is_empty() and default.can_interact_with_node(player, pos) +end + ----------------------------------------------------- -- Chests -- ----------------------------------------------------- @@ -36,6 +42,13 @@ local function chest_override(name) local override_def = {} + override_def._lua_inv_inventory = function(pos) + local inv = lua_inv.inventory(pos) + inv:set_size("main", 32) + + return inv + end + override_def.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) minetest.sound_play(def.sound_open, {gain = 0.3, pos = pos, max_hear_distance = 10}, true) @@ -50,18 +63,7 @@ local function chest_override(name) sound = def.sound_close, swap = name } end - override_def.can_dig = function(pos, player) - local inv = lua_inv.fetch_node_inventory(pos, true) - - return inv and inv:is_empty("main") and default.can_interact_with_node(player, pos) - end - - override_def._lua_inv_inventory = function(pos) - local inv = lua_inv.inventory(pos) - inv:set_size("main", 32) - - return inv - end + override_def.can_dig = can_dig_container minetest.override_item(name, override_def) minetest.override_item(name.."_open", override_def) @@ -69,3 +71,291 @@ end chest_override("default:chest") chest_override("default:chest_locked") + +----------------------------------------------------- +-- Furnaces -- +----------------------------------------------------- + +local function furnace_formspec(pos) + return lua_inv.dynamic_formspec({ + lua_inv.formspec_element("size", {{8, 10}}), + lua_inv.dynamic_list({k = "nodemeta", v = {pos.x, pos.y, pos.z}}, "src", 2.75, 0.5, 1, 1), + lua_inv.dynamic_list({k = "nodemeta", v = {pos.x, pos.y, pos.z}}, "fuel", 2.75, 2.5, 1, 1), + lua_inv.dynamic_list({k = "nodemeta", v = {pos.x, pos.y, pos.z}}, "dst", 4.75, 0.96, 2, 2), + lua_inv.active_indicator(2.75, 1.5, 1, 1, "default_furnace_fire_bg.png", "default_furnace_fire_fg.png", "fuel_percent"), + lua_inv.active_indicator(3.75, 1.5, 1, 1, "gui_furnace_arrow_bg.png", "gui_furnace_arrow_fg.png^[transformR270", "item_percent"), + lua_inv.dynamic_list("current_player", "main", 0, 4.85, 8, 1), + lua_inv.dynamic_list("current_player", "main", 0, 6.08, 8, 3, 8), + lua_inv.stack_mode_selector(0, 9.1) + }) +end + +local function swap_node(pos, name) + local node = minetest.get_node(pos) + if node.name == name then + return + end + node.name = name + minetest.swap_node(pos, node) +end + +local function override_furnace(name) + local def = minetest.registered_items[name] + + local override_def = {} + + override_def._lua_inv_inventory = function(pos) + local inv = lua_inv.inventory(pos, + --Allow Change + function(inv, change) + if not lua_inv.set_list_take_only(inv, change, "dst") then + return false + end + + local fuel = lua_inv.change_involves_list(change, "fuel") + if fuel then + if change.key == "name" then + fuel = ItemStack(change.val) + elseif fuel:get_name() ~= "" then + fuel = ItemStack(fuel:get_name()) + end + + if minetest.get_craft_result({method = "fuel", width = 1, items = {lua_inv.itemstack_to_userdata(fuel)}}).time ~= 0 then + return true + end + + if not lua_inv.set_list_take_only(inv, change, "fuel") then + return false + end + end + + return true + end, + + nil, + + --After Change + function(inv, change) + minetest.get_node_timer(inv.parent):start(1) + end + ) + + inv:set_size("src", 1) + inv:set_size("fuel", 1) + inv:set_size("dst", 4) + + return inv + end + + ---[[ + override_def.on_timer = function(pos, elapsed) + local meta = minetest.get_meta(pos) + + local fuel_time = meta:get_float("fuel_time") + local src_time = meta:get_float("src_time") + local fuel_totaltime = meta:get_float("fuel_totaltime") + + local inv = lua_inv.fetch_node_inventory(pos) + local srclist, fuellist + local dst_full = false + + local timer_elapsed = meta:get_int("timer_elapsed") + meta:set_int("timer_elapsed", timer_elapsed + 1) + + local cookable, cooked + local fuel + + local update = true + while elapsed > 0 and update do + update = false + + srclist = {lua_inv.itemstack_to_userdata(inv:get_stack("src", 1))} + fuellist = {lua_inv.itemstack_to_userdata(inv:get_stack("fuel", 1))} + + -- + -- Cooking + -- + + -- Check if we have cookable content + local aftercooked + cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist}) + cookable = cooked.time ~= 0 + + cooked.item = lua_inv.itemstack_from_userdata(cooked.item) + aftercooked.items[1] = lua_inv.itemstack_from_userdata(aftercooked.items[1]) + + local el = math.min(elapsed, fuel_totaltime - fuel_time) + if cookable then -- fuel lasts long enough, adjust el to cooking duration + el = math.min(el, cooked.time - src_time) + end + + -- Check if we have enough fuel to burn + if fuel_time < fuel_totaltime then + -- The furnace is currently active and has enough fuel + fuel_time = fuel_time + el + -- If there is a cookable item then check if it is ready yet + if cookable then + src_time = src_time + el + if src_time >= cooked.time then + -- Place result in dst list if possible + if inv:room_for_item("dst", cooked.item) then + for i = 1, inv:get_size("dst") do + local stack = inv:get_stack("dst", i) + if cooked.item:item_fits(stack) then + rawset(stack, "name", cooked.item:get_name()) + rawset(stack, "count", stack:get_count() + cooked.item:get_count()) + rawset(stack, "wear", stack:get_wear() + cooked.item:get_wear()) + + break + end + end + + inv:set_stack("src", 1, aftercooked.items[1]) + src_time = src_time - cooked.time + update = true + else + dst_full = true + end + -- Play cooling sound + minetest.sound_play("default_cool_lava", + {pos = pos, max_hear_distance = 16, gain = 0.1}, true) + else + -- Item could not be cooked: probably missing fuel + update = true + end + end + else + -- Furnace ran out of fuel + if cookable then + -- We need to get new fuel + local afterfuel + fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist}) + + fuel.item = lua_inv.itemstack_from_userdata(fuel.item) + afterfuel.items[1] = lua_inv.itemstack_from_userdata(afterfuel.items[1]) + + if fuel.time == 0 then + -- No valid fuel in fuel list + fuel_totaltime = 0 + src_time = 0 + else + -- Take fuel from fuel list + inv:set_stack("fuel", 1, afterfuel.items[1]) + -- Put replacements in dst list or drop them on the furnace. + local replacements = fuel.replacements + if replacements[1] then + local leftover = replacements[1] + + for i = 1, inv:get_size("dst") do + local stack = inv:get_stack("dst", i) + if replacements[1]:item_fits(stack) then + rawset(stack, "name", cooked.item:get_name()) + rawset(stack, "count", stack:get_count() + cooked.item:get_count()) + rawset(stack, "count", stack:get_wear() + cooked.item:get_wear()) + + replacements[1]:set_count(0) + break + end + end + + if not leftover:is_empty() then + local above = vector.new(pos.x, pos.y + 1, pos.z) + local drop_pos = minetest.find_node_near(above, 1, {"air"}) or above + minetest.item_drop(replacements[1], nil, drop_pos) + end + end + update = true + fuel_totaltime = fuel.time + (fuel_totaltime - fuel_time) + end + else + -- We don't need to get new fuel since there is no cookable item + fuel_totaltime = 0 + src_time = 0 + end + fuel_time = 0 + end + + elapsed = elapsed - el + end + + if fuel and fuel_totaltime > fuel.time then + fuel_totaltime = fuel.time + end + if srclist and srclist[1]:is_empty() then + src_time = 0 + end + + -- + -- Update formspec, infotext and node + -- + local item_state + local fuel_percent = 0 + local item_percent = 0 + + if cookable then + item_percent = math.floor(src_time / cooked.time * 100) + end + + local active = false + local result = false + + if fuel_totaltime ~= 0 then + active = true + fuel_percent = 100 - math.floor(fuel_time / fuel_totaltime * 100) + swap_node(pos, name.."_active") + -- make sure timer restarts automatically + result = true + + -- Play sound every 5 seconds while the furnace is active + if timer_elapsed == 0 or (timer_elapsed+1) % 5 == 0 then + minetest.sound_play("default_furnace_active", + {pos = pos, max_hear_distance = 16, gain = 0.5}, true) + end + else + item_percent = 0 + formspec = default.get_furnace_inactive_formspec() + swap_node(pos, name) + -- stop timer on the inactive furnace + minetest.get_node_timer(pos):stop() + meta:set_int("timer_elapsed", 0) + end + + -- + -- Set meta values + -- + meta:set_float("fuel_totaltime", fuel_totaltime) + meta:set_float("fuel_time", fuel_time) + meta:set_float("src_time", src_time) + meta:set_float("fuel_percent", fuel_percent) + meta:set_float("item_percent", item_percent) + + for playername, formspec in pairs(lua_inv.open_formspecs) do + if formspec.meta:get_string("formname") == name then + formspec.meta:set_float("fuel_percent", fuel_percent) + formspec.meta:set_float("item_percent", item_percent) + + lua_inv.show_formspec(minetest.get_player_by_name(playername), name, formspec) + end + end + + return result + end--]] + + override_def.on_construct = function() end + + override_def.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local meta = minetest.get_meta(pos) + local formspec = furnace_formspec(pos) + formspec.meta:set_float("fuel_percent", meta:get_float("fuel_percent")) + formspec.meta:set_float("item_percent", meta:get_float("item_percent")) + + lua_inv.show_formspec(clicker, name, formspec) + end + + override_def.can_dig = can_dig_container + + minetest.override_item(name, override_def) + minetest.override_item(name.."_active", override_def) +end + +override_furnace("default:furnace") diff --git a/settingtypes.txt b/settingtypes.txt new file mode 100644 index 0000000..4663703 --- /dev/null +++ b/settingtypes.txt @@ -0,0 +1,5 @@ +#Adds an animated torch, a D6 that changes it sprite according to what you roll, and a stackable pickaxe. +lua_inv_test_items (Register various items to test lua_inv features) bool false + +#Adds an extra crosshair that won't be invisible to mobile players, and makes the aux1 (E) key act like a right-click, as the "place" control doesn't work +lua_inv_mobile_support (Enable features required for Mobile users) bool true diff --git a/textures/lua_inv_crosshair.png b/textures/lua_inv_crosshair.png new file mode 100644 index 0000000..da1444d Binary files /dev/null and b/textures/lua_inv_crosshair.png differ