123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- local MP = minetest.get_modpath(minetest.get_current_modname())
- local S, NS = dofile(MP.."/intllib.lua")
- local F = minetest.formspec_escape
- local modpath_default = minetest.get_modpath("default")
- local modpath_sfinv = minetest.get_modpath("sfinv")
- local modpath_unified_inventory = minetest.get_modpath("unified_inventory")
- -- table_def can have the following:
- --{
- -- alphabetize_items = true or false,
- -- description = string,
- -- append_to_formspec = string,
- -- input_width = number, -- height and width of the input inventory. Note that if you make this too small some recipes may no longer be craftable.
- -- input_height = number,
- -- output_width = number, -- height and width of the output inventory
- -- output_height = number,
- -- controls_x = number, -- location of the column of controls for controlling output display
- -- controls_y = number,
- --}
- simplecrafting_lib.register_player_craft_type = function(craft_type, table_def)
- if table_def == nil then
- table_def = {}
- end
- local input_width = table_def.input_width or 2
- local input_height = table_def.input_height or 5
- local output_width = table_def.output_width or 8
- local output_height = table_def.output_height or 6
- local controls_x = table_def.controls_x or 9.3
- local controls_y = table_def.controls_y or 6.5
- local input_list_name = "craft"
- local input_count = input_width * input_height
- local output_count = output_width * output_height
- local show_player_inventory = true
- -- Unified inventory has strict limitations on the size of the crafting interface, and
- -- has a hard-coded player inventory display
- if modpath_unified_inventory then
- input_width = 2
- input_height = 4
- output_width = 5
- output_height = 4
- controls_x = 7.3
- controls_y = 0
- show_player_inventory = false
- end
- -- This is to vertically align the input and output inventories,
- -- keeping them centered relative to each other.
- local y_displace_input = 0
- local y_displace_output = 0
- if input_height < output_height then
- y_displace_input = (output_height-input_height)/2
- elseif input_height > output_height then
- y_displace_output = (input_height-output_height)/2
- end
- -- pre-declare this so that get_or_create_context can reference it
- local update_output
- -- context contains persistent player state
- local get_or_create_context = function(player)
- local player_name = player:get_player_name()
- local context
- if modpath_sfinv then
- context = sfinv.get_or_create_context(player)
- -- elseif modpath_unified_inventory then
- -- context = unified_inventory.get_per_player_formspec(player:get_player_name())
- else
- simplecrafting_lib.player_contexts = simplecrafting_lib.player_contexts or {}
- context = simplecrafting_lib.player_contexts[player_name]
- if not context then
- context = {}
- simplecrafting_lib.player_contexts[player_name] = context
- end
- end
- if context.simplecrafting_lib_row == nil then context.simplecrafting_lib_row = 0 end -- the currently selected output page
-
- -- Create a detached inventory to hold prospective crafting outputs
- if context.simplecrafting_lib_output_inventory_name == nil then
- context.simplecrafting_lib_output_inventory_name = "simplecrafting_" .. craft_type .. "_" .. player_name
- end
- if context.simplecrafting_lib_output_inventory == nil then
- context.simplecrafting_lib_output_inventory = minetest.create_detached_inventory(context.simplecrafting_lib_output_inventory_name, {
- allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
- return 0
- end,
- allow_put = function(inv, listname, index, stack, player)
- return 0
- end,
- allow_take = function(inv, listname, index, stack, player)
- return -1
- end,
- on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
- end,
- on_take = function(inv, listname, index, stack, player)
- if stack and stack:get_count() > 0 then
- local player_inv = minetest.get_inventory({type="player", name=player_name})
- if listname == "main" then
- simplecrafting_lib.craft_stack(craft_type, stack, player_inv, input_list_name, player_inv, input_list_name, player)
- if simplecrafting_lib.award_crafting then
- simplecrafting_lib.award_crafting(player, stack)
- end
- end
- update_output(player_inv, player)
- return stack:get_count()
- end
- end,
- }, player_name)
- if context.simplecrafting_lib_output_inventory == nil then
- minetest.log("error", "[simplecrafting_lib] get_or_create_context failed to create a detached inventory to hold crafting outputs")
- end
- end
- if context.simplecrafting_lib_max_mode == nil then context.simplecrafting_lib_max_mode = false end
- return context
- end
- -- updates the contents of the detached output inventory to match the input inventory's contents
- update_output = function(player_inv, player)
- local context = get_or_create_context(player)
- local max_mode = context.simplecrafting_lib_max_mode
- local craftable = simplecrafting_lib.get_craftable_items(craft_type, player_inv:get_list(input_list_name), max_mode, table_def.alphabetize_items)
- -- Output size is the number of multiples of output_count that we can fit the craftable outputs into,
- -- with a minimum of one multuple so there's an empty page if there's no recipes to craft
- local output_size = math.max(math.ceil(#craftable / output_count), 1) * output_count
- context.simplecrafting_lib_output_inventory:set_size("main", output_size)
- context.simplecrafting_lib_output_inventory:set_list("main", craftable)
- end
- -- refreshes the inventory formspec when there's been a change that would affect it
- local update_formspec = function(player, context)
- if modpath_unified_inventory then
- unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player:get_player_name()])
- elseif modpath_sfinv then
- sfinv.set_player_inventory_formspec(player, context)
- end
- end
- local make_formspec = function(player)
- local context = get_or_create_context(player)
- local player_inv = minetest.get_inventory({type="player", name=player:get_player_name()})
- update_output(player_inv, player)
- local row = context.simplecrafting_lib_row or 0
- local item_count
- if context.simplecrafting_lib_output_inventory then
- item_count = context.simplecrafting_lib_output_inventory:get_size("main")
- else
- item_count = output_count
- end
- local max_mode = context.simplecrafting_lib_max_mode or false
- local output_inventory = context.simplecrafting_lib_output_inventory_name
- if item_count < output_count then
- row = 0
- context.simplecrafting_lib_row = row
- elseif (row*output_width)+output_count > item_count then
- row = (item_count - output_count) / output_width
- context.simplecrafting_lib_row = row
- end
-
- local inventory = {
- "list[current_player;"..input_list_name..";0,"..y_displace_input..";"..input_width..","..input_height..";]"..
- "list[detached:"..output_inventory..";main;"..tostring(input_width+0.2)..","..y_displace_output..";"..output_width..","..output_height..";"..tostring(row*output_width), "]",
- }
- if show_player_inventory then
- inventory[#inventory+1] = "list[current_player;main;1.1,"..tostring(output_height+0.25)..";8,1;]"..
- "list[current_player;main;1.1,"..tostring(output_height+1.5)..";8,3;8]"
- end
- inventory[#inventory+1] = "listring[detached:"..output_inventory..";main]"..
- "listring[current_player;main]"..
- "listring[current_player;"..input_list_name.."]"..
- "listring[current_player;main]"
-
- if table_def.description then
- inventory[#inventory+1] = "label[0,0;"..table_def.description.."]"
- end
-
- if modpath_default then
- inventory[#inventory+1] = default.gui_bg .. default.gui_bg_img .. default.gui_slots
- end
-
- local pages = false
- local page_button_y = controls_y + 0.6
- if item_count > ((row/output_height)+1) * output_count then
- inventory[#inventory+1] = "button["..controls_x..","..page_button_y..";1,0.75;next;»]"..
- "tooltip[next;"..F(S("Next page of crafting products")).."]"
- page_button_y = page_button_y + 0.8
- pages = true
- end
- if row >= output_height then
- inventory[#inventory+1] = "button["..controls_x..","..page_button_y..";1,0.75;prev;«]"..
- "tooltip[prev;"..F(S("Previous page of crafting products")).."]"
- pages = true
- end
- if pages then
- inventory[#inventory+1] = "label["..controls_x..","..controls_y..";" .. F(S("Page @1", tostring(row/output_height+1))) .. "]"
- end
-
- if max_mode then
- inventory[#inventory+1] = "button["..controls_x..","..tostring(controls_y+2.2)..";1,0.75;max_mode;"..F(S("Max\nOutput")).."]"
- else
- inventory[#inventory+1] = "button["..controls_x..","..tostring(controls_y+2.2)..";1,0.75;max_mode;"..F(S("Min\nOutput")).."]"
- end
-
- if table_def.append_to_formspec then
- inventory[#inventory+1] = table_def.append_to_formspec
- end
- return table.concat(inventory)
- end
- minetest.register_on_joinplayer(function(player)
- local player_name = player:get_player_name()
- local player_inv = minetest.get_inventory({type="player", name=player_name})
- player_inv:set_size(input_list_name, input_count)
- -- TEMP code to save crafting inputs from a brief window when this mod was using this inventory for crafting inputs
- local deprecated_input_list_name = craft_type .. "_input"
- if not player_inv:is_empty(deprecated_input_list_name) then
- local old_items = player_inv:get_list(deprecated_input_list_name)
- for _, item in ipairs(old_items) do
- local leftover = player_inv:add_item(input_list_name, item)
- minetest.item_drop(leftover, player, player:get_pos())
- end
- player_inv:set_list(deprecated_input_list_name, {})
- player_inv:set_size(deprecated_input_list_name, 0)
- end
- --TEMP end of temp code
-
- update_output(player_inv, player)
- update_formspec(player, get_or_create_context(player))
- end)
- minetest.register_on_leaveplayer(function(player)
- local player_name = player:get_player_name()
- simplecrafting_lib.player_contexts[player_name] = nil
- minetest.remove_detached_inventory("simplecrafting_" .. craft_type .. "_" .. player_name)
- end)
- minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
- if action == "move" then
- if inventory_info.to_list == input_list_name then
- if inventory_info.from_list == input_list_name then
- return inventory_info.count
- end
- local stack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index)
- if simplecrafting_lib.is_possible_input(craft_type, stack:get_name()) then
- return inventory_info.count
- end
- return 0
- end
- if inventory_info.to_list == "main" then
- return inventory_info.count
- end
- end
- end)
- minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
- if inventory_info.to_list == input_list_name or inventory_info.from_list == input_list_name then
- local context = get_or_create_context(player)
- update_output(inventory, player)
- update_formspec(player, context)
- end
- end)
-
- local handle_receive_fields = function(player, fields, context)
- local row = context.simplecrafting_lib_row
- local refresh = false
- if fields.next then
- minetest.sound_play("paperflip1", {to_player=player:get_player_name(), gain = 1.0})
- row = row + output_height
- elseif fields.prev then
- minetest.sound_play("paperflip2", {to_player=player:get_player_name(), gain = 1.0})
- row = row - output_height
- elseif fields.max_mode then
- context.simplecrafting_lib_max_mode = not context.simplecrafting_lib_max_mode
- refresh = true
- else
- return false
- end
- context.simplecrafting_lib_row = row
- if refresh then
- local player_inv = minetest.get_inventory({type="player", name=player:get_player_name()})
- update_output(player_inv, player)
- end
- return true
- end
- if modpath_unified_inventory then
- local background = ""
- for x = 0, input_width - 1 do
- for y = 0 + y_displace_input, input_height + y_displace_input - 1 do
- background = background .. "background["..x..","..y..";1,1;ui_single_slot.png]"
- end
- end
- for x = input_width + 0.2, input_width + 0.2 + output_width - 1 do
- for y = 0 + y_displace_output, y_displace_output + output_height - 1 do
- background = background .. "background["..x..","..y..";1,1;ui_single_slot.png]"
- end
- end
- unified_inventory.register_page("craft", {
- get_formspec = function(player, perplayer_formspec)
- local formspec = make_formspec(player) .. background
- if unified_inventory.trash_enabled or unified_inventory.is_creative(player_name) or minetest.get_player_privs(player_name).give then
- formspec = formspec.."label["..controls_x..","..tostring(controls_y+2.8)..";" .. F(S("Trash:")) .. "]"
- .."background["..controls_x..","..tostring(controls_y+3.3)..";1,1;ui_single_slot.png]"
- .."list[detached:trash;main;"..controls_x..","..tostring(controls_y+3.3)..";1,1;]"
- end
- --Alas, have run out of room to fit this.
- -- if unified_inventory.is_creative(player_name) then
- -- formspec = formspec.."label[0,"..(formspecy + 1.5)..";" .. F(S("Refill:")) .. "]"
- -- formspec = formspec.."list[detached:"..F(player_name).."refill;main;0,"..(formspecy +2)..";1,1;]"
- -- end
- return {formspec=formspec}
- end,
- })
- --unified_inventory.register_page("craftguide", {
- --})
-
- minetest.register_on_player_receive_fields(function(player, formname, fields)
- if formname ~= "" then -- Unified_inventory is using the empty string as its formname.
- return
- end
- local player_name = player:get_player_name()
- local context = get_or_create_context(player)
-
- if handle_receive_fields(player, fields, context) then
- unified_inventory.set_inventory_formspec(player, unified_inventory.current_page[player_name])
- return true
- end
- end)
-
- elseif modpath_sfinv then
- sfinv.override_page("sfinv:crafting", {
- title = "Crafting",
- get = function(self, player, context)
- return sfinv.make_formspec(player, context, make_formspec(player), false, "size[10.2,10.2]")
- end,
- on_player_receive_fields = function(self, player, context, fields)
- if handle_receive_fields(player, fields, context) then
- sfinv.set_player_inventory_formspec(player, context)
- return true
- end
- end,
- })
-
- simplecrafting_lib.set_crafting_guide_def(craft_type, {
- output_width = 10,
- output_height = 6,
- recipes_per_page = 3,
- })
-
- sfinv.register_page("simplecrafting_lib:guide_"..craft_type, {
- title = "Guide",
- get = function(self, player, context)
- local formspec, size = simplecrafting_lib.make_guide_formspec(craft_type, player:get_player_name())
- return sfinv.make_formspec(player, context, formspec, false, "size[10.2,10.2]")
- end,
- on_player_receive_fields = function(self, player, context, fields)
- if simplecrafting_lib.handle_guide_receive_fields(craft_type, player, fields) then
- sfinv.set_player_inventory_formspec(player, context)
- return true
- end
- end,
- })
-
- end
- end
|