Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 78 additions & 43 deletions autocrafter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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]"
Expand All @@ -370,6 +391,7 @@ local function update_meta(meta, enabled)
end
end
end

local size = "10.2,14"
local fs =
"formspec_version[2]" ..
Expand All @@ -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) ..
Expand All @@ -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()
Expand Down Expand Up @@ -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)
Expand All @@ -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()
Expand All @@ -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)
Expand Down
86 changes: 86 additions & 0 deletions locale/pipeworks.it.tr
Original file line number Diff line number Diff line change
@@ -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 <player>:<channel> for fully private channels=Usa <giocatore>:<canale> 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
6 changes: 5 additions & 1 deletion locale/template.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -64,7 +69,6 @@ Auto-Tap=
Pipe Segment=
Pipe Segment (legacy)=


## routing tubes
Pneumatic tube segment=
Broken Tube=
Expand Down