Merge branch 'master' into xno_tree_trap
21 files added
8 files renamed
48 files modified
106 files deleted
| | |
| | | unused_args = false |
| | | allow_defined_top = true |
| | | max_line_length = 999 |
| | | max_line_length = 150 |
| | | -- Allow shadowed variables (callbacks in callbacks) |
| | | redefined = false |
| | | |
| | | globals = { |
| | | "technic", "minetest", |
| | |
| | | "craftguide", "i3" |
| | | } |
| | | |
| | | files["concrete/init.lua"].ignore = { "steel_ingot" } |
| | | files["technic/machines/MV/tool_workshop.lua"].ignore = { "pos" } |
| | | files["technic/machines/other/frames.lua"].ignore = { "item_texture", "item_type", "adj", "connected", "" } |
| | | files["technic/machines/register/battery_box.lua"].ignore = { "pos", "tube_upgrade" } |
| | | files["technic/machines/register/cables.lua"].ignore = { "name", "from_below", "p" } |
| | | files["technic/machines/register/common.lua"].ignore = { "result" } |
| | | |
| | | files["technic/machines/register/generator.lua"].ignore = { "node" } |
| | | files["technic/machines/switching_station.lua"].ignore = { "pos1", "tier", "poshash" } |
| | | files["technic/radiation.lua"].ignore = { "LAVA_VISC" } |
| | | files["technic/tools/chainsaw.lua"].ignore = { "pos" } |
| | | files["technic/tools/mining_drill.lua"].ignore = { "mode" } |
| | | files["technic_chests/register.lua"].ignore = { "fs_helpers", "name", "locked_after_place" } |
| | | |
| | | files["technic_cnc/cnc.lua"].ignore = { "multiplier" } |
| | | files["wrench/init.lua"].ignore = { "name", "stack" } |
| | | -- Loop warning |
| | | files["technic/machines/other/frames.lua"].ignore = { "" } |
| | | -- Long lines |
| | | files["technic_cnc/cnc_api.lua"].ignore = { "" } |
New file |
| | |
| | | Minetest Mod: technic |
| | | Copyright (C) 2012-2022 RealBadAngel and contributors |
| | | |
| | | This library is free software; you can redistribute it and/or |
| | | modify it under the terms of the GNU Lesser General Public |
| | | License as published by the Free Software Foundation; either |
| | | version 2.1 of the License, or (at your option) any later version. |
| | | |
| | | This library 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 |
| | | Lesser General Public License for more details. |
| | | |
| | | You should have received a copy of the GNU Lesser General Public |
| | | License along with this library; if not, write to the Free Software |
| | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | |
| | | * Minetest 5.0.0 or newer |
| | | * [Minetest Game](https://github.com/minetest/minetest_game/) |
| | | * [mesecons](https://github.com/minetest-mods/mesecons) -> signalling events |
| | | * [pipeworks](https://gitlab.com/VanessaE/pipeworks/) -> automation of item transport |
| | | * [pipeworks](https://github.com/mt-mods/pipeworks) -> automation of item transport |
| | | * [moreores](https://github.com/minetest-mods/moreores/) -> additional ores |
| | | * [basic_materials](https://gitlab.com/VanessaE/basic_materials) -> basic craft items |
| | | * Supports [moretrees](https://gitlab.com/VanessaE/moretrees) -> rubber trees |
| | | * [basic_materials](https://github.com/mt-mods/basic_materials) -> basic craft items |
| | | * Supports [moretrees](https://github.com/mt-mods/moretrees) -> rubber trees |
| | | * Consult `depends.txt` or `mod.conf` of each mod for further dependency information. |
| | | |
| | | |
| | | ## FAQ |
| | | |
| | | The modpack is explained in the [Manual](manual.md) included in this repository. |
| | | The modpack is explained in the **[Manual](manual.md)** included in this repository. |
| | | Machine and tool descriptions can be found on the **[GitHub Wiki](https://github.com/minetest-mods/technic/wiki)**. |
| | | |
| | | 1. My technic circuit doesn't work. No power is distributed. |
| | | * Make sure you have a switching station connected. |
| | |
| | | * Each machine type requires its own cable type. If you do not have a |
| | | matching circuit, consider using a "Supply Converter" for simplicity. |
| | | |
| | | The API documentation can be found here: [Technic API](technic/doc/api.md) |
| | | For modders: **[Technic Lua API](technic/doc/api.md)** |
| | | |
| | | |
| | | ## License |
| | | |
| | | Unless otherwise stated, all components of this modpack are licensed under the |
| | | LGPLv2 or later. See also the individual mod folders for their |
| | | [LGPLv2 or later](LICENSE.txt). See also the individual mod folders for their |
| | | secondary/alternate licenses, if any. |
| | | |
| | | |
| | |
| | | "technic:concrete_post_with_platform") |
| | | end |
| | | |
| | | local steel_ingot |
| | | if minetest.get_modpath("technic_worldgen") then |
| | | steel_ingot = "technic:carbon_steel_ingot" |
| | | else |
| | | steel_ingot = "default:steel_ingot" |
| | | end |
| | | |
| | | minetest.register_craft({ |
| | | output = 'technic:concrete_post_platform 6', |
| | | recipe = { |
New file |
| | |
| | | # technic_concrete japanese translation |
| | | # technic_concreteの日本語への翻訳 |
| | | # by damiemk |
| | | |
| | | Rebar = 鉄筋 |
| | | Concrete Block = コンクリートのブロック |
| | | Blast-resistant Concrete Block = 耐爆性コンクリートのブロック |
| | | Concrete Post Platform = コンクリートのプラットフォーム |
| | | Concrete Post = コンクリートポスト |
| | |
| | | tiles={"technic_granite.png"}, |
| | | }) |
| | | |
| | | stairsplus:register_all("technic", "granite_bricks", "technic:granite_bricks", { |
| | | description=S("Granite Bricks"), |
| | | groups={cracky=1, not_in_creative_inventory=1}, |
| | | tiles={"technic_granite_bricks.png"}, |
| | | }) |
| | | |
| | | stairsplus:register_all("technic", "concrete", "technic:concrete", { |
| | | description=S("Concrete"), |
| | | groups={cracky=3, not_in_creative_inventory=1}, |
| | |
| | | tiles={"technic_stainless_steel_block.png"}, |
| | | }) |
| | | |
| | | function register_technic_stairs_alias(modname, origname, newmod, newname) |
| | | minetest.register_alias(modname .. ":slab_" .. origname, newmod..":slab_" .. newname) |
| | | minetest.register_alias(modname .. ":slab_" .. origname .. "_inverted", newmod..":slab_" .. newname .. "_inverted") |
| | | minetest.register_alias(modname .. ":slab_" .. origname .. "_wall", newmod..":slab_" .. newname .. "_wall") |
| | | minetest.register_alias(modname .. ":slab_" .. origname .. "_quarter", newmod..":slab_" .. newname .. "_quarter") |
| | | minetest.register_alias(modname .. ":slab_" .. origname .. "_quarter_inverted", newmod..":slab_" .. newname .. "_quarter_inverted") |
| | | minetest.register_alias(modname .. ":slab_" .. origname .. "_quarter_wall", newmod..":slab_" .. newname .. "_quarter_wall") |
| | | minetest.register_alias(modname .. ":slab_" .. origname .. "_three_quarter", newmod..":slab_" .. newname .. "_three_quarter") |
| | | minetest.register_alias(modname .. ":slab_" .. origname .. "_three_quarter_inverted", newmod..":slab_" .. newname .. "_three_quarter_inverted") |
| | | minetest.register_alias(modname .. ":slab_" .. origname .. "_three_quarter_wall", newmod..":slab_" .. newname .. "_three_quarter_wall") |
| | | minetest.register_alias(modname .. ":stair_" .. origname, newmod..":stair_" .. newname) |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_inverted", newmod..":stair_" .. newname .. "_inverted") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_wall", newmod..":stair_" .. newname .. "_wall") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_wall_half", newmod..":stair_" .. newname .. "_wall_half") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_wall_half_inverted", newmod..":stair_" .. newname .. "_wall_half_inverted") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_half", newmod..":stair_" .. newname .. "_half") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_half_inverted", newmod..":stair_" .. newname .. "_half_inverted") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_right_half", newmod..":stair_" .. newname .. "_right_half") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_right_half_inverted", newmod..":stair_" .. newname .. "_right_half_inverted") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_wall_half", newmod..":stair_" .. newname .. "_wall_half") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_wall_half_inverted", newmod..":stair_" .. newname .. "_wall_half_inverted") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_inner", newmod..":stair_" .. newname .. "_inner") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_inner_inverted", newmod..":stair_" .. newname .. "_inner_inverted") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_outer", newmod..":stair_" .. newname .. "_outer") |
| | | minetest.register_alias(modname .. ":stair_" .. origname .. "_outer_inverted", newmod..":stair_" .. newname .. "_outer_inverted") |
| | | minetest.register_alias(modname .. ":panel_" .. origname .. "_bottom", newmod..":panel_" .. newname .. "_bottom") |
| | | minetest.register_alias(modname .. ":panel_" .. origname .. "_top", newmod..":panel_" .. newname .. "_top") |
| | | minetest.register_alias(modname .. ":panel_" .. origname .. "_vertical", newmod..":panel_" .. newname .. "_vertical") |
| | | minetest.register_alias(modname .. ":micro_" .. origname .. "_bottom", newmod..":micro_" .. newname .. "_bottom") |
| | | minetest.register_alias(modname .. ":micro_" .. origname .. "_top", newmod..":micro_" .. newname .. "_top") |
| | | function register_technic_stairs_alias(origmod, origname, newmod, newname) |
| | | local func = minetest.register_alias |
| | | local function remap(kind, suffix) |
| | | -- Old: stairsplus:slab_concrete_wall |
| | | -- New: technic:slab_concrete_wall |
| | | func(("%s:%s_%s%s"):format(origmod, kind, origname, suffix), |
| | | ("%s:%s_%s%s"):format(newmod, kind, newname, suffix)) |
| | | end |
| | | |
| | | -- Slabs |
| | | remap("slab", "") |
| | | remap("slab", "_inverted") |
| | | remap("slab", "_wall") |
| | | remap("slab", "_quarter") |
| | | remap("slab", "_quarter_inverted") |
| | | remap("slab", "_quarter_wall") |
| | | remap("slab", "_three_quarter") |
| | | remap("slab", "_three_quarter_inverted") |
| | | remap("slab", "_three_quarter_wall") |
| | | |
| | | -- Stairs |
| | | remap("stair", "") |
| | | remap("stair", "_inverted") |
| | | remap("stair", "_wall") |
| | | remap("stair", "_wall_half") |
| | | remap("stair", "_wall_half_inverted") |
| | | remap("stair", "_half") |
| | | remap("stair", "_half_inverted") |
| | | remap("stair", "_right_half") |
| | | remap("stair", "_right_half_inverted") |
| | | remap("stair", "_inner") |
| | | remap("stair", "_inner_inverted") |
| | | remap("stair", "_outer") |
| | | remap("stair", "_outer_inverted") |
| | | |
| | | -- Other |
| | | remap("panel", "_bottom") |
| | | remap("panel", "_top") |
| | | remap("panel", "_vertical") |
| | | remap("micro", "_bottom") |
| | | remap("micro", "_top") |
| | | end |
| | | |
| | | register_technic_stairs_alias("stairsplus", "concrete", "technic", "concrete") |
New file |
| | |
| | | # technic_extranodes japanese translation |
| | | # technic_extranodesの日本語への翻訳 |
| | | # by damiemk |
| | | |
| | | Marble = 大理石 |
| | | Marble Bricks = 大理石のレンガ |
| | | Granite = 花崗岩 |
| | | Concrete = コンクリート |
| | |
| | | |
| | | * [Minetest Game Documentation](https://wiki.minetest.net/Main_Page) |
| | | * [Mesecons Documentation](http://mesecons.net/items.html) |
| | | * [Pipeworks Documentation](https://gitlab.com/VanessaE/pipeworks/-/wikis/home) |
| | | * [Pipeworks Documentation](https://github.com/mt-mods/pipeworks/wiki/) |
| | | * [Moreores Forum Post](https://forum.minetest.net/viewtopic.php?t=549) |
| | | * [Basic materials Repository](https://gitlab.com/VanessaE/basic_materials) |
| | | |
| | | ## Recipes |
| | | ## 1.0 Recipes |
| | | |
| | | Recipes for items registered by technic are not specifically documented here. |
| | | Please consult a craft guide mod to look up the recipes in-game. |
| | | |
| | | **Recommended mod:** [Unified Inventory](https://github.com/minetest-mods/unified_inventory) |
| | | |
| | | ## Substances |
| | | ## 2.0 Substances |
| | | |
| | | ### Ores |
| | | ### 2.1 Ores |
| | | |
| | | Technic registers a few ores which are needed to craft machines or items. |
| | | Each ore type is found at a specific range of elevations so you will |
| | |
| | | |
| | | Note ²: *These ores are provided by moreores. TODO: Add reference link* |
| | | |
| | | #### Chromium |
| | | Use: stainless steel |
| | | |
| | | Generated below: -100m, more commonly below -200m |
| | | |
| | | #### Coal ¹ |
| | | Use: Fuel, alloy as carbon |
| | | |
| | |
| | | usually in dust form, as an ingredient in alloying recipes, wherever |
| | | elemental carbon is required. |
| | | |
| | | #### Iron ¹ |
| | | Use: multiple, mainly for alloys with carbon (coal). |
| | | |
| | | #### Copper ¹ |
| | | Copper is a common metal, used either on its own for its electrical |
| | | conductivity, or as the base component of alloys. |
| | | Although common, it is very heavily used, and most of the time it will |
| | | be the material that most limits your activity. |
| | | |
| | | #### Diamond ¹ |
| | | Use: mainly for cutting machines |
| | | |
| | | Diamond is a precious gemstone. It is used moderately, mainly for reasons |
| | | connected to its extreme hardness. |
| | | |
| | | #### Gold ¹ |
| | | Use: various |
| | | |
| | | Generated below: -64m, more commonly below -256m |
| | | |
| | | Gold is a precious metal. It is most notably used in electrical items due to |
| | | its combination of good conductivity and corrosion resistance. |
| | | |
| | | #### Iron ¹ |
| | | Use: multiple, mainly for alloys with carbon (coal). |
| | | |
| | | #### Lead |
| | | Use: batteries, HV nuclear reactor layout |
| | | |
| | | Generated below: 16m, more common below -128m |
| | | |
| | | #### Mese ¹ |
| | | Use: various |
| | | |
| | | Mese is a precious gemstone, and unlike diamond it is entirely fictional. |
| | | It is used in small quantities, wherever some magic needs to be imparted. |
| | | |
| | | #### Mithril ² |
| | | Use: chests |
| | | |
| | | Generated below: -512m, evenly common |
| | | |
| | | Mithril is a fictional ore, being derived from J. R. R. Tolkien's |
| | | Middle-Earth setting. It is little used. |
| | | |
| | | #### Silver ² |
| | | Use: conductors |
| | | |
| | | Generated below: -2m, evenly common |
| | | |
| | | Silver is a semi-precious metal and is the best conductor of all the pure elements. |
| | | |
| | | #### Tin ¹ |
| | | Use: batteries, bronze |
| | | |
| | | Tin is a common metal but is used rarely. Its abundance is well in excess |
| | | of its usage, so you will usually have a surplus of it. |
| | | |
| | | #### Zinc |
| | | Use: brass |
| | | |
| | | Depth: 2m, more commonly below -32m |
| | | |
| | | Zinc only has a few uses but is a common metal. |
| | | |
| | | #### Chromium |
| | | Use: stainless steel |
| | | |
| | | Depth: -100m, more commonly below -200m |
| | | |
| | | #### Uranium |
| | | Use: nuclear reactor fuel |
| | |
| | | |
| | | Keep a safety distance of a meter to avoid being harmed by radiation. |
| | | |
| | | #### Silver ² |
| | | Use: conductors |
| | | #### Zinc |
| | | Use: brass |
| | | |
| | | Depth: -2m, evenly common |
| | | Generated below: 2m, more commonly below -32m |
| | | |
| | | Silver is a semi-precious metal and is the best conductor of all the pure elements. |
| | | Zinc only has a few uses but is a common metal. |
| | | |
| | | #### Gold ¹ |
| | | Use: various |
| | | |
| | | Depth: -64m, more commonly below -256m |
| | | |
| | | Gold is a precious metal. It is most notably used in electrical items due to |
| | | its combination of good conductivity and corrosion resistance. |
| | | |
| | | #### Mithril ² |
| | | Use: chests |
| | | |
| | | Depth: -512m, evenly common |
| | | |
| | | Mithril is a fictional ore, being derived from J. R. R. Tolkien's |
| | | Middle-Earth setting. It is little used. |
| | | |
| | | #### Mese ¹ |
| | | Use: various |
| | | |
| | | Mese is a precious gemstone, and unlike diamond it is entirely fictional. |
| | | It is used in small quantities, wherever some magic needs to be imparted. |
| | | |
| | | #### Diamond ¹ |
| | | Use: mainly for cutting machines |
| | | |
| | | Diamond is a precious gemstone. It is used moderately, mainly for reasons |
| | | connected to its extreme hardness. |
| | | |
| | | ### Rocks |
| | | ### 2.2 Rocks |
| | | |
| | | This section describes the rock types added by technic. Further rock types |
| | | are supported by technic machines. These can be processed using the grinder: |
| | |
| | | stone. It has mainly decorative use, but also appears in a couple of |
| | | machine recipes. |
| | | |
| | | ### Rubber |
| | | #### Sulfur |
| | | Uses: battery box |
| | | |
| | | Sulur is generated around some lava patches (caves). |
| | | |
| | | |
| | | ### 2.3 Rubber |
| | | Rubber is a biologically-derived material that has industrial uses due |
| | | to its electrical resistivity and its impermeability. In technic, it |
| | | is used in a few recipes, and it must be acquired by tapping rubber trees. |
| | |
| | | |
| | | To obtain rubber from latex, alloy latex with coal dust. |
| | | |
| | | ### Metals |
| | | ## 3.0 Metal processing |
| | | Generally, each metal can exist in five forms: |
| | | |
| | | * ore -> stone containing the lump |
| | |
| | | Metals can be converted between dust, ingot and block, but can't be converted |
| | | from them back to ore or lump forms. |
| | | |
| | | #### Grinding |
| | | ### Grinding |
| | | Ores can be processed as follows: |
| | | |
| | | * ore -> lump (digging) -> ingot (melting) |
| | |
| | | At the expense of some energy consumption, the grinder can extract more material |
| | | from the lump, resulting in 2x dust which can be melted to two ingots in total. |
| | | |
| | | #### Alloying |
| | | Alloying recipes in which a metal is the base ingredient, to produce a |
| | | metal alloy, always come in two forms, using the metal either as dust |
| | | or as an ingot. If the secondary ingredient is also a metal, it must |
| | | be supplied in the same form as the base ingredient. The output alloy |
| | | is also returned in the same form. |
| | | ### Alloying |
| | | Input: two ingredients of the same form - lump or dust |
| | | |
| | | Example: 2x copper ingots + zinc ingot -> 3x brass ingot (alloying) |
| | | Output: resulting alloy, as an ingot |
| | | |
| | | The same will also work for dust ingredients, resulting in brass dist. |
| | | Example: 2x copper ingots + 1x zinc ingot -> 3x brass ingot (alloying) |
| | | |
| | | ### iron and its alloys ### |
| | | Note that grinding before alloying is the preferred method to gain more output. |
| | | |
| | | Iron forms several important alloys. In real-life history, iron was the |
| | | second metal to be used as the base component of deliberately-constructed |
| | | alloys (the first was copper), and it was the first metal whose working |
| | | required processes of any metallurgical sophistication. The game |
| | | mechanics around iron broadly imitate the historical progression of |
| | | processes around it, rather than the less-varied modern processes. |
| | | #### iron and its alloys |
| | | |
| | | The two-component alloying system of iron with carbon is of huge |
| | | importance, both in the game and in real life. The basic Minetest game |
| | | doesn't distinguish between these pure iron and these alloys at all, |
| | | but technic introduces a distinction based on the carbon content, and |
| | | renames some items of the basic game accordingly. |
| | | Historically iron was the first metal whose working required processes of any |
| | | metallurgical sophistication. The mod's mechanics around iron broadly imitate |
| | | the historical progression of processes around it to get more variety. |
| | | |
| | | The iron/carbon spectrum is represented in the game by three metal |
| | | substances: wrought iron, carbon steel, and cast iron. Wrought iron |
| | | has low carbon content (less than 0.25%), resists shattering, and |
| | | is easily welded, but is relatively soft and susceptible to rusting. |
| | | In real-life history it was used for rails, gates, chains, wire, pipes, |
| | | fasteners, and other purposes. Cast iron has high carbon content |
| | | (2.1% to 4%), is especially hard, and resists corrosion, but is |
| | | relatively brittle, and difficult to work. Historically it was used |
| | | to build large structures such as bridges, and for cannons, cookware, |
| | | and engine cylinders. Carbon steel has medium carbon content (0.25% |
| | | to 2.1%), and intermediate properties: moderately hard and also tough, |
| | | somewhat resistant to corrosion. In real life it is now used for most |
| | | of the purposes previously satisfied by wrought iron and many of those |
| | | of cast iron, but has historically been especially important for its |
| | | use in swords, armor, skyscrapers, large bridges, and machines. |
| | | Notable alloys: |
| | | |
| | | In real-life history, the first form of iron to be refined was |
| | | wrought iron, which is nearly pure iron, having low carbon content. |
| | | It was produced from ore by a low-temperature furnace process (the |
| | | "bloomery") in which the ore/iron remains solid and impurities (slag) |
| | | are progressively removed by hammering ("working", hence "wrought"). |
| | | This began in the middle East, around 1800 BCE. |
| | | * Wrought iron: <0.25% carbon |
| | | * Resists shattering but is relatively soft. |
| | | * Known since: 1800 BC (approx.) |
| | | * Cast iron: 2.1% to 4% carbon. |
| | | * Especially hard and rather corrosion-resistant |
| | | * Known since: 1200 BC (approx.) |
| | | * Carbon steel: 0.25% to 2.1% carbon. |
| | | * Intermediate of the two above. |
| | | * Known since: 1600 AD (approx.) |
| | | |
| | | Historically, the next forms of iron to be refined were those of high |
| | | carbon content. This was the result of the development of a more |
| | | sophisticated kind of furnace, the blast furnace, capable of reaching |
| | | higher temperatures. The real advantage of the blast furnace is that it |
| | | melts the metal, allowing it to be cast straight into a shape supplied by |
| | | a mould, rather than having to be gradually beaten into the desired shape. |
| | | A side effect of the blast furnace is that carbon from the furnace's fuel |
| | | is unavoidably incorporated into the metal. Normally iron is processed |
| | | twice through the blast furnace: once producing "pig iron", which has |
| | | very high carbon content and lots of impurities but lower melting point, |
| | | casting it into rough ingots, then remelting the pig iron and casting it |
| | | into the final moulds. The result is called "cast iron". Pig iron was |
| | | first produced in China around 1200 BCE, and cast iron later in the 5th |
| | | century BCE. Incidentally, the Chinese did not have the bloomery process, |
| | | so this was their first iron refining process, and, unlike the rest of |
| | | the world, their first wrought iron was made from pig iron rather than |
| | | directly from ore. |
| | | Technic introduces a distinction based on the carbon content, and renames some |
| | | items of the basic game accordingly. Iron and Steel are now distinguished. |
| | | |
| | | Carbon steel, with intermediate carbon content, was developed much later, |
| | | in Europe in the 17th century CE. It required a more sophisticated |
| | | process, because the blast furnace made it extremely difficult to achieve |
| | | a controlled carbon content. Tweaks of the blast furnace would sometimes |
| | | produce an intermediate carbon content by luck, but the first processes to |
| | | reliably produce steel were based on removing almost all the carbon from |
| | | pig iron and then explicitly mixing a controlled amount of carbon back in. |
| | | Notable references: |
| | | |
| | | In the game, the bloomery process is represented by ordinary cooking |
| | | or grinding of an iron lump. The lump represents unprocessed ore, |
| | | and is identified only as "iron", not specifically as wrought iron. |
| | | This standard refining process produces dust or an ingot which is |
| | | specifically identified as wrought iron. Thus the standard refining |
| | | process produces the (nearly) pure metal. |
| | | * https://en.wikipedia.org/wiki/Iron |
| | | * https://en.wikipedia.org/wiki/Stainless_steel |
| | | * ... plus many more. |
| | | |
| | | Cast iron is trickier. You might expect from the real-life notes above |
| | | that cooking an iron lump (representing ore) would produce pig iron that |
| | | can then be cooked again to produce cast iron. This is kind of the case, |
| | | but not exactly, because as already noted cooking an iron lump produces |
| | | wrought iron. The game doesn't distinguish between low-temperature |
| | | and high-temperature cooking processes: the same furnace is used not |
| | | just to cast all kinds of metal but also to cook food. So there is no |
| | | distinction between cooking processes to produce distinct wrought iron |
| | | and pig iron. But repeated cooking *is* available as a game mechanic, |
| | | and is indeed used to produce cast iron: re-cooking a wrought iron ingot |
| | | produces a cast iron ingot. So pig iron isn't represented in the game as |
| | | a distinct item; instead wrought iron stands in for pig iron in addition |
| | | to its realistic uses as wrought iron. |
| | | Processes: |
| | | |
| | | Carbon steel is produced by a more regular in-game process: alloying |
| | | wrought iron with coal dust (which is essentially carbon). This bears |
| | | a fair resemblance to the historical development of carbon steel. |
| | | This alloying recipe is relatively time-consuming for the amount of |
| | | material processed, when compared against other alloying recipes, and |
| | | carbon steel is heavily used, so it is wise to alloy it in advance, |
| | | when you're not waiting for it. |
| | | * Iron -> Wrought iron (melting) |
| | | * Wrought iron -> Cast iron (melting) |
| | | * Wrought iron + coal dust -> Carbon steel (alloying) |
| | | * Carbon steel + coal dust -> Cast iron (alloying) |
| | | * Carbon steel + chromium -> Stainless steel (alloying) |
| | | |
| | | There are additional recipes that permit all three of these types of iron |
| | | to be converted into each other. Alloying carbon steel again with coal |
| | | dust produces cast iron, with its higher carbon content. Cooking carbon |
| | | steel or cast iron produces wrought iron, in an abbreviated form of the |
| | | bloomery process. |
| | | Reversible processes: |
| | | |
| | | There's one more iron alloy in the game: stainless steel. It is managed |
| | | in a completely regular manner, created by alloying carbon steel with |
| | | chromium. |
| | | * Cast iron -> Wrought iron (melting) |
| | | * Carbon steel -> Wrought iron (melting) |
| | | |
| | | ### uranium enrichment ### |
| | | Check your preferred crafting guide for more information. |
| | | |
| | | |
| | | ### Uranium enrichment |
| | | |
| | | When uranium is to be used to fuel a nuclear reactor, it is not |
| | | sufficient to merely isolate and refine uranium metal. It is necessary |
| | |
| | | industrial processes |
| | | -------------------- |
| | | |
| | | ### alloying ### |
| | | ### Alloying |
| | | |
| | | In technic, alloying is a way of combining items to create other items, |
| | | distinct from standard crafting. Alloying always uses inputs of exactly |
| | | two distinct types, and produces a single output. Like cooking, which |
| | | takes a single input, it is performed using a powered machine, known |
| | | generically as an "alloy furnace". An alloy furnace always has two |
| | | input slots, and it doesn't matter which way round the two ingredients |
| | | are placed in the slots. Many alloying recipes require one or both |
| | | slots to contain a stack of more than one of the ingredient item: the |
| | | quantity required of each ingredient is part of the recipe. |
| | | In Technic, alloying is a way of combining items to create other items, |
| | | distinct from standard crafting. Alloying always uses inputs of exactly |
| | | two distinct types, and produces a single output. |
| | | |
| | | As with the furnaces used for cooking, there are multiple kinds of alloy |
| | | furnace, powered in different ways. The most-used alloy furnaces are |
| | | electrically powered. There is also an alloy furnace that is powered |
| | | by directly burning fuel, just like the basic cooking furnace. Building |
| | | almost any electrical machine, including the electrically-powered alloy |
| | | furnaces, requires a machine casing component, one ingredient of which |
| | | is brass, an alloy. It is therefore necessary to use the fuel-fired |
| | | alloy furnace in the early part of the game, on the way to building |
| | | electrical machinery. |
| | | Check your preferred crafting guide for more information. |
| | | |
| | | Alloying recipes are mainly concerned with metals. These recipes |
| | | combine a base metal with some other element, most often another metal, |
| | | to produce a new metal. This is discussed in the section on metal. |
| | | There are also a few alloying recipes in which the base ingredient is |
| | | non-metallic, such as the recipe for the silicon wafer. |
| | | |
| | | ### grinding, extracting, and compressing ### |
| | | ### Grinding, extracting, and compressing |
| | | |
| | | Grinding, extracting, and compressing are three distinct, but very |
| | | similar, ways of converting one item into another. They are all quite |
| | |
| | | It recovers both components of binary metal/metal alloys. It can't |
| | | recover the carbon from steel or cast iron. |
| | | |
| | | chests |
| | | Chests |
| | | ------ |
| | | |
| | | The technic mod replaces the basic Minetest game's single type of |
| | | chest with a range of chests that have different sizes and features. |
| | | The chest types are identified by the materials from which they are made; |
| | | the better chests are made from more exotic materials. The chest types |
| | | form a linear sequence, each being (with one exception noted below) |
| | | strictly more powerful than the preceding one. The sequence begins with |
| | | the wooden chest from the basic game, and each later chest type is built |
| | | by upgrading a chest of the preceding type. The chest types are: |
| | | See [GitHub Wiki / Chests](https://github.com/minetest-mods/technic/wiki/Chests) |
| | | |
| | | 1. wooden chest: 8×4 (32) slots |
| | | 2. iron chest: 9×5 (45) slots |
| | | 3. copper chest: 12×5 (60) slots |
| | | 4. silver chest: 12×6 (72) slots |
| | | 5. gold chest: 15×6 (90) slots |
| | | 6. mithril chest: 15×6 (90) slots |
| | | Features of extended chests: |
| | | |
| | | The iron and later chests have the ability to sort their contents, |
| | | when commanded by a button in their interaction forms. Item types are |
| | | sorted in the same order used in the unified\_inventory craft guide. |
| | | The copper and later chests also have an auto-sorting facility that can |
| | | be enabled from the interaction form. An auto-sorting chest automatically |
| | | sorts its contents whenever a player closes the chest. The contents will |
| | | then usually be in a sorted state when the chest is opened, but may not |
| | | be if pneumatic tubes have operated on the chest while it was closed, |
| | | or if two players have the chest open simultaneously. |
| | | * Larger storage space |
| | | * Labelling |
| | | * Advanced item sorting |
| | | |
| | | The silver and gold chests, but not the mithril chest, have a built-in |
| | | sign-like capability. They can be given a textual label, which will |
| | | be visible when hovering over the chest. The gold chest, but again not |
| | | the mithril chest, can be further labelled with a colored patch that is |
| | | visible from a moderate distance. |
| | | |
| | | The mithril chest is currently an exception to the upgrading system. |
| | | It has only as many inventory slots as the preceding (gold) type, and has |
| | | fewer of the features. It has no feature that other chests don't have: |
| | | it is strictly weaker than the gold chest. It is planned that in the |
| | | future it will acquire some unique features, but for now the only reason |
| | | to use it is aesthetic. |
| | | |
| | | The size of the largest chests is dictated by the maximum size |
| | | of interaction form that the game engine can successfully display. |
| | | If in the future the engine becomes capable of handling larger forms, |
| | | by scaling them to fit the screen, the sequence of chest sizes will |
| | | likely be revised. |
| | | |
| | | As with the chest of the basic Minetest game, each chest type comes |
| | | in both locked and unlocked flavors. All of the chests work with the |
| | | pneumatic tubes of the pipeworks mod. |
| | | |
| | | radioactivity |
| | | ------------- |
| | |
| | | Tricky shine paths can also be addressed by just keeping players out of |
| | | the dangerous area. |
| | | |
| | | electrical power |
| | | ---------------- |
| | | ## Electrical power |
| | | |
| | | Most machines in technic are electrically powered. To operate them it is |
| | | necessary to construct an electrical power network. The network links |
| | | together power generators and power-consuming machines, connecting them |
| | | using power cables. |
| | | Electrical networks in Technic are defined by a single tier (see below) |
| | | and consist of: |
| | | |
| | | There are three tiers of electrical networking: low voltage (LV), |
| | | medium voltage (MV), and high voltage (HV). Each network must operate |
| | | at a single voltage, and most electrical items are specific to a single |
| | | voltage. Generally, the machines of higher tiers are more powerful, |
| | | but consume more energy and are more expensive to build, than machines |
| | | of lower tiers. It is normal to build networks of all three tiers, |
| | | in ascending order as one progresses through the game, but it is not |
| | | strictly necessary to do this. Building HV equipment requires some parts |
| | | that can only be manufactured using electrical machines, either LV or MV, |
| | | so it is not possible to build an HV network first, but it is possible |
| | | to skip either LV or MV on the way to HV. |
| | | * 1x Switching Station (central management unit) |
| | | * Any further stations are disabled automatically |
| | | * Electricity producers (PR) |
| | | * Electricity consumers/receivers (RE) |
| | | * Accumulators/batteries (BA) |
| | | |
| | | Each voltage has its own cable type, with distinctive insulation. Cable |
| | | segments connect to each other and to compatible machines automatically. |
| | | Incompatible electrical items don't connect. All non-cable electrical |
| | | items must be connected via cable: they don't connect directly to each |
| | | other. Most electrical items can connect to cables in any direction, |
| | | but there are a couple of important exceptions noted below. |
| | | ### Tiers |
| | | |
| | | To be useful, an electrical network must connect at least one power |
| | | generator to at least one power-consuming machine. In addition to these |
| | | items, the network must have a "switching station" in order to operate: |
| | | no energy will flow without one. Unlike most electrical items, the |
| | | switching station is not voltage-specific: the same item will manage |
| | | a network of any tier. However, also unlike most electrical items, |
| | | it is picky about the direction in which it is connected to the cable: |
| | | the cable must be directly below the switching station. |
| | | * LV: Low Voltage. Low material costs but is slower. |
| | | * MV: Medium Voltage. Higher processing speed. |
| | | * HV: High Voltage. High material costs but is the fastest. |
| | | |
| | | Hovering over a network's switching station will show the aggregate energy |
| | | supply and demand, which is useful for troubleshooting. Electrical energy |
| | | is measured in "EU", and power (energy flow) in EU per second (EU/s). |
| | | Energy is shifted around a network instantaneously once per second. |
| | | Tiers can be converted from one to another using the Supply Converter node. |
| | | Its top connects to the input, the bottom to the output network. Configure |
| | | the input power by right-clicking it. |
| | | |
| | | In a simple network with only generators and consumers, if total |
| | | demand exceeds total supply then no energy will flow, the machines |
| | | will do nothing, and the generators' output will be lost. To handle |
| | | this situation, it is recommended to add a battery box to the network. |
| | | A battery box will store generated energy, and when enough has been |
| | | stored to run the consumers for one second it will deliver it to the |
| | | consumers, letting them run part-time. It also stores spare energy |
| | | when supply exceeds demand, to let consumers run full-time when their |
| | | demand occasionally peaks above the supply. More battery boxes can |
| | | be added to cope with larger periods of mismatched supply and demand, |
| | | such as those resulting from using solar generators (which only produce |
| | | energy in the daytime). |
| | | ### Machine upgrade slots |
| | | |
| | | When there are electrical networks of multiple tiers, it can be appealing |
| | | to generate energy on one tier and transfer it to another. The most |
| | | direct way to do this is with the "supply converter", which can be |
| | | directly wired into two networks. It is another tier-independent item, |
| | | and also particular about the direction of cable connections: it must |
| | | have the cable of one network directly above, and the cable of another |
| | | network directly below. The supply converter demands 10000 EU/s from |
| | | the network above, and when this network gives it power it supplies 9000 |
| | | EU/s to the network below. Thus it is only 90% efficient, unlike most of |
| | | the electrical system which is 100% efficient in moving energy around. |
| | | To transfer more than 10000 EU/s between networks, connect multiple |
| | | supply converters in parallel. |
| | | Generally, machines of MV and HV tiers have two upgrade slots. |
| | | Only specific items will have any upgrading effect. The occupied slots do |
| | | count, but not the actual stack size. |
| | | |
| | | powered machines |
| | | ---------------- |
| | | **Type 1: Energy upgrade** |
| | | |
| | | ### powered machine tiers ### |
| | | Consists of any battery item. Reduces the machine's power consumption |
| | | regardless the charge of the item. |
| | | |
| | | Each powered machine takes its power in some specific form, being |
| | | either fuel-fired (burning fuel directly) or electrically powered at |
| | | some specific voltage. There is a general progression through the |
| | | game from using fuel-fired machines to electrical machines, and to |
| | | higher electrical voltages. The most important kinds of machine come |
| | | in multiple variants that are powered in different ways, so the earlier |
| | | ones can be superseded. However, some machines are only available for |
| | | a specific power tier, so the tier can't be entirely superseded. |
| | | **Type 2: Tube upgrade** |
| | | |
| | | ### powered machine upgrades ### |
| | | Consists of a control logic unit item. Ejects processed items into pneumatic |
| | | tubes for quicker processing. |
| | | |
| | | Some machines have inventory slots that are used to upgrade them in |
| | | some way. Generally, machines of MV and HV tiers have two upgrade slots, |
| | | and machines of lower tiers (fuel-fired and LV) do not. Any item can |
| | | be placed in an upgrade slot, but only specific items will have any |
| | | upgrading effect. It is possible to have multiple upgrades of the same |
| | | type, but this can't be achieved by stacking more than one upgrade item |
| | | in one slot: it is necessary to put the same kind of item in more than one |
| | | upgrade slot. The ability to upgrade machines is therefore very limited. |
| | | Two kinds of upgrade are currently possible: an energy upgrade and a |
| | | tube upgrade. |
| | | |
| | | An energy upgrade consists of a battery item, the same kind of battery |
| | | that serves as a mobile energy store. The effect of an energy upgrade |
| | | is to improve in some way the machine's use of electrical energy, most |
| | | often by making it use less energy. The upgrade effect has no relation |
| | | to energy stored in the battery: the battery's charge level is irrelevant |
| | | and will not be affected. |
| | | |
| | | A tube upgrade consists of a control logic unit item. The effect of a |
| | | tube upgrade is to make the machine able, or more able, to eject items |
| | | it has finished with into pneumatic tubes. The machines that can take |
| | | this kind of upgrade are in any case capable of accepting inputs from |
| | | pneumatic tubes. These upgrades are essential in using powered machines |
| | | as components in larger automated systems. |
| | | |
| | | ### tubes with powered machines ### |
| | | ### Machines + Tubes (pipeworks) |
| | | |
| | | Generally, powered machines of MV and HV tiers can work with pneumatic |
| | | tubes, and those of lower tiers cannot. (As an exception, the fuel-fired |
| | |
| | | name = technic |
| | | description = technic |
| | | min_minetest_version = 5.0 |
New file |
| | |
| | | # Safety feature for the chainsaw tool aimed to prevent cutting structures |
| | | # built by players. |
| | | # |
| | | # Trunk nodes generated by mapgen have a rotation of '0' whereas manually |
| | | # placed trunks usually have another value. However, some mods might generate |
| | | # trees with rotation != 0, which renders the chainsaw useless on them. |
| | | # |
| | | # Disabling this feature will sacrifice safety for convenience. |
| | | technic_safe_chainsaw (Chainsaw safety feature) bool true |
| | |
| | | Technic |
| | | ======= |
| | | # Technic (main mod) |
| | | |
| | | License |
| | | ------- |
| | | |
| | | ## License |
| | | |
| | | ### Code |
| | | |
| | | Copyright (C) 2012-2014 Maciej Kasatkin (RealBadAngel) |
| | | |
| | | Technic chests code is licensed under the GNU LGPLv2+. |
| | | |
| | | Texture licenses: |
| | | |
| | | ### Textures |
| | | |
| | | BlockMen modified by Zefram (CC BY-SA 3.0): |
| | | * technic_chernobylite_block.png |
| | |
| | | leftshift (CC BY-SA 3.0): |
| | | * technic_river_water_can.png |
| | | |
| | | Neuromancer vis Minetest Game (CC BY-SA 3.0) |
| | | * `technic_*_electric_furnace_*.png` (derived) |
| | | |
| | | [LB Photo Realism Reload](https://www.curseforge.com/minecraft/texture-packs/lb-photo-realism-reload) (CC 0) |
| | | * `technic_geothermal_*.png` (derived) |
| | | * `technic_water_mill_*.png` (derived) |
| | | * `technic_*_alloy_furnace_*.png` (derived) |
| | | * `technic_*_compressor_*.png` (derived) |
| | | * `technic_*_grinder_*.png` (derived) |
| | | |
| | | RealBadAngel: (WTFPL) |
| | | * Everything else. |
| | | |
| | | CC BY-SA 3.0: <http://creativecommons.org/licenses/by-sa/3.0/> |
| | | |
| | | Sound licenses: |
| | | ### Sounds |
| | | |
| | | veikk0 (Veikko Mäkelä) (CC BY-SA 4.0): |
| | | * technic_hv_nuclear_reactor_siren_danger_loop.ogg |
| | | * Derived from "Nuclear alarm.wav" by Freesound.org user rene___ from <https://freesound.org/people/rene___/sounds/56778/>. Originally licensed under CC0 1.0 <https://creativecommons.org/publicdomain/zero/1.0/> |
| | | |
| | | CC BY-SA 4.0: <https://creativecommons.org/licenses/by-sa/4.0/> |
| | | |
| | | ### References |
| | | |
| | | CC BY-SA 3.0: http://creativecommons.org/licenses/by-sa/3.0/ |
| | | |
| | | CC BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/ |
| | |
| | | |
| | | This file documents the functions within the technic modpack for use in mods. |
| | | |
| | | [Switch to plaintext format](https://raw.githubusercontent.com/minetest-mods/technic/master/technic/doc/api.md) |
| | | |
| | | **Undocumented API may change at any time.** |
| | | |
| | | |
| | | ## Tiers |
| | | Tier are network types. List of pre-registered tiers: |
| | |
| | | * `technic.is_tier_cable(nodename, tier)` |
| | | * Tells whether the node `nodename` is the cable of the tier `tier`. |
| | | * Short version of `technic.get_cable_tier(nodename) == tier` |
| | | * `technic.register_cable_tier(nodename, tier)` |
| | | * Register user defined cable to list of known tier cables. |
| | | * `nodename`: string, name of the node |
| | | * `tier`: string, tier name |
| | | |
| | | |
| | | ## Machines |
| | | The machine type indicates the direction of power flow. |
| | | List of pre-registered machine types: |
| | | |
| | | * `technic.receiver = "RE"` e.g. grinder |
| | | * `technic.producer = "PR"` e.g. solar panel |
| | | * `technic.receiver = "RE"`: consumes energy. e.g. grinder |
| | | * `technic.producer = "PR"`: provides energy. e.g. solar panel |
| | | * `technic.producer_receiver = "PR_RE"` supply converter |
| | | * `technic.battery = "BA"` e.g. LV battery box |
| | | * `technic.battery = "BA"`: stores energy. e.g. LV battery box |
| | | |
| | | Available functions: |
| | | |
| | | * `technic.register_base_machine(data)` |
| | | * Registers a new node and defines the underlying machine behaviour. `data` fields: |
| | | * `tier`: string, see #Tiers |
| | | * `typename`: string, equivalent to the processing type registered |
| | | by `technic.register_recipe`. Examples: `"cooking"` `"alloy"` |
| | | * `machine_name`: string, node name |
| | | * `machine_desc`: string, node description |
| | | * `demand`: table, EU consumption values for each upgrade level. |
| | | Up to three indices. Index 1 == no upgrade. Example: `{3000, 2000, 1000}`. |
| | | * `upgrade`: (boolean), whether to add upgrade slots |
| | | * `modname`: (string), mod origin |
| | | * `tube`: (boolean), whether the machine has Pipeworks connectivity |
| | | * `can_insert`: (func), see Pipeworks documentation |
| | | * Accepts all inputs by default, if `tube = 1` |
| | | * See also: `technic.can_insert_unique_stack` |
| | | * `insert_object`: (func), see Pipeworks documentation |
| | | * Accepts all inputs by default, if `tube = 1` |
| | | * See also: `technic.insert_object_unique_stack` |
| | | * `connect_sides`: (table), see Lua API documentation. Defaults to all directions but front. |
| | | * `technic.register_machine(tier, nodename, machine_type)` |
| | | * Register an existing node as machine, bound to the network tier |
| | | * `tier`: see `register_tier` |
| | | * `tier`: string, see #Tiers |
| | | * `nodename`: string, node name |
| | | * `machine_type`: string, following options are possible: |
| | | * `"RE"`: Receiver |
| | | * `"PR"`: Producer |
| | | * `"BA"`: Battery, energy storage |
| | | * `technic.receiver = "RE"`: Consumes energy |
| | | * `technic.producer = "PR"`: Provides energy |
| | | * `technic.battery = "BA"`: Energy storage |
| | | * See also `Machine types` |
| | | |
| | | Functions to use for callbacks: |
| | | Callbacks for pipeworks item transfer: |
| | | |
| | | * `technic.can_insert_unique_stack(pos, node, stack, direction)` |
| | | * `technic.insert_object_unique_stack(pos, node, stack, direction)` |
| | | * Functions for the parameters `can_insert` and `insert_object` to avoid |
| | | filling multiple inventory slots with same type of item. |
| | | |
| | | ### Specific machines |
| | | * `technic.register_solar_array(data)` |
| | | * data is a table (TODO) |
| | | ### Recipes |
| | | |
| | | * `technic.register_recipe_type(typename, recipedef)` |
| | | * Registers a new recipe type used for machine processing |
| | | * `typename`: string, name of the recipe type |
| | | * Fields of `recipedef`: |
| | | * `description`: string, descriptor of the recipe type |
| | | * `input_size`: (numeric), count of input ItemStacks. default 1 |
| | | * `output_size`: (numeric), count of output ItemStacks. default 1 |
| | | * `technic.register_recipe(recipe)` |
| | | * Registers a individual input/output recipe. Fields of `recipe`: |
| | | * `input`: table, integer-indexed list of input ItemStacks. |
| | | * `output`: table/ItemStack, single output or list of output ItemStacks. |
| | | * `time`: numeric, process time in seconds. |
| | | * `technic.get_recipe(typename, items)` |
| | | * `typename`: string, see `technic.register_recipe_type` |
| | | * `items`: table, integer-indexed list of input ItemStacks. |
| | | * Returns: `recipe` table on success, `nil` otherwise |
| | | |
| | | |
| | | The following functions can be used to register recipes for |
| | | a specific machine type: |
| | | |
| | | * Centrifuge |
| | | * `technic.register_separating_recipe(recipe)` |
| | | * Compressor |
| | | * `technic.register_compressor_recipe(recipe)` |
| | | * Furnaces (electric, normal) |
| | | * `minetest.register_recipe(recipe)` |
| | | * Extractor |
| | | * `technic.register_extractor_recipe(recipe)` |
| | | * Freezer |
| | | * `technic.register_freezer_recipe(recipe)` |
| | | * Grinder |
| | | * `technic.register_grinder_recipe(recipe)` |
| | | |
| | | |
| | | ## Tools |
| | |
| | | * If `technic.power_tools[itemstack:get_name()]` is `nil` (or `false`), this |
| | | function does nothing, else that value is the maximum charge. |
| | | * The itemstack metadata is changed to contain the charge. |
| | | * `technic.get_charge(itemstack)` |
| | | * Returns the charge and max charge of the given itemstack. |
| | | * If the itemstack is not an RE chargeable item, both return values will be zero. |
| | | * `technic.set_charge(itemstack, charge)` |
| | | * Modifies the charge of the given itemstack. |
| | | |
| | | ### Node-specific |
| | | * `technic.get_or_load_node(pos)` |
| | |
| | | |
| | | Additional definition fields: |
| | | |
| | | * `wear_represents = "string"` |
| | | * `<itemdef>.wear_represents = "string"` |
| | | * Specifies how the tool wear level is handled. Available modes: |
| | | * `"mechanical_wear"`: represents physical damage |
| | | * `"technic_RE_charge"`: represents electrical charge |
| | | * `<itemdef>.technic_run(pos, node)` |
| | | * This function is currently used to update the node. |
| | | * `<itemdef>.technic_run = function(pos, node) ...` |
| | | * This callback is used to update the node. |
| | | Modders have to manually change the information about supply etc. in the |
| | | node metadata. |
| | | * Technic-registered machines use this callback by default. |
| | | * `<itemdef>.technic_disabled_machine_name = "string"` |
| | | * Specifies the machine's node name to use when it's not connected connected to a network |
| | | * `<itemdef>.technic_on_disable = function(pos, node) ...` |
| | | * This callback is run when the machine is no longer connected to a technic-powered network. |
| | | * `<itemdef>.technic_get_charge = function(itemstack) ...` |
| | | * Optional callback to overwrite the default charge behaviour. |
| | | * `itemstack`: ItemStack, the tool to analyse |
| | | * Return values: |
| | | * `charge`: Electrical charge of the tool |
| | | * `max_charge`: Upper charge limit |
| | | * Etc. `local charge, maxcharge = itemdef.technic_get_charge(itemstack)` |
| | | * `<itemdef>.technic_set_charge = function(itemstack, charge) ...` |
| | | * Optional callback to overwrite the default charge behaviour. |
| | | * `itemstack`: ItemStack, the tool to update |
| | | * `charge`: numeric, value between `0` and `max_charge` |
| | | |
| | | |
| | | ## Node Metadata fields |
| | | Nodes connected to the network will have one or more of these parameters as meta |
| | |
| | | multiple tiers (or networks). |
| | | |
| | | |
| | | ## Switching Station mechanics |
| | | ## Manual: Network basics |
| | | |
| | | The switching station is the center of all power distribution on an electric |
| | | network. |
| | | network. This node is used to calculate the power supply of the network and |
| | | to distribute the power across nodes. |
| | | |
| | | The station collects power from sources (PR), distributes it to sinks (RE), |
| | | and uses the excess/shortfall to charge and discharge batteries (BA). |
| | | The switching station is the center of all electricity distribution. It collects |
| | | power from sources (PR), distributes it to sinks (RE), and uses the |
| | | excess/shortfall to charge and discharge batteries (BA). |
| | | |
| | | For now, all supply and demand values are expressed in kW. |
| | | As a thumb of rule, "EU" (energy unit) values are expressed in kW. |
| | | |
| | | It works like this: |
| | | All PR,BA,RE nodes are indexed and tagged with the switching station. |
| | | The tagging is a workaround to allow more stations to be built without allowing |
| | | a cheat with duplicating power. |
| | | All the RE nodes are queried for their current EU demand. Those which are off |
| | | would require no or a small standby EU demand, while those which are on would |
| | | require more. |
| | | If the total demand is less than the available power they are all updated with |
| | | the demand number. |
| | | If any surplus exists from the PR nodes the batteries will be charged evenly |
| | | with this. |
| | | If the total demand requires draw on the batteries they will be discharged |
| | | evenly. |
| | | Network functionality: |
| | | |
| | | If the total demand is more than the available power all RE nodes will be shut |
| | | down. We have a brown-out situation. |
| | | |
| | | Hence for now all the power distribution logic resides in this single node. |
| | | 1. All PR, BA, RE nodes are indexed and tagged with one switching station. |
| | | The tagging is a workaround to allow more stations to be built without allowing |
| | | a cheat with duplicating power. |
| | | 2. All the RE nodes are queried for their current EU demand. |
| | | If the total demand is less than the available power they are all updated |
| | | with the demand number. |
| | | 3. BA nodes are evenly charged from energy surplus. |
| | | 4. Excess power draw will discharge batteries evenly. |
| | | 5. If the total demand is more than the available power all RE nodes will be shut |
| | | down. We have a brown-out situation. |
| | | |
| | | ## Deprecated functions |
| | | |
| | |
| | | end |
| | | |
| | | |
| | | --- Returns the meta of an item |
| | | -- Gets overridden when legacy.lua is loaded |
| | | function technic.get_stack_meta(itemstack) |
| | | return itemstack:get_meta() |
| | | end |
| | | |
| | | --- Same as technic.get_stack_meta for cans |
| | | function technic.get_stack_meta_cans(itemstack) |
| | | return itemstack:get_meta() |
| | | end |
| | | |
| | | |
| | | --- Fully charge RE chargeable item. |
| | | -- Must be defined early to reference in item definitions. |
| | | function technic.refill_RE_charge(stack) |
| | | local max_charge = technic.power_tools[stack:get_name()] |
| | | if not max_charge then return stack end |
| | | local meta = technic.get_stack_meta(stack) |
| | | meta:set_int("technic:charge", max_charge) |
| | | technic.set_RE_wear(stack, max_charge, max_charge) |
| | | local meta = minetest.deserialize(stack:get_metadata()) or {} |
| | | meta.charge = max_charge |
| | | stack:set_metadata(minetest.serialize(meta)) |
| | | return stack |
| | | end |
| | | |
| | |
| | | -- Minetest 0.4.7 mod: technic |
| | | -- namespace: technic |
| | | -- (c) 2012-2013 by RealBadAngel <mk@realbadangel.pl> |
| | | |
| | | if not minetest.get_translator then |
| | | error("[technic] Your Minetest version is no longer supported." |
| | | .. " (version < 5.0.0)") |
| | | end |
| | | |
| | | local load_start = os.clock() |
| | | |
| | |
| | | if rawget(_G, "intllib") then |
| | | technic.getter = intllib.Getter() |
| | | else |
| | | technic.getter = function(s,a,...)if a==nil then return s end a={a,...}return s:gsub("(@?)@(%(?)(%d+)(%)?)",function(e,o,n,c)if e==""then return a[tonumber(n)]..(o==""and c or"")else return"@"..o..n..c end end) end |
| | | -- Intllib copypasta: TODO replace with the client-side translation API |
| | | technic.getter = function(s,a,...) |
| | | if a==nil then return s end |
| | | a={a,...} |
| | | return s:gsub("(@?)@(%(?)(%d+)(%)?)", function(e,o,n,c) |
| | | if e==""then |
| | | return a[tonumber(n)]..(o==""and c or"") |
| | | end |
| | | return "@"..o..n..c |
| | | end) |
| | | end |
| | | end |
| | | local S = technic.getter |
| | | |
| | |
| | | minetest.register_alias("technic:lv_cable"..i, "technic:lv_cable") |
| | | end |
| | | |
| | | -- Item meta |
| | | |
| | | -- Meta keys that have changed |
| | | technic.legacy_meta_keys = { |
| | | ["charge"] = "technic:charge", |
| | | } |
| | | |
| | | -- Converts legacy itemstack metadata string to itemstack meta and returns the ItemStackMetaRef |
| | | function technic.get_stack_meta(itemstack) |
| | | local meta = itemstack:get_meta() |
| | | local legacy_string = meta:get("") -- Get deprecated metadata |
| | | if legacy_string then |
| | | local legacy_table = minetest.deserialize(legacy_string) |
| | | if legacy_table then |
| | | local table = meta:to_table() |
| | | for k, v in pairs(legacy_table) do |
| | | table.fields[technic.legacy_meta_keys[k] or k] = v |
| | | end |
| | | meta:from_table(table) |
| | | end |
| | | meta:set_string("", "") -- Remove deprecated metadata |
| | | end |
| | | return meta |
| | | end |
| | | |
| | | -- Same as technic.get_stack_meta for cans. |
| | | -- (Cans didn't store a serialized table in the legacy metadata string, but just a number.) |
| | | function technic.get_stack_meta_cans(itemstack) |
| | | local meta = itemstack:get_meta() |
| | | local legacy_string = meta:get("") -- Get deprecated metadata |
| | | if legacy_string then |
| | | meta:set_string("can_level", legacy_string) |
| | | meta:set_string("", "") -- Remove deprecated metadata |
| | | return meta |
| | | end |
| | | return meta |
| | | end |
| | |
| | | else |
| | | formspec = formspec.."button[0,1;5,1;mesecon_mode_0;"..S("Controlled by Mesecon Signal").."]" |
| | | end |
| | | -- TODO: String replacement with %s will stop working with client-side translations |
| | | if meta:get_int("enabled") == 0 then |
| | | formspec = formspec.."button[0,1.75;5,1;enable;"..S("%s Disabled"):format(S("%s Forcefield Emitter"):format("HV")).."]" |
| | | formspec = formspec.."button[0,1.75;5,1;enable;".. |
| | | S("%s Disabled"):format(S("%s Forcefield Emitter"):format("HV")).."]" |
| | | else |
| | | formspec = formspec.."button[0,1.75;5,1;disable;"..S("%s Enabled"):format(S("%s Forcefield Emitter"):format("HV")).."]" |
| | | formspec = formspec.."button[0,1.75;5,1;disable;".. |
| | | S("%s Enabled"):format(S("%s Forcefield Emitter"):format("HV")).."]" |
| | | end |
| | | meta:set_string("formspec", formspec) |
| | | end |
| | |
| | | }) |
| | | |
| | | local function make_reactor_formspec(meta) |
| | | local f = "size[8,9]".. |
| | | "label[0,0;"..S("Nuclear Reactor Rod Compartment").."]".. |
| | | "list[current_name;src;2,1;3,2;]".. |
| | | "list[current_player;main;0,5;8,4;]".. |
| | | "listring[]".. |
| | | "button[5.5,1.5;2,1;start;Start]".. |
| | | "checkbox[5.5,2.5;autostart;automatic Start;"..meta:get_string("autostart").."]" |
| | | local f = |
| | | "formspec_version[4]".. |
| | | "size[10.75,10.75]".. |
| | | "label[0.2,0.4;"..S("Nuclear Reactor Rod Compartment").."]".. |
| | | "list[current_name;src;1.5,1;3,2;]".. |
| | | "list[current_player;main;0.5,5.5;8,4;]".. |
| | | "listring[]".. |
| | | "button[5.7,1;2,1;start;Start]".. |
| | | "checkbox[5.7,2.75;autostart;automatic Start;"..meta:get_string("autostart").."]" |
| | | if not digiline_remote_path then |
| | | return f |
| | | end |
| | | local digiline_enabled = meta:get_string("enable_digiline") |
| | | f = f.."checkbox[0.5,2.8;enable_digiline;Enable Digiline;"..digiline_enabled.."]" |
| | | f = f.."checkbox[1.5,3.75;enable_digiline;Enable Digiline channel;"..digiline_enabled.."]" |
| | | if digiline_enabled ~= "true" then |
| | | return f |
| | | end |
| | | return f.. |
| | | "button_exit[4.6,3.69;2,1;save;Save]".. |
| | | "field[1,4;4,1;remote_channel;Digiline Remote Channel;${remote_channel}]" |
| | | "field[2,4.2;4.25,1;remote_channel;;${remote_channel}]" .. |
| | | "button_exit[6.5,4.2;2,1;save;Save]" |
| | | end |
| | | |
| | | local SS_OFF = 0 |
| | |
| | | --]] |
| | | local function reactor_structure_badness(pos) |
| | | local vm = VoxelManip() |
| | | |
| | | -- Blast-resistant Concrete Block layer outer positions |
| | | local pos1 = vector.subtract(pos, 3) |
| | | local pos2 = vector.add(pos, 3) |
| | | |
| | | local MinEdge, MaxEdge = vm:read_from_map(pos1, pos2) |
| | | local data = vm:get_data() |
| | | local area = VoxelArea:new({MinEdge=MinEdge, MaxEdge=MaxEdge}) |
| | |
| | | for z = pos1.z, pos2.z do |
| | | for y = pos1.y, pos2.y do |
| | | for x = pos1.x, pos2.x do |
| | | -- In the entire volume, make sure there is: |
| | | local cid = data[area:index(x, y, z)] |
| | | if x == pos1.x or x == pos2.x or |
| | | y == pos1.y or y == pos2.y or |
| | | z == pos1.z or z == pos2.z then |
| | | -- r=3 : Blast-resistant Concrete Block shell |
| | | if cid == c_blast_concrete then |
| | | blast_layer = blast_layer + 1 |
| | | end |
| | | elseif x == pos1.x+1 or x == pos2.x-1 or |
| | | y == pos1.y+1 or y == pos2.y-1 or |
| | | z == pos1.z+1 or z == pos2.z-1 then |
| | | -- r=2 : Lead Block shell |
| | | if cid == c_lead then |
| | | lead_layer = lead_layer + 1 |
| | | elseif cid == c_steel then |
| | |
| | | elseif x == pos1.x+2 or x == pos2.x-2 or |
| | | y == pos1.y+2 or y == pos2.y-2 or |
| | | z == pos1.z+2 or z == pos2.z-2 then |
| | | -- r=1 : Water cooling |
| | | if cid == c_water_source or cid == c_water_flowing then |
| | | water_layer = water_layer + 1 |
| | | end |
| | |
| | | end |
| | | |
| | | if steel_layer >= 96 then |
| | | -- Legacy: convert stainless steel to lead |
| | | -- Why don't we accept both without conversion? |
| | | for z = pos1.z+1, pos2.z-1 do |
| | | for y = pos1.y+1, pos2.y-1 do |
| | | for x = pos1.x+1, pos2.x-1 do |
| | |
| | | if water_layer > 25 then water_layer = 25 end |
| | | if lead_layer > 96 then lead_layer = 96 end |
| | | if blast_layer > 216 then blast_layer = 216 end |
| | | -- Amount of missing blocks |
| | | return (25 - water_layer) + (96 - lead_layer) + (216 - blast_layer) |
| | | end |
| | | |
| | |
| | | end |
| | | meta:set_int("HV_EU_supply", 0) |
| | | meta:set_int("burn_time", 0) |
| | | meta:set_string("infotext", S("%s Idle"):format(reactor_desc)) |
| | | meta:set_string("infotext", S("@1 Idle", reactor_desc)) |
| | | technic.swap_node(pos, "technic:hv_nuclear_reactor_core") |
| | | meta:set_int("structure_accumulated_badness", 0) |
| | | siren_clear(pos, meta) |
| | |
| | | local radius = meta:get_int("size") |
| | | local diameter = radius*2 + 1 |
| | | local machine_name = S("%s Quarry"):format("HV") |
| | | if meta:get_int("enabled") == 0 or meta:get_int("purge_on") == 1 then |
| | | meta:set_string("infotext", S(meta:get_int("purge_on") == 1 and "%s purging cache" or "%s Disabled"):format(machine_name)) |
| | | local do_purge = meta:get_int("purge_on") == 1 |
| | | if meta:get_int("enabled") == 0 or do_purge then |
| | | local infotext = do_purge and |
| | | S("%s purging cache") or S("%s Disabled") |
| | | meta:set_string("infotext", infotext:format(machine_name)) |
| | | meta:set_int("HV_EU_demand", 0) |
| | | elseif meta:get_int("dug") == diameter*diameter * (quarry_dig_above_nodes+1+quarry_max_depth) then |
| | | meta:set_string("infotext", S("%s Finished"):format(machine_name)) |
| | | meta:set_int("HV_EU_demand", 0) |
| | | else |
| | | meta:set_string("infotext", S(meta:get_int("HV_EU_input") >= quarry_demand and "%s Active" or "%s Unpowered"):format(machine_name)) |
| | | local infotext = meta:get_int("HV_EU_input") >= quarry_demand |
| | | and S("%s Active") or S("%s Unpowered") |
| | | meta:set_string("infotext", infotext:format(machine_name)) |
| | | meta:set_int("HV_EU_demand", quarry_demand) |
| | | end |
| | | end |
| | |
| | | end |
| | | end |
| | | |
| | | -- Determines whether the quarry can dig the node at "pos" |
| | | -- "startpos" is located a few nodes above the quarry in South West direction (X-, Z-) |
| | | -- Returns the node to dig (to avoid double minetest.get_node lookup) |
| | | local function quarry_can_dig_node(startpos, pos, quarry_owner) |
| | | if minetest.is_protected(pos, quarry_owner) then |
| | | return nil |
| | | end |
| | | |
| | | local node = technic.get_or_load_node(pos) or minetest.get_node(pos) |
| | | local def = minetest.registered_nodes[node.name] or {diggable=false} |
| | | -- doors mod among other thing does NOT like a nil digger... |
| | | local fakedigger = pipeworks.create_fake_player({ |
| | | name = quarry_owner |
| | | }) |
| | | if not def.diggable or (def.can_dig and not def.can_dig(pos, fakedigger)) then |
| | | return nil |
| | | end |
| | | |
| | | -- Find airlike nodes on top of the current node. The entire Y column must be free. |
| | | for ay = pos.y+1, startpos.y do |
| | | local checkpos = {x=pos.x, y=ay, z=pos.z} |
| | | local checknode = technic.get_or_load_node(checkpos) or minetest.get_node(checkpos) |
| | | |
| | | local cdef = minetest.registered_nodes[checknode.name] or {} |
| | | local is_kind_of_gas = cdef.buildable_to and cdef.sunlight_propagates and not cdef.walkable |
| | | and not cdef.diggable and (cdef.drawtype == "airlike" or cdef.drawtype == "glasslike") |
| | | if not is_kind_of_gas then |
| | | return nil |
| | | end |
| | | end |
| | | |
| | | return node |
| | | end |
| | | |
| | | local function quarry_run(pos, node) |
| | | local meta = minetest.get_meta(pos) |
| | | local inv = meta:get_inventory() |
| | |
| | | vector.new(0, -ry, 0)), |
| | | vector.multiply(pdir, rp)), |
| | | vector.multiply(qdir, rq)) |
| | | local can_dig = true |
| | | if can_dig and minetest.is_protected and minetest.is_protected(digpos, owner) then |
| | | can_dig = false |
| | | end |
| | | local dignode |
| | | if can_dig then |
| | | dignode = technic.get_or_load_node(digpos) or minetest.get_node(digpos) |
| | | local dignodedef = minetest.registered_nodes[dignode.name] or {diggable=false} |
| | | -- doors mod among other thing does NOT like a nil digger... |
| | | local fakedigger = pipeworks.create_fake_player({ |
| | | name = owner |
| | | }) |
| | | if not dignodedef.diggable or (dignodedef.can_dig and not dignodedef.can_dig(digpos, fakedigger)) then |
| | | can_dig = false |
| | | end |
| | | end |
| | | |
| | | if can_dig then |
| | | for ay = startpos.y, digpos.y+1, -1 do |
| | | local checkpos = {x=digpos.x, y=ay, z=digpos.z} |
| | | local checknode = technic.get_or_load_node(checkpos) or minetest.get_node(checkpos) |
| | | if checknode.name ~= "air" then |
| | | can_dig = false |
| | | break |
| | | end |
| | | end |
| | | end |
| | | nd = nd + 1 |
| | | if can_dig then |
| | | |
| | | local dignode = quarry_can_dig_node(startpos, digpos, owner) |
| | | if dignode then |
| | | minetest.remove_node(digpos) |
| | | local drops = minetest.get_node_drops(dignode.name, "") |
| | | for _, dropped_item in ipairs(drops) do |
| | |
| | | } |
| | | }) |
| | | |
| | | if (minetest.get_modpath('everness')) then |
| | | minetest.register_craft({ |
| | | output = 'technic:lv_grinder', |
| | | recipe = { |
| | | {'everness:coral_desert_stone', 'default:diamond', 'everness:coral_desert_stone'}, |
| | | {'everness:coral_desert_stone', 'technic:machine_casing', 'everness:coral_desert_stone'}, |
| | | {'technic:granite', 'technic:lv_cable', 'technic:granite'}, |
| | | } |
| | | }) |
| | | |
| | | minetest.register_craft({ |
| | | output = 'technic:lv_grinder', |
| | | recipe = { |
| | | {'everness:forsaken_desert_stone', 'default:diamond', 'everness:forsaken_desert_stone'}, |
| | | {'everness:forsaken_desert_stone', 'technic:machine_casing', 'everness:forsaken_desert_stone'}, |
| | | {'technic:granite', 'technic:lv_cable', 'technic:granite'}, |
| | | } |
| | | }) |
| | | end |
| | | |
| | | technic.register_grinder({tier="LV", demand={200}, speed=1}) |
| | | |
| | |
| | | dofile(path.."/compressor.lua") |
| | | |
| | | dofile(path.."/music_player.lua") |
| | | -- NEW LV LAMPS |
| | | dofile(path.."/led.lua") |
| | | dofile(path.."/lamp.lua") |
New file |
| | |
| | | |
| | | -- LV Lamp |
| | | -- Illuminates a 7x7x3(H) volume below itself with light bright as the sun. |
| | | |
| | | |
| | | local S = technic.getter |
| | | |
| | | local desc = S("@1 Lamp", S("LV")) |
| | | local active_desc = S("@1 Active", desc) |
| | | local unpowered_desc = S("@1 Unpowered", desc) |
| | | local off_desc = S("@1 Off", desc) |
| | | local demand = 50 |
| | | |
| | | |
| | | -- Invisible light source node used for illumination |
| | | minetest.register_node("technic:dummy_light_source", { |
| | | description = S("Dummy light source node"), |
| | | inventory_image = "technic_dummy_light_source.png", |
| | | wield_image = "technic_dummy_light_source.png", |
| | | paramtype = "light", |
| | | drawtype = "airlike", |
| | | light_source = 14, |
| | | sunlight_propagates = true, |
| | | walkable = false, |
| | | buildable_to = true, |
| | | diggable = false, |
| | | pointable = false, |
| | | --drop = "", -- Intentionally allowed to drop itself |
| | | groups = {not_in_creative_inventory = 1} |
| | | }) |
| | | |
| | | |
| | | local function illuminate(pos, active) |
| | | local pos1 = {x = pos.x - 3, y = pos.y - 1, z = pos.z - 3} |
| | | local pos2 = {x = pos.x + 3, y = pos.y - 3, z = pos.z + 3} |
| | | |
| | | local find_node = active and "air" or "technic:dummy_light_source" |
| | | local set_node = {name = (active and "technic:dummy_light_source" or "air")} |
| | | |
| | | for _,p in pairs(minetest.find_nodes_in_area(pos1, pos2, find_node)) do |
| | | minetest.set_node(p, set_node) |
| | | end |
| | | end |
| | | |
| | | local function lamp_run(pos, node) |
| | | local meta = minetest.get_meta(pos) |
| | | |
| | | if meta:get_int("LV_EU_demand") == 0 then |
| | | return -- Lamp is turned off |
| | | end |
| | | |
| | | local eu_input = meta:get_int("LV_EU_input") |
| | | |
| | | if node.name == "technic:lv_lamp_active" then |
| | | if eu_input < demand then |
| | | technic.swap_node(pos, "technic:lv_lamp") |
| | | meta:set_string("infotext", unpowered_desc) |
| | | illuminate(pos, false) |
| | | else |
| | | illuminate(pos, true) |
| | | end |
| | | elseif node.name == "technic:lv_lamp" then |
| | | if eu_input >= demand then |
| | | technic.swap_node(pos, "technic:lv_lamp_active") |
| | | meta:set_string("infotext", active_desc) |
| | | illuminate(pos, true) |
| | | end |
| | | end |
| | | end |
| | | |
| | | local function lamp_toggle(pos, node, player) |
| | | if not player or minetest.is_protected(pos, player:get_player_name()) then |
| | | return |
| | | end |
| | | local meta = minetest.get_meta(pos) |
| | | if meta:get_int("LV_EU_demand") == 0 then |
| | | meta:set_string("infotext", active_desc) |
| | | meta:set_int("LV_EU_demand", demand) |
| | | else |
| | | illuminate(pos, false) |
| | | technic.swap_node(pos, "technic:lv_lamp") |
| | | meta:set_string("infotext", off_desc) |
| | | meta:set_int("LV_EU_demand", 0) |
| | | end |
| | | end |
| | | |
| | | local common_fields = { |
| | | drawtype = "nodebox", |
| | | node_box = { |
| | | type = "fixed", |
| | | fixed = {0.5,0.5,0.5,-0.5,-0.2,-0.5} |
| | | }, |
| | | tiles = { |
| | | "technic_lv_lamp_top.png", |
| | | "technic_lv_lamp_bottom.png", |
| | | "technic_lv_lamp_side.png", |
| | | "technic_lv_lamp_side.png", |
| | | "technic_lv_lamp_side.png", |
| | | "technic_lv_lamp_side.png" |
| | | }, |
| | | connect_sides = {"front", "back", "left", "right", "top"}, |
| | | can_dig = technic.machine_can_dig, |
| | | technic_run = lamp_run, |
| | | on_destruct = illuminate, |
| | | on_rightclick = lamp_toggle |
| | | } |
| | | |
| | | local ndef |
| | | |
| | | ndef = { |
| | | description = desc, |
| | | groups = {cracky = 2, technic_machine = 1, technic_lv = 1}, |
| | | on_construct = function(pos) |
| | | local meta = minetest.get_meta(pos) |
| | | meta:set_string("infotext", desc) |
| | | meta:set_int("LV_EU_demand", demand) |
| | | end |
| | | } |
| | | |
| | | for k, v in pairs(common_fields) do |
| | | ndef[k] = v |
| | | end |
| | | |
| | | minetest.register_node("technic:lv_lamp", ndef) |
| | | |
| | | |
| | | ndef = { |
| | | description = active_desc, |
| | | paramtype = "light", |
| | | light_source = 14, |
| | | drop = "technic:lv_lamp", |
| | | groups = {cracky = 2, technic_machine = 1, technic_lv = 1, not_in_creative_inventory = 1}, |
| | | technic_on_disable = function(pos) |
| | | illuminate(pos, false) |
| | | technic.swap_node(pos, "technic:lv_lamp") |
| | | end, |
| | | } |
| | | |
| | | for k, v in pairs(common_fields) do |
| | | ndef[k] = v |
| | | end |
| | | |
| | | minetest.register_node("technic:lv_lamp_active", ndef) |
| | | |
| | | |
| | | technic.register_machine("LV", "technic:lv_lamp", technic.receiver) |
| | | technic.register_machine("LV", "technic:lv_lamp_active", technic.receiver) |
| | | |
| | | minetest.register_craft({ |
| | | output = "technic:lv_lamp", |
| | | recipe = { |
| | | {"default:glass", "default:glass", "default:glass"}, |
| | | {"technic:lv_led", "technic:lv_led", "technic:lv_led"}, |
| | | {"mesecons_materials:glue", "technic:lv_cable", "mesecons_materials:glue"}, |
| | | } |
| | | }) |
New file |
| | |
| | | -- LED |
| | | -- Intended primarily as a core component for LED lamps. |
| | | |
| | | local S = technic.getter |
| | | |
| | | local desc = S("@1 LED", S("LV")) |
| | | local active_desc = S("@1 Active", desc) |
| | | local unpowered_desc = S("@1 Unpowered", desc) |
| | | local demand = 5 |
| | | |
| | | |
| | | local function led_run(pos, node) |
| | | local meta = minetest.get_meta(pos) |
| | | local eu_input = meta:get_int("LV_EU_input") |
| | | |
| | | if eu_input < demand and node.name == "technic:lv_led_active" then |
| | | technic.swap_node(pos, "technic:lv_led") |
| | | meta:set_string("infotext", unpowered_desc) |
| | | elseif eu_input >= demand and node.name == "technic:lv_led" then |
| | | technic.swap_node(pos, "technic:lv_led_active") |
| | | meta:set_string("infotext", active_desc) |
| | | end |
| | | end |
| | | |
| | | local common_fields = { |
| | | drawtype = "nodebox", |
| | | node_box = { |
| | | type = "fixed", |
| | | fixed = {0.5, 0.5, 0.5, -0.5, 0.3, -0.5} |
| | | }, |
| | | tiles = { |
| | | "technic_lv_led_top.png", |
| | | "technic_lv_led.png", |
| | | "technic_lv_led_side.png", |
| | | "technic_lv_led_side2.png", |
| | | "technic_lv_led_side2.png", |
| | | "technic_lv_led_side2.png", |
| | | }, |
| | | |
| | | connect_sides = {"front", "back", "left", "right", "top", "bottom"}, |
| | | can_dig = technic.machine_can_dig, |
| | | technic_run = led_run, |
| | | } |
| | | |
| | | local ndef |
| | | |
| | | ndef = { |
| | | description = desc, |
| | | inventory_image = "technic_lv_led_inv.png", |
| | | sunlight_propagates = true, |
| | | groups = {cracky = 2, technic_machine = 1, technic_lv = 1}, |
| | | |
| | | on_construct = function(pos) |
| | | local meta = minetest.get_meta(pos) |
| | | meta:set_string("infotext", desc) |
| | | meta:set_int("LV_EU_demand", demand) |
| | | end, |
| | | } |
| | | |
| | | for k, v in pairs(common_fields) do |
| | | ndef[k] = v |
| | | end |
| | | |
| | | minetest.register_node("technic:lv_led", ndef) |
| | | |
| | | |
| | | ndef = { |
| | | description = active_desc, |
| | | paramtype = "light", |
| | | light_source = 9, |
| | | drop = "technic:lv_led", |
| | | groups = {cracky = 2, technic_machine = 1, technic_lv = 1, not_in_creative_inventory = 1}, |
| | | technic_on_disable = function(pos) |
| | | technic.swap_node(pos, "technic:lv_led") |
| | | end, |
| | | } |
| | | |
| | | for k, v in pairs(common_fields) do |
| | | ndef[k] = v |
| | | end |
| | | |
| | | minetest.register_node("technic:lv_led_active", ndef) |
| | | |
| | | |
| | | technic.register_machine("LV", "technic:lv_led", technic.receiver) |
| | | technic.register_machine("LV", "technic:lv_led_active", technic.receiver) |
| | | |
| | | minetest.register_craft({ |
| | | output = "technic:lv_led 2", |
| | | recipe = { |
| | | {"", "homedecor:plastic_sheeting", ""}, |
| | | {"homedecor:plastic_sheeting", "technic:doped_silicon_wafer", "homedecor:plastic_sheeting"}, |
| | | {"", "technic:fine_silver_wire", ""}, |
| | | } |
| | | }) |
| | |
| | | end |
| | | |
| | | -- Appliances: |
| | | -- has_supply: pos of supply node if the appliance has a power radiator near with sufficient power for the demand else "" |
| | | -- has_supply: pos of supply node if the appliance has a power radiator near |
| | | -- with sufficient power for the demand else "" |
| | | -- EU_demand: The power demand of the device. |
| | | -- EU_charge: Actual use. set to EU_demand if active==1 |
| | | -- active: set to 1 if the device is on |
| | |
| | | end |
| | | |
| | | local function set_display(pos, meta) |
| | | local ESC = minetest.formspec_escape |
| | | meta:set_string("infotext", S(meta:get_int("enabled") ~= 0 and "%s Enabled" or "%s Disabled"):format(desc)) |
| | | meta:set_string("formspec", |
| | | "size[5,3.5]".. |
| | | "item_image[0,0;1,1;technic:admin_anchor]".. |
| | | "label[1,0;"..minetest.formspec_escape(desc).."]".. |
| | | "label[0,1;"..minetest.formspec_escape(S("Owner:").." "..meta:get_string("owner")).."]".. |
| | | "label[1,0;"..ESC(desc).."]".. |
| | | "label[0,1;"..ESC(S("Owner:").." "..meta:get_string("owner")).."]".. |
| | | (meta:get_int("locked") == 0 and |
| | | "button[3,1;2,1;lock;"..minetest.formspec_escape(S("Unlocked")).."]" or |
| | | "button[3,1;2,1;unlock;"..minetest.formspec_escape(S("Locked")).."]").. |
| | | "field[0.25,2.3;1,1;radius;"..minetest.formspec_escape(S("Radius:"))..";"..meta:get_int("radius").."]".. |
| | | "button[3,1;2,1;lock;"..ESC(S("Unlocked")).."]" or |
| | | "button[3,1;2,1;unlock;"..ESC(S("Locked")).."]").. |
| | | "field[0.25,2.3;1,1;radius;"..ESC(S("Radius:"))..";"..meta:get_int("radius").."]".. |
| | | (meta:get_int("enabled") == 0 and |
| | | "button[3,2;2,1;enable;"..minetest.formspec_escape(S("Disabled")).."]" or |
| | | "button[3,2;2,1;disable;"..minetest.formspec_escape(S("Enabled")).."]").. |
| | | "label[0,3;"..minetest.formspec_escape(S("Keeping %d/%d map blocks loaded"):format(#currently_forceloaded_positions(meta), #compute_forceload_positions(pos, meta))).."]") |
| | | "button[3,2;2,1;enable;"..ESC(S("Disabled")).."]" or |
| | | "button[3,2;2,1;disable;"..ESC(S("Enabled")).."]").. |
| | | "label[0,3;"..ESC(S("Keeping %d/%d map blocks loaded"):format( |
| | | #currently_forceloaded_positions(meta), #compute_forceload_positions(pos, meta) |
| | | )).."]") |
| | | end |
| | | |
| | | minetest.register_node("technic:admin_anchor", { |
| | |
| | | end, |
| | | can_dig = function (pos, player) |
| | | local meta = minetest.get_meta(pos) |
| | | return meta:get_int("locked") == 0 or (player and player:is_player() and player:get_player_name() == meta:get_string("owner")) |
| | | return meta:get_int("locked") == 0 or |
| | | (player and player:is_player() and player:get_player_name() == meta:get_string("owner")) |
| | | end, |
| | | on_destruct = function (pos) |
| | | local meta = minetest.get_meta(pos) |
| | |
| | | forceload_off(meta) |
| | | if fields.disable then meta:set_int("enabled", 0) end |
| | | if fields.enable then meta:set_int("enabled", 1) end |
| | | if fields.radius and string.find(fields.radius, "^[0-9]+$") and tonumber(fields.radius) < 256 then meta:set_int("radius", fields.radius) end |
| | | if fields.radius |
| | | and string.find(fields.radius, "^[0-9]+$") |
| | | and tonumber(fields.radius) < 256 then |
| | | meta:set_int("radius", fields.radius) |
| | | end |
| | | if meta:get_int("enabled") ~= 0 then |
| | | forceload_on(pos, meta) |
| | | end |
| | |
| | | return false |
| | | end |
| | | |
| | | local function table_empty(table) |
| | | for _, __ in pairs(table) do |
| | | local function table_empty(what) |
| | | for _ in pairs(what) do |
| | | return false |
| | | end |
| | | return true |
| | | end |
| | | |
| | | local function add_table(table, toadd) |
| | | local function add_table(what, toadd) |
| | | local i = 1 |
| | | while true do |
| | | local o = table[i] |
| | | local o = what[i] |
| | | if o == toadd then return end |
| | | if o == nil then break end |
| | | i = i + 1 |
| | | end |
| | | table[i] = toadd |
| | | what[i] = toadd |
| | | end |
| | | |
| | | local function move_nodes_vect(poslist, vect, must_not_move, owner) |
| | |
| | | |
| | | on_rightclick = function(pos, node, placer, itemstack, pointed_thing) |
| | | if is_supported_node(itemstack:get_name()) then |
| | | -- Stripped down version of "core.item_place_node" |
| | | if minetest.is_protected(pos, placer:get_player_name()) then |
| | | minetest.log("action", placer:get_player_name() |
| | | .. " tried to place " .. itemstack:get_name() |
| | |
| | | end |
| | | |
| | | -- Run script hook |
| | | local callback = nil |
| | | for _, _ in ipairs(minetest.registered_on_placenodes) do |
| | | for _, callback in ipairs(minetest.registered_on_placenodes) do |
| | | -- Copy pos and node because callback can modify them |
| | | local pos_copy = { x = pos.x, y = pos.y, z = pos.z } |
| | | local newnode_copy = { name = def.name, param1 = 0, param2 = 0 } |
| | |
| | | local pos = vector.round(self.object:getpos()) |
| | | frames_pos[pos_to_string(pos)] = node.name |
| | | |
| | | local stack = ItemStack(node.name) |
| | | local itemtable = stack:to_table() |
| | | local itemname = nil |
| | | |
| | | if itemtable then |
| | | itemname = stack:to_table().name |
| | | end |
| | | |
| | | local item_texture = nil |
| | | local item_type = "" |
| | | if minetest.registered_items[itemname] then |
| | | item_texture = minetest.registered_items[itemname].inventory_image |
| | | item_type = minetest.registered_items[itemname].type |
| | | end |
| | | local prop = { |
| | | is_visible = true, |
| | | textures = { node.name }, |
| | |
| | | end |
| | | |
| | | local run = function(pos, node) |
| | | local below = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}) |
| | | local meta = minetest.get_meta(pos) |
| | | local meta = minetest.get_meta(pos) |
| | | local network_id = tonumber(meta:get_string(tier.."_network")) |
| | | |
| | | if not technic.is_tier_cable(below.name, tier) then |
| | | if not technic.networks[network_id] then |
| | | meta:set_string("infotext", S("%s Battery Box Has No Network"):format(tier)) |
| | | return |
| | | end |
| | |
| | | drop = "technic:"..ltier.."_battery_box0", |
| | | on_construct = function(pos) |
| | | local meta = minetest.get_meta(pos) |
| | | local EU_upgrade, tube_upgrade = 0, 0 |
| | | local EU_upgrade, _ = 0 |
| | | if data.upgrade then |
| | | EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta) |
| | | EU_upgrade, _ = technic.handle_machine_upgrades(meta) |
| | | end |
| | | local max_charge = data.max_charge * (1 + EU_upgrade / 10) |
| | | local charge = meta:get_int("internal_EU_charge") |
| | |
| | | meta = minetest.get_meta(pos) |
| | | if not pipeworks.may_configure(pos, sender) then return end |
| | | fs_helpers.on_receive_fields(pos, fields) |
| | | local EU_upgrade, tube_upgrade = 0, 0 |
| | | local EU_upgrade, _ = 0 |
| | | if data.upgrade then |
| | | EU_upgrade, tube_upgrade = technic.handle_machine_upgrades(meta) |
| | | EU_upgrade, _ = technic.handle_machine_upgrades(meta) |
| | | end |
| | | local max_charge = data.max_charge * (1 + EU_upgrade / 10) |
| | | local charge = meta:get_int("internal_EU_charge") |
| | |
| | | end |
| | | ) |
| | | |
| | | function technic.get_charge(itemstack) |
| | | -- check if is chargable |
| | | local tool_name = itemstack:get_name() |
| | | if not technic.power_tools[tool_name] then |
| | | return 0, 0 |
| | | end |
| | | local item_meta = technic.get_stack_meta(itemstack) |
| | | return item_meta:get_int("technic:charge"), technic.power_tools[tool_name] |
| | | end |
| | | |
| | | function technic.set_charge(itemstack, charge) |
| | | local tool_name = itemstack:get_name() |
| | | if technic.power_tools[tool_name] then |
| | | technic.set_RE_wear(itemstack, charge, technic.power_tools[tool_name]) |
| | | end |
| | | local item_meta = technic.get_stack_meta(itemstack) |
| | | item_meta:set_int("technic:charge", charge) |
| | | end |
| | | |
| | | function technic.charge_tools(meta, batt_charge, charge_step) |
| | | local inv = meta:get_inventory() |
| | | if inv:is_empty("src") then |
| | |
| | | end |
| | | local src_stack = inv:get_stack("src", 1) |
| | | |
| | | local tool_name = src_stack:get_name() |
| | | if not technic.power_tools[tool_name] then |
| | | -- get callbacks |
| | | local src_def = src_stack:get_definition() |
| | | local technic_get_charge = src_def.technic_get_charge or technic.get_charge |
| | | local technic_set_charge = src_def.technic_set_charge or technic.set_charge |
| | | |
| | | -- get tool charge |
| | | local tool_charge, item_max_charge = technic_get_charge(src_stack) |
| | | if item_max_charge==0 then |
| | | return batt_charge, false |
| | | end |
| | | -- Set meta data for the tool if it didn't do it itself |
| | | local src_meta = minetest.deserialize(src_stack:get_metadata()) or {} |
| | | if not src_meta.charge then |
| | | src_meta.charge = 0 |
| | | end |
| | | |
| | | -- Do the charging |
| | | local item_max_charge = technic.power_tools[tool_name] |
| | | local tool_charge = src_meta.charge |
| | | if tool_charge >= item_max_charge then |
| | | return batt_charge, true |
| | | elseif batt_charge <= 0 then |
| | |
| | | charge_step = math.min(charge_step, item_max_charge - tool_charge) |
| | | tool_charge = tool_charge + charge_step |
| | | batt_charge = batt_charge - charge_step |
| | | technic.set_RE_wear(src_stack, tool_charge, item_max_charge) |
| | | src_meta.charge = tool_charge |
| | | src_stack:set_metadata(minetest.serialize(src_meta)) |
| | | technic_set_charge(src_stack, tool_charge) |
| | | inv:set_stack("src", 1, src_stack) |
| | | return batt_charge, (tool_charge == item_max_charge) |
| | | end |
| | |
| | | if inv:is_empty("dst") then |
| | | return batt_charge, false |
| | | end |
| | | local srcstack = inv:get_stack("dst", 1) |
| | | local toolname = srcstack:get_name() |
| | | if technic.power_tools[toolname] == nil then |
| | | local src_stack = inv:get_stack("dst", 1) |
| | | |
| | | -- get callbacks |
| | | local src_def = src_stack:get_definition() |
| | | local technic_get_charge = src_def.technic_get_charge or technic.get_charge |
| | | local technic_set_charge = src_def.technic_set_charge or technic.set_charge |
| | | |
| | | -- get tool charge |
| | | local tool_charge, item_max_charge = technic_get_charge(src_stack) |
| | | if item_max_charge==0 then |
| | | return batt_charge, false |
| | | end |
| | | -- Set meta data for the tool if it didn't do it itself :-( |
| | | local src_meta = minetest.deserialize(srcstack:get_metadata()) |
| | | src_meta = src_meta or {} |
| | | if not src_meta.charge then |
| | | src_meta.charge = 0 |
| | | end |
| | | |
| | | -- Do the discharging |
| | | local item_max_charge = technic.power_tools[toolname] |
| | | local tool_charge = src_meta.charge |
| | | if tool_charge <= 0 then |
| | | return batt_charge, true |
| | | elseif batt_charge >= max_charge then |
| | |
| | | charge_step = math.min(charge_step, tool_charge) |
| | | tool_charge = tool_charge - charge_step |
| | | batt_charge = batt_charge + charge_step |
| | | technic.set_RE_wear(srcstack, tool_charge, item_max_charge) |
| | | src_meta.charge = tool_charge |
| | | srcstack:set_metadata(minetest.serialize(src_meta)) |
| | | inv:set_stack("dst", 1, srcstack) |
| | | technic_set_charge(src_stack, tool_charge) |
| | | inv:set_stack("dst", 1, src_stack) |
| | | return batt_charge, (tool_charge == 0) |
| | | end |
| | | |
| | |
| | | return cable_tier[name] |
| | | end |
| | | |
| | | function technic.register_cable_tier(name, tier) |
| | | assert(technic.machines[tier], "Tier does not exist") |
| | | assert(type(name) == "string", "Invalid node name") |
| | | |
| | | cable_tier[name] = tier |
| | | end |
| | | |
| | | local function check_connections(pos) |
| | | -- Build a table of all machines |
| | | local machines = {} |
| | |
| | | local tier = network.tier |
| | | |
| | | -- Actually add it to the (cached) network |
| | | -- This is similar to check_node_subp |
| | | -- !! IMPORTANT: ../switching_station.lua -> check_node_subp() must be kept in sync |
| | | technic.cables[minetest.hash_node_position(pos)] = network_id |
| | | pos.visited = 1 |
| | | if technic.is_tier_cable(name, tier) then |
| | | if technic.is_tier_cable(node.name, tier) then |
| | | -- Found a cable |
| | | table.insert(network.all_nodes,pos) |
| | | elseif technic.machines[tier][node.name] then |
| | | meta:set_string(tier.."_network",minetest.pos_to_string(sw_pos)) |
| | | if technic.machines[tier][node.name] == technic.producer then |
| | | table.insert(network.PR_nodes,pos) |
| | | elseif technic.machines[tier][node.name] == technic.receiver then |
| | | table.insert(network.RE_nodes,pos) |
| | | elseif technic.machines[tier][node.name] == technic.producer_receiver then |
| | | table.insert(network.PR_nodes,pos) |
| | | table.insert(network.RE_nodes,pos) |
| | | elseif technic.machines[tier][node.name] == "SPECIAL" and |
| | | (pos.x ~= sw_pos.x or pos.y ~= sw_pos.y or pos.z ~= sw_pos.z) and |
| | | from_below then |
| | | table.insert(network.SP_nodes,pos) |
| | | elseif technic.machines[tier][node.name] == technic.battery then |
| | | table.insert(network.BA_nodes,pos) |
| | | -- Found a machine |
| | | local eu_type = technic.machines[tier][node.name] |
| | | meta:set_string(tier.."_network", string.format("%.20g", network_id)) |
| | | if eu_type == technic.producer then |
| | | table.insert(network.PR_nodes, pos) |
| | | elseif eu_type == technic.receiver then |
| | | table.insert(network.RE_nodes, pos) |
| | | elseif eu_type == technic.producer_receiver then |
| | | table.insert(network.PR_nodes, pos) |
| | | table.insert(network.RE_nodes, pos) |
| | | elseif eu_type == technic.battery then |
| | | table.insert(network.BA_nodes, pos) |
| | | end |
| | | -- Note: SPECIAL (i.e. switching station) is not traversed! |
| | | end |
| | | elseif dead_end and not placed then |
| | | -- Dead end removed, remove it from the network |
| | |
| | | technic.register_recipe("compressing", data) |
| | | end |
| | | |
| | | -- Defuse the default recipes, since we have |
| | | -- the compressor to take over in a more realistic manner. |
| | | local crafts_to_clear = { |
| | | "default:desert_sand", |
| | | "default:sand", |
| | | "default:silver_sand", |
| | | } |
| | | |
| | | local dependent_crafts_to_clear = { |
| | | everness = { |
| | | "everness:coral_sand", |
| | | "everness:coral_forest_deep_ocean_sand", |
| | | "everness:coral_white_sand", |
| | | "everness:crystal_sand", |
| | | "everness:cursed_sand", |
| | | "everness:cursed_lands_deep_ocean_sand", |
| | | "everness:crystal_forest_deep_ocean_sand", |
| | | "everness:mineral_sand", |
| | | }, |
| | | nether = { |
| | | "nether:brick", |
| | | "nether:brick_compressed", |
| | | "nether:rack", |
| | | "nether:rack_deep", |
| | | }, |
| | | } |
| | | |
| | | -- Add dependent recipes to main collection of |
| | | -- recipes to be cleared if their mods are used. |
| | | for dependency, crafts in pairs(dependent_crafts_to_clear) do |
| | | if minetest.get_modpath(dependency) then |
| | | for _, craft_entry in ipairs(crafts) do |
| | | table.insert(crafts_to_clear, craft_entry) |
| | | end |
| | | end |
| | | end |
| | | |
| | | -- Clear recipes |
| | | for _, craft_name in ipairs(crafts_to_clear) do |
| | | -- Regular bricks are 2x2 shaped, nether bricks are 3x3 shaped (irregular) |
| | | local is_regular = string.sub(craft_name, 1, 12) ~= "nether:brick" |
| | | local shaped_recipe |
| | | |
| | | if is_regular then |
| | | shaped_recipe = { |
| | | {craft_name, craft_name}, |
| | | {craft_name, craft_name}, |
| | | } |
| | | else |
| | | shaped_recipe = { |
| | | {craft_name, craft_name, craft_name}, |
| | | {craft_name, craft_name, craft_name}, |
| | | {craft_name, craft_name, craft_name}, |
| | | } |
| | | end |
| | | |
| | | minetest.clear_craft({ |
| | | type = "shaped", |
| | | recipe = shaped_recipe, |
| | | }) |
| | | end |
| | | |
| | | -- |
| | | -- Compile compressor recipes |
| | | -- |
| | | local recipes = { |
| | | {"default:snowblock", "default:ice"}, |
| | | {"default:sand 2", "default:sandstone"}, |
| | |
| | | {"technic:uranium35_ingot 5", "technic:uranium_fuel"}, |
| | | } |
| | | |
| | | -- defuse the default sandstone recipe, since we have the compressor to take over in a more realistic manner |
| | | minetest.clear_craft({ |
| | | recipe = { |
| | | {"default:sand", "default:sand"}, |
| | | {"default:sand", "default:sand"}, |
| | | local dependent_recipes = { |
| | | everness = { |
| | | {"everness:coral_deep_ocean_sand 2", "everness:coral_deep_ocean_sandstone_block"}, |
| | | {"everness:coral_sand 2", "everness:coral_sandstone"}, |
| | | {"everness:coral_white_sand 2", "everness:coral_white_sandstone"}, |
| | | {"everness:crystal_forest_deep_ocean_sand 2", "everness:crystal_forest_deep_ocean_sandstone_block"}, |
| | | {"everness:crystal_sand 2", "everness:crystal_sandstone"}, |
| | | {"everness:cursed_lands_deep_ocean_sand 2", "everness:cursed_lands_deep_ocean_sandstone_block"}, |
| | | {"everness:cursed_sand 2", "everness:cursed_sandstone_block"}, |
| | | {"everness:mineral_sand 2", "everness:mineral_sandstone"}, |
| | | }, |
| | | }) |
| | | minetest.clear_craft({ |
| | | recipe = { |
| | | {"default:desert_sand", "default:desert_sand"}, |
| | | {"default:desert_sand", "default:desert_sand"}, |
| | | nether = { |
| | | {"nether:brick 9", "nether:brick_compressed"}, |
| | | {"nether:brick_compressed 9", "nether:nether_lump"}, |
| | | {"nether:rack", "nether:brick",}, |
| | | {"nether:rack_deep", "nether:brick_deep"}, |
| | | }, |
| | | }) |
| | | minetest.clear_craft({ |
| | | recipe = { |
| | | {"default:silver_sand", "default:silver_sand"}, |
| | | {"default:silver_sand", "default:silver_sand"}, |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | -- Add dependent recipes to main recipe collection |
| | | -- if their mods are used. |
| | | for dependency, recipes_to_add in pairs(dependent_recipes) do |
| | | if minetest.get_modpath(dependency) then |
| | | for _, recipe_entry in ipairs(recipes_to_add) do |
| | | table.insert(recipes, recipe_entry) |
| | | end |
| | | end |
| | | end |
| | | |
| | | -- Register compressor recipes |
| | | for _, data in pairs(recipes) do |
| | | technic.register_compressor_recipe({input = {data[1]}, output = data[2]}) |
| | | end |
| | | |
| | |
| | | {"technic:sulfur_lump", "technic:sulfur_dust 2"}, |
| | | {"default:stone", "technic:stone_dust"}, |
| | | {"default:sand", "technic:stone_dust"}, |
| | | {"default:desert_sand", "technic:stone_dust"}, |
| | | {"default:silver_sand", "technic:stone_dust"}, |
| | | |
| | | -- Other |
| | | {"default:cobble", "default:gravel"}, |
| | |
| | | {"default:ice", "default:snowblock"}, |
| | | } |
| | | |
| | | local dependent_recipes = { |
| | | -- Sandstones |
| | | everness = { |
| | | {"everness:coral_deep_ocean_sandstone_block", "everness:coral_deep_ocean_sand 2"}, |
| | | {"everness:coral_sandstone", "everness:coral_sand 2"}, |
| | | {"everness:coral_white_sandstone", "everness:coral_white_sand 2"}, |
| | | {"everness:crystal_forest_deep_ocean_sandstone_block", "everness:crystal_forest_deep_ocean_sand 2"}, |
| | | {"everness:crystal_sandstone", "everness:crystal_sand 2"}, |
| | | {"everness:cursed_lands_deep_ocean_sandstone_block", "everness:cursed_lands_deep_ocean_sand 2"}, |
| | | {"everness:cursed_sandstone_block", "everness:cursed_sand 2"}, |
| | | {"everness:mineral_sandstone", "everness:mineral_sand 2"}, |
| | | -- Lumps and wheat |
| | | {"everness:pyrite_lump", "technic:pyrite_dust 2"}, |
| | | }, |
| | | farming = { |
| | | {"farming:seed_wheat", "farming:flour 1"}, |
| | | }, |
| | | gloopores = { |
| | | {"gloopores:alatro_lump", "technic:alatro_dust 2"}, |
| | | {"gloopores:kalite_lump", "technic:kalite_dust 2"}, |
| | | {"gloopores:arol_lump", "technic:arol_dust 2"}, |
| | | {"gloopores:talinite_lump", "technic:talinite_dust 2"}, |
| | | {"gloopores:akalin_lump", "technic:akalin_dust 2"}, |
| | | }, |
| | | homedecor = { |
| | | {"home_decor:brass_ingot", "technic:brass_dust 1"}, |
| | | }, |
| | | moreores = { |
| | | {"moreores:mithril_lump", "technic:mithril_dust 2"}, |
| | | {"moreores:silver_lump", "technic:silver_dust 2"}, |
| | | }, |
| | | nether = { |
| | | {"nether:nether_lump", "technic:nether_dust 2"}, |
| | | }, |
| | | } |
| | | |
| | | for dependency, materials_to_add in pairs(dependent_recipes) do |
| | | if minetest.get_modpath(dependency) then |
| | | for _, material_entry in ipairs(materials_to_add) do |
| | | table.insert(recipes, material_entry) |
| | | end |
| | | end |
| | | end |
| | | |
| | | -- defuse the sandstone -> 4 sand recipe to avoid infinite sand bugs (also consult the inverse compressor recipe) |
| | | minetest.clear_craft({ |
| | | recipe = { |
| | | {"default:sandstone"} |
| | | }, |
| | | recipe = {{"default:sandstone"}}, |
| | | }) |
| | | minetest.clear_craft({ |
| | | recipe = { |
| | | {"default:desert_sandstone"} |
| | | }, |
| | | recipe = {{"default:desert_sandstone"}}, |
| | | }) |
| | | minetest.clear_craft({ |
| | | recipe = { |
| | | {"default:silver_sandstone"} |
| | | }, |
| | | recipe = {{"default:silver_sandstone"}}, |
| | | }) |
| | | |
| | | if minetest.get_modpath("farming") then |
| | | table.insert(recipes, {"farming:seed_wheat", "farming:flour 1"}) |
| | | if minetest.get_modpath("everness") then |
| | | minetest.clear_craft({ |
| | | recipe = {{"everness:mineral_sandstone"}}, |
| | | }) |
| | | -- Currently (2024-03-09), there seem to be no reverse recipes for any of the other everness sandstones. |
| | | end |
| | | |
| | | if minetest.get_modpath("moreores") then |
| | | table.insert(recipes, {"moreores:mithril_lump", "technic:mithril_dust 2"}) |
| | | table.insert(recipes, {"moreores:silver_lump", "technic:silver_dust 2"}) |
| | | end |
| | | |
| | | if minetest.get_modpath("gloopores") or minetest.get_modpath("glooptest") then |
| | | table.insert(recipes, {"gloopores:alatro_lump", "technic:alatro_dust 2"}) |
| | | table.insert(recipes, {"gloopores:kalite_lump", "technic:kalite_dust 2"}) |
| | | table.insert(recipes, {"gloopores:arol_lump", "technic:arol_dust 2"}) |
| | | table.insert(recipes, {"gloopores:talinite_lump", "technic:talinite_dust 2"}) |
| | | table.insert(recipes, {"gloopores:akalin_lump", "technic:akalin_dust 2"}) |
| | | end |
| | | |
| | | if minetest.get_modpath("homedecor") then |
| | | table.insert(recipes, {"home_decor:brass_ingot", "technic:brass_dust 1"}) |
| | | end |
| | | |
| | | for _, data in pairs(recipes) do |
| | | for _, data in ipairs(recipes) do |
| | | technic.register_grinder_recipe({input = {data[1]}, output = data[2]}) |
| | | end |
| | | |
| | | -- dusts |
| | | -- Dusts |
| | | local function register_dust(name, ingot) |
| | | local lname = string.lower(name) |
| | | lname = string.gsub(lname, ' ', '_') |
| | |
| | | end |
| | | end |
| | | |
| | | -- Sorted alphibeticaly |
| | | register_dust("Brass", "basic_materials:brass_ingot") |
| | | register_dust("Bronze", "default:bronze_ingot") |
| | | register_dust("Carbon Steel", "technic:carbon_steel_ingot") |
| | | register_dust("Cast Iron", "technic:cast_iron_ingot") |
| | | register_dust("Chernobylite", "technic:chernobylite_block") |
| | | register_dust("Chromium", "technic:chromium_ingot") |
| | | register_dust("Coal", nil) |
| | | register_dust("Copper", "default:copper_ingot") |
| | | register_dust("Lead", "technic:lead_ingot") |
| | | register_dust("Gold", "default:gold_ingot") |
| | | register_dust("Mithril", "moreores:mithril_ingot") |
| | | register_dust("Silver", "moreores:silver_ingot") |
| | | register_dust("Stainless Steel", "technic:stainless_steel_ingot") |
| | | register_dust("Stone", "default:stone") |
| | | register_dust("Sulfur", nil) |
| | | register_dust("Tin", "default:tin_ingot") |
| | | register_dust("Wrought Iron", "technic:wrought_iron_ingot") |
| | | register_dust("Zinc", "technic:zinc_ingot") |
| | | if minetest.get_modpath("gloopores") or minetest.get_modpath("glooptest") then |
| | | register_dust("Akalin", "glooptest:akalin_ingot") |
| | | register_dust("Alatro", "glooptest:alatro_ingot") |
| | | register_dust("Arol", "glooptest:arol_ingot") |
| | | register_dust("Kalite", nil) |
| | | register_dust("Talinite", "glooptest:talinite_ingot") |
| | | -- Sorted alphabetically |
| | | local dusts = { |
| | | {"Brass", "basic_materials:brass_ingot"}, |
| | | {"Bronze", "default:bronze_ingot"}, |
| | | {"Carbon Steel", "technic:carbon_steel_ingot"}, |
| | | {"Cast Iron", "technic:cast_iron_ingot"}, |
| | | {"Chernobylite", "technic:chernobylite_block"}, |
| | | {"Chromium", "technic:chromium_ingot"}, |
| | | {"Coal", nil}, |
| | | {"Copper", "default:copper_ingot"}, |
| | | {"Lead", "technic:lead_ingot"}, |
| | | {"Gold", "default:gold_ingot"}, |
| | | {"Mithril", "moreores:mithril_ingot"}, |
| | | {"Silver", "moreores:silver_ingot"}, |
| | | {"Stainless Steel", "technic:stainless_steel_ingot"}, |
| | | {"Stone", "default:stone"}, |
| | | {"Sulfur", nil}, |
| | | {"Tin", "default:tin_ingot"}, |
| | | {"Wrought Iron", "technic:wrought_iron_ingot"}, |
| | | {"Zinc", "technic:zinc_ingot"}, |
| | | } |
| | | |
| | | local dependent_dusts = { |
| | | everness = { |
| | | {"Pyrite", "everness:pyrite_ingot"}, |
| | | }, |
| | | gloopores = { |
| | | {"Akalin", "glooptest:akalin_ingot"}, |
| | | {"Alatro", "glooptest:alatro_ingot"}, |
| | | {"Arol", "glooptest:arol_ingot"}, |
| | | {"Kalite", nil}, |
| | | {"Talinite", "glooptest:talinite_ingot"}, |
| | | }, |
| | | nether = { |
| | | {"Nether", "nether:nether_ingot"}, |
| | | }, |
| | | } |
| | | |
| | | for dependency, dusts_to_add in pairs(dependent_dusts) do |
| | | if minetest.get_modpath(dependency) then |
| | | for _, dust_entry in pairs(dusts_to_add) do |
| | | table.insert(dusts, dust_entry) |
| | | end |
| | | end |
| | | end |
| | | |
| | | for _, data in ipairs(dusts) do |
| | | register_dust(data[1], data[2]) |
| | | end |
| | | |
| | | -- Uranium |
| | | for p = 0, 35 do |
| | | local nici = (p ~= 0 and p ~= 7 and p ~= 35) and 1 or nil |
| | | local psuffix = p == 7 and "" or p |
| | |
| | | end |
| | | end |
| | | |
| | | -- Fuels |
| | | minetest.register_craft({ |
| | | type = "fuel", |
| | | recipe = "technic:coal_dust", |
| | |
| | | return |
| | | end |
| | | |
| | | local remain = 0.9 |
| | | local efficiency = 0.9 |
| | | -- Machine information |
| | | local machine_name = S("Supply Converter") |
| | | local meta = minetest.get_meta(pos) |
| | |
| | | enabled = enabled == "1" |
| | | end |
| | | enabled = enabled and (meta:get_int("mesecon_mode") == 0 or meta:get_int("mesecon_effect") ~= 0) |
| | | local demand = enabled and meta:get_int("power") or 0 |
| | | |
| | | local pos_up = {x=pos.x, y=pos.y+1, z=pos.z} |
| | | local pos_down = {x=pos.x, y=pos.y-1, z=pos.z} |
| | |
| | | local to = technic.get_cable_tier(name_down) |
| | | |
| | | if from and to then |
| | | local input = meta:get_int(from.."_EU_input") |
| | | meta:set_int(from.."_EU_demand", demand) |
| | | meta:set_int(from.."_EU_supply", 0) |
| | | meta:set_int(to.."_EU_demand", 0) |
| | | meta:set_int(to.."_EU_supply", input * remain) |
| | | meta:set_string("infotext", S("@1 (@2 @3 -> @4 @5)", machine_name, |
| | | technic.EU_string(input), from, |
| | | technic.EU_string(input * remain), to)) |
| | | -- Get the "to" network switching station for EU demand calculation |
| | | local network_hash = technic.cables[minetest.hash_node_position(pos_down)] |
| | | local network = network_hash and minetest.get_position_from_hash(network_hash) |
| | | local sw_pos = network and {x=network.x,y=network.y+1,z=network.z} |
| | | local timeout = 0 |
| | | for tier in pairs(technic.machines) do |
| | | -- Supply converter must be connected to a network |
| | | timeout = math.max(meta:get_int(tier.."_EU_timeout"), timeout) |
| | | end |
| | | if timeout > 0 and sw_pos and minetest.get_node(sw_pos).name == "technic:switching_station" then |
| | | local sw_meta = minetest.get_meta(sw_pos) |
| | | local demand = 0 |
| | | if enabled then |
| | | -- Reverse evaluate the required machine and round to a nice number |
| | | demand = sw_meta:get_int("ba_demand") + sw_meta:get_int("demand") |
| | | demand = 100 * math.ceil(demand / efficiency / 100) |
| | | -- Do not draw more than the limit |
| | | demand = math.min(demand, meta:get_int("power")) |
| | | end |
| | | |
| | | local input = meta:get_int(from.."_EU_input") -- actual input |
| | | meta:set_int(from.."_EU_demand", demand) -- desired input |
| | | meta:set_int(from.."_EU_supply", 0) |
| | | meta:set_int(to.."_EU_demand", 0) |
| | | meta:set_int(to.."_EU_supply", input * efficiency) |
| | | meta:set_string("infotext", S("@1 (@2 @3 -> @4 @5)", machine_name, |
| | | technic.EU_string(input), from, |
| | | technic.EU_string(input * efficiency), to)) |
| | | else |
| | | meta:set_string("infotext",S("%s Has No Network"):format(machine_name)) |
| | | end |
| | | else |
| | | meta:set_string("infotext", S("%s Has Bad Cabling"):format(machine_name)) |
| | | if to then |
| | |
| | | meta:set_string("active", 1) |
| | | meta:set_string("channel", "switching_station"..minetest.pos_to_string(pos)) |
| | | meta:set_string("formspec", "field[channel;Channel;${channel}]") |
| | | local poshash = minetest.hash_node_position(pos) |
| | | technic.redundant_warn.poshash = nil |
| | | end, |
| | | after_dig_node = function(pos) |
| | | minetest.forceload_free_block(pos) |
| | | pos.y = pos.y - 1 |
| | | minetest.forceload_free_block(pos) |
| | | local poshash = minetest.hash_node_position(pos) |
| | | technic.redundant_warn.poshash = nil |
| | | end, |
| | | on_receive_fields = function(pos, formname, fields, sender) |
| | |
| | | end |
| | | |
| | | -- Add a wire node to the LV/MV/HV network |
| | | -- Returns: indicator whether the cable is new in the network |
| | | local hash_node_position = minetest.hash_node_position |
| | | local function add_network_node(nodes, pos, network_id) |
| | | local node_id = minetest.hash_node_position(pos) |
| | | local node_id = hash_node_position(pos) |
| | | technic.cables[node_id] = network_id |
| | | if nodes[node_id] then |
| | | return false |
| | |
| | | end |
| | | |
| | | -- Generic function to add found connected nodes to the right classification array |
| | | local check_node_subp = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos, from_below, network_id, queue) |
| | | -- !! IMPORTANT: register/cables.lua -> clear_networks() must be kept in sync |
| | | local check_node_subp = function(network, pos, machines, sw_pos, from_below, network_id, queue) |
| | | technic.get_or_load_node(pos) |
| | | local name = minetest.get_node(pos).name |
| | | |
| | | if technic.is_tier_cable(name, tier) then |
| | | add_cable_node(all_nodes, pos,network_id, queue) |
| | | elseif machines[name] then |
| | | --dprint(name.." is a "..machines[name]) |
| | | local meta = minetest.get_meta(pos) |
| | | meta:set_string(tier.."_network",minetest.pos_to_string(sw_pos)) |
| | | if machines[name] == technic.producer then |
| | | add_network_node(PR_nodes, pos, network_id) |
| | | elseif machines[name] == technic.receiver then |
| | | add_network_node(RE_nodes, pos, network_id) |
| | | elseif machines[name] == technic.producer_receiver then |
| | | add_network_node(PR_nodes, pos, network_id) |
| | | add_network_node(RE_nodes, pos, network_id) |
| | | elseif machines[name] == "SPECIAL" and |
| | | (pos.x ~= sw_pos.x or pos.y ~= sw_pos.y or pos.z ~= sw_pos.z) and |
| | | from_below then |
| | | -- Another switching station -> disable it |
| | | add_network_node(SP_nodes, pos, network_id) |
| | | meta:set_int("active", 0) |
| | | elseif machines[name] == technic.battery then |
| | | add_network_node(BA_nodes, pos, network_id) |
| | | end |
| | | |
| | | meta:set_int(tier.."_EU_timeout", 2) -- Touch node |
| | | if technic.is_tier_cable(name, network.tier) then |
| | | add_cable_node(network.all_nodes, pos, network_id, queue) |
| | | return |
| | | end |
| | | |
| | | local eu_type = machines[name] |
| | | if not eu_type then |
| | | return |
| | | end |
| | | |
| | | --dprint(name.." is a "..machines[name]) |
| | | local meta = minetest.get_meta(pos) |
| | | -- Normal tostring() does not have enough precision, neither does meta:set_int() |
| | | -- Lua 5.1 bug: Cannot use hexadecimal notation for compression (see LuaJIT #911) |
| | | meta:set_string(network.tier.."_network", string.format("%.20g", network_id)) |
| | | |
| | | if eu_type == technic.producer then |
| | | add_network_node(network.PR_nodes, pos, network_id) |
| | | elseif eu_type == technic.receiver then |
| | | add_network_node(network.RE_nodes, pos, network_id) |
| | | elseif eu_type == technic.producer_receiver then |
| | | add_network_node(network.PR_nodes, pos, network_id) |
| | | add_network_node(network.RE_nodes, pos, network_id) |
| | | elseif eu_type == technic.battery then |
| | | add_network_node(network.BA_nodes, pos, network_id) |
| | | elseif eu_type == "SPECIAL" and from_below and |
| | | not vector.equals(pos, sw_pos) then |
| | | -- Another switching station -> disable it |
| | | add_network_node(network.SP_nodes, pos, network_id) |
| | | meta:set_int("active", 0) |
| | | end |
| | | |
| | | meta:set_int(network.tier.."_EU_timeout", 2) -- Touch node |
| | | end |
| | | |
| | | -- Traverse a network given a list of machines and a cable type name |
| | | local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, pos, machines, tier, sw_pos, network_id, queue) |
| | | local traverse_network = function(network, pos, machines, sw_pos, network_id, queue) |
| | | local positions = { |
| | | {x=pos.x+1, y=pos.y, z=pos.z}, |
| | | {x=pos.x-1, y=pos.y, z=pos.z}, |
| | |
| | | {x=pos.x, y=pos.y, z=pos.z+1}, |
| | | {x=pos.x, y=pos.y, z=pos.z-1}} |
| | | for i, cur_pos in pairs(positions) do |
| | | check_node_subp(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, cur_pos, machines, tier, sw_pos, i == 3, network_id, queue) |
| | | check_node_subp(network, cur_pos, machines, sw_pos, i == 3, network_id, queue) |
| | | end |
| | | end |
| | | |
| | |
| | | end |
| | | end |
| | | |
| | | local get_network = function(sw_pos, pos1, tier) |
| | | local network_id = minetest.hash_node_position(pos1) |
| | | local get_network = function(sw_pos, cable_pos, tier) |
| | | local network_id = minetest.hash_node_position(cable_pos) |
| | | local cached = technic.networks[network_id] |
| | | if cached and cached.tier == tier then |
| | | -- Re-use cached system data |
| | | touch_nodes(cached.PR_nodes, tier) |
| | | touch_nodes(cached.BA_nodes, tier) |
| | | touch_nodes(cached.RE_nodes, tier) |
| | | for _, pos in ipairs(cached.SP_nodes) do |
| | | -- Disable all other switching stations (again) |
| | | local meta = minetest.get_meta(pos) |
| | | meta:set_int("active", 0) |
| | | meta:set_string("active_pos", minetest.serialize(sw_pos)) |
| | | end |
| | | return cached.PR_nodes, cached.BA_nodes, cached.RE_nodes |
| | | end |
| | | local PR_nodes = {} |
| | | local BA_nodes = {} |
| | | local RE_nodes = {} |
| | | local SP_nodes = {} |
| | | local all_nodes = {} |
| | | |
| | | local machines = technic.machines[tier] |
| | | local network = { |
| | | tier = tier, |
| | | PR_nodes = {}, |
| | | BA_nodes = {}, |
| | | RE_nodes = {}, |
| | | SP_nodes = {}, |
| | | all_nodes = {} |
| | | } |
| | | -- Traverse the network step by step starting from the node underneath the switching station |
| | | local queue = {} |
| | | add_cable_node(all_nodes, pos1, network_id, queue) |
| | | add_cable_node(network.all_nodes, cable_pos, network_id, queue) |
| | | while next(queue) do |
| | | local to_visit = {} |
| | | for _, pos in ipairs(queue) do |
| | | traverse_network(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_nodes, |
| | | pos, technic.machines[tier], tier, sw_pos, network_id, to_visit) |
| | | traverse_network(network, pos, machines, sw_pos, network_id, to_visit) |
| | | end |
| | | queue = to_visit |
| | | end |
| | | PR_nodes = flatten(PR_nodes) |
| | | BA_nodes = flatten(BA_nodes) |
| | | RE_nodes = flatten(RE_nodes) |
| | | SP_nodes = flatten(SP_nodes) |
| | | all_nodes = flatten(all_nodes) |
| | | technic.networks[network_id] = {tier = tier, all_nodes = all_nodes, SP_nodes = SP_nodes, |
| | | PR_nodes = PR_nodes, RE_nodes = RE_nodes, BA_nodes = BA_nodes} |
| | | return PR_nodes, BA_nodes, RE_nodes |
| | | |
| | | -- Convert { [hash] = pos, ... } to { pos, ... } |
| | | network.PR_nodes = flatten(network.PR_nodes) |
| | | network.BA_nodes = flatten(network.BA_nodes) |
| | | network.RE_nodes = flatten(network.RE_nodes) |
| | | network.SP_nodes = flatten(network.SP_nodes) |
| | | network.all_nodes = flatten(network.all_nodes) |
| | | technic.networks[network_id] = network |
| | | |
| | | return network.PR_nodes, network.BA_nodes, network.RE_nodes |
| | | end |
| | | |
| | | ----------------------------------------------- |
| | |
| | | technic.powerctrl_state = true |
| | | |
| | | minetest.register_chatcommand("powerctrl", { |
| | | params = "state", |
| | | params = "[on/off]", |
| | | description = "Enables or disables technic's switching station ABM", |
| | | privs = { basic_privs = true }, |
| | | func = function(name, state) |
| | | if state == "on" then |
| | | technic.powerctrl_state = true |
| | | else |
| | | technic.powerctrl_state = false |
| | | end |
| | | technic.powerctrl_state = (state:trim():lower() == "on") |
| | | minetest.chat_send_player(name, "Technic switching station: " .. |
| | | (technic.powerctrl_state and "on" or "off")) |
| | | end |
| | | }) |
| | | |
| | | -- Run all the nodes |
| | | -- Run `technic_run` on all nodes in the power grid |
| | | local function run_nodes(list, run_stage) |
| | | for _, pos in ipairs(list) do |
| | | technic.get_or_load_node(pos) |
| | |
| | | |
| | | minetest.register_abm({ |
| | | nodenames = {"technic:switching_station"}, |
| | | label = "Switching Station", -- allows the mtt profiler to profile this abm individually |
| | | label = "Switching Station", -- name for the Minetest mod profiler |
| | | interval = 1, |
| | | chance = 1, |
| | | action = function(pos, node, active_object_count, active_object_count_wider) |
| | | if not technic.powerctrl_state then return end |
| | | local meta = minetest.get_meta(pos) |
| | | local meta = minetest.get_meta(pos) |
| | | local meta1 |
| | | local pos1 = {} |
| | | |
| | | local tier = "" |
| | | local PR_nodes |
| | | local BA_nodes |
| | | local RE_nodes |
| | | local PR_nodes, BA_nodes, RE_nodes |
| | | local machine_name = S("Switching Station") |
| | | |
| | | -- Which kind of network are we on: |
| | | pos1 = {x=pos.x, y=pos.y-1, z=pos.z} |
| | | local cable_pos = {x=pos.x, y=pos.y-1, z=pos.z} |
| | | |
| | | --Disable if necessary |
| | | if meta:get_int("active") ~= 1 then |
| | | minetest.forceload_free_block(pos) |
| | | minetest.forceload_free_block(pos1) |
| | | minetest.forceload_free_block(cable_pos) |
| | | meta:set_string("infotext",S("%s Already Present"):format(machine_name)) |
| | | |
| | | local poshash = minetest.hash_node_position(pos) |
| | |
| | | return |
| | | end |
| | | |
| | | local name = minetest.get_node(pos1).name |
| | | local name = minetest.get_node(cable_pos).name |
| | | local tier = technic.get_cable_tier(name) |
| | | if tier then |
| | | -- Forceload switching station |
| | | minetest.forceload_block(pos) |
| | | minetest.forceload_block(pos1) |
| | | PR_nodes, BA_nodes, RE_nodes = get_network(pos, pos1, tier) |
| | | minetest.forceload_block(cable_pos) |
| | | PR_nodes, BA_nodes, RE_nodes = get_network(pos, cable_pos, tier) |
| | | else |
| | | --dprint("Not connected to a network") |
| | | meta:set_string("infotext", S("%s Has No Network"):format(machine_name)) |
| | | minetest.forceload_free_block(pos) |
| | | minetest.forceload_free_block(pos1) |
| | | minetest.forceload_free_block(cable_pos) |
| | | return |
| | | end |
| | | |
| | |
| | | end |
| | | --dprint("Total RE demand:"..RE_eu_demand) |
| | | |
| | | -- Get all the power from the BA nodes |
| | | local BA_eu_supply = 0 |
| | | -- Batteries |
| | | local BA_eu_supply, BA_eu_demand = 0, 0 |
| | | for _, pos1 in pairs(BA_nodes) do |
| | | meta1 = minetest.get_meta(pos1) |
| | | BA_eu_supply = BA_eu_supply + meta1:get_int(eu_supply_str) |
| | | end |
| | | --dprint("Total BA supply:"..BA_eu_supply) |
| | | |
| | | -- Get all the demand from the BA nodes |
| | | local BA_eu_demand = 0 |
| | | for _, pos1 in pairs(BA_nodes) do |
| | | meta1 = minetest.get_meta(pos1) |
| | | BA_eu_demand = BA_eu_demand + meta1:get_int(eu_demand_str) |
| | | end |
| | | -- Expose value for the supply converter |
| | | meta:set_int("ba_demand", BA_eu_demand) |
| | | --dprint("Total BA supply:"..BA_eu_supply) |
| | | --dprint("Total BA demand:"..BA_eu_demand) |
| | | |
| | | meta:set_string("infotext", S("@1. Supply: @2 Demand: @3", |
| | |
| | | end |
| | | |
| | | -- Data that will be used by the power monitor |
| | | meta:set_int("supply",PR_eu_supply) |
| | | meta:set_int("demand",RE_eu_demand) |
| | | meta:set_int("supply", PR_eu_supply) |
| | | meta:set_int("demand", RE_eu_demand) |
| | | |
| | | -- If the PR supply is enough for the RE demand supply them all |
| | | if PR_eu_supply >= RE_eu_demand then |
| | |
| | | for tier, machines in pairs(technic.machines) do |
| | | if machines[node.name] and switching_station_timeout_count(pos, tier) then |
| | | local nodedef = minetest.registered_nodes[node.name] |
| | | if nodedef and nodedef.technic_disabled_machine_name then |
| | | node.name = nodedef.technic_disabled_machine_name |
| | | minetest.swap_node(pos, node) |
| | | elseif nodedef and nodedef.technic_on_disable then |
| | | nodedef.technic_on_disable(pos, node) |
| | | end |
| | | if nodedef then |
| | | local meta = minetest.get_meta(pos) |
| | | meta:set_string("infotext", S("%s Has No Network"):format(nodedef.description)) |
| | | end |
| | | if nodedef and nodedef.technic_disabled_machine_name then |
| | | node.name = nodedef.technic_disabled_machine_name |
| | | minetest.swap_node(pos, node) |
| | | end |
| | | if nodedef and nodedef.technic_on_disable then |
| | | nodedef.technic_on_disable(pos, node) |
| | | end |
| | | end |
| | | end |
| | | end, |
| | |
| | | name = technic |
| | | depends = default, pipeworks, technic_worldgen, basic_materials |
| | | optional_depends = bucket, screwdriver, mesecons, mesecons_mvps, digilines, digiline_remote, intllib, unified_inventory, vector_extras, dye, craftguide,i3 |
| | | optional_depends = bucket, screwdriver, mesecons, mesecons_mvps, digilines, digiline_remote, intllib, unified_inventory, vector_extras, dye, craftguide, i3, everness, nether |
| | |
| | | liquidtype = state, |
| | | liquid_alternative_flowing = "technic:corium_flowing", |
| | | liquid_alternative_source = "technic:corium_source", |
| | | liquid_viscosity = LAVA_VISC, |
| | | liquid_viscosity = 7, -- like lava |
| | | liquid_renewable = false, |
| | | damage_per_second = 6, |
| | | post_effect_color = {a=192, r=80, g=160, b=80}, |
| | |
| | | |
| | | -- Wear down a tool depending on the remaining charge. |
| | | function technic.set_RE_wear(itemstack, item_load, max_load) |
| | | if (minetest.registered_items[itemstack:get_name()].wear_represents or "mechanical_wear") ~= "technic_RE_charge" then return itemstack end |
| | | local def = minetest.registered_items[itemstack:get_name()] |
| | | if (def.wear_represents or "mechanical_wear") ~= "technic_RE_charge" then |
| | | return itemstack |
| | | end |
| | | local temp |
| | | if item_load == 0 then |
| | | temp = 0 |
| | |
| | | itemstack:set_wear(temp) |
| | | end |
| | | |
| | | local function get_can_level(itemstack) |
| | | if itemstack:get_metadata() == "" then |
| | | return 0 |
| | | else |
| | | return tonumber(itemstack:get_metadata()) |
| | | end |
| | | end |
| | | |
| | | function technic.register_can(d) |
| | | local data = {} |
| | | for k, v in pairs(d) do data[k] = v end |
| | |
| | | if pointed_thing.type ~= "node" then return end |
| | | local node = minetest.get_node(pointed_thing.under) |
| | | if node.name ~= data.liquid_source_name then return end |
| | | local charge = get_can_level(itemstack) |
| | | local meta = technic.get_stack_meta_cans(itemstack) |
| | | local charge = meta:get_int("can_level") |
| | | if charge == data.can_capacity then return end |
| | | if minetest.is_protected(pointed_thing.under, user:get_player_name()) then |
| | | minetest.log("action", user:get_player_name().." tried to take "..node.name.." at protected position "..minetest.pos_to_string(pointed_thing.under).." with a "..data.can_name) |
| | | minetest.log("action", user:get_player_name().. |
| | | " tried to take "..node.name.. |
| | | " at protected position "..minetest.pos_to_string(pointed_thing.under).. |
| | | " with a "..data.can_name) |
| | | return |
| | | end |
| | | minetest.remove_node(pointed_thing.under) |
| | | charge = charge + 1 |
| | | itemstack:set_metadata(tostring(charge)) |
| | | meta:set_int("can_level", charge) |
| | | set_can_wear(itemstack, charge, data.can_capacity) |
| | | return itemstack |
| | | end, |
| | |
| | | -- Try to place node above the pointed source, or abort. |
| | | if not def.buildable_to or node_name == data.liquid_source_name then return end |
| | | end |
| | | local charge = get_can_level(itemstack) |
| | | local meta = technic.get_stack_meta_cans(itemstack) |
| | | local charge = meta:get_int("can_level") |
| | | if charge == 0 then return end |
| | | if minetest.is_protected(pos, user:get_player_name()) then |
| | | minetest.log("action", user:get_player_name().." tried to place "..data.liquid_source_name.." at protected position "..minetest.pos_to_string(pos).." with a "..data.can_name) |
| | | minetest.log("action", user:get_player_name().. |
| | | " tried to place "..data.liquid_source_name.. |
| | | " at protected position "..minetest.pos_to_string(pos).. |
| | | " with a "..data.can_name) |
| | | return |
| | | end |
| | | minetest.set_node(pos, {name=data.liquid_source_name}) |
| | | charge = charge - 1 |
| | | itemstack:set_metadata(tostring(charge)) |
| | | meta:set_int("can_level", charge) |
| | | set_can_wear(itemstack, charge, data.can_capacity) |
| | | return itemstack |
| | | end, |
| | | on_refill = function(stack) |
| | | stack:set_metadata(tostring(data.can_capacity)) |
| | | local meta = technic.get_stack_meta_cans(stack) |
| | | meta:set_int("can_level", data.can_capacity) |
| | | set_can_wear(stack, data.can_capacity, data.can_capacity) |
| | | return stack |
| | | end, |
| | |
| | | -- Configuration |
| | | |
| | | local chainsaw_max_charge = 30000 -- Maximum charge of the saw |
| | | -- Gives 2500 nodes on a single charge (about 50 complete normal trees) |
| | | local chainsaw_charge_per_node = 12 |
| | | -- Cut down tree leaves. Leaf decay may cause slowness on large trees |
| | | -- if this is disabled. |
| | | local chainsaw_leaves = true |
| | | |
| | | -- First value is node name; second is whether the node is considered even if chainsaw_leaves is false. |
| | | local nodes = { |
| | | -- The default trees |
| | | {"default:acacia_tree", true}, |
| | | {"default:aspen_tree", true}, |
| | | {"default:jungletree", true}, |
| | | {"default:papyrus", true}, |
| | | {"default:cactus", true}, |
| | | {"default:tree", true}, |
| | | {"default:apple", true}, |
| | | {"default:pine_tree", true}, |
| | | {"default:acacia_leaves", false}, |
| | | {"default:aspen_leaves", false}, |
| | | {"default:leaves", false}, |
| | | {"default:jungleleaves", false}, |
| | | {"default:pine_needles", false}, |
| | | local chainsaw_efficiency = 0.92 -- Drops less items |
| | | |
| | | -- The default bushes |
| | | {"default:acacia_bush_stem", true}, |
| | | {"default:bush_stem", true}, |
| | | {"default:pine_bush_stem", true}, |
| | | {"default:acacia_bush_leaves", false}, |
| | | {"default:blueberry_bush_leaves", false}, |
| | | {"default:blueberry_bush_leaves_with_berries", false}, |
| | | {"default:bush_leaves", false}, |
| | | {"default:pine_bush_needles", false}, |
| | | |
| | | -- Rubber trees from moretrees or technic_worldgen if moretrees isn't installed |
| | | -- {"moretrees:rubber_tree_trunk_empty", true}, |
| | | -- {"moretrees:rubber_tree_trunk", true}, |
| | | {"moretrees:rubber_tree_leaves", false}, |
| | | |
| | | -- Support moretrees (trunk) |
| | | {"moretrees:acacia_trunk", true}, |
| | | {"moretrees:apple_tree_trunk", true}, |
| | | {"moretrees:beech_trunk", true}, |
| | | {"moretrees:birch_trunk", true}, |
| | | {"moretrees:cedar_trunk", true}, |
| | | {"moretrees:date_palm_ffruit_trunk", true}, |
| | | {"moretrees:date_palm_fruit_trunk", true}, |
| | | {"moretrees:date_palm_mfruit_trunk", true}, |
| | | {"moretrees:date_palm_trunk", true}, |
| | | {"moretrees:fir_trunk", true}, |
| | | {"moretrees:jungletree_trunk", true}, |
| | | {"moretrees:oak_trunk", true}, |
| | | {"moretrees:palm_trunk", true}, |
| | | {"moretrees:palm_fruit_trunk", true}, |
| | | {"moretrees:palm_fruit_trunk_gen", true}, |
| | | {"moretrees:pine_trunk", true}, |
| | | {"moretrees:poplar_trunk", true}, |
| | | {"moretrees:sequoia_trunk", true}, |
| | | {"moretrees:spruce_trunk", true}, |
| | | {"moretrees:willow_trunk", true}, |
| | | -- Support moretrees (leaves) |
| | | {"moretrees:acacia_leaves", false}, |
| | | {"moretrees:apple_tree_leaves", false}, |
| | | {"moretrees:beech_leaves", false}, |
| | | {"moretrees:birch_leaves", false}, |
| | | {"moretrees:cedar_leaves", false}, |
| | | {"moretrees:date_palm_leaves", false}, |
| | | {"moretrees:fir_leaves", false}, |
| | | {"moretrees:fir_leaves_bright", false}, |
| | | {"moretrees:jungletree_leaves_green", false}, |
| | | {"moretrees:jungletree_leaves_yellow", false}, |
| | | {"moretrees:jungletree_leaves_red", false}, |
| | | {"moretrees:oak_leaves", false}, |
| | | {"moretrees:palm_leaves", false}, |
| | | {"moretrees:poplar_leaves", false}, |
| | | {"moretrees:pine_leaves", false}, |
| | | {"moretrees:sequoia_leaves", false}, |
| | | {"moretrees:spruce_leaves", false}, |
| | | {"moretrees:willow_leaves", false}, |
| | | -- Support moretrees (fruit) |
| | | {"moretrees:acorn", false}, |
| | | {"moretrees:apple_blossoms", false}, |
| | | {"moretrees:cedar_cone", false}, |
| | | {"moretrees:coconut", false}, |
| | | {"moretrees:coconut_0", false}, |
| | | {"moretrees:coconut_1", false}, |
| | | {"moretrees:coconut_2", false}, |
| | | {"moretrees:coconut_3", false}, |
| | | {"moretrees:dates_f0", false}, |
| | | {"moretrees:dates_f1", false}, |
| | | {"moretrees:dates_f2", false}, |
| | | {"moretrees:dates_f3", false}, |
| | | {"moretrees:dates_f4", false}, |
| | | {"moretrees:dates_fn", false}, |
| | | {"moretrees:dates_m0", false}, |
| | | {"moretrees:dates_n", false}, |
| | | {"moretrees:fir_cone", false}, |
| | | {"moretrees:pine_cone", false}, |
| | | {"moretrees:spruce_cone", false}, |
| | | |
| | | -- Support growing_trees |
| | | {"growing_trees:trunk", true}, |
| | | {"growing_trees:medium_trunk", true}, |
| | | {"growing_trees:big_trunk", true}, |
| | | {"growing_trees:trunk_top", true}, |
| | | {"growing_trees:trunk_sprout", true}, |
| | | {"growing_trees:branch_sprout", true}, |
| | | {"growing_trees:branch", true}, |
| | | {"growing_trees:branch_xmzm", true}, |
| | | {"growing_trees:branch_xpzm", true}, |
| | | {"growing_trees:branch_xmzp", true}, |
| | | {"growing_trees:branch_xpzp", true}, |
| | | {"growing_trees:branch_zz", true}, |
| | | {"growing_trees:branch_xx", true}, |
| | | {"growing_trees:leaves", false}, |
| | | |
| | | -- Support cool_trees |
| | | {"bamboo:trunk", true}, |
| | | {"bamboo:leaves", false}, |
| | | {"birch:trunk", true}, |
| | | {"birch:leaves", false}, |
| | | {"cherrytree:trunk", true}, |
| | | {"cherrytree:blossom_leaves", false}, |
| | | {"cherrytree:leaves", false}, |
| | | {"chestnuttree:trunk", true}, |
| | | {"chestnuttree:leaves", false}, |
| | | {"clementinetree:trunk", true}, |
| | | {"clementinetree:leaves", false}, |
| | | {"ebony:trunk", true}, |
| | | {"ebony:creeper", false}, |
| | | {"ebony:creeper_leaves", false}, |
| | | {"ebony:leaves", false}, |
| | | {"jacaranda:trunk", true}, |
| | | {"jacaranda:blossom_leaves", false}, |
| | | {"larch:trunk", true}, |
| | | {"larch:leaves", false}, |
| | | {"lemontree:trunk", true}, |
| | | {"lemontree:leaves", false}, |
| | | {"mahogany:trunk", true}, |
| | | {"mahogany:leaves", false}, |
| | | {"palm:trunk", true}, |
| | | {"palm:leaves", false}, |
| | | |
| | | -- Support growing_cactus |
| | | {"growing_cactus:sprout", true}, |
| | | {"growing_cactus:branch_sprout_vertical", true}, |
| | | {"growing_cactus:branch_sprout_vertical_fixed", true}, |
| | | {"growing_cactus:branch_sprout_xp", true}, |
| | | {"growing_cactus:branch_sprout_xm", true}, |
| | | {"growing_cactus:branch_sprout_zp", true}, |
| | | {"growing_cactus:branch_sprout_zm", true}, |
| | | {"growing_cactus:trunk", true}, |
| | | {"growing_cactus:branch_trunk", true}, |
| | | {"growing_cactus:branch", true}, |
| | | {"growing_cactus:branch_xp", true}, |
| | | {"growing_cactus:branch_xm", true}, |
| | | {"growing_cactus:branch_zp", true}, |
| | | {"growing_cactus:branch_zm", true}, |
| | | {"growing_cactus:branch_zz", true}, |
| | | {"growing_cactus:branch_xx", true}, |
| | | |
| | | -- Support farming_plus |
| | | {"farming_plus:banana_leaves", false}, |
| | | {"farming_plus:banana", false}, |
| | | {"farming_plus:cocoa_leaves", false}, |
| | | {"farming_plus:cocoa", false}, |
| | | |
| | | -- Support nature |
| | | {"nature:blossom", false}, |
| | | |
| | | -- Support snow |
| | | {"snow:needles", false}, |
| | | {"snow:needles_decorated", false}, |
| | | {"snow:star", false}, |
| | | |
| | | -- Support vines (also generated by moretrees if available) |
| | | {"vines:vines", false}, |
| | | |
| | | {"trunks:moss", false}, |
| | | {"trunks:moss_fungus", false}, |
| | | {"trunks:treeroot", false}, |
| | | |
| | | -- Support ethereal |
| | | {"ethereal:bamboo", true}, |
| | | {"ethereal:bamboo_leaves", false}, |
| | | {"ethereal:banana_trunk", true}, |
| | | {"ethereal:bananaleaves", false}, |
| | | {"ethereal:banana", false}, |
| | | {"ethereal:birch_trunk", true}, |
| | | {"ethereal:birch_leaves", false}, |
| | | {"ethereal:frost_tree", true}, |
| | | {"ethereal:frost_leaves", false}, |
| | | {"ethereal:mushroom_trunk", true}, |
| | | {"ethereal:mushroom", false}, |
| | | {"ethereal:mushroom_pore", true}, |
| | | {"ethereal:orangeleaves", false}, |
| | | {"ethereal:orange", false}, |
| | | {"ethereal:palm_trunk", true}, |
| | | {"ethereal:palmleaves", false}, |
| | | {"ethereal:coconut", false}, |
| | | {"ethereal:redwood_trunk", true}, |
| | | {"ethereal:redwood_leaves", false}, |
| | | {"ethereal:sakura_trunk", true}, |
| | | {"ethereal:sakura_leaves", false}, |
| | | {"ethereal:sakura_leaves2", false}, |
| | | {"ethereal:scorched_tree", true}, |
| | | {"ethereal:willow_trunk", true}, |
| | | {"ethereal:willow_twig", false}, |
| | | {"ethereal:yellow_trunk", true}, |
| | | {"ethereal:yellowleaves", false}, |
| | | {"ethereal:golden_apple", false}, |
| | | } |
| | | |
| | | local timber_nodenames = {} |
| | | for _, node in pairs(nodes) do |
| | | if chainsaw_leaves or node[2] then |
| | | timber_nodenames[node[1]] = true |
| | | end |
| | | end |
| | | -- Maximal dimensions of the tree to cut (giant sequoia) |
| | | local tree_max_radius = 10 |
| | | local tree_max_height = 70 |
| | | |
| | | local S = technic.getter |
| | | |
| | | --[[ |
| | | Format: [node_name] = dig_cost |
| | | |
| | | This table is filled automatically afterwards to support mods such as: |
| | | |
| | | cool_trees |
| | | ethereal |
| | | moretrees |
| | | ]] |
| | | local tree_nodes = { |
| | | -- For the sake of maintenance, keep this sorted alphabetically! |
| | | ["default:acacia_bush_stem"] = -1, |
| | | ["default:bush_stem"] = -1, |
| | | ["default:pine_bush_stem"] = -1, |
| | | |
| | | ["default:cactus"] = -1, |
| | | ["default:papyrus"] = -1, |
| | | |
| | | -- dfcaves "fruits" |
| | | ["df_trees:blood_thorn_spike"] = -1, |
| | | ["df_trees:blood_thorn_spike_dead"] = -1, |
| | | ["df_trees:tunnel_tube_fruiting_body"] = -1, |
| | | |
| | | ["ethereal:bamboo"] = -1, |
| | | } |
| | | |
| | | local tree_nodes_by_cid = { |
| | | -- content ID indexed table, data populated on mod load. |
| | | -- Format: [node_name] = cost_number |
| | | } |
| | | |
| | | -- Function to decide whether or not to cut a certain node (and at which energy cost) |
| | | local function populate_costs(name, def) |
| | | repeat |
| | | if tree_nodes[name] then |
| | | break -- Manually specified node to chop |
| | | end |
| | | if (def.groups.tree or 0) > 0 then |
| | | break -- Tree node |
| | | end |
| | | if (def.groups.leaves or 0) > 0 and chainsaw_leaves then |
| | | break -- Leaves |
| | | end |
| | | if (def.groups.leafdecay_drop or 0) > 0 then |
| | | break -- Food |
| | | end |
| | | return -- Abort function: do not dig this node |
| | | |
| | | -- luacheck: push ignore 511 |
| | | until 1 |
| | | -- luacheck: pop |
| | | |
| | | -- Add the node cost to the content ID indexed table |
| | | local content_id = minetest.get_content_id(name) |
| | | |
| | | -- Make it so that the giant sequoia can be cut with a full charge |
| | | local cost = tree_nodes[name] or 0 |
| | | if def.groups.choppy then |
| | | cost = math.max(cost, def.groups.choppy * 14) -- trunks (usually 3 * 14) |
| | | end |
| | | if def.groups.snappy then |
| | | cost = math.max(cost, def.groups.snappy * 2) -- leaves |
| | | end |
| | | tree_nodes_by_cid[content_id] = math.max(4, cost) |
| | | end |
| | | |
| | | minetest.register_on_mods_loaded(function() |
| | | local ndefs = minetest.registered_nodes |
| | | -- Populate hardcoded nodes |
| | | for name in pairs(tree_nodes) do |
| | | local ndef = ndefs[name] |
| | | if ndef and ndef.groups then |
| | | populate_costs(name, ndef) |
| | | end |
| | | end |
| | | |
| | | -- Find all trees and leaves |
| | | for name, def in pairs(ndefs) do |
| | | if def.groups then |
| | | populate_costs(name, def) |
| | | end |
| | | end |
| | | end) |
| | | |
| | | |
| | | technic.register_power_tool("technic:chainsaw", chainsaw_max_charge) |
| | | |
| | | -- This function checks if the specified node should be sawed |
| | | local function check_if_node_sawed(pos) |
| | | local node_name = minetest.get_node(pos).name |
| | | if timber_nodenames[node_name] |
| | | or (chainsaw_leaves and minetest.get_item_group(node_name, "leaves") ~= 0) |
| | | or minetest.get_item_group(node_name, "tree") ~= 0 then |
| | | return true |
| | | local pos9dir = { |
| | | { 1, 0, 0}, |
| | | {-1, 0, 0}, |
| | | { 0, 0, 1}, |
| | | { 0, 0, -1}, |
| | | { 1, 0, 1}, |
| | | {-1, 0, -1}, |
| | | { 1, 0, -1}, |
| | | {-1, 0, 1}, |
| | | { 0, 1, 0}, -- up |
| | | } |
| | | |
| | | local cutter = { |
| | | -- See function cut_tree() |
| | | } |
| | | |
| | | local safe_cut = minetest.settings:get_bool("technic_safe_chainsaw") ~= false |
| | | local c_air = minetest.get_content_id("air") |
| | | local function dig_recursive(x, y, z) |
| | | local i = cutter.area:index(x, y, z) |
| | | if cutter.seen[i] then |
| | | return |
| | | end |
| | | cutter.seen[i] = 1 -- Mark as visited |
| | | |
| | | if safe_cut and cutter.param2[i] ~= 0 then |
| | | -- Do not dig manually placed nodes |
| | | -- Problem: moretrees' generated jungle trees use param2 = 2 |
| | | return |
| | | end |
| | | |
| | | return false |
| | | end |
| | | local c_id = cutter.data[i] |
| | | local cost = tree_nodes_by_cid[c_id] |
| | | if not cost or cost > cutter.charge then |
| | | return -- Cannot dig this node |
| | | end |
| | | |
| | | -- Table for saving what was sawed down |
| | | local produced = {} |
| | | -- Count dug nodes |
| | | cutter.drops[c_id] = (cutter.drops[c_id] or 0) + 1 |
| | | cutter.seen[i] = 2 -- Mark as dug (for callbacks) |
| | | cutter.data[i] = c_air |
| | | cutter.charge = cutter.charge - cost |
| | | |
| | | -- Save the items sawed down so that we can drop them in a nice single stack |
| | | local function handle_drops(drops) |
| | | for _, item in ipairs(drops) do |
| | | local stack = ItemStack(item) |
| | | local name = stack:get_name() |
| | | local p = produced[name] |
| | | if not p then |
| | | produced[name] = stack |
| | | else |
| | | p:set_count(p:get_count() + stack:get_count()) |
| | | -- Expand maximal bounds for area protection check |
| | | if x < cutter.minp.x then cutter.minp.x = x end |
| | | if y < cutter.minp.y then cutter.minp.y = y end |
| | | if z < cutter.minp.z then cutter.minp.z = z end |
| | | if x > cutter.maxp.x then cutter.maxp.x = x end |
| | | if y > cutter.maxp.y then cutter.maxp.y = y end |
| | | if z > cutter.maxp.z then cutter.maxp.z = z end |
| | | |
| | | -- Traverse neighbors |
| | | local xn, yn, zn |
| | | for _, offset in ipairs(pos9dir) do |
| | | xn, yn, zn = x + offset[1], y + offset[2], z + offset[3] |
| | | if cutter.area:contains(xn, yn, zn) then |
| | | dig_recursive(xn, yn, zn) |
| | | end |
| | | end |
| | | end |
| | | |
| | | --- Iterator over positions to try to saw around a sawed node. |
| | | -- This returns positions in a 3x1x3 area around the position, plus the |
| | | -- position above it. This does not return the bottom position to prevent |
| | | -- the chainsaw from cutting down nodes below the cutting position. |
| | | -- @param pos Sawing position. |
| | | local function iterSawTries(pos) |
| | | -- Copy position to prevent mangling it |
| | | local pos = vector.new(pos) |
| | | local i = 0 |
| | | local handle_drops |
| | | |
| | | return function() |
| | | i = i + 1 |
| | | -- Given a (top view) area like so (where 5 is the starting position): |
| | | -- X --> |
| | | -- Z 123 |
| | | -- | 456 |
| | | -- V 789 |
| | | -- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9, |
| | | -- and the position above 5. |
| | | if i == 1 then |
| | | -- Move to starting position |
| | | pos.x = pos.x - 1 |
| | | pos.z = pos.z - 1 |
| | | elseif i == 4 or i == 7 then |
| | | -- Move to next X and back to start of Z when we reach |
| | | -- the end of a Z line. |
| | | pos.x = pos.x + 1 |
| | | pos.z = pos.z - 2 |
| | | elseif i == 5 then |
| | | -- Skip the middle position (we've already run on it) |
| | | -- and double-increment the counter. |
| | | pos.z = pos.z + 2 |
| | | i = i + 1 |
| | | elseif i <= 9 then |
| | | -- Go to next Z. |
| | | pos.z = pos.z + 1 |
| | | elseif i == 10 then |
| | | -- Move back to center and up. |
| | | -- The Y+ position must be last so that we don't dig |
| | | -- straight upward and not come down (since the Y- |
| | | -- position isn't checked). |
| | | pos.x = pos.x - 1 |
| | | pos.z = pos.z - 1 |
| | | pos.y = pos.y + 1 |
| | | else |
| | | return nil |
| | | end |
| | | return pos |
| | | end |
| | | end |
| | | local function chainsaw_dig(player, pos, remaining_charge) |
| | | local minp = { |
| | | x = pos.x - (tree_max_radius + 1), |
| | | y = pos.y, |
| | | z = pos.z - (tree_max_radius + 1) |
| | | } |
| | | local maxp = { |
| | | x = pos.x + (tree_max_radius + 1), |
| | | y = pos.y + tree_max_height, |
| | | z = pos.z + (tree_max_radius + 1) |
| | | } |
| | | |
| | | -- This function does all the hard work. Recursively we dig the node at hand |
| | | -- if it is in the table and then search the surroundings for more stuff to dig. |
| | | local function recursive_dig(pos, remaining_charge) |
| | | if remaining_charge < chainsaw_charge_per_node then |
| | | return remaining_charge |
| | | end |
| | | local node = minetest.get_node(pos) |
| | | local vm = minetest.get_voxel_manip() |
| | | local emin, emax = vm:read_from_map(minp, maxp) |
| | | |
| | | if not check_if_node_sawed(pos) then |
| | | return remaining_charge |
| | | cutter = { |
| | | area = VoxelArea:new{MinEdge=emin, MaxEdge=emax}, |
| | | data = vm:get_data(), |
| | | param2 = vm:get_param2_data(), |
| | | seen = {}, |
| | | drops = {}, -- [content_id] = count |
| | | minp = vector.copy(pos), |
| | | maxp = vector.copy(pos), |
| | | charge = remaining_charge |
| | | } |
| | | |
| | | dig_recursive(pos.x, pos.y, pos.z) |
| | | |
| | | -- Check protection |
| | | local player_name = player:get_player_name() |
| | | if minetest.is_area_protected(cutter.minp, cutter.maxp, player_name, 6) then |
| | | minetest.chat_send_player(player_name, "The chainsaw cannot cut this tree. The cuboid " .. |
| | | minetest.pos_to_string(cutter.minp) .. ", " .. minetest.pos_to_string(cutter.maxp) .. |
| | | " contains protected nodes.") |
| | | minetest.record_protection_violation(pos, player_name) |
| | | return |
| | | end |
| | | |
| | | -- Wood found - cut it |
| | | handle_drops(minetest.get_node_drops(node.name, "")) |
| | | minetest.remove_node(pos) |
| | | remaining_charge = remaining_charge - chainsaw_charge_per_node |
| | | minetest.sound_play("chainsaw", { |
| | | pos = pos, |
| | | gain = 1.0, |
| | | max_hear_distance = 20 |
| | | }) |
| | | |
| | | -- Check surroundings and run recursively if any charge left |
| | | for npos in iterSawTries(pos) do |
| | | if remaining_charge < chainsaw_charge_per_node then |
| | | break |
| | | end |
| | | if check_if_node_sawed(npos) then |
| | | remaining_charge = recursive_dig(npos, remaining_charge) |
| | | else |
| | | minetest.check_for_falling(npos) |
| | | handle_drops(pos) |
| | | |
| | | vm:set_data(cutter.data) |
| | | vm:write_to_map(true) |
| | | vm:update_map() |
| | | |
| | | -- Update falling nodes |
| | | for i, status in pairs(cutter.seen) do |
| | | if status == 2 then -- actually dug |
| | | minetest.check_for_falling(cutter.area:position(i)) |
| | | end |
| | | end |
| | | return remaining_charge |
| | | end |
| | | |
| | | -- Function to randomize positions for new node drops |
| | |
| | | return pos |
| | | end |
| | | |
| | | -- Chainsaw entry point |
| | | local function chainsaw_dig(pos, current_charge) |
| | | -- Start sawing things down |
| | | local remaining_charge = recursive_dig(pos, current_charge) |
| | | minetest.sound_play("chainsaw", {pos = pos, gain = 1.0, |
| | | max_hear_distance = 10}) |
| | | local drop_inv = minetest.create_detached_inventory("technic:chainsaw_drops", {}, ":technic") |
| | | handle_drops = function(pos) |
| | | local n_slots = 100 |
| | | drop_inv:set_size("main", n_slots) |
| | | drop_inv:set_list("main", {}) |
| | | |
| | | -- Now drop items for the player |
| | | for name, stack in pairs(produced) do |
| | | -- Drop stacks of stack max or less |
| | | local count, max = stack:get_count(), stack:get_stack_max() |
| | | stack:set_count(max) |
| | | while count > max do |
| | | minetest.add_item(get_drop_pos(pos), stack) |
| | | count = count - max |
| | | -- Put all dropped items into the detached inventory |
| | | for c_id, count in pairs(cutter.drops) do |
| | | local name = minetest.get_name_from_content_id(c_id) |
| | | |
| | | -- Add drops in bulk -> keep some randomness |
| | | while count > 0 do |
| | | local drops = minetest.get_node_drops(name, "") |
| | | -- higher numbers are faster but return uneven sapling counts |
| | | local decrement = math.ceil(count * 0.3) |
| | | decrement = math.min(count, math.max(5, decrement)) |
| | | |
| | | for _, stack in ipairs(drops) do |
| | | stack = ItemStack(stack) |
| | | local total = math.ceil(stack:get_count() * decrement * chainsaw_efficiency) |
| | | local stack_max = stack:get_stack_max() |
| | | |
| | | -- Split into full stacks |
| | | while total > 0 do |
| | | local size = math.min(total, stack_max) |
| | | stack:set_count(size) |
| | | drop_inv:add_item("main", stack) |
| | | total = total - size |
| | | end |
| | | end |
| | | count = count - decrement |
| | | end |
| | | stack:set_count(count) |
| | | end |
| | | |
| | | -- Drop in random places |
| | | for i = 1, n_slots do |
| | | local stack = drop_inv:get_stack("main", i) |
| | | if stack:is_empty() then |
| | | break |
| | | end |
| | | minetest.add_item(get_drop_pos(pos), stack) |
| | | end |
| | | |
| | | -- Clean up |
| | | produced = {} |
| | | |
| | | return remaining_charge |
| | | drop_inv:set_size("main", 0) -- free RAM |
| | | end |
| | | |
| | | |
| | |
| | | return itemstack |
| | | end |
| | | |
| | | local meta = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta or not meta.charge or |
| | | meta.charge < chainsaw_charge_per_node then |
| | | return |
| | | end |
| | | local meta = technic.get_stack_meta(itemstack) |
| | | local charge = meta:get_int("technic:charge") |
| | | |
| | | local name = user:get_player_name() |
| | | if minetest.is_protected(pointed_thing.under, name) then |
| | |
| | | |
| | | -- Send current charge to digging function so that the |
| | | -- chainsaw will stop after digging a number of nodes |
| | | meta.charge = chainsaw_dig(pointed_thing.under, meta.charge) |
| | | chainsaw_dig(user, pointed_thing.under, charge) |
| | | charge = cutter.charge |
| | | |
| | | cutter = {} -- Free RAM |
| | | |
| | | if not technic.creative_mode then |
| | | technic.set_RE_wear(itemstack, meta.charge, chainsaw_max_charge) |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | meta:set_int("technic:charge", charge) |
| | | technic.set_RE_wear(itemstack, charge, chainsaw_max_charge) |
| | | end |
| | | return itemstack |
| | | end, |
| | |
| | | local hotbar = inv:get_list("main") |
| | | for i = 1, 8 do |
| | | if hotbar[i]:get_name() == "technic:flashlight" then |
| | | local meta = minetest.deserialize(hotbar[i]:get_metadata()) |
| | | if meta and meta.charge and meta.charge >= 2 then |
| | | local meta = technic.get_stack_meta(hotbar[i]) |
| | | local charge = meta:get_int("technic:charge") |
| | | if charge >= 2 then |
| | | if not technic.creative_mode then |
| | | meta.charge = meta.charge - 2; |
| | | technic.set_RE_wear(hotbar[i], meta.charge, flashlight_max_charge) |
| | | hotbar[i]:set_metadata(minetest.serialize(meta)) |
| | | charge = charge - 2; |
| | | meta:set_int("technic:charge", charge) |
| | | technic.set_RE_wear(hotbar[i], charge, flashlight_max_charge) |
| | | inv:set_stack("main", i, hotbar[i]) |
| | | end |
| | | return true |
| | |
| | | {S("3x3 nodes.")}, |
| | | } |
| | | |
| | | local function drill_dig_it0 (pos,player) |
| | | local function drill_dig_it0(pos, player) |
| | | if minetest.is_protected(pos, player:get_player_name()) then |
| | | minetest.record_protection_violation(pos, player:get_player_name()) |
| | | return |
| | | end |
| | | local node = minetest.get_node(pos) |
| | | if node.name == "air" or node.name == "ignore" then return end |
| | | if node.name == "default:lava_source" then return end |
| | | if node.name == "default:lava_flowing" then return end |
| | | if node.name == "default:water_source" then minetest.remove_node(pos) return end |
| | | if node.name == "default:water_flowing" then minetest.remove_node(pos) return end |
| | | local def = minetest.registered_nodes[node.name] |
| | | if not def then return end |
| | | def.on_dig(pos, node, player) |
| | | local ndef = minetest.registered_nodes[node.name] |
| | | if not ndef or ndef.drawtype == "airlike" then |
| | | -- Covers "air", "ignore", unknown nodes and more. |
| | | return |
| | | end |
| | | local groups = ndef and ndef.groups or {} |
| | | |
| | | if groups.lava then |
| | | return |
| | | end |
| | | if groups.water then |
| | | minetest.remove_node(pos) |
| | | return |
| | | end |
| | | ndef.on_dig(pos, node, player) |
| | | end |
| | | |
| | | local function drill_dig_it1 (player) |
| | |
| | | return nodedef and nodedef.pointable |
| | | end |
| | | |
| | | local function mining_drill_mk2_setmode(user,itemstack) |
| | | local player_name=user:get_player_name() |
| | | local item=itemstack:to_table() |
| | | local mode = nil |
| | | local meta=minetest.deserialize(item["metadata"]) |
| | | if meta==nil then |
| | | meta={} |
| | | mode=0 |
| | | local function mining_drill_mkX_setmode(user, itemstack, drill_type, max_modes) |
| | | local player_name = user:get_player_name() |
| | | local meta = technic.get_stack_meta(itemstack) |
| | | |
| | | if not meta:contains("mode") then |
| | | minetest.chat_send_player(player_name, |
| | | S("Use while sneaking to change Mining Drill Mk%d modes."):format(drill_type)) |
| | | end |
| | | if meta["mode"]==nil then |
| | | minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk%d modes."):format(2)) |
| | | meta["mode"]=0 |
| | | mode=0 |
| | | end |
| | | mode=(meta["mode"]) |
| | | mode=mode+1 |
| | | if mode>=5 then mode=1 end |
| | | minetest.chat_send_player(player_name, S("Mining Drill Mk%d Mode %d"):format(2, mode)..": "..mining_drill_mode_text[mode][1]) |
| | | itemstack:set_name("technic:mining_drill_mk2_"..mode); |
| | | meta["mode"]=mode |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | local mode = meta:get_int("mode") + 1 |
| | | if mode > max_modes then mode = 1 end |
| | | |
| | | minetest.chat_send_player(player_name, |
| | | S("Mining Drill Mk%d Mode %d"):format(2, mode).. |
| | | ": "..mining_drill_mode_text[mode][1]) |
| | | itemstack:set_name(("technic:mining_drill_mk%d_%s"):format(drill_type, mode)) |
| | | meta:set_int("mode", mode) |
| | | return itemstack |
| | | end |
| | | |
| | | local function mining_drill_mk3_setmode(user,itemstack) |
| | | local player_name=user:get_player_name() |
| | | local item=itemstack:to_table() |
| | | local meta=minetest.deserialize(item["metadata"]) |
| | | if meta==nil then |
| | | meta={} |
| | | mode=0 |
| | | end |
| | | if meta["mode"]==nil then |
| | | minetest.chat_send_player(player_name, S("Use while sneaking to change Mining Drill Mk%d modes."):format(3)) |
| | | meta["mode"]=0 |
| | | mode=0 |
| | | end |
| | | mode=(meta["mode"]) |
| | | mode=mode+1 |
| | | if mode>=6 then mode=1 end |
| | | minetest.chat_send_player(player_name, S("Mining Drill Mk%d Mode %d"):format(3, mode)..": "..mining_drill_mode_text[mode][1]) |
| | | itemstack:set_name("technic:mining_drill_mk3_"..mode); |
| | | meta["mode"]=mode |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | return itemstack |
| | | end |
| | | |
| | | |
| | | local function mining_drill_mk2_handler(itemstack, user, pointed_thing) |
| | | local function mining_drill_mkX_handler(itemstack, user, pointed_thing, drill_type, max_modes) |
| | | local keys = user:get_player_control() |
| | | local meta = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta or not meta.mode or keys.sneak then |
| | | return mining_drill_mk2_setmode(user, itemstack) |
| | | end |
| | | if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) or not meta.charge then |
| | | return |
| | | end |
| | | local charge_to_take = cost_to_use(2, meta.mode) |
| | | if meta.charge >= charge_to_take then |
| | | local pos = minetest.get_pointed_thing_position(pointed_thing, false) |
| | | drill_dig_it(pos, user, meta.mode) |
| | | if not technic.creative_mode then |
| | | meta.charge = meta.charge - charge_to_take |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | technic.set_RE_wear(itemstack, meta.charge, max_charge[2]) |
| | | local meta = technic.get_stack_meta(itemstack) |
| | | |
| | | -- Mode switching (if possible) |
| | | if max_modes > 1 then |
| | | if not meta:contains("mode") or keys.sneak then |
| | | return mining_drill_mkX_setmode(user, itemstack, drill_type, max_modes) |
| | | end |
| | | end |
| | | if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) then |
| | | return |
| | | end |
| | | |
| | | local charge = meta:get_int("technic:charge") |
| | | local mode = meta:contains("mode") and meta:get_int("mode") or 1 |
| | | |
| | | -- Check whether the tool has enough charge |
| | | local charge_to_take = cost_to_use(drill_type, mode) |
| | | if charge < charge_to_take then |
| | | return |
| | | end |
| | | |
| | | -- Do the actual shoorting action |
| | | local pos = minetest.get_pointed_thing_position(pointed_thing, false) |
| | | drill_dig_it(pos, user, mode) |
| | | if not technic.creative_mode then |
| | | charge = charge - charge_to_take |
| | | meta:set_int("technic:charge", charge) |
| | | technic.set_RE_wear(itemstack, charge, max_charge[drill_type]) |
| | | end |
| | | return itemstack |
| | | end |
| | | |
| | | local function mining_drill_mk3_handler(itemstack, user, pointed_thing) |
| | | local keys = user:get_player_control() |
| | | local meta = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta or not meta.mode or keys.sneak then |
| | | return mining_drill_mk3_setmode(user, itemstack) |
| | | end |
| | | if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) or not meta.charge then |
| | | return |
| | | end |
| | | local charge_to_take = cost_to_use(3, meta.mode) |
| | | if meta.charge >= charge_to_take then |
| | | local pos = minetest.get_pointed_thing_position(pointed_thing, false) |
| | | drill_dig_it(pos, user, meta.mode) |
| | | if not technic.creative_mode then |
| | | meta.charge = meta.charge - charge_to_take |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | technic.set_RE_wear(itemstack, meta.charge, max_charge[3]) |
| | | end |
| | | end |
| | | return itemstack |
| | | end |
| | | -- Simple mining drill registration |
| | | |
| | | technic.register_power_tool("technic:mining_drill", max_charge[1]) |
| | | |
| | |
| | | wear_represents = "technic_RE_charge", |
| | | on_refill = technic.refill_RE_charge, |
| | | on_use = function(itemstack, user, pointed_thing) |
| | | if pointed_thing.type ~= "node" or not pos_is_pointable(pointed_thing.under) then |
| | | return itemstack |
| | | end |
| | | local meta = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta or not meta.charge then |
| | | return |
| | | end |
| | | local charge_to_take = cost_to_use(1, 1) |
| | | if meta.charge >= charge_to_take then |
| | | local pos = minetest.get_pointed_thing_position(pointed_thing, false) |
| | | drill_dig_it(pos, user, 1) |
| | | if not technic.creative_mode then |
| | | meta.charge = meta.charge - charge_to_take |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | technic.set_RE_wear(itemstack, meta.charge, max_charge[1]) |
| | | end |
| | | end |
| | | mining_drill_mkX_handler(itemstack, user, pointed_thing, 1, 1) |
| | | return itemstack |
| | | end, |
| | | }) |
| | | |
| | | -- Mk2 registration |
| | | |
| | | minetest.register_tool("technic:mining_drill_mk2", { |
| | | description = S("Mining Drill Mk%d"):format(2), |
| | |
| | | wear_represents = "technic_RE_charge", |
| | | on_refill = technic.refill_RE_charge, |
| | | on_use = function(itemstack, user, pointed_thing) |
| | | mining_drill_mk2_handler(itemstack, user, pointed_thing) |
| | | mining_drill_mkX_handler(itemstack, user, pointed_thing, 2, 4) |
| | | return itemstack |
| | | end, |
| | | }) |
| | |
| | | on_refill = technic.refill_RE_charge, |
| | | groups = {not_in_creative_inventory=1}, |
| | | on_use = function(itemstack, user, pointed_thing) |
| | | mining_drill_mk2_handler(itemstack, user, pointed_thing) |
| | | mining_drill_mkX_handler(itemstack, user, pointed_thing, 2, 4) |
| | | return itemstack |
| | | end, |
| | | }) |
| | | end |
| | | |
| | | -- Mk3 registration |
| | | |
| | | minetest.register_tool("technic:mining_drill_mk3", { |
| | | description = S("Mining Drill Mk%d"):format(3), |
| | |
| | | wear_represents = "technic_RE_charge", |
| | | on_refill = technic.refill_RE_charge, |
| | | on_use = function(itemstack, user, pointed_thing) |
| | | mining_drill_mk3_handler(itemstack,user,pointed_thing) |
| | | return itemstack |
| | | mining_drill_mkX_handler(itemstack, user, pointed_thing, 3, 5) |
| | | return itemstack |
| | | end, |
| | | }) |
| | | |
| | |
| | | on_refill = technic.refill_RE_charge, |
| | | groups = {not_in_creative_inventory=1}, |
| | | on_use = function(itemstack, user, pointed_thing) |
| | | mining_drill_mk3_handler(itemstack,user,pointed_thing) |
| | | return itemstack |
| | | mining_drill_mkX_handler(itemstack, user, pointed_thing, 3, 5) |
| | | return itemstack |
| | | end, |
| | | }) |
| | | end |
| | |
| | | wear_represents = "technic_RE_charge", |
| | | on_refill = technic.refill_RE_charge, |
| | | on_use = function(itemstack, user) |
| | | local meta = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta or not meta.charge or meta.charge == 0 then |
| | | local meta = technic.get_stack_meta(itemstack) |
| | | local charge = meta:get_int("technic:charge") |
| | | if charge == 0 then |
| | | return |
| | | end |
| | | |
| | | local range = m[2] |
| | | if meta.charge < m[4] then |
| | | if charge < m[4] then |
| | | if not allow_entire_discharging then |
| | | return |
| | | end |
| | | -- If charge is too low, give the laser a shorter range |
| | | range = range * meta.charge / m[4] |
| | | range = range * charge / m[4] |
| | | end |
| | | laser_shoot(user, range, "technic_laser_beam_mk" .. m[1] .. ".png", |
| | | "technic_laser_mk" .. m[1]) |
| | | if not technic.creative_mode then |
| | | meta.charge = math.max(meta.charge - m[4], 0) |
| | | technic.set_RE_wear(itemstack, meta.charge, m[3]) |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | charge = math.max(charge - m[4], 0) |
| | | meta:set_int("technic:charge", charge) |
| | | technic.set_RE_wear(itemstack, charge, m[3]) |
| | | end |
| | | return itemstack |
| | | end, |
| | |
| | | |
| | | technic.register_power_tool("technic:prospector", 300000) |
| | | |
| | | local function get_metadata(toolstack) |
| | | local m = minetest.deserialize(toolstack:get_metadata()) |
| | | if not m then m = {} end |
| | | if not m.charge then m.charge = 0 end |
| | | if not m.target then m.target = "" end |
| | | if not m.look_depth then m.look_depth = 7 end |
| | | if not m.look_radius then m.look_radius = 1 end |
| | | return m |
| | | -- Helper function to consolidate ItemStackMetaRef access and initialize |
| | | local function meta_to_table(meta) |
| | | local t = {} |
| | | local mt = meta:to_table() |
| | | |
| | | t.charge = tonumber(mt.fields["technic:charge"]) or 0 |
| | | t.target = mt.fields.target or "" |
| | | t.look_depth = tonumber(mt.fields.look_depth) or 7 |
| | | t.look_radius = tonumber(mt.fields.look_radius) or 1 |
| | | return t |
| | | end |
| | | |
| | | minetest.register_tool("technic:prospector", { |
| | |
| | | on_use = function(toolstack, user, pointed_thing) |
| | | if not user or not user:is_player() or user.is_fake_player then return end |
| | | if pointed_thing.type ~= "node" then return end |
| | | local toolmeta = get_metadata(toolstack) |
| | | local meta = technic.get_stack_meta(toolstack) |
| | | local toolmeta = meta_to_table(meta) |
| | | local look_diameter = toolmeta.look_radius * 2 + 1 |
| | | local charge_to_take = toolmeta.look_depth * (toolmeta.look_depth + 1) * look_diameter * look_diameter |
| | | if toolmeta.charge < charge_to_take then return end |
| | |
| | | end |
| | | if not technic.creative_mode then |
| | | toolmeta.charge = toolmeta.charge - charge_to_take |
| | | toolstack:set_metadata(minetest.serialize(toolmeta)) |
| | | meta:set_int("technic:charge", toolmeta.charge) |
| | | technic.set_RE_wear(toolstack, toolmeta.charge, technic.power_tools[toolstack:get_name()]) |
| | | end |
| | | -- What in the heaven's name is this evil sorcery ? |
| | | local start_pos = pointed_thing.under |
| | | local forward = minetest.facedir_to_dir(minetest.dir_to_facedir(user:get_look_dir(), true)) |
| | | local right = forward.x ~= 0 and { x=0, y=1, z=0 } or (forward.y ~= 0 and { x=0, y=0, z=1 } or { x=1, y=0, z=0 }) |
| | |
| | | for f = 0, toolmeta.look_depth-1 do |
| | | for r = 0, look_diameter-1 do |
| | | for u = 0, look_diameter-1 do |
| | | if minetest.get_node(vector.add(vector.add(vector.add(base_pos, vector.multiply(forward, f)), vector.multiply(right, r)), vector.multiply(up, u))).name == toolmeta.target then found = true end |
| | | if minetest.get_node( |
| | | vector.add( |
| | | vector.add( |
| | | vector.add(base_pos, |
| | | vector.multiply(forward, f)), |
| | | vector.multiply(right, r)), |
| | | vector.multiply(up, u)) |
| | | ).name == toolmeta.target then |
| | | found = true |
| | | break |
| | | end |
| | | end |
| | | if found then break end |
| | | end |
| | | if found then break end |
| | | end |
| | | if math.random() < 0.02 then found = not found end |
| | | minetest.chat_send_player(user:get_player_name(), minetest.registered_nodes[toolmeta.target].description.." is "..(found and "present" or "absent").." in "..look_diameter.."x"..look_diameter.."x"..toolmeta.look_depth.." region") |
| | | minetest.sound_play("technic_prospector_"..(found and "hit" or "miss"), { pos = vector.add(user:get_pos(), { x = 0, y = 1, z = 0 }), gain = 1.0, max_hear_distance = 10 }) |
| | | if math.random() < 0.02 then |
| | | found = not found |
| | | end |
| | | |
| | | local ndef = minetest.registered_nodes[toolmeta.target] |
| | | minetest.chat_send_player(user:get_player_name(), |
| | | ndef.description.." is "..(found and "present" or "absent").. |
| | | " in "..look_diameter.."x"..look_diameter.."x"..toolmeta.look_depth.." region") |
| | | |
| | | minetest.sound_play("technic_prospector_"..(found and "hit" or "miss"), { |
| | | pos = vector.add(user:get_pos(), { x = 0, y = 1, z = 0 }), |
| | | gain = 1.0, |
| | | max_hear_distance = 10 |
| | | }) |
| | | return toolstack |
| | | end, |
| | | on_place = function(toolstack, user, pointed_thing) |
| | | if not user or not user:is_player() or user.is_fake_player then return end |
| | | local toolmeta = get_metadata(toolstack) |
| | | local meta = technic.get_stack_meta(toolstack) |
| | | local toolmeta = meta_to_table(meta) |
| | | local pointed |
| | | if pointed_thing.type == "node" then |
| | | local pname = minetest.get_node(pointed_thing.under).name |
| | |
| | | if not user or not user:is_player() or user.is_fake_player then return end |
| | | local toolstack = user:get_wielded_item() |
| | | if toolstack:get_name() ~= "technic:prospector" then return true end |
| | | local toolmeta = get_metadata(toolstack) |
| | | local meta = technic.get_stack_meta(toolstack) |
| | | for field, value in pairs(fields) do |
| | | if field:sub(1, 7) == "target_" then |
| | | toolmeta.target = field:sub(8) |
| | | end |
| | | if field:sub(1, 12) == "look_radius_" then |
| | | toolmeta.look_radius = field:sub(13) |
| | | end |
| | | if field:sub(1, 11) == "look_depth_" then |
| | | toolmeta.look_depth = field:sub(12) |
| | | meta:set_string("target", field:sub(8)) |
| | | elseif field:sub(1, 12) == "look_radius_" then |
| | | meta:set_string("look_radius", field:sub(13)) |
| | | elseif field:sub(1, 11) == "look_depth_" then |
| | | meta:set_string("look_depth", field:sub(12)) |
| | | end |
| | | end |
| | | toolstack:set_metadata(minetest.serialize(toolmeta)) |
| | | user:set_wielded_item(toolstack) |
| | | return true |
| | | end) |
| | |
| | | -- contrary to the default screwdriver, do not check for can_dig, to allow rotating machines with CLU's in them |
| | | -- this is consistent with the previous sonic screwdriver |
| | | |
| | | local meta1 = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta1 or not meta1.charge or meta1.charge < 100 then |
| | | local meta = technic.get_stack_meta(itemstack) |
| | | local charge = meta:get_int("technic:charge") |
| | | if charge < 100 then |
| | | return |
| | | end |
| | | |
| | |
| | | minetest.swap_node(pos, node) |
| | | |
| | | if not technic.creative_mode then |
| | | meta1.charge = meta1.charge - 100 |
| | | itemstack:set_metadata(minetest.serialize(meta1)) |
| | | technic.set_RE_wear(itemstack, meta1.charge, sonic_screwdriver_max_charge) |
| | | charge = charge - 100 |
| | | meta:set_int("technic:charge", charge) |
| | | technic.set_RE_wear(itemstack, charge, sonic_screwdriver_max_charge) |
| | | end |
| | | |
| | | return itemstack |
| | |
| | | wear_represents = "technic_RE_charge", |
| | | on_refill = technic.refill_RE_charge, |
| | | on_use = function(itemstack, user, pointed_thing) |
| | | local meta = minetest.deserialize(itemstack:get_metadata()) |
| | | if not meta or not meta.charge then |
| | | local meta = technic.get_stack_meta(itemstack) |
| | | local charge = meta:get_int("technic:charge") |
| | | if charge < vacuum_charge_per_object then |
| | | return |
| | | end |
| | | if meta.charge > vacuum_charge_per_object then |
| | | minetest.sound_play("vacuumcleaner", { |
| | | to_player = user:get_player_name(), |
| | | gain = 0.4, |
| | | }) |
| | | end |
| | | minetest.sound_play("vacuumcleaner", { |
| | | to_player = user:get_player_name(), |
| | | gain = 0.4, |
| | | }) |
| | | local pos = user:get_pos() |
| | | local inv = user:get_inventory() |
| | | for _, object in ipairs(minetest.get_objects_inside_radius(pos, vacuum_range)) do |
| | | local luaentity = object:get_luaentity() |
| | | if not object:is_player() and luaentity and luaentity.name == "__builtin:item" and luaentity.itemstring ~= "" then |
| | | if inv and inv:room_for_item("main", ItemStack(luaentity.itemstring)) then |
| | | meta.charge = meta.charge - vacuum_charge_per_object |
| | | if meta.charge < vacuum_charge_per_object then |
| | | charge = charge - vacuum_charge_per_object |
| | | if charge < vacuum_charge_per_object then |
| | | return |
| | | end |
| | | inv:add_item("main", ItemStack(luaentity.itemstring)) |
| | |
| | | end |
| | | end |
| | | |
| | | technic.set_RE_wear(itemstack, meta.charge, vacuum_max_charge) |
| | | itemstack:set_metadata(minetest.serialize(meta)) |
| | | meta:set_int("technic:charge", charge) |
| | | technic.set_RE_wear(itemstack, charge, vacuum_max_charge) |
| | | return itemstack |
| | | end, |
| | | }) |
| | |
| | | technic.chests.groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, |
| | | tubedevice=1, tubedevice_receiver=1} |
| | | tubedevice=1, tubedevice_receiver=1, technic_chest=1} |
| | | technic.chests.groups_noinv = {snappy=2, choppy=2, oddly_breakable_by_hand=2, |
| | | tubedevice=1, tubedevice_receiver=1, not_in_creative_inventory=1} |
| | | tubedevice=1, tubedevice_receiver=1, not_in_creative_inventory=1, technic_chest=1} |
| | | |
| | | technic.chests.tube = { |
| | | insert_object = function(pos, node, stack, direction) |
New file |
| | |
| | | # technic_chests japanese translation |
| | | # technic_chestsの日本語への翻訳 |
| | | # by damiemk |
| | | |
| | | %s Chest = %s のチェスト |
| | | %s Locked Chest = %s ロックされたチェスト |
| | | %s Locked Chest (owned by %s) = %s のロックされたチェスト (%s が所有) |
| | | Color Filter: %s = カラーフィルター: %s |
| | | Edit chest description: = チェストの説明を編集する: |
| | | |
| | | # Colors |
| | | Black = 黒 |
| | | Blue = 青 |
| | | Brown = 茶色 |
| | | Cyan = シアン |
| | | Dark Green = 濃い緑色 |
| | | Dark Grey = 暗灰色 |
| | | Green = 緑 |
| | | Grey = 灰色 |
| | | Magenta = マジェンタ |
| | | Orange = 橙色 |
| | | Pink = 桃色 |
| | | Red = 赤 |
| | | Violet = 紫 |
| | | White = 白 |
| | | Yellow = 黄色 |
| | | None = デフォルト |
| | | |
| | | # Materials |
| | | Copper = 銅 |
| | | Gold = 金 |
| | | Iron = 鉄 |
| | | Mithril = ミスリル |
| | | Silver = 銀 |
| | | Wooden = 木造 |
| | | |
| | | # Sorting |
| | | Sort = 組織する |
| | | Auto-sort is %s = 自動組織が %s になっている |
| | | Off = オフ |
| | | On = オン |
| | |
| | | local S = rawget(_G, "intllib") and intllib.Getter() or function(s) return s end |
| | | |
| | | local pipeworks = rawget(_G, "pipeworks") |
| | | local fs_helpers = rawget(_G, "fs_helpers") |
| | | local fs_helpers |
| | | local tubelib_exists = minetest.global_exists("tubelib") |
| | | |
| | | local registered_chest_data = {} -- data passed to :register() |
| | | |
| | | local allow_label = "" |
| | | local tube_entry = "" |
| | | local shift_edit_field = 0 |
| | | |
| | | if not minetest.get_modpath("pipeworks") then |
| | | -- Pipeworks is not installed. Simulate using a dummy table... |
| | |
| | | fs_helpers.cycling_button = function() return "" end |
| | | else |
| | | fs_helpers = pipeworks.fs_helpers |
| | | allow_label = "label[0.9,0.36;Allow splitting incoming stacks from tubes]" |
| | | shift_edit_field = 3 |
| | | allow_label = "Allow splitting incoming stacks from tubes" |
| | | tube_entry = "^pipeworks_tube_connection_metallic.png" |
| | | end |
| | | |
| | | -- Change the appearance of the chest |
| | | local chest_mark_colors = { |
| | | {"black", S("Black")}, |
| | | {"blue", S("Blue")}, |
| | |
| | | |
| | | local function set_formspec(pos, data, page) |
| | | local meta = minetest.get_meta(pos) |
| | | local formspec = data.base_formspec |
| | | formspec = formspec..fs_helpers.cycling_button( |
| | | meta, |
| | | "image_button[0,0.35;1,0.6", |
| | | "splitstacks", |
| | | { |
| | | pipeworks.button_off, |
| | | pipeworks.button_on |
| | | } |
| | | )..allow_label |
| | | |
| | | -- Static formspec elements are in base_formspec |
| | | local fs = { data.base_formspec } |
| | | |
| | | -- Pipeworks splitting setting |
| | | fs[#fs + 1] = fs_helpers.cycling_button( |
| | | meta, |
| | | "image_button[0,0.5;1,0.6", |
| | | "splitstacks", |
| | | { |
| | | pipeworks.button_off, |
| | | pipeworks.button_on |
| | | } |
| | | ) |
| | | |
| | | if data.autosort then |
| | | local status = meta:get_int("autosort") |
| | | formspec = formspec.."button["..(data.hileft+2)..","..(data.height+1.1)..";3,0.8;autosort_to_"..(1-status)..";"..S("Auto-sort is %s"):format(status == 1 and S("On") or S("Off")).."]" |
| | | fs[#fs + 1] = ("checkbox[%g,%g;autosort_to_%s;%s;%s]"):format( |
| | | data.hileft + 2.2, data.lotop - 1.15, |
| | | tostring(1 - status), S("Auto-sort upon exit"), tostring(status == 1)) |
| | | end |
| | | |
| | | if data.infotext then |
| | | local formspec_infotext = minetest.formspec_escape(meta:get_string("infotext")) |
| | | |
| | | local button_fmt = "image_button[%g,0;0.8,0.8;%s;%s;]" |
| | | if page == "main" then |
| | | formspec = formspec.."image_button["..(shift_edit_field+data.hileft+2.1)..",0.1;0.8,0.8;" |
| | | .."technic_pencil_icon.png;edit_infotext;]" |
| | | .."label["..(shift_edit_field+data.hileft+3)..",0;"..formspec_infotext.."]" |
| | | fs[#fs + 1] = button_fmt:format(data.hileft + 6.1, |
| | | "technic_pencil_icon.png", "edit_infotext") |
| | | |
| | | fs[#fs + 1] = "label["..(data.hileft+7.1)..",0.1;"..formspec_infotext.."]" |
| | | elseif page == "edit_infotext" then |
| | | formspec = formspec.."image_button["..(shift_edit_field+data.hileft+2.1)..",0.1;0.8,0.8;" |
| | | .."technic_checkmark_icon.png;save_infotext;]" |
| | | .."field["..(shift_edit_field+data.hileft+3.3)..",0.2;4.8,1;" |
| | | .."infotext_box;"..S("Edit chest description:")..";" |
| | | fs[#fs + 1] = button_fmt:format(data.hileft + 6.1, |
| | | "technic_checkmark_icon.png", "save_infotext") |
| | | |
| | | fs[#fs + 1] = "field["..(data.hileft+7.3)..",0.2;4,1;" |
| | | .."infotext_box;;" |
| | | ..formspec_infotext.."]" |
| | | end |
| | | end |
| | |
| | | else |
| | | colorName = S("None") |
| | | end |
| | | formspec = formspec.."label["..(data.coleft+0.2)..","..(data.lotop+3)..";"..S("Color Filter: %s"):format(colorName).."]" |
| | | fs[#fs + 1] = "label["..(data.coleft+0.2)..","..(data.lotop+3)..";"..S("Color Filter: %s"):format(colorName).."]" |
| | | end |
| | | meta:set_string("formspec", formspec) |
| | | meta:set_string("formspec", table.concat(fs)) |
| | | end |
| | | |
| | | local function sort_inventory(inv) |
| | |
| | | |
| | | if fields.sort or (data.autosort and fields.quit and meta:get_int("autosort") == 1) then |
| | | sort_inventory(meta:get_inventory()) |
| | | return -- No formspec update |
| | | end |
| | | if fields.edit_infotext then |
| | | page = "edit_infotext" |
| | |
| | | fs_helpers.on_receive_fields(pos, fields) |
| | | end |
| | | |
| | | meta:get_inventory():set_size("main", data.width * data.height) |
| | | set_formspec(pos, data, page) |
| | | end |
| | | end |
| | |
| | | function technic.chests:definition(name, data) |
| | | local lname = name:lower() |
| | | name = S(name) |
| | | local d = {} |
| | | for k, v in pairs(data) do d[k] = v end |
| | | data = d |
| | | |
| | | -- Calculate formspec positions |
| | | data.lowidth = 8 |
| | | data.ovwidth = math.max(data.lowidth, data.width) |
| | | data.hileft = (data.ovwidth - data.width) / 2 |
| | |
| | | data.lotop = data.height + 2 |
| | | data.ovheight = data.lotop + 4 |
| | | |
| | | local locked_after_place = nil |
| | | local front = {"technic_"..lname.."_chest_front.png"} |
| | | data.base_formspec = "size["..data.ovwidth..","..data.ovheight.."]".. |
| | | "label[0,0;"..S("%s Chest"):format(name).."]".. |
| | | "list[context;main;"..data.hileft..",1;"..data.width..","..data.height..";]".. |
| | | "list[current_player;main;"..data.loleft..","..data.lotop..";8,4;]".. |
| | | "background[-0.19,-0.25;"..(data.ovwidth+0.4)..","..(data.ovheight+0.75)..";technic_chest_form_bg.png]".. |
| | | "background["..data.hileft..",1;"..data.width..","..data.height..";technic_"..lname.."_chest_inventory.png]".. |
| | | "background["..data.loleft..","..data.lotop..";8,4;technic_main_inventory.png]".. |
| | | "listring[]" |
| | | -- Set up constant formspec fields |
| | | local fs = { |
| | | "size["..data.ovwidth..","..data.ovheight.."]", |
| | | "label[0,0;"..S("%s Chest"):format(name).."]", |
| | | "list[context;main;"..data.hileft..",1;"..data.width..","..data.height..";]", |
| | | "list[current_player;main;"..data.loleft..","..data.lotop..";8,4;]", |
| | | "listring[]" |
| | | } |
| | | if #allow_label > 0 then |
| | | fs[#fs + 1] = ("label[0.9,0.5;%s]"):format(allow_label) |
| | | end |
| | | |
| | | if data.color then |
| | | fs[#fs + 1] = get_color_buttons(data.coleft, data.lotop) |
| | | end |
| | | |
| | | if data.sort then |
| | | data.base_formspec = data.base_formspec.."button["..data.hileft..","..(data.height+1.1)..";1,0.8;sort;"..S("Sort").."]" |
| | | fs[#fs + 1] = ("button[%g,%g;2,0.7;sort;%s]"):format( |
| | | data.hileft, data.lotop - 1, S("Sort now")) |
| | | end |
| | | if data.color then |
| | | data.base_formspec = data.base_formspec..get_color_buttons(data.coleft, data.lotop) |
| | | end |
| | | data.base_formspec = table.concat(fs) |
| | | |
| | | local front = {"technic_"..lname.."_chest_front.png"} |
| | | local locked_after_place |
| | | if data.locked then |
| | | locked_after_place = function(pos, placer) |
| | | local meta = minetest.get_meta(pos) |
| | |
| | | } |
| | | |
| | | function technic.chests:register(name, data) |
| | | data = table.copy(data) -- drop reference |
| | | local def = technic.chests:definition(name, data) |
| | | |
| | | local nn = "technic:"..name:lower()..(data.locked and "_locked" or "").."_chest" |
| | | minetest.register_node(":"..nn, def) |
| | | registered_chest_data[nn] = data |
| | | |
| | | if tubelib_exists then |
| | | tubelib.register_node(nn, {}, _TUBELIB_CALLBACKS) |
| | |
| | | colordef.drop = nn |
| | | colordef.groups = self.groups_noinv |
| | | colordef.tiles = { def.tiles[1], def.tiles[2], def.tiles[3], def.tiles[4], def.tiles[5], mk_front("technic_chest_overlay"..postfix..".png") } |
| | | minetest.register_node(":"..nn..postfix, colordef) |
| | | |
| | | local new_name = nn .. postfix |
| | | minetest.register_node(":" .. new_name, colordef) |
| | | registered_chest_data[new_name] = data -- for all colors |
| | | |
| | | if tubelib_exists then |
| | | tubelib.register_node(nn..postfix, {}, _TUBELIB_CALLBACKS) |
| | | end |
| | |
| | | end |
| | | end |
| | | |
| | | |
| | | -- Migration of chest formspecs |
| | | -- Group is specified in common.lua |
| | | minetest.register_lbm({ |
| | | label = "technic_chests formspec upgrade", |
| | | name = "technic_chests:upgrade_formspec", |
| | | nodenames = {"group:technic_chest"}, |
| | | run_at_every_load = false, |
| | | action = function(pos, node) |
| | | set_formspec(pos, registered_chest_data[node.name], "main") |
| | | end |
| | | }) |
| | |
| | | allow_metadata_inventory_take = technic.machine_inventory_take |
| | | allow_metadata_inventory_move = technic.machine_inventory_move |
| | | can_dig = technic.machine_can_dig |
| | | desc_tr = S("%s CNC Machine"):format("LV") |
| | | desc_tr = S("@1 CNC Machine", S("LV")) |
| | | else |
| | | minetest.register_craft({ |
| | | output = 'technic:cnc', |
| | |
| | | end |
| | | end |
| | | |
| | | local onesize_products = { |
| | | slope = 2, |
| | | slope_edge = 1, |
| | | slope_inner_edge = 1, |
| | | pyramid = 2, |
| | | spike = 1, |
| | | cylinder = 2, |
| | | oblate_spheroid = 1, |
| | | sphere = 1, |
| | | stick = 8, |
| | | slope_upsdown = 2, |
| | | slope_edge_upsdown = 1, |
| | | slope_inner_edge_upsdown = 1, |
| | | cylinder_horizontal = 2, |
| | | slope_lying = 2, |
| | | onecurvededge = 1, |
| | | twocurvededge = 1, |
| | | } |
| | | local twosize_products = { |
| | | element_straight = 2, |
| | | element_end = 2, |
| | | element_cross = 1, |
| | | element_t = 1, |
| | | element_edge = 2, |
| | | } |
| | | local function add_buttons(do_variants, t, x, y) |
| | | local X_OFFSET = 1 |
| | | local BUTTONS_PER_ROW = 7 |
| | | |
| | | local cnc_formspec = |
| | | "size[9,11;]".. |
| | | "label[1,0;"..S("Choose Milling Program:").."]".. |
| | | "image_button[1,0.5;1,1;technic_cnc_slope.png;slope; ]".. |
| | | "image_button[2,0.5;1,1;technic_cnc_slope_edge.png;slope_edge; ]".. |
| | | "image_button[3,0.5;1,1;technic_cnc_slope_inner_edge.png;slope_inner_edge; ]".. |
| | | "image_button[4,0.5;1,1;technic_cnc_pyramid.png;pyramid; ]".. |
| | | "image_button[5,0.5;1,1;technic_cnc_spike.png;spike; ]".. |
| | | "image_button[6,0.5;1,1;technic_cnc_cylinder.png;cylinder; ]".. |
| | | "image_button[7,0.5;1,1;technic_cnc_oblate_spheroid.png;oblate_spheroid; ]".. |
| | | "image_button[8,0.5;1,1;technic_cnc_stick.png;stick; ]".. |
| | | -- ipairs: only iterate over continuous integers |
| | | for _, data in ipairs(technic_cnc.programs) do |
| | | -- Never add full variants. Only add half variants when asked |
| | | if not data.half_counterpart and (do_variants == (data.full_counterpart ~= nil)) then |
| | | --print("add", data.suffix) |
| | | t[#t + 1] = ("image_button[%g,%g;1,1;%s.png;%s; ]"):format( |
| | | x + X_OFFSET, y, data.suffix, data.short_name |
| | | ) |
| | | t[#t + 1] = ("tooltip[%s;%s]"):format( |
| | | data.short_name, minetest.formspec_escape(data.desc .. " (* " .. data.output .. ")") |
| | | ) |
| | | |
| | | "image_button[1,1.5;1,1;technic_cnc_slope_upsdwn.png;slope_upsdown; ]".. |
| | | "image_button[2,1.5;1,1;technic_cnc_slope_edge_upsdwn.png;slope_edge_upsdown; ]".. |
| | | "image_button[3,1.5;1,1;technic_cnc_slope_inner_edge_upsdwn.png;slope_inner_edge_upsdown; ]".. |
| | | "image_button[4,1.5;1,1;technic_cnc_cylinder_horizontal.png;cylinder_horizontal; ]".. |
| | | "image_button[5,1.5;1,1;technic_cnc_sphere.png;sphere; ]".. |
| | | x = x + 1 |
| | | if x == BUTTONS_PER_ROW then |
| | | x = 0 |
| | | y = y + 1 |
| | | end |
| | | end |
| | | end |
| | | end |
| | | |
| | | "image_button[1,2.5;1,1;technic_cnc_slope_lying.png;slope_lying; ]".. |
| | | "image_button[2,2.5;1,1;technic_cnc_onecurvededge.png;onecurvededge; ]".. |
| | | "image_button[3,2.5;1,1;technic_cnc_twocurvededge.png;twocurvededge; ]".. |
| | | local function make_formspec() |
| | | local t = { |
| | | "size[9,11;]", |
| | | "label[1,0;"..S("Choose Milling Program:").."]", |
| | | } |
| | | add_buttons(false, t, 0, 0.5) |
| | | |
| | | "label[1,3.5;"..S("Slim Elements half / normal height:").."]".. |
| | | t[#t + 1] = ( |
| | | "label[1,3.5;"..S("Slim Elements half / normal height:").."]".. |
| | | "image_button[1,4;1,0.5;technic_cnc_full.png;full; ]".. |
| | | "image_button[1,4.5;1,0.5;technic_cnc_half.png;half; ]" |
| | | ) |
| | | add_buttons(true, t, 1, 4) |
| | | |
| | | "image_button[1,4;1,0.5;technic_cnc_full.png;full; ]".. |
| | | "image_button[1,4.5;1,0.5;technic_cnc_half.png;half; ]".. |
| | | "image_button[2,4;1,1;technic_cnc_element_straight.png;element_straight; ]".. |
| | | "image_button[3,4;1,1;technic_cnc_element_end.png;element_end; ]".. |
| | | "image_button[4,4;1,1;technic_cnc_element_cross.png;element_cross; ]".. |
| | | "image_button[5,4;1,1;technic_cnc_element_t.png;element_t; ]".. |
| | | "image_button[6,4;1,1;technic_cnc_element_edge.png;element_edge; ]".. |
| | | t[#t + 1] = ( |
| | | "label[0, 5;"..S("In:").."]".. |
| | | "list[current_name;src;0.5,5.5;1,1;]".. |
| | | "label[4, 5;"..S("Out:").."]".. |
| | | "list[current_name;dst;5,5.5;4,1;]".. |
| | | |
| | | "label[0, 5.5;"..S("In:").."]".. |
| | | "list[current_name;src;0.5,5.5;1,1;]".. |
| | | "label[4, 5.5;"..S("Out:").."]".. |
| | | "list[current_name;dst;5,5.5;4,1;]".. |
| | | "list[current_player;main;0,7;8,4;]".. |
| | | "listring[current_name;dst]".. |
| | | "listring[current_player;main]".. |
| | | "listring[current_name;src]".. |
| | | "listring[current_player;main]" |
| | | ) |
| | | |
| | | "list[current_player;main;0,7;8,4;]".. |
| | | "listring[current_name;dst]".. |
| | | "listring[current_player;main]".. |
| | | "listring[current_name;src]".. |
| | | "listring[current_player;main]" |
| | | return table.concat(t) |
| | | end |
| | | |
| | | local cnc_formspec = nil |
| | | |
| | | minetest.register_on_mods_loaded(function() |
| | | technic_cnc._populate_shortcuts() |
| | | cnc_formspec = make_formspec() |
| | | end) |
| | | |
| | | |
| | | -- The form handler is declared here because we need it in both the inactive and active modes |
| | | -- in order to be able to change programs wile it is running. |
| | |
| | | local inv = meta:get_inventory() |
| | | local inputstack = inv:get_stack("src", 1) |
| | | local inputname = inputstack:get_name() |
| | | local multiplier = 0 |
| | | local size = meta:get_int("size") |
| | | if size < 1 then size = 1 end |
| | | |
| | | for k, _ in pairs(fields) do |
| | | -- Set a multipier for the half/full size capable blocks |
| | | if twosize_products[k] ~= nil then |
| | | multiplier = size * twosize_products[k] |
| | | else |
| | | multiplier = onesize_products[k] |
| | | local program = technic_cnc.programs["technic_cnc_" .. k] |
| | | if size == 1 and program and program.full_counterpart then |
| | | program = technic_cnc.programs["technic_cnc_" .. k .. "_double"] |
| | | end |
| | | if program then |
| | | local multiplier = program.output |
| | | local product = inputname .. "_" .. program.suffix |
| | | |
| | | if onesize_products[k] ~= nil or twosize_products[k] ~= nil then |
| | | meta:set_float( "cnc_multiplier", multiplier) |
| | | meta:set_string("cnc_user", sender:get_player_name()) |
| | | end |
| | | |
| | | if onesize_products[k] ~= nil or (twosize_products[k] ~= nil and size==2) then |
| | | meta:set_string("cnc_product", inputname .. "_technic_cnc_" .. k) |
| | | --print(inputname .. "_technic_cnc_" .. k) |
| | | break |
| | | end |
| | | if program.half_counterpart then -- is full |
| | | if size == 1 then |
| | | meta:set_string("cnc_product", product) |
| | | --print(product, multiplier) |
| | | end |
| | | break -- no larger sizes allowed |
| | | end |
| | | |
| | | if twosize_products[k] ~= nil and size==1 then |
| | | meta:set_string("cnc_product", inputname .. "_technic_cnc_" .. k .. "_double") |
| | | --print(inputname .. "_technic_cnc_" .. k .. "_double") |
| | | -- half for normal |
| | | meta:set_string("cnc_product", product) |
| | | --print(product, multiplier) |
| | | break |
| | | end |
| | | end |
| | |
| | | (not minetest.registered_nodes[result]) or |
| | | (not inv:room_for_item("dst", result)) then |
| | | technic.swap_node(pos, machine_node) |
| | | meta:set_string("infotext", S("%s Idle"):format(machine_name)) |
| | | meta:set_string("infotext", S("@1 Idle", machine_name)) |
| | | meta:set_string("cnc_product", "") |
| | | meta:set_int("LV_EU_demand", 0) |
| | | return |
| | |
| | | |
| | | if eu_input < demand then |
| | | technic.swap_node(pos, machine_node) |
| | | meta:set_string("infotext", S("%s Unpowered"):format(machine_name)) |
| | | meta:set_string("infotext", S("@1 Unpowered", machine_name)) |
| | | elseif eu_input >= demand then |
| | | technic.swap_node(pos, machine_node.."_active") |
| | | meta:set_string("infotext", S("%s Active"):format(machine_name)) |
| | | meta:set_string("infotext", S("@1 Active", machine_name)) |
| | | meta:set_int("src_time", meta:get_int("src_time") + 1) |
| | | if meta:get_int("src_time") >= 3 then -- 3 ticks per output |
| | | meta:set_int("src_time", 0) |
| | | srcstack = inv:get_stack("src", 1) |
| | | local srcstack = inv:get_stack("src", 1) |
| | | srcstack:take_item() |
| | | inv:set_stack("src", 1, srcstack) |
| | | inv:add_item("dst", result.." "..meta:get_int("cnc_multiplier")) |
| | |
| | | -- Again code is adapted from the NonCubic Blocks MOD v1.4 by yves_de_beck |
| | | |
| | | local S = technic_cnc.getter |
| | | local ALPHA_CLIP = minetest.features.use_texture_alpha_string_modes and "clip" or true |
| | | |
| | | -- REGISTER NONCUBIC FORMS, CREATE MODELS AND RECIPES: |
| | | ------------------------------------------------------ |
| | | |
| | | -- Define slope boxes for the various nodes |
| | | --[[ |
| | | Additional keys after registration: |
| | | programs[program.suffix] = program |
| | | |
| | | Additional fields after registration: |
| | | program.short_name = (trimmed suffix) |
| | | program.full_counterpart = suffix (optional, for full/half variants) |
| | | program.half_counterpart = suffix (optional, for full/half variants) |
| | | ]] |
| | | ------------------------------------------- |
| | | technic_cnc.programs = { |
| | | { suffix = "technic_cnc_stick", |
| | | model = {-0.15, -0.5, -0.15, 0.15, 0.5, 0.15}, |
| | | desc = S("Stick") |
| | | desc = S("Stick"), |
| | | output = 8 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_end_double", |
| | | model = {-0.3, -0.5, -0.3, 0.3, 0.5, 0.5}, |
| | | desc = S("Element End Double") |
| | | desc = S("Element End Double"), |
| | | output = 2 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_cross_double", |
| | |
| | | {0.3, -0.5, -0.3, 0.5, 0.5, 0.3}, |
| | | {-0.3, -0.5, -0.5, 0.3, 0.5, 0.5}, |
| | | {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3}}, |
| | | desc = S("Element Cross Double") |
| | | desc = S("Element Cross Double"), |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_t_double", |
| | |
| | | {-0.3, -0.5, -0.5, 0.3, 0.5, 0.3}, |
| | | {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3}, |
| | | {0.3, -0.5, -0.3, 0.5, 0.5, 0.3}}, |
| | | desc = S("Element T Double") |
| | | desc = S("Element T Double"), |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_edge_double", |
| | | model = { |
| | | {-0.3, -0.5, -0.5, 0.3, 0.5, 0.3}, |
| | | {-0.5, -0.5, -0.3, -0.3, 0.5, 0.3}}, |
| | | desc = S("Element Edge Double") |
| | | desc = S("Element Edge Double"), |
| | | output = 2 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_straight_double", |
| | | model = {-0.3, -0.5, -0.5, 0.3, 0.5, 0.5}, |
| | | desc = S("Element Straight Double") |
| | | desc = S("Element Straight Double"), |
| | | output = 2 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_end", |
| | | model = {-0.3, -0.5, -0.3, 0.3, 0, 0.5}, |
| | | desc = S("Element End") |
| | | desc = S("Element End"), |
| | | output = nil -- calculated |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_cross", |
| | |
| | | {0.3, -0.5, -0.3, 0.5, 0, 0.3}, |
| | | {-0.3, -0.5, -0.5, 0.3, 0, 0.5}, |
| | | {-0.5, -0.5, -0.3, -0.3, 0, 0.3}}, |
| | | desc = S("Element Cross") |
| | | desc = S("Element Cross"), |
| | | output = nil -- calculated |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_t", |
| | |
| | | {-0.3, -0.5, -0.5, 0.3, 0, 0.3}, |
| | | {-0.5, -0.5, -0.3, -0.3, 0, 0.3}, |
| | | {0.3, -0.5, -0.3, 0.5, 0, 0.3}}, |
| | | desc = S("Element T") |
| | | desc = S("Element T"), |
| | | output = nil -- calculated |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_edge", |
| | | model = { |
| | | {-0.3, -0.5, -0.5, 0.3, 0, 0.3}, |
| | | {-0.5, -0.5, -0.3, -0.3, 0, 0.3}}, |
| | | desc = S("Element Edge") |
| | | desc = S("Element Edge"), |
| | | output = nil -- calculated |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_element_straight", |
| | | model = {-0.3, -0.5, -0.5, 0.3, 0, 0.5}, |
| | | desc = S("Element Straight") |
| | | desc = S("Element Straight"), |
| | | output = nil -- calculated |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_oblate_spheroid", |
| | |
| | | { -8/16, -4/16, -8/16, 8/16, 4/16, 8/16 }, |
| | | { -6/16, -8/16, -6/16, 6/16, -4/16, 6/16 } |
| | | } |
| | | } |
| | | }, |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_sphere", |
| | | model = "technic_cnc_sphere.obj", |
| | | desc = S("Sphere") |
| | | desc = S("Sphere"), |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_cylinder_horizontal", |
| | | model = "technic_cnc_cylinder_horizontal.obj", |
| | | desc = S("Horizontal Cylinder") |
| | | desc = S("Horizontal Cylinder"), |
| | | output = 2 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_cylinder", |
| | | model = "technic_cnc_cylinder.obj", |
| | | desc = S("Cylinder") |
| | | desc = S("Cylinder"), |
| | | output = 2 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_twocurvededge", |
| | | model = "technic_cnc_two_curved_edge.obj", |
| | | desc = S("Two Curved Edge/Corner Block") |
| | | desc = S("Two Curved Edge/Corner Block"), |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_onecurvededge", |
| | | model = "technic_cnc_one_curved_edge.obj", |
| | | desc = S("One Curved Edge Block") |
| | | desc = S("One Curved Edge Block"), |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_spike", |
| | |
| | | { -6/16, -4/16, -6/16, 6/16, 0, 6/16 }, |
| | | { -8/16, -8/16, -8/16, 8/16, -4/16, 8/16 } |
| | | } |
| | | } |
| | | }, |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_pyramid", |
| | |
| | | { -6/16, -6/16, -6/16, 6/16, -4/16, 6/16 }, |
| | | { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 } |
| | | } |
| | | } |
| | | }, |
| | | output = 2 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_slope_inner_edge_upsdown", |
| | |
| | | { -0.5, 0.25, -0.25, 0.5, 0, 0.5 }, |
| | | { -0.5, 0.5, -0.5, 0.5, 0.25, 0.5 } |
| | | } |
| | | } |
| | | }, |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_slope_edge_upsdown", |
| | |
| | | { 0, 0, 0, 8/16, -4/16, 8/16 }, |
| | | { 4/16, -4/16, 4/16, 8/16, -8/16, 8/16 } |
| | | } |
| | | } |
| | | }, |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_slope_inner_edge", |
| | |
| | | { -0.5, 0.25, 0.25, 0.5, 0.5, 0.5 }, |
| | | { 0.25, 0.25, -0.5, 0.5, 0.5, 0.5 } |
| | | } |
| | | } |
| | | }, |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_slope_edge", |
| | |
| | | { -4/16, -4/16, -4/16, 8/16, 0, 8/16 }, |
| | | { -8/16, -8/16, -8/16, 8/16, -4/16, 8/16 } |
| | | } |
| | | } |
| | | }, |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_slope_upsdown", |
| | |
| | | { -8/16, 0, 0, 8/16, -4/16, 8/16 }, |
| | | { -8/16, -4/16, 4/16, 8/16, -8/16, 8/16 } |
| | | } |
| | | } |
| | | }, |
| | | output = 1 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_slope_lying", |
| | |
| | | { -4/16, -8/16, -4/16, 0, 8/16, 8/16 }, |
| | | { -8/16, -8/16, -8/16, -4/16, 8/16, 8/16 } |
| | | } |
| | | } |
| | | }, |
| | | output = 2 |
| | | }, |
| | | |
| | | { suffix = "technic_cnc_slope", |
| | |
| | | { -8/16, -4/16, -4/16, 8/16, 0, 8/16 }, |
| | | { -8/16, -8/16, -8/16, 8/16, -4/16, 8/16 } |
| | | } |
| | | } |
| | | }, |
| | | output = 2 |
| | | }, |
| | | |
| | | } |
| | | |
| | | technic_cnc._populate_shortcuts = function() |
| | | -- Program quick access by string key |
| | | for _, data in ipairs(technic_cnc.programs) do |
| | | technic_cnc.programs[data.suffix] = data |
| | | data.short_name = assert(data.suffix:match("technic_cnc_(%S+)")) |
| | | end |
| | | |
| | | -- Detect half/full counterparts |
| | | for k, data in pairs(technic_cnc.programs) do |
| | | if type(k) == "string" then |
| | | local full = technic_cnc.programs[k .. "_double"] |
| | | if full then |
| | | full.half_counterpart = k |
| | | data.full_counterpart = k .. "_double" |
| | | data.output = full.output * 2 |
| | | |
| | | --print("populate", k) |
| | | end |
| | | end |
| | | end |
| | | |
| | | -- Final checks |
| | | for _, data in ipairs(technic_cnc.programs) do |
| | | assert(type(data.output) == "number", data.suffix) |
| | | assert(type(data.short_name) == "string", data.suffix) |
| | | end |
| | | end |
| | | |
| | | -- Allow disabling certain programs for some node. Default is allowing all types for all nodes |
| | | technic_cnc.programs_disable = { |
| | |
| | | tiles = images, |
| | | paramtype = "light", |
| | | paramtype2 = "facedir", |
| | | use_texture_alpha = ALPHA_CLIP, |
| | | walkable = true, |
| | | groups = groups, |
| | | selection_box = sbox, |
| | |
| | | groups, images, description.." "..data.desc, data.cbox, data.sbox) |
| | | end |
| | | end |
| | | end |
| | | |
| | | |
| | | -- REGISTER NEW TECHNIC_CNC_API's PART 2: technic_cnc..register_element_end(subname, recipeitem, groups, images, desc_element_xyz) |
| | | ----------------------------------------------------------------------------------------------------------------------- |
| | | function technic_cnc.register_slope_edge_etc(recipeitem, groups, images, desc_slope, desc_slope_lying, desc_slope_upsdown, desc_slope_edge, desc_slope_inner_edge, desc_slope_upsdwn_edge, desc_slope_upsdwn_inner_edge, desc_pyramid, desc_spike, desc_onecurvededge, desc_twocurvededge, desc_cylinder, desc_cylinder_horizontal, desc_spheroid, desc_element_straight, desc_element_edge, desc_element_t, desc_element_cross, desc_element_end) |
| | | |
| | | technic_cnc.register_slope(recipeitem, groups, images, desc_slope) |
| | | technic_cnc.register_slope_lying(recipeitem, groups, images, desc_slope_lying) |
| | | technic_cnc.register_slope_upsdown(recipeitem, groups, images, desc_slope_upsdown) |
| | | technic_cnc.register_slope_edge(recipeitem, groups, images, desc_slope_edge) |
| | | technic_cnc.register_slope_inner_edge(recipeitem, groups, images, desc_slope_inner_edge) |
| | | technic_cnc.register_slope_edge_upsdown(recipeitem, groups, images, desc_slope_upsdwn_edge) |
| | | technic_cnc.register_slope_inner_edge_upsdown(recipeitem, groups, images, desc_slope_upsdwn_inner_edge) |
| | | technic_cnc.register_pyramid(recipeitem, groups, images, desc_pyramid) |
| | | technic_cnc.register_spike(recipeitem, groups, images, desc_spike) |
| | | technic_cnc.register_onecurvededge(recipeitem, groups, images, desc_onecurvededge) |
| | | technic_cnc.register_twocurvededge(recipeitem, groups, images, desc_twocurvededge) |
| | | technic_cnc.register_cylinder(recipeitem, groups, images, desc_cylinder) |
| | | technic_cnc.register_cylinder_horizontal(recipeitem, groups, images, desc_cylinder_horizontal) |
| | | technic_cnc.register_spheroid(recipeitem, groups, images, desc_spheroid) |
| | | technic_cnc.register_element_straight(recipeitem, groups, images, desc_element_straight) |
| | | technic_cnc.register_element_edge(recipeitem, groups, images, desc_element_edge) |
| | | technic_cnc.register_element_t(recipeitem, groups, images, desc_element_t) |
| | | technic_cnc.register_element_cross(recipeitem, groups, images, desc_element_cross) |
| | | technic_cnc.register_element_end(recipeitem, groups, images, desc_element_end) |
| | | end |
| | | |
| | | -- REGISTER STICKS: noncubic.register_xyz(recipeitem, groups, images, desc_element_xyz) |
| | | ------------------------------------------------------------------------------------------------------------ |
| | | function technic_cnc.register_stick_etc(recipeitem, groups, images, desc_stick) |
| | | technic_cnc.register_stick(recipeitem, groups, images, desc_stick) |
| | | end |
| | | |
| | | function technic_cnc.register_elements(recipeitem, groups, images, desc_element_straight_double, desc_element_edge_double, desc_element_t_double, desc_element_cross_double, desc_element_end_double) |
| | | technic_cnc.register_element_straight_double(recipeitem, groups, images, desc_element_straight_double) |
| | | technic_cnc.register_element_edge_double(recipeitem, groups, images, desc_element_edge_double) |
| | | technic_cnc.register_element_t_double(recipeitem, groups, images, desc_element_t_double) |
| | | technic_cnc.register_element_cross_double(recipeitem, groups, images, desc_element_cross_double) |
| | | technic_cnc.register_element_end_double(recipeitem, groups, images, desc_element_end_double) |
| | | end |
| | | |
| | |
| | | |
| | | local S = technic_cnc.getter |
| | | |
| | | -- DIRT |
| | | ------- |
| | | technic_cnc.register_all("default:dirt", |
| | | {snappy=2,choppy=2,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, |
| | | {"default_dirt.png"}, |
| | | S("Dirt")) |
| | | -- (DIRT WITH) GRASS |
| | | -------------------- |
| | | technic_cnc.register_all("default:dirt_with_grass", |
| | | {snappy=2,choppy=2,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, |
| | | {"default_grass.png"}, |
| | | S("Grassy dirt")) |
| | | -- WOOD |
| | | ------- |
| | | technic_cnc.register_all("default:wood", |
| | | {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1}, |
| | | {"default_wood.png"}, |
| | | S("Wooden")) |
| | | -- STONE |
| | | -------- |
| | | technic_cnc.register_all("default:stone", |
| | | {cracky=3, not_in_creative_inventory=1}, |
| | | {"default_stone.png"}, |
| | | S("Stone")) |
| | | -- COBBLE |
| | | --------- |
| | | technic_cnc.register_all("default:cobble", |
| | | {cracky=3, not_in_creative_inventory=1}, |
| | | {"default_cobble.png"}, |
| | | S("Cobble")) |
| | | -- BRICK |
| | | -------- |
| | | technic_cnc.register_all("default:brick", |
| | | {cracky=3, not_in_creative_inventory=1}, |
| | | {"default_brick.png"}, |
| | | S("Brick")) |
| | | local function register_material(nodename, tiles_override, descr_override) |
| | | local ndef = minetest.registered_nodes[nodename] |
| | | if not ndef then |
| | | return |
| | | end |
| | | |
| | | -- SANDSTONE |
| | | ------------ |
| | | technic_cnc.register_all("default:sandstone", |
| | | {crumbly=2, cracky=3, not_in_creative_inventory=1}, |
| | | {"default_sandstone.png"}, |
| | | S("Sandstone")) |
| | | local groups = { |
| | | cracky = ndef.groups.cracky, |
| | | crumbly = ndef.groups.crumbly, |
| | | choppy = ndef.groups.choppy, |
| | | flammable = ndef.groups.flammable, |
| | | level = ndef.groups.level, |
| | | snappy = ndef.groups.snappy, |
| | | wood = ndef.groups.wood, |
| | | oddly_breakable_by_hand = ndef.groups.oddly_breakable_by_hand, |
| | | not_in_creative_inventory = 1, |
| | | } |
| | | local count = 0 |
| | | for _ in pairs(groups) do |
| | | count = count + 1 |
| | | end |
| | | assert(count >= 2, "Too few groups. node name=" .. nodename) |
| | | |
| | | -- LEAVES |
| | | --------- |
| | | technic_cnc.register_all("default:leaves", |
| | | {snappy=2, choppy=2, oddly_breakable_by_hand=3, not_in_creative_inventory=1}, |
| | | {"default_leaves.png"}, |
| | | S("Leaves")) |
| | | -- TREE |
| | | ------- |
| | | technic_cnc.register_all("default:tree", |
| | | {snappy=1, choppy=2, oddly_breakable_by_hand=2, flammable=3, wood=1, not_in_creative_inventory=1}, |
| | | {"default_tree.png"}, |
| | | S("Tree")) |
| | | local tiles = tiles_override or { ndef.tiles[#ndef.tiles] } |
| | | assert(tiles and #tiles == 1, "Unknown tile format in node name=" .. nodename) |
| | | |
| | | -- Bronze |
| | | -------- |
| | | technic_cnc.register_all("default:bronzeblock", |
| | | {cracky=1, level=2, not_in_creative_inventory=1}, |
| | | {"default_bronze_block.png"}, |
| | | S("Bronze")) |
| | | |
| | | |
| | | local steeltex = "default_steel_block.png" |
| | | local steelname = "Steel" |
| | | |
| | | if technic_cnc.technic_modpath then |
| | | steeltex = "technic_wrought_iron_block.png" |
| | | steelname = "Wrought Iron" |
| | | |
| | | -- Stainless Steel |
| | | -------- |
| | | technic_cnc.register_all("technic:stainless_steel_block", |
| | | {cracky=1, level=2, not_in_creative_inventory=1}, |
| | | {"technic_stainless_steel_block.png"}, |
| | | S("Stainless Steel")) |
| | | |
| | | -- Marble |
| | | ------------ |
| | | technic_cnc.register_all("technic:marble", |
| | | {cracky=3, not_in_creative_inventory=1}, |
| | | {"technic_marble.png"}, |
| | | S("Marble")) |
| | | |
| | | -- Granite |
| | | ------------ |
| | | technic_cnc.register_all("technic:granite", |
| | | {cracky=1, not_in_creative_inventory=1}, |
| | | {"technic_granite.png"}, |
| | | S("Granite")) |
| | | |
| | | -- Blast-resistant concrete |
| | | --------------------------- |
| | | |
| | | technic_cnc.register_all("technic:blast_resistant_concrete", |
| | | {cracky=2, level=2, not_in_creative_inventory=1}, |
| | | {"technic_blast_resistant_concrete_block.png"}, |
| | | S("Blast-resistant concrete")) |
| | | technic_cnc.register_all(nodename, |
| | | groups, |
| | | tiles, |
| | | descr_override or ndef.description or "<unknown>" |
| | | ) |
| | | end |
| | | |
| | | -- STEEL |
| | | --------------- |
| | | technic_cnc.register_all("default:steelblock", |
| | | {cracky=1, level=2, not_in_creative_inventory=1}, |
| | | {steeltex}, |
| | | S(steelname)) |
| | | register_material("default:dirt") |
| | | register_material("default:dirt_with_grass", {"default_grass.png"}, S("Grassy dirt")) |
| | | register_material("default:wood", nil, S("Wooden")) |
| | | register_material("default:stone") |
| | | register_material("default:cobble") |
| | | register_material("default:sandstone") |
| | | register_material("default:leaves") |
| | | register_material("default:tree") |
| | | register_material("default:bronzeblock", nil, S("Bronze")) |
| | | |
| | | local steelname = S("Steel") |
| | | |
| | | if technic_cnc.technic_modpath then |
| | | steelname = S("Wrought Iron") |
| | | |
| | | register_material("technic:stainless_steel_block", nil, S("Stainless Steel")) |
| | | register_material("technic:stainless_steel_block") |
| | | register_material("technic:marble") |
| | | register_material("technic:granite") |
| | | register_material("technic:blast_resistant_concrete") |
| | | register_material("technic:blast_resistant_concrete") |
| | | end |
| | | |
| | | register_material("default:steelblock", nil, steelname) |
| | | |
| | | |
| | | -- CONCRETE AND CEMENT |
| | | ---------------------- |
| | | |
| | | technic_cnc.register_all("basic_materials:concrete_block", |
| | | {cracky=2, level=2, not_in_creative_inventory=1}, |
| | | {"basic_materials_concrete_block.png"}, |
| | | S("Concrete")) |
| | | |
| | | technic_cnc.register_all("basic_materials:cement_block", |
| | | {cracky=2, level=2, not_in_creative_inventory=1}, |
| | | {"basic_materials_cement_block.png"}, |
| | | S("Cement")) |
| | | |
| | | technic_cnc.register_all("basic_materials:brass_block", |
| | | {cracky=1, level=2, not_in_creative_inventory=1}, |
| | | {"basic_materials_brass_block.png"}, |
| | | S("Brass block")) |
| | | register_material("basic_materials:concrete_block") |
| | | register_material("basic_materials:cement_block") |
| | | register_material("basic_materials:brass_block") |
| | |
| | | technic_cnc = {} |
| | | |
| | | technic_cnc.technic_modpath = minetest.get_modpath("technic") |
| | | technic_cnc.getter = minetest.get_translator("technic_cnc") |
| | | |
| | | technic_cnc.use_technic = technic_cnc.technic_modpath |
| | | and minetest.settings:get_bool("technic_cnc_use_technic") ~= false |
| | | |
| | | if rawget(_G, "intllib") then |
| | | technic_cnc.getter = intllib.Getter() |
| | | else |
| | | technic_cnc.getter = function(s,a,...)if a==nil then return s end a={a,...}return s:gsub("(@?)@(%(?)(%d+)(%)?)",function(e,o,n,c)if e==""then return a[tonumber(n)]..(o==""and c or"")else return"@"..o..n..c end end) end |
| | | end |
| | | |
| | | dofile(modpath.."/cnc.lua") |
| | | dofile(modpath.."/cnc_api.lua") |
New file |
| | |
| | | # textdomain: technic_cnc |
| | | ## CNC |
| | | |
| | | ##[ cnc.lua ]## |
| | | CNC Machine=CNC-Maschine |
| | | @1 CNC Machine=@1 CNC-Maschine |
| | | LV=LV |
| | | Choose Milling Program:=Wähle das Fräsprogramm aus: |
| | | Slim Elements half / normal height:=Schmale halb- / normalhohe Elemente: |
| | | In:=Eingabe: |
| | | Out:=Ausgabe: |
| | | @1 Idle=@1 (wartend) |
| | | @1 Unpowered=@1 (unbestromt) |
| | | @1 Active=@1 (aktiv) |
| | | |
| | | ##[ cnc_api.lua ]## |
| | | Stick=Stock |
| | | Element End Double=Endelement |
| | | Element Cross Double=Kreuzelement |
| | | Element T Double=T-Element |
| | | Element Edge Double=Eckelement |
| | | Element Straight Double=Gerades Element |
| | | Element End=Halbes Endelement |
| | | Element Cross=Halbes Kreuzelement |
| | | Element T=Halbes T-Element |
| | | Element Edge=Halbes Eckelement |
| | | Element Straight=Halbes Gerades Eleent |
| | | Oblate spheroid=Sphärenstück |
| | | Sphere=Sphäre |
| | | Horizontal Cylinder=Horizontaler Zylinder |
| | | Cylinder=Zylinder |
| | | Two Curved Edge/Corner Block=Doppelt gekrümmter Eck/-Randblock |
| | | One Curved Edge Block=Einfach gekrümmter Eckblock |
| | | Spike=Spitze |
| | | Pyramid=Pyramide |
| | | Slope Upside Down Inner Edge/Corner=Schräge (kopfüber), innere Ecke |
| | | Slope Upside Down Outer Edge/Corner=Schräge (kopfüber), äussere Ecke |
| | | Slope Inner Edge/Corner=Schräge, innere Ecke |
| | | Slope Outer Edge/Corner=Schräge äussere Ecke |
| | | Slope Upside Down=Schräge (kopfüber) |
| | | Slope Lying=Liegende Schräge |
| | | Slope=Schräge |
| | | |
| | | ##[ cnc_materials.lua ]## |
| | | Grassy dirt=Erde mit Gras |
| | | Wooden=Holz |
| | | Bronze=Bronze |
| | | Steel=Stahl |
| | | Wrought Iron=Schmiedeeisen |
| | | Stainless Steel=Edelstahl |
| | |
| | | # textdomain: technic_cnc |
| | | ## CNC |
| | | CNC Machine = |
| | | %s CNC Machine = |
| | | Cylinder = |
| | | Element Cross = |
| | | Element Cross Double = |
| | | Element Edge = |
| | | Element Edge Double = |
| | | Element End = |
| | | Element End Double = |
| | | Element Straight = |
| | | Element Straight Double = |
| | | Element T = |
| | | Element T Double = |
| | | Horizontal Cylinder = |
| | | One Curved Edge Block = |
| | | Pyramid = |
| | | Slope = |
| | | Slope Edge = |
| | | Slope Inner Edge = |
| | | Slope Lying = |
| | | Slope Upside Down = |
| | | Slope Upside Down Edge = |
| | | Slope Upside Down Inner Edge = |
| | | Sphere = |
| | | Spike = |
| | | Stick = |
| | | Two Curved Edge Block = |
| | | Brick = |
| | | Cobble = |
| | | Dirt = |
| | | Leaves = |
| | | Sandstone = |
| | | Stone = |
| | | Tree = |
| | | Wooden = |
| | | |
| | | ##[ cnc.lua ]## |
| | | CNC Machine= |
| | | @1 CNC Machine= |
| | | LV= |
| | | Choose Milling Program:= |
| | | Slim Elements half / normal height:= |
| | | In:= |
| | | Out:= |
| | | @1 Idle= |
| | | @1 Unpowered= |
| | | @1 Active= |
| | | |
| | | ##[ cnc_api.lua ]## |
| | | Stick= |
| | | Element End Double= |
| | | Element Cross Double= |
| | | Element T Double= |
| | | Element Edge Double= |
| | | Element Straight Double= |
| | | Element End= |
| | | Element Cross= |
| | | Element T= |
| | | Element Edge= |
| | | Element Straight= |
| | | Oblate spheroid= |
| | | Sphere= |
| | | Horizontal Cylinder= |
| | | Cylinder= |
| | | Two Curved Edge/Corner Block= |
| | | One Curved Edge Block= |
| | | Spike= |
| | | Pyramid= |
| | | Slope Upside Down Inner Edge/Corner= |
| | | Slope Upside Down Outer Edge/Corner= |
| | | Slope Inner Edge/Corner= |
| | | Slope Outer Edge/Corner= |
| | | Slope Upside Down= |
| | | Slope Lying= |
| | | Slope= |
| | | |
| | | ##[ cnc_materials.lua ]## |
| | | Grassy dirt= |
| | | Wooden= |
| | | Bronze= |
| | | Steel= |
| | | Wrought Iron= |
| | | Stainless Steel= |
| | |
| | | sounds = default.node_sound_stone_defaults(), |
| | | }) |
| | | |
| | | minetest.register_node( ":technic:granite_bricks", { |
| | | description = S("Granite Bricks"), |
| | | tiles = { "technic_granite_bricks.png" }, |
| | | is_ground_content = false, |
| | | groups = {cracky=1}, |
| | | sounds = default.node_sound_stone_defaults(), |
| | | }) |
| | | |
| | | minetest.register_node( ":technic:marble", { |
| | | description = S("Marble"), |
| | | tiles = { "technic_marble.png" }, |
| | |
| | | minetest.register_node( ":technic:marble_bricks", { |
| | | description = S("Marble Bricks"), |
| | | tiles = { "technic_marble_bricks.png" }, |
| | | is_ground_content = true, |
| | | is_ground_content = false, |
| | | groups = {cracky=3}, |
| | | sounds = default.node_sound_stone_defaults(), |
| | | }) |
| | |
| | | }) |
| | | |
| | | minetest.register_craft({ |
| | | output = 'technic:granite_bricks 4', |
| | | recipe = { |
| | | {'technic:granite','technic:granite'}, |
| | | {'technic:granite','technic:granite'} |
| | | } |
| | | }) |
| | | |
| | | minetest.register_craft({ |
| | | output = 'technic:marble_bricks 4', |
| | | recipe = { |
| | | {'technic:marble','technic:marble'}, |
| | |
| | | end |
| | | |
| | | local function restore(pos, placer, itemstack) |
| | | local name = itemstack:get_name() |
| | | local node = minetest.get_node(pos) |
| | | local meta = minetest.get_meta(pos) |
| | | local inv = meta:get_inventory() |
| | | local data = itemstack:get_meta():get_string("data") |
| | | data = (data ~= "" and data) or itemstack:get_metadata() |
| | | data = minetest.deserialize(data) |
| | | |
| | | if not data then |
| | | minetest.remove_node(pos) |
| | | minetest.log("error", placer:get_player_name().." wanted to place ".. |
| | | name.." at "..minetest.pos_to_string(pos).. |
| | | itemstack:get_name().." at "..minetest.pos_to_string(pos).. |
| | | ", but it had no data.") |
| | | minetest.log("verbose", "itemstack: "..itemstack:to_string()) |
| | | return true |
| | | end |
| | | |
| | | local node = minetest.get_node(pos) |
| | | minetest.set_node(pos, {name = data.name, param2 = node.param2}) |
| | | for name, value in pairs(data.metas) do |
| | | local meta_type = get_meta_type(data.name, name) |
| | | |
| | | -- Apply stored metadata to the current node |
| | | local meta = minetest.get_meta(pos) |
| | | local inv = meta:get_inventory() |
| | | for key, value in pairs(data.metas) do |
| | | local meta_type = get_meta_type(data.name, key) |
| | | if meta_type == wrench.META_TYPE_INT then |
| | | meta:set_int(name, value) |
| | | meta:set_int(key, value) |
| | | elseif meta_type == wrench.META_TYPE_FLOAT then |
| | | meta:set_float(name, value) |
| | | meta:set_float(key, value) |
| | | elseif meta_type == wrench.META_TYPE_STRING then |
| | | meta:set_string(name, value) |
| | | meta:set_string(key, value) |
| | | end |
| | | end |
| | | local lists = data.lists |
| | | for listname, list in pairs(lists) do |
| | | |
| | | for listname, list in pairs(data.lists) do |
| | | inv:set_list(listname, list) |
| | | end |
| | | itemstack:take_item() |
| | | return itemstack |
| | | end |
| | | |
| | | for name, info in pairs(wrench.registered_nodes) do |
| | | local olddef = minetest.registered_nodes[name] |
| | | if olddef then |
| | | local newdef = {} |
| | | for key, value in pairs(olddef) do |
| | | newdef[key] = value |
| | | minetest.register_on_mods_loaded(function() |
| | | -- Delayed registration for foreign mod support |
| | | for name, info in pairs(wrench.registered_nodes) do |
| | | local olddef = minetest.registered_nodes[name] |
| | | if olddef then |
| | | local newdef = {} |
| | | for key, value in pairs(olddef) do |
| | | newdef[key] = value |
| | | end |
| | | newdef.stack_max = 1 |
| | | newdef.description = S("%s with items"):format(newdef.description) |
| | | newdef.groups = {} |
| | | newdef.groups.not_in_creative_inventory = 1 |
| | | newdef.on_construct = nil |
| | | newdef.on_destruct = nil |
| | | newdef.after_place_node = restore |
| | | minetest.register_node(":"..get_pickup_name(name), newdef) |
| | | end |
| | | newdef.stack_max = 1 |
| | | newdef.description = S("%s with items"):format(newdef.description) |
| | | newdef.groups = {} |
| | | newdef.groups.not_in_creative_inventory = 1 |
| | | newdef.on_construct = nil |
| | | newdef.on_destruct = nil |
| | | newdef.after_place_node = restore |
| | | minetest.register_node(":"..get_pickup_name(name), newdef) |
| | | end |
| | | end |
| | | end) |
| | | |
| | | minetest.register_tool("wrench:wrench", { |
| | | description = S("Wrench"), |
| | |
| | | minetest.record_protection_violation(pos, player_name) |
| | | return |
| | | end |
| | | local name = minetest.get_node(pos).name |
| | | local def = wrench.registered_nodes[name] |
| | | local node_name = minetest.get_node(pos).name |
| | | local def = wrench.registered_nodes[node_name] |
| | | if not def then |
| | | return |
| | | end |
| | | |
| | | local stack = ItemStack(get_pickup_name(name)) |
| | | local stack_pickup = ItemStack(get_pickup_name(node_name)) |
| | | local player_inv = placer:get_inventory() |
| | | if not player_inv:room_for_item("main", stack) then |
| | | if not player_inv:room_for_item("main", stack_pickup) then |
| | | return |
| | | end |
| | | local meta = minetest.get_meta(pos) |
| | |
| | | end |
| | | end |
| | | |
| | | -- Do the actual pickup: |
| | | local metadata = {} |
| | | metadata.name = name |
| | | metadata.name = node_name |
| | | metadata.version = LATEST_SERIALIZATION_VERSION |
| | | |
| | | -- Serialize inventory lists + items |
| | | local inv = meta:get_inventory() |
| | | local lists = {} |
| | | for _, listname in pairs(def.lists or {}) do |
| | |
| | | end |
| | | metadata.lists = lists |
| | | |
| | | local item_meta = stack:get_meta() |
| | | -- Serialize node metadata fields |
| | | local item_meta = stack_pickup:get_meta() |
| | | metadata.metas = {} |
| | | for name, meta_type in pairs(def.metas or {}) do |
| | | for key, meta_type in pairs(def.metas or {}) do |
| | | if meta_type == wrench.META_TYPE_INT then |
| | | metadata.metas[name] = meta:get_int(name) |
| | | metadata.metas[key] = meta:get_int(key) |
| | | elseif meta_type == wrench.META_TYPE_FLOAT then |
| | | metadata.metas[name] = meta:get_float(name) |
| | | metadata.metas[key] = meta:get_float(key) |
| | | elseif meta_type == wrench.META_TYPE_STRING then |
| | | metadata.metas[name] = meta:get_string(name) |
| | | metadata.metas[key] = meta:get_string(key) |
| | | end |
| | | end |
| | | |
| | | item_meta:set_string("data", minetest.serialize(metadata)) |
| | | minetest.remove_node(pos) |
| | | itemstack:add_wear(65535 / 20) |
| | | player_inv:add_item("main", stack) |
| | | player_inv:add_item("main", stack_pickup) |
| | | return itemstack |
| | | end, |
| | | }) |
New file |
| | |
| | | # technic_wrench japanese translation |
| | | # technic_wrenchの日本語への翻訳 |
| | | # by damiemk |
| | | |
| | | Wrench = レンチ |
| | | %s with items = アイテム付きレンチ %s |