From ceecfd187c93745ce2151a30d37932392e88c3dd Mon Sep 17 00:00:00 2001 From: mrkubax10 Date: Fri, 29 May 2026 23:24:13 +0200 Subject: [PATCH] Implement Sawmill --- api/common.lua | 1 + api/registration.lua | 7 ++ compatibility.lua | 2 + craftitems.lua | 2 + crafts.lua | 65 ++++++++++++++++ guide.lua | 39 +++++++++- init.lua | 1 + locale/industrialtest.pl.po | 18 ++++- locale/industrialtest.pot | 16 ++++ machines/sawmill.lua | 73 +++++++++++++++++ machines/simple_electric_item_processor.lua | 82 +++++++++++++++++--- textures/industrialtest_guide_sawmill.png | Bin 0 -> 7865 bytes 12 files changed, 294 insertions(+), 12 deletions(-) create mode 100644 machines/sawmill.lua create mode 100644 textures/industrialtest_guide_sawmill.png diff --git a/api/common.lua b/api/common.lua index 1ae7982..d242fc5 100644 --- a/api/common.lua +++ b/api/common.lua @@ -19,6 +19,7 @@ industrialtest.api={ compressorRecipes={}, extractorRecipes={}, cableFormerRecipes={}, + sawmillRecipeProviders={}, geothermalGeneratorFuels={}, waterMillFuels={}, rotaryMaceratorModifiers={}, diff --git a/api/registration.lua b/api/registration.lua index 02ab63c..5044dbd 100644 --- a/api/registration.lua +++ b/api/registration.lua @@ -200,6 +200,13 @@ function industrialtest.api.getCableFormerRecipeResult(recipe) return industrialtest.api.cableFormerRecipes[recipe] end +-- \brief Registers function which provides recipes for sawmill +-- \param provider function +-- \returns nil +function industrialtest.api.registerSawmillRecipeProvider(provider) + table.insert(industrialtest.api.sawmillRecipeProviders,provider) +end + -- \brief Registers fuel that can be used in geothermal generator -- \param fuel Table with following keys: , , -- which is a table containing items which are tables with following keys: , diff --git a/compatibility.lua b/compatibility.lua index f361247..dac5768 100644 --- a/compatibility.lua +++ b/compatibility.lua @@ -481,6 +481,7 @@ if industrialtest.mclAvailable then industrialtest.elementKeys.stick="mcl_core:stick" industrialtest.elementKeys.flint="mcl_core:flint" industrialtest.elementKeys.snowball="mcl_throwing:snowball" + industrialtest.elementKeys.torch="mcl_core:torch" industrialtest.elementKeys.snowBlock="mcl_core:snowblock" industrialtest.elementKeys.string="mcl_mobitems:string" industrialtest.elementKeys.junglePlanks="mcl_core:junglewood" @@ -724,6 +725,7 @@ elseif industrialtest.mtgAvailable then industrialtest.elementKeys.stick="default:stick" industrialtest.elementKeys.flint="default:flint" industrialtest.elementKeys.snowball="default:snow" + industrialtest.elementKeys.torch="default:torch" industrialtest.elementKeys.snowBlock="default:snowblock" industrialtest.elementKeys.blueDye="dye:blue" industrialtest.elementKeys.yellowDust="dye:yellow" diff --git a/craftitems.lua b/craftitems.lua index e37aade..0eb663d 100644 --- a/craftitems.lua +++ b/craftitems.lua @@ -474,6 +474,8 @@ industrialtest.api.registerCompressorRecipe({ recipe="industrialtest:hydrated_coal_dust" }) +industrialtest.api.registerResourceDust("saw","Saw",{},"#4c4007",false) + -- Plates industrialtest.api.registerPlate("bronze_plate",S("Bronze Plate"),{ { diff --git a/crafts.lua b/crafts.lua index 6875e64..a855470 100644 --- a/crafts.lua +++ b/crafts.lua @@ -75,6 +75,71 @@ if industrialtest.mclAvailable then }) end +-- Sawmill recipe providers +industrialtest.api.registerSawmillRecipeProvider(function(itemstack) + local srcAfter=ItemStack(itemstack:get_name()) + srcAfter:set_count(itemstack:get_count()-1) + if minetest.get_item_group(itemstack:get_name(),"tree")>0 then + local treeMapping={} + if industrialtest.mtgAvailable then + treeMapping={ + ["default:tree"]="default:wood", + ["default:jungletree"]="default:junglewood", + ["default:pine_tree"]="default:pine_wood", + ["default:acacia_tree"]="default:acacia_wood", + ["default:aspen_tree"]="default:aspen_wood" + } + elseif industrialtest.mclAvailable then + treeMapping={ + ["mcl_trees:tree_oak"]="mcl_trees:wood_oak", + ["mcl_trees:tree_dark_oak"]="mcl_trees:wood_dark_oak", + ["mcl_trees:tree_jungle"]="mcl_trees:wood_jungle", + ["mcl_trees:tree_spruce"]="mcl_trees:wood_spruce", + ["mcl_trees:tree_acacia"]="mcl_trees:wood_acacia", + ["mcl_trees:tree_birch"]="mcl_trees:wood_birch", + ["mcl_trees:bark_oak"]="mcl_trees:wood_oak", + ["mcl_trees:bark_dark_oak"]="mcl_trees:wood_dark_oak", + ["mcl_trees:bark_jungle"]="mcl_trees:wood_jungle", + ["mcl_trees:bark_spruce"]="mcl_trees:wood_spruce", + ["mcl_trees:bark_acacia"]="mcl_trees:wood_acacia", + ["mcl_trees:bark_birch"]="mcl_trees:wood_birch" + } + end + local woodNode=treeMapping[itemstack:get_name()] + if not woodNode then + return nil + end + return { + item={ + ItemStack(woodNode.." 5"), + ItemStack("industrialtest:saw_dust 2") + }, + time=3, + src=srcAfter + } + end + if minetest.get_item_group(itemstack:get_name(),"wood")>0 then + return { + item={ + ItemStack(industrialtest.elementKeys.stick.." 4"), + ItemStack("industrialtest:saw_dust 2") + }, + time=2, + src=srcAfter + } + end + return nil +end) + +minetest.register_craft({ + type="shaped", + output=industrialtest.elementKeys.torch.." 2", + recipe={ + {"industrialtest:saw_dust"}, + {industrialtest.elementKeys.stick} + } +}) + -- Geothermal Generator fuels industrialtest.api.registerGeothermalGeneratorFuel({ name=industrialtest.elementKeys.lavaSource, diff --git a/guide.lua b/guide.lua index 52d8a04..0101e46 100644 --- a/guide.lua +++ b/guide.lua @@ -909,6 +909,42 @@ local pages={ } }, + { + name="sawmill", + title=S("Sawmill"), + icon="industrialtest:sawmill", + content={ + [[ + ||Sawmill|| + + ||Sawmill allows for transforming wood into planks and planks into sticks more efficiently. The byproduct of wood cutting is the Saw Dust.|| + + ]], + createMachineInformationTable({ + { + name="inputVoltage", + value="LV" + }, + { + name="recipe", + value="Wood cutting" + }, + { + name="powerCapacity", + value=string.format("%d EU", industrialtest.Sawmill.capacity) + }, + { + name="opPower", + value=string.format("%d EU", industrialtest.Sawmill.opPower) + } + },S("Sawmill")), + [[ + + ||Picture 1. Sawmill cutting Oak Log.|| + ]] + } + }, + { name="solarPanels", title=S("Solar panels"), @@ -1946,7 +1982,8 @@ local function getGuideFormspec(playerName,pageName) elementKeyIronPickaxe=industrialtest.elementKeys.ironPickaxe, elementKeyStickyResin=industrialtest.elementKeys.stickyResin, elementKeyRubber=industrialtest.elementKeys.rubber, - elementKeyRubberWood=industrialtest.elementKeys.rubberWood + elementKeyRubberWood=industrialtest.elementKeys.rubberWood, + elementKeyWood=industrialtest.elementKeys.wood }) table.insert(formspec,string.format("hypertext[4.2,0.4;10.7,10.3;content;%s]",content)) break diff --git a/init.lua b/init.lua index adf4f66..2d37a07 100644 --- a/init.lua +++ b/init.lua @@ -66,6 +66,7 @@ dofile(modpath.."/machines/recycler.lua") dofile(modpath.."/machines/rotary_macerator.lua") dofile(modpath.."/machines/tool_workshop.lua") dofile(modpath.."/machines/transformer.lua") +dofile(modpath.."/machines/sawmill.lua") dofile(modpath.."/machines/solar_panel_generator.lua") dofile(modpath.."/machines/wind_mill.lua") diff --git a/locale/industrialtest.pl.po b/locale/industrialtest.pl.po index 66e93e7..06da49f 100644 --- a/locale/industrialtest.pl.po +++ b/locale/industrialtest.pl.po @@ -1459,4 +1459,20 @@ msgstr "Blok surowego irydu" #: minerals.lua:42, minerals.lua:101 msgid "Block of Iridium" -msgstr "Blok irydu" \ No newline at end of file +msgstr "Blok irydu" + +#: machines/sawmill.lua:20, guide.lua:914, guide.lua:918, guide.lua:940 +msgid "Sawmill" +msgstr "Tartak" + +#: craftitems.lua:477 +msgid "Saw Dust" +msgstr "Trociny" + +#: guide.lua.920 +msgid "Sawmill allows for transforming wood into planks and planks into sticks more efficiently. The byproduct of wood cutting is the Saw Dust." +msgstr "Tartak pozwala na bardziej efektywne przetwarzanie drewna w deski i desek w patyki. Produktem ubocznym cięcia drewna są Trociny." + +#: guide.lua:943 +msgid "Picture 1. Sawmill cutting Oak Log." +msgstr "Obraz 1. Tartak tnący Dębowy pień." diff --git a/locale/industrialtest.pot b/locale/industrialtest.pot index a605088..dd6c421 100644 --- a/locale/industrialtest.pot +++ b/locale/industrialtest.pot @@ -1460,3 +1460,19 @@ msgstr "" #: minerals.lua:42, minerals.lua:101 msgid "Block of Iridium" msgstr "" + +#: machines/sawmill.lua:20, guide.lua:914, guide.lua:918, guide.lua:940 +msgid "Sawmill" +msgstr "" + +#: craftitems.lua:477 +msgid "Saw Dust" +msgstr "" + +#: guide.lua.920 +msgid "Sawmill allows for transforming wood into planks and planks into sticks more efficiently. The byproduct of wood cutting is the Saw Dust." +msgstr "" + +#: guide.lua:943 +msgid "Picture 1. Sawmill cutting Oak Log." +msgstr "" diff --git a/machines/sawmill.lua b/machines/sawmill.lua new file mode 100644 index 0000000..74d1753 --- /dev/null +++ b/machines/sawmill.lua @@ -0,0 +1,73 @@ +-- IndustrialTest +-- Copyright (C) 2026 mrkubax10 + +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +local S=minetest.get_translator("industrialtest") +industrialtest.Sawmill=industrialtest.internal.derive(industrialtest.SimpleElectricItemProcessor,{ + name="industrialtest:sawmill", + description=S("Sawmill"), + tiles={ + "industrialtest_machine_block.png", + "industrialtest_machine_block.png", + "industrialtest_machine_block.png", + "industrialtest_machine_block.png", + "industrialtest_machine_block.png", + "industrialtest_machine_block.png^industrialtest_sawmill_front.png" + }, + requiresWrench=true, + active={ + tiles={ + "industrialtest_machine_block.png", + "industrialtest_machine_block.png", + "industrialtest_machine_block.png", + "industrialtest_machine_block.png", + "industrialtest_machine_block.png", + "industrialtest_machine_block.png^industrialtest_sawmill_front_active.png" + } + }, + suplStorageLists={ + "sawdust" + }, + capacity=industrialtest.api.lvPowerFlow*2, + flow=industrialtest.api.lvPowerFlow, + opPower=50, + efficiency=0.5 +}) + +function industrialtest.Sawmill.getCraftResult(self,itemstack) + for _,provider in ipairs(industrialtest.api.sawmillRecipeProviders) do + local result=provider(itemstack) + if result then + return result + end + end + return { + item="", + time=0, + src=ItemStack(itemstack:get_name()) + } +end + +industrialtest.Sawmill:register() + +minetest.register_craft({ + type="shaped", + output="industrialtest:sawmill", + recipe={ + {"",industrialtest.elementKeys.ironIngot,""}, + {industrialtest.elementKeys.stick,"industrialtest:machine_block",industrialtest.elementKeys.stick}, + {industrialtest.elementKeys.tinIngot,"industrialtest:electronic_circuit",industrialtest.elementKeys.tinIngot} + } +}) diff --git a/machines/simple_electric_item_processor.lua b/machines/simple_electric_item_processor.lua index 5983b15..75dfda7 100644 --- a/machines/simple_electric_item_processor.lua +++ b/machines/simple_electric_item_processor.lua @@ -40,6 +40,11 @@ function industrialtest.SimpleElectricItemProcessor.onConstruct(self,pos) local inv=meta:get_inventory() inv:set_size("src",1) inv:set_size("dst",1) + if self.suplStorageLists then + for _,list in ipairs(self.suplStorageLists) do + inv:set_size(list,1) + end + end inv:set_size("powerStorage",1) inv:set_size("upgrades",4) meta:set_float("srcTime",-1) @@ -65,6 +70,7 @@ function industrialtest.SimpleElectricItemProcessor.getFormspec(self,pos) or "image[4.9,2.8;1,1;gui_furnace_arrow_bg.png^[transformR270]"), industrialtest.internal.getItemSlotBg(6.4,2.8,1,1), "list[context;dst;6.4,2.8;1,1]", + self:getSuplStorageFormspec(), industrialtest.internal.getItemSlotBg(9,0.9,1,4), "list[context;upgrades;9,0.9;1,4]", "listring[context;src]", @@ -105,8 +111,15 @@ function industrialtest.SimpleElectricItemProcessor.onMetadataInventoryMove(self meta:set_float("srcTime",-1) meta:set_float("maxSrcTime",0) self:updateFormspec(pos) - elseif fromList=="dst" and dstSlot:get_free_space()>0 then - self:triggerIfNeeded(pos) + end + local outputLists=self:getOutputLists() + for _,outputList in ipairs(outputLists) do + if outputList==fromList then + local slot=inv:get_stack(outputList,1) + if slot:get_free_space()>0 then + self:triggerIfNeeded(pos) + end + end end end @@ -120,13 +133,19 @@ function industrialtest.SimpleElectricItemProcessor.onMetadataInventoryTake(self local meta=minetest.get_meta(pos) local inv=meta:get_inventory() local srcSlot=inv:get_stack("src",1) - local dstSlot=inv:get_stack("dst",1) if listname=="src" and srcSlot:is_empty() then meta:set_float("srcTime",-1) meta:set_float("maxSrcTime",0) self:updateFormspec(pos) - elseif listname=="dst" and dstSlot:get_free_space()>0 then - self:triggerIfNeeded(pos) + end + local outputLists=self:getOutputLists() + for _,outputList in ipairs(outputLists) do + if outputList==listname then + local slot=inv:get_stack(outputList,1) + if slot:get_free_space()>0 then + self:triggerIfNeeded(pos) + end + end end end @@ -152,7 +171,7 @@ function industrialtest.SimpleElectricItemProcessor.shouldActivate(self,pos) local srcSlot=inv:get_stack("src",1) if srcSlot:get_count()>0 then local output=self:getCraftResult(srcSlot) - return output and output.time>0 and inv:room_for_item("dst",output.item) + return output and output.time>0 and self:roomForOutput(inv,output.item) end return meta:contains("recipeOverride") and meta:contains("recipeOverrideMaxTime") and meta:get_string("recipeOverride")~="" @@ -178,7 +197,7 @@ function industrialtest.SimpleElectricItemProcessor.shouldDeactivate(self,pos) end local output=self:getCraftResult(srcSlot) - return not output or output.time==0 or not inv:room_for_item("dst",output.item) + return not output or output.time==0 or not self:roomForOutput(inv,output.item) end function industrialtest.SimpleElectricItemProcessor.activeUpdate(self,pos,elapsed,meta,inv) @@ -219,9 +238,16 @@ function industrialtest.SimpleElectricItemProcessor.activeUpdate(self,pos,elapse if srcSlot:get_count()>=speed*usedItems then multiplier=speed end - if output.item:get_count()>0 then - output.item:set_count(output.item:get_count()*multiplier) - inv:add_item("dst",output.item) + local outputs=type(output.item)=="userdata" and {output.item} or output.item + local lists=self:getOutputLists() + for i,output in ipairs(outputs) do + if i>#lists then + break + end + if output:get_count()>0 then + output:set_count(output:get_count()*multiplier) + inv:add_item(lists[i],output) + end end srcSlot:set_count(srcSlot:get_count()-multiplier*usedItems) inv:set_stack("src",1,srcSlot) @@ -233,6 +259,42 @@ function industrialtest.SimpleElectricItemProcessor.activeUpdate(self,pos,elapse return true end +function industrialtest.SimpleElectricItemProcessor.getOutputLists(self) + local lists=table.copy(self.suplStorageLists) + table.insert(lists,1,"dst") + return lists +end + +function industrialtest.SimpleElectricItemProcessor.getSuplStorageFormspec(self) + if not self.suplStorageLists then + return "" + end + local formspec={} + local slotY=2.8 + for i,list in ipairs(self.suplStorageLists) do + local slotX=6.4+i+i*0.1 + table.insert(formspec,industrialtest.internal.getItemSlotBg(slotX,slotY,1,1)) + table.insert(formspec,string.format("list[context;%s;%f,%f;1,1]",list,slotX,slotY)) + end + return table.concat(formspec,"") +end + +function industrialtest.SimpleElectricItemProcessor.roomForOutput(self,inv,outputItem) + if type(outputItem)=="userdata" then + return inv:room_for_item("dst",outputItem) + end + local lists=self:getOutputLists() + for i,itemstack in ipairs(outputItem) do + if i>#lists then + return false + end + if not inv:room_for_item(lists[i],itemstack) then + return false + end + end + return true +end + function industrialtest.SimpleElectricItemProcessor.isRecipeOverride(meta) if meta:contains("recipeOverride") and meta:contains("recipeOverrideMaxTime") and meta:get_string("recipeOverride")~="" then return meta:get_string("recipeOverride") diff --git a/textures/industrialtest_guide_sawmill.png b/textures/industrialtest_guide_sawmill.png new file mode 100644 index 0000000000000000000000000000000000000000..12d82fccadc3cf5ffa3f1a36fcf343e53bb1b0ba GIT binary patch literal 7865 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 M*qGOzz4_CB16IRbP5=M^ literal 0 HcmV?d00001