diff --git a/autocrafter.lua b/autocrafter.lua index deeca6d..c9dd3bf 100644 --- a/autocrafter.lua +++ b/autocrafter.lua @@ -25,8 +25,8 @@ local function get_item_info(stack) return description, name end --- Get best matching recipe for what user has put in crafting grid. --- This function does not consider crafting method (mix vs craft) +-- get best matching recipe for what user has put in crafting grid. +-- this function does not consider crafting method (mix vs craft) local function get_matching_craft(output_name, example_recipe) local recipes = core.get_all_craft_recipes(output_name) if not recipes then @@ -92,7 +92,7 @@ local function get_craft(pos, inventory, hash) return craft end --- From a consumption table with groups and an inventory index, +-- from a consumption table with groups and an inventory index, -- build a consumption table without groups local function calculate_consumption(inv_index, consumption_with_groups) inv_index = table.copy(inv_index) @@ -103,8 +103,8 @@ local function calculate_consumption(inv_index, consumption_with_groups) -- table of ingredients defined as one or more groups each local grouped_ingredients = {} - -- First consume all non-group requirements - -- This is done to avoid consuming a non-group item which + -- first consume all non-group requirements + -- this is done to avoid consuming a non-group item which -- is also in a group for key, count in pairs(consumption_with_groups) do if key:sub(1, 6) == "group:" then @@ -141,15 +141,15 @@ local function calculate_consumption(inv_index, consumption_with_groups) return found == count_ingredient_groups end - -- Next, resolve groups using the remaining items in the inventory + -- next, resolve groups using the remaining items in the inventory if next(grouped_ingredients) ~= nil then local take for itemname, count in pairs(inv_index) do if count > 0 then -- groupname is the string as defined by recipe. - -- e.g. group:dye,color_blue + -- e.g. group:dye,color_blue -- groups holds the group names split into a list - -- ready to be passed to core.get_item_group() + -- ready to be passed to core.get_item_group() for groupname, groups in pairs(grouped_ingredients) do if consumption_with_groups[groupname] > 0 and ingredient_groups_match_item(groups, itemname) @@ -172,7 +172,7 @@ local function calculate_consumption(inv_index, consumption_with_groups) end end - -- Finally, check everything has been consumed + -- finally, check everything has been consumed for key, count in pairs(consumption_with_groups) do if count > 0 then return nil @@ -207,43 +207,57 @@ local function has_room_for_output(list_output, index_output) return true end -local function autocraft(inventory, craft) +local function autocraft(inventory, craft, pos) if not craft then return false end - -- check if output and all replacements fit in dst local output = craft.output.item local out_items = count_index(craft.decremented_input) - out_items[output:get_name()] = - (out_items[output:get_name()] or 0) + output:get_count() + out_items[output:get_name()] = (out_items[output:get_name()] or 0) + output:get_count() if not has_room_for_output(inventory:get_list("dst"), out_items) then return false end - - -- check if we have enough material available - local inv_index = count_index(inventory:get_list("src")) + local inv_list = inventory:get_list("src") + local inv_index = count_index(inv_list) local consumption = calculate_consumption(inv_index, craft.consumption) + if not consumption then return false end + -- ixcludes buckets and non-stackable items + -- logic of the added reserve + local meta = core.get_meta(pos) + if meta:get_int("reserve") == 1 then + local total_in_inv = 0 + local total_needed = 0 + + for itemname, number in pairs(consumption) do + local def = core.registered_items[itemname] + local stack_max = def and def.stack_max or 1 + + -- if the object is stackable + if stack_max > 1 then + total_needed = total_needed + number + total_in_inv = total_in_inv + (inv_index[itemname] or 0) + end + end - -- consume material + -- if the total does not exceed the required total by at least 1, we stop. + if total_needed > 0 and total_in_inv <= total_needed then + return false + end + end + + -- consumption of objects for itemname, number in pairs(consumption) do - -- We have to do that since remove_item does not work if count > stack_max for _ = 1, number do inventory:remove_item("src", ItemStack(itemname)) end end - -- craft the result into the dst inventory and add any "replacements" as well inventory:add_item("dst", output) - local leftover for i = 1, 9 do - leftover = inventory:add_item("dst", craft.decremented_input[i]) - if leftover and not leftover:is_empty() then - core.log("warning", "[pipeworks] autocrafter didn't " .. - "calculate output space correctly.") - end + inventory:add_item("dst", craft.decremented_input[i]) end return true end @@ -263,7 +277,7 @@ local function run_autocrafter(pos, elapsed) end for _ = 1, math.floor(elapsed / craft_time) do - local continue = autocraft(inventory, craft) + local continue = autocraft(inventory, craft, pos) if not continue then return false end end return true @@ -344,10 +358,17 @@ local function on_output_change(pos, inventory, stack) end -- returns false if we shouldn't bother attempting to start the timer again --- after this + local function update_meta(meta, enabled) local state = enabled and "on" or "off" meta:set_int("enabled", enabled and 1 or 0) + + -- Reserve State + local res_state = meta:get_int("reserve") == 1 + local res_icon = res_state and "pipeworks_button_on.png" or "pipeworks_button_off.png" + local res_status_txt = res_state and S("Reserve: ON") or S("Reserve: OFF") + local res_tooltip = res_status_txt .. "\n" .. S("Keep 1 item in slot to prevent other items from filling it.") + local list_backgrounds = "" if core.get_modpath("i3") or core.get_modpath("mcl_formspec") then list_backgrounds = "style_type[box;colors=#666]" @@ -370,6 +391,7 @@ local function update_meta(meta, enabled) end end end + local size = "10.2,14" local fs = "formspec_version[2]" .. @@ -379,8 +401,11 @@ local function update_meta(meta, enabled) "list[context;recipe;0.22,0.22;3,3;]" .. "image[4,1.45;1,1;[combine:16x16^[noalpha^[colorize:#141318:255]" .. "list[context;output;4,1.45;1,1;]" .. - "image_button[4,2.6;1,0.6;pipeworks_button_" .. state .. ".png;" .. - state .. ";;;false;pipeworks_button_interm.png]" .. + "image_button[4.1,2.6;0.8,0.5;pipeworks_button_" .. state .. ".png;" .. state .. ";;;false;pipeworks_button_interm.png]" .. + "image_button[4.1,3.1;0.8,0.5;" .. res_icon .. ";btn_reserve;;;false;pipeworks_button_interm.png]" .. + "style[label_res;font_size=12]" .. + "label[3.6,3.95;" .. res_status_txt .. "]" .. + "tooltip[btn_reserve;" .. res_tooltip .. "]" .. "list[context;dst;5.28,0.22;4,3;]" .. "list[context;src;0.22,5;8,3;]" .. pipeworks.fs_helpers.get_inv(9) .. @@ -389,38 +414,33 @@ local function update_meta(meta, enabled) "listring[current_player;main]" .. "listring[context;dst]" .. "listring[current_player;main]" + if core.get_modpath("digilines") then - fs = fs .. "field[0.22,4.1;4.5,0.75;channel;" .. S("Channel") .. - ";${channel}]" .. - "button[5,4.1;2,0.75;set_channel;" .. S("Set") .. "]" .. - "button_exit[7.2,4.1;2,0.75;close;" .. S("Close") .. "]" + + fs = fs .. "field[0.22,4.1;4.0,0.5;channel;" .. S("Channel") .. ";${channel}]" .. + "button[4.5,4.1;1.2,0.5;set_channel;" .. S("Set") .. "]" .. + "button_exit[6.0,4.1;1.5,0.5;close;" .. S("Close") .. "]" end meta:set_string("formspec", fs) - -- toggling the button doesn't quite call for running a recipe change check - -- so instead we run a minimal version for infotext setting only - -- this might be more written code, but actually executes less - local output = meta:get_inventory():get_stack("output", 1) - if output:is_empty() then -- doesn't matter if paused or not + local output_stack = meta:get_inventory():get_stack("output", 1) + if output_stack:is_empty() then meta:set_string("infotext", S("unconfigured Autocrafter")) return false end - - local description, name = get_item_info(output) + local description, name = get_item_info(output_stack) local infotext = enabled and S("'@1' Autocrafter (@2)", description, name) or S("paused '@1' Autocrafter", description) - meta:set_string("infotext", infotext) return enabled end - -- 1st version of the autocrafter had actual items in the crafting grid -- the 2nd replaced these with virtual items, dropped the content on update and -- set "virtual_items" to string "1" -- the third added an output inventory, changed the formspec and added a button -- for enabling/disabling -- so we work out way backwards on this history and update each single case --- to the newest version +-- to the newest version local function upgrade_autocrafter(pos, meta) local meta = meta or core.get_meta(pos) local inv = meta:get_inventory() @@ -484,6 +504,7 @@ core.register_node("pipeworks:autocrafter", { inv:set_size("recipe", 3 * 3) inv:set_size("dst", 4 * 3) inv:set_size("output", 1) + meta:set_int("reserve", 0) update_meta(meta, false) end, on_receive_fields = function(pos, formname, fields, sender) @@ -493,6 +514,8 @@ core.register_node("pipeworks:autocrafter", { return end local meta = core.get_meta(pos) + + -- Machine on/off management if fields.on then update_meta(meta, false) core.get_node_timer(pos):stop() @@ -501,10 +524,22 @@ core.register_node("pipeworks:autocrafter", { start_crafter(pos) end end + + -- Channel Management (if present) if fields.channel then meta:set_string("channel", fields.channel) end + + -- Reserve button management + if fields.btn_reserve then + local current_res = meta:get_int("reserve") + local new_res = (current_res == 1 and 0 or 1) + meta:set_int("reserve", new_res) + -- Update the interface to show color change + update_meta(meta, meta:get_int("enabled") == 1) + end end, + can_dig = function(pos, player) upgrade_autocrafter(pos) local meta = core.get_meta(pos) diff --git a/locale/pipeworks.it.tr b/locale/pipeworks.it.tr new file mode 100644 index 0000000..07c67f6 --- /dev/null +++ b/locale/pipeworks.it.tr @@ -0,0 +1,86 @@ +# textdomain: pipeworks + +## generic interaction +Set=Imposta +Cancel=Annulla + +## digilines interfacing +Channel=Canale + +## init +Allow splitting incoming stacks from tubes=Permetti di dividere gli stack in entrata dai tubi + +## autocrafter +Unknown item=Oggetto sconosciuto +unconfigured Autocrafter: unknown recipe=Autocrafter non configurato: ricetta sconosciuta +unconfigured Autocrafter=Autocrafter non configurato +'@1' Autocrafter (@2)=Autocrafter di '@1' (@2) +Save=Salva +paused '@1' Autocrafter=Autocrafter di '@1' in pausa +Autocrafter=Autocrafter + +# NUOVE TRADUZIONI PER LA RISERVA: +Reserve: ON=Riserva: ON +Reserve: OFF=Riserva: OFF +Keep 1 item in slot to prevent other items from filling it.=Mantieni 1 pezzo nello slot per evitare che altri oggetti lo riempiano. + +## devices +Pump/Intake Module=Modulo Pompa/Aspirazione +Valve=Valvola +Decorative grating=Grata decorativa +Spigot outlet=Rubinetto di scarico +Airtight Pipe entry/exit=Ingresso/Uscita tubo ermetico +Flow Sensor=Sensore di flusso +Flow sensor (on)=Sensore di flusso (acceso) +empty=vuoto +@1% full=@1% pieno +Expansion Tank (@1)=Serbatoio di espansione (@1) +Fluid Storage Tank (@1)=Serbatoio di stoccaggio liquidi (@1) +Fountainhead=Sorgente a fontana +Straight-only Pipe=Tubo solo dritto + +## filter-injector +(slot #@1 next)=(slot #@1 successivo) +@1 Filter-Injector=Iniettore-Filtro @1 +Sequence slots by Priority=Sequenza slot per priorità +Sequence slots Randomly=Sequenza slot casuale +Sequence slots by Rotation=Sequenza slot per rotazione +Exact match - off=Corrispondenza esatta - OFF +Exact match - on=Corrispondenza esatta - ON +Prefer item types:=Preferisci tipi di oggetto: +Itemwise=Per oggetto +Stackwise=Per stack +Digiline=Digiline + +## routing tubes +Pneumatic tube segment=Segmento di tubo pneumatico +Broken Tube=Tubo rotto +High Priority Tube Segment=Segmento di tubo ad alta priorità +Accelerating Pneumatic Tube Segment=Segmento di tubo pneumatico acceleratore +Crossing Pneumatic Tube Segment=Segmento di tubo pneumatico a incrocio +One way tube=Tubo a senso unico + +## sorting tubes +Sorting Pneumatic Tube Segment=Segmento di tubo pneumatico di smistamento +Sorting pneumatic tube=Tubo pneumatico di smistamento + +## teleport tube +Receive=Ricevi +Channels are public by default=I canali sono pubblici per impostazione predefinita +Use : for fully private channels=Usa : per canali privati +Teleporting Pneumatic Tube Segment=Segmento di tubo pneumatico di teletrasporto +Teleporting Tube=Tubo di teletrasporto +Unconfigured Teleportation Tube=Tubo di teletrasporto non configurato + +## trashcan +Trash Can=Cestino dei rifiuti + +## vacuum tubes +Radius=Raggio +Vacuuming Pneumatic Tube Segment=Segmento di tubo pneumatico aspirante +Adjustable Vacuuming Tube=Tubo aspirante regolabile + +## wielder +Node Breaker=Rompiblocco +Deployer=Posizionatore +Dispenser=Dispenser diff --git a/locale/template.txt b/locale/template.txt index b9c5293..c03b825 100644 --- a/locale/template.txt +++ b/locale/template.txt @@ -21,6 +21,11 @@ unconfigured Autocrafter= Save= paused '@1' Autocrafter= Autocrafter= +# Reserve button: +Reserve: ON= +Reserve: OFF= + +Keep 1 item in slot to prevent other items from filling it.= ## compat-furnaces Allow splitting incoming material (not fuel) stacks from tubes= @@ -64,7 +69,6 @@ Auto-Tap= Pipe Segment= Pipe Segment (legacy)= - ## routing tubes Pneumatic tube segment= Broken Tube=