Compare commits
	
		
			78 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e306003eb9 | ||
|  | 25648b134f | ||
|  | 4a5a22a3e3 | ||
|  | 85e342c08c | ||
|  | 0ff7cb769b | ||
|  | 3bece9cec5 | ||
|  | 59643c45d4 | ||
|  | b268e3d526 | ||
|  | 87e512ff24 | ||
|  | 18df2813a0 | ||
|  | 221fc1376e | ||
|  | 9f373d6528 | ||
|  | 6731db14e5 | ||
|  | a9079c49e0 | ||
|  | f80372a0f8 | ||
|  | 80dee96dbe | ||
|  | d65c4aadd2 | ||
|  | 98675a2ae9 | ||
|  | ba2bdf8368 | ||
|  | d5ff69d1d9 | ||
|  | f47da0c045 | ||
|  | a08ba2bb93 | ||
|  | 410e341da5 | ||
|  | 5826c2feaa | ||
|  | b221d69717 | ||
|  | a296446da1 | ||
|  | 49d4105a2b | ||
|  | fda8a3d042 | ||
|  | dfcf64c1d0 | ||
|  | 0921c326a8 | ||
|  | 9b7c44b453 | ||
|  | 86e083c409 | ||
|  | 21e044478e | ||
|  | 521c0b74bb | ||
|  | aad1b2875a | ||
|  | 66e20a9231 | ||
|  | 705961e2fe | ||
|  | 6a9dfec36f | ||
|  | d4609f23f2 | ||
|  | 091bb2406d | ||
|  | c40189eabf | ||
|  | f61bb82bd1 | ||
|  | 7d39136764 | ||
|  | 4775d98fb7 | ||
|  | d623715d94 | ||
|  | 718a5beda1 | ||
|  | fa39b24ed5 | ||
|  | bce5306abe | ||
|  | 167ab93905 | ||
|  | 5beb84bed9 | ||
|  | f9b0906a82 | ||
|  | 9a39a94272 | ||
|  | 349676f243 | ||
|  | 0f6bdb1bde | ||
|  | 0211c582e9 | ||
|  | d2b68a6bef | ||
|  | 140701c99e | ||
|  | 1c219487d3 | ||
|  | 43acec2900 | ||
|  | 0f7810e538 | ||
|  | 11e43ffe13 | ||
|  | d8fe9ad16c | ||
|  | c06a56daff | ||
|  | cd5a3ee1ef | ||
|  | a5b36b041e | ||
|  | b9f89a0e39 | ||
|  | 03bb4dab46 | ||
|  | d7336670f2 | ||
|  | 3c85abb3b2 | ||
|  | 11f2b4f4b3 | ||
|  | 00618d13b5 | ||
|  | 6154a04c00 | ||
|  | 438c0877f6 | ||
|  | 88f2bc388f | ||
|  | a8daa417c4 | ||
|  | befe3ecc86 | ||
|  | df7f2e464a | ||
|  | 31a052d7e6 | 
							
								
								
									
										20
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,20 @@ | ||||
| --- | ||||
| name: Bug report | ||||
| about: Report a problem within technic | ||||
| title: '' | ||||
| labels: Bug | ||||
| assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| Technic has no main developer and largely depends on | ||||
| user-provided Pull Requests. It will take a while until | ||||
| even important issues are noticed. | ||||
| Please consider proposing a PR directly. | ||||
| _______________________________________________ | ||||
|  | ||||
|  | ||||
| **Bug description** | ||||
|  | ||||
|  | ||||
| **Steps to reproduce this issue** | ||||
							
								
								
									
										11
									
								
								.github/workflows/check-release.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | ||||
| on: [push, pull_request] | ||||
| name: Check & Release | ||||
| jobs: | ||||
|   lint: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@master | ||||
|       - name: lint | ||||
|         uses: Roang-zero1/factorio-mod-luacheck@master | ||||
|         with: | ||||
|           luacheckrc_url: "" | ||||
							
								
								
									
										40
									
								
								.luacheckrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,40 @@ | ||||
| unused_args = false | ||||
| allow_defined_top = true | ||||
| max_line_length = 150 | ||||
| -- Allow shadowed variables (callbacks in callbacks) | ||||
| redefined = false | ||||
|  | ||||
| globals = { | ||||
|     "technic", "minetest", | ||||
|     "srcstack", | ||||
| } | ||||
|  | ||||
| read_globals = { | ||||
|     string = {fields = {"split", "trim"}}, | ||||
|     table = {fields = {"copy", "getn"}}, | ||||
|  | ||||
|     "intllib", "VoxelArea", | ||||
|     "default", "stairsplus", | ||||
|  | ||||
|     "PseudoRandom", "ItemStack", | ||||
|     "mg", "tubelib", "vector", | ||||
|  | ||||
|     "moretrees", "bucket", | ||||
|     "unified_inventory", "digilines", | ||||
|  | ||||
|     "pipeworks", "screwdriver", | ||||
|     "VoxelManip", "unifieddyes", | ||||
|  | ||||
|     "Settings", "mesecon", | ||||
|     "digiline_remote", | ||||
|  | ||||
|     "protector", "isprotect", | ||||
|     "homedecor_expect_infinite_stacks", | ||||
|      | ||||
|     "craftguide", "i3" | ||||
| } | ||||
|  | ||||
| -- Loop warning | ||||
| files["technic/machines/other/frames.lua"].ignore = { "" } | ||||
| -- Long lines | ||||
| files["technic_cnc/cnc_api.lua"].ignore = { "" } | ||||
							
								
								
									
										16
									
								
								LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | ||||
| 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 | ||||
							
								
								
									
										64
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1,23 +1,55 @@ | ||||
| Technic | ||||
| ======= | ||||
| # Technic | ||||
|  | ||||
| [](https://github.com/minetest-mods/technic/actions) | ||||
| [](https://www.gnu.org/licenses/old-licenses/lgpl-2.0.en.html) | ||||
|  | ||||
| This Minetest modpack adds machinery and automation procedure content to your | ||||
| world. A few notable features: | ||||
|  | ||||
|   * Electric circuits | ||||
|   * Automated material processing (ores, wood, ...) | ||||
|   * Extended chest functionalities | ||||
|  | ||||
| ## Dependencies | ||||
|  | ||||
|   * 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://github.com/mt-mods/pipeworks) -> automation of item transport | ||||
|   * [moreores](https://github.com/minetest-mods/moreores/) -> additional ores | ||||
|   * [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. | ||||
| 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. | ||||
| 2. My wires do not connect to the machines. | ||||
|     * Each machine type requires its own cable type. If you do not have a | ||||
|       matching circuit, consider using a "Supply Converter" for simplicity. | ||||
|  | ||||
| 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](LICENSE.txt). See also the individual mod folders for their | ||||
| secondary/alternate licenses, if any. | ||||
|  | ||||
|  | ||||
| ### Credits | ||||
|  | ||||
| Contributors in alphabetical order: | ||||
|  | ||||
| Credits for contributing to the project (in alphabetical order): | ||||
|   * kpoppel | ||||
|   * Nekogloop | ||||
|   * Nore/Ekdohibs | ||||
|   * ShadowNinja | ||||
|   * VanessaE | ||||
|   * And many others... | ||||
|  | ||||
| FAQ | ||||
| --- | ||||
|  | ||||
| 1. My technic circuit doesn't work.  No power is distrubuted. | ||||
|   * A: Make sure you have a switching station connected. | ||||
|  | ||||
| License | ||||
| ------- | ||||
|  | ||||
| Unless otherwise stated, all components of this modpack are licensed under the | ||||
| LGPL, V2 or later.  See also the individual mod folders for their | ||||
| secondary/alternate licenses, if any. | ||||
|   | ||||
| @@ -1,4 +0,0 @@ | ||||
| default | ||||
| basic_materials | ||||
| intllib? | ||||
| moreblocks? | ||||
| @@ -16,13 +16,6 @@ for i = 32, 63 do | ||||
| 			"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 = { | ||||
|   | ||||
							
								
								
									
										9
									
								
								concrete/locale/ja.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,9 @@ | ||||
| # technic_concrete japanese translation | ||||
| # technic_concreteの日本語への翻訳 | ||||
| # by damiemk | ||||
|  | ||||
| Rebar = 鉄筋 | ||||
| Concrete Block = コンクリートのブロック | ||||
| Blast-resistant Concrete Block = 耐爆性コンクリートのブロック | ||||
| Concrete Post Platform = コンクリートのプラットフォーム | ||||
| Concrete Post = コンクリートポスト | ||||
| @@ -1,9 +0,0 @@ | ||||
| default | ||||
| technic_worldgen | ||||
| basic_materials | ||||
| concrete | ||||
| unifieddyes? | ||||
| intllib? | ||||
| moreblocks? | ||||
| steel? | ||||
| streetsmod? | ||||
| @@ -27,6 +27,12 @@ if minetest.get_modpath("moreblocks") then | ||||
| 		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}, | ||||
| @@ -57,36 +63,47 @@ if minetest.get_modpath("moreblocks") then | ||||
| 		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") | ||||
|   | ||||
							
								
								
									
										8
									
								
								extranodes/locale/ja.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | ||||
| # technic_extranodes japanese translation | ||||
| # technic_extranodesの日本語への翻訳 | ||||
| # by damiemk | ||||
|  | ||||
| Marble = 大理石 | ||||
| Marble Bricks = 大理石のレンガ | ||||
| Granite = 花崗岩 | ||||
| Concrete = コンクリート | ||||
							
								
								
									
										672
									
								
								manual.md
									
									
									
									
									
								
							
							
						
						| @@ -1,354 +1,241 @@ | ||||
| Minetest technic modpack user manual | ||||
| ==================================== | ||||
| # Technic User Manual | ||||
|  | ||||
| The technic modpack extends the Minetest game with many new elements, | ||||
| mainly constructable machines and tools.  It is a large modpack, and | ||||
| tends to dominate gameplay when it is used.  This manual describes how | ||||
| to use the technic modpack, mainly from a player's perspective. | ||||
| The technic modpack extends Minetest Game (shipped with Minetest by default) | ||||
| with many new elements, mainly constructable machines and tools. This manual | ||||
| describes how to use the modpack, mainly from a player's perspective. | ||||
|  | ||||
| The technic modpack depends on some other modpacks: | ||||
|  | ||||
| *   the basic Minetest game | ||||
| *   mesecons, which supports the construction of logic systems based on | ||||
|     signalling elements | ||||
| *   pipeworks, which supports the automation of item transport | ||||
| *   moreores, which provides some additional ore types | ||||
| *   basic_materials, which provides some basic craft items | ||||
|  | ||||
| This manual doesn't explain how to use these other modpacks, which have | ||||
| their own manuals: | ||||
| Documentation of the mod dependencies can be found here: | ||||
|  | ||||
| *   [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 for constructable items in technic are generally not guessable, | ||||
| and are also not specifically documented here.  You should use a | ||||
| craft guide mod to look up the recipes in-game.  For the best possible | ||||
| guidance, use the unified\_inventory mod, with which technic registers | ||||
| its specialised recipe types. | ||||
| ## 1.0 Recipes | ||||
|  | ||||
| substances | ||||
| ---------- | ||||
| Recipes for items registered by technic are not specifically documented here. | ||||
| Please consult a craft guide mod to look up the recipes in-game. | ||||
|  | ||||
| ### ore ### | ||||
| **Recommended mod:** [Unified Inventory](https://github.com/minetest-mods/unified_inventory) | ||||
|  | ||||
| The technic mod makes extensive use of not just the default ores but also | ||||
| some that are added by mods.  You will need to mine for all the ore types | ||||
| in the course of the game.  Each ore type is found at a specific range of | ||||
| elevations, and while the ranges mostly overlap, some have non-overlapping | ||||
| ranges, so you will ultimately need to mine at more than one elevation | ||||
| to find all the ores.  Also, because one of the best elevations to mine | ||||
| at is very deep, you will be unable to mine there early in the game. | ||||
| ## 2.0 Substances | ||||
|  | ||||
| Elevation is measured in meters, relative to a reference plane that | ||||
| is not quite sea level.  (The standard sea level is at an elevation | ||||
| of about +1.4.)  Positive elevations are above the reference plane and | ||||
| negative elevations below.  Because elevations are always described this | ||||
| way round, greater numbers when higher, we avoid the word "depth". | ||||
| ### 2.1 Ores | ||||
|  | ||||
| The ores that matter in technic are coal, iron, copper, tin, zinc, | ||||
| chromium, uranium, silver, gold, mithril, mese, and diamond. | ||||
| 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 | ||||
| ultimately need to mine at more than one elevation to find all the ores. | ||||
|  | ||||
| Coal is part of the basic Minetest game.  It is found from elevation | ||||
| +64 downwards, so is available right on the surface at the start of | ||||
| the game, but it is far less abundant above elevation 0 than below. | ||||
| It is initially used as a fuel, driving important machines in the early | ||||
| part of the game.  It becomes less important as a fuel once most of your | ||||
| machines are electrically powered, but burning fuel remains a way to | ||||
| generate electrical power.  Coal is also used, usually in dust form, as | ||||
| an ingredient in alloying recipes, wherever elemental carbon is required. | ||||
| Elevation (Y axis) is measured in meters. The reference is usually at sea | ||||
| level. Ores can generally be found more commonly by going downwards to -1000m. | ||||
|  | ||||
| Iron is part of the basic Minetest game.  It is found from elevation | ||||
| +2 downwards, and its abundance increases in stages as one descends, | ||||
| reaching its maximum from elevation -64 downwards.  It is a common metal, | ||||
| used frequently as a structural component.  In technic, unlike the basic | ||||
| game, iron is used in multiple forms, mainly alloys based on iron and | ||||
| including carbon (coal). | ||||
| Note ¹: *These ores are provided by Minetest Game. See [Ores](https://wiki.minetest.net/Ores#Ores_overview) for a rough overview* | ||||
|  | ||||
| Copper is part of the basic Minetest game (having migrated there from | ||||
| moreores).  It is found from elevation -16 downwards, but is more abundant | ||||
| from elevation -64 downwards.  It is a common metal, used either on its | ||||
| own for its electrical conductivity, or as the base component of alloys. | ||||
| 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 | ||||
|  | ||||
| Burning coal is a way to generate electrical power. Coal is also used, | ||||
| usually in dust form, as an ingredient in alloying recipes, wherever | ||||
| elemental carbon is required. | ||||
|  | ||||
| #### 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. | ||||
|  | ||||
| Tin is part of the basic Minetest game (having migrated there from | ||||
| moreores).  It is found from elevation +8 downwards, with no | ||||
| elevation-dependent variations in abundance beyond that point. | ||||
| It is a common metal.  Its main use in pure form is as a component | ||||
| of electrical batteries.  Apart from that its main purpose is | ||||
| as the secondary ingredient in bronze (the base being copper), but bronze | ||||
| is itself little used.  Its abundance is well in excess of its usage, | ||||
| so you will usually have a surplus of it. | ||||
| #### Diamond ¹ | ||||
| Use: mainly for cutting machines | ||||
|  | ||||
| Zinc is supplied by technic.  It is found from elevation +2 downwards, | ||||
| with no elevation-dependent variations in abundance beyond that point. | ||||
| It is a common metal.  Its main use is as the secondary ingredient | ||||
| in brass (the base being copper), but brass is itself little used. | ||||
| Its abundance is well in excess of its usage, so you will usually have | ||||
| a surplus of it. | ||||
| Diamond is a precious gemstone. It is used moderately, mainly for reasons | ||||
| connected to its extreme hardness. | ||||
|  | ||||
| Chromium is supplied by technic.  It is found from elevation -100 | ||||
| downwards, with no elevation-dependent variations in abundance beyond | ||||
| that point.  It is a moderately common metal.  Its main use is as the | ||||
| secondary ingredient in stainless steel (the base being iron). | ||||
| #### Gold ¹ | ||||
| Use: various | ||||
|  | ||||
| Uranium is supplied by technic.  It is found only from elevation -80 down | ||||
| to -300; using it therefore requires one to mine above elevation -300 even | ||||
| though deeper mining is otherwise more productive.  It is a moderately | ||||
| common metal, useful only for reasons related to radioactivity: it forms | ||||
| the fuel for nuclear reactors, and is also one of the best radiation | ||||
| shielding materials available.  It is not difficult to find enough uranium | ||||
| ore to satisfy these uses.  Beware that the ore is slightly radioactive: | ||||
| it will slightly harm you if you stand as close as possible to it. | ||||
| It is safe when more than a meter away or when mined. | ||||
| Generated below: -64m, more commonly below -256m | ||||
|  | ||||
| Silver is supplied by the moreores mod.  It is found from elevation -2 | ||||
| downwards, with no elevation-dependent variations in abundance beyond | ||||
| that point.  It is a semi-precious metal.  It is little used, being most | ||||
| notably used in electrical items due to its conductivity, being the best | ||||
| conductor of all the pure elements. | ||||
| Gold is a precious metal. It is most notably used in electrical items due to | ||||
| its combination of good conductivity and corrosion resistance. | ||||
|  | ||||
| Gold is part of the basic Minetest game (having migrated there from | ||||
| moreores).  It is found from elevation -64 downwards, but is more | ||||
| abundant from elevation -256 downwards.  It is a precious metal.  It is | ||||
| little used, being most notably used in electrical items due to its | ||||
| combination of good conductivity (third best of all the pure elements) | ||||
| and corrosion resistance. | ||||
| #### Iron ¹ | ||||
| Use: multiple, mainly for alloys with carbon (coal). | ||||
|  | ||||
| Mithril is supplied by the moreores mod.  It is found from elevation | ||||
| -512 downwards, the deepest ceiling of any minable substance, with | ||||
| no elevation-dependent variations in abundance beyond that point. | ||||
| It is a rare precious metal, and unlike all the other metals described | ||||
| here it is entirely fictional, being derived from J. R. R. Tolkien's | ||||
| #### 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. | ||||
|  | ||||
| Mese is part of the basic Minetest game.  It is found from elevation | ||||
| -64 downwards.  The ore is more abundant from elevation -256 downwards, | ||||
| and from elevation -1024 downwards there are also occasional blocks of | ||||
| solid mese (each yielding as much mese as nine blocks of ore).  It is a | ||||
| precious gemstone, and unlike diamond it is entirely fictional.  It is | ||||
| used in many recipes, though mainly not in large quantities, wherever | ||||
| some magical quality needs to be imparted. | ||||
| #### Silver ² | ||||
| Use: conductors | ||||
|  | ||||
| Diamond is part of the basic Minetest game (having migrated there from | ||||
| technic).  It is found from elevation -128 downwards, but is more abundant | ||||
| from elevation -256 downwards.  It is a precious gemstone.  It is used | ||||
| moderately, mainly for reasons connected to its extreme hardness. | ||||
| Generated below: -2m, evenly common | ||||
|  | ||||
| ### rock ### | ||||
| Silver is a semi-precious metal and is the best conductor of all the pure elements. | ||||
|  | ||||
| In addition to the ores, there are multiple kinds of rock that need to be | ||||
| mined in their own right, rather than for minerals.  The rock types that | ||||
| matter in technic are standard stone, desert stone, marble, and granite. | ||||
| #### Tin ¹ | ||||
| Use: batteries, bronze | ||||
|  | ||||
| Standard stone is part of the basic Minetest game.  It is extremely | ||||
| common.  As in the basic game, when dug it yields cobblestone, which can | ||||
| be cooked to turn it back into standard stone.  Cobblestone is used in | ||||
| recipes only for some relatively primitive machines.  Standard stone is | ||||
| used in a couple of machine recipes.  These rock types gain additional | ||||
| significance with technic because the grinder can be used to turn them | ||||
| into dirt and sand.  This, especially when combined with an automated | ||||
| cobblestone generator, can be an easier way to acquire sand than | ||||
| collecting it where it occurs naturally. | ||||
| 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. | ||||
|  | ||||
| Desert stone is part of the basic Minetest game.  It is found specifically | ||||
| in desert biomes, and only from elevation +2 upwards.  Although it is | ||||
| easily accessible, therefore, its quantity is ultimately quite limited. | ||||
| It is used in a few recipes. | ||||
| #### Uranium | ||||
| Use: nuclear reactor fuel | ||||
|  | ||||
| Marble is supplied by technic.  It is found in dense clusters from | ||||
| elevation -50 downwards.  It has mainly decorative use, but also appears | ||||
| in one machine recipe. | ||||
| Depth: -80m until -300m, more commonly between -100m and -200m | ||||
|  | ||||
| Granite is supplied by technic.  It is found in dense clusters from | ||||
| elevation -150 downwards.  It is much harder to dig than standard stone, | ||||
| so impedes mining when it is encountered.  It has mainly decorative use, | ||||
| but also appears in a couple of machine recipes. | ||||
| It is a moderately common metal, useful only for reasons related to radioactivity: | ||||
| it forms the fuel for nuclear reactors, and is also one of the best radiation | ||||
| shielding materials available. | ||||
|  | ||||
| ### rubber ### | ||||
| Keep a safety distance of a meter to avoid being harmed by radiation. | ||||
|  | ||||
| #### Zinc | ||||
| Use: brass | ||||
|  | ||||
| Generated below: 2m, more commonly below -32m | ||||
|  | ||||
| Zinc only has a few uses but is a common metal. | ||||
|  | ||||
|  | ||||
| ### 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 (plain) | ||||
|  * Cobblestone | ||||
|  * Desert Stone | ||||
|  | ||||
| #### Marble | ||||
| Depth: -50m, evenly common | ||||
|  | ||||
| Marble is found in dense clusters and has mainly decorative use, but also | ||||
| appears in one machine recipe. | ||||
|  | ||||
| #### Granite | ||||
| Depth: -150m, evenly common | ||||
|  | ||||
| Granite is found in dense clusters and is much harder to dig than standard | ||||
| stone. It has mainly decorative use, but also appears in a couple of | ||||
| machine recipes. | ||||
|  | ||||
| #### 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. | ||||
|  | ||||
| If you have the moretrees mod installed, the rubber trees you need | ||||
| are those defined by that mod.  If not, technic supplies a copy of the | ||||
| moretrees rubber tree. | ||||
| Rubber trees are provided by technic if the moretrees mod is not present. | ||||
|  | ||||
| Extracting rubber requires a specific tool, a tree tap.  Using the tree | ||||
| tap (by left-clicking) on a rubber tree trunk block extracts a lump of | ||||
| raw latex from the trunk.  Each trunk block can be repeatedly tapped for | ||||
| latex, at intervals of several minutes; its appearance changes to show | ||||
| whether it is currently ripe for tapping.  Each tree has several trunk | ||||
| blocks, so several latex lumps can be extracted from a tree in one visit. | ||||
| Extract raw latex from rubber using the "Tree Tap" tool. Punch/left-click the | ||||
| tool on a rubber tree trunk to extract a lump of raw latex from the trunk. | ||||
| Emptied trunks will regenerate at intervals of several minutes, which can be | ||||
| observed by its appearance. | ||||
|  | ||||
| Raw latex isn't used directly.  It must be vulcanized to produce finished | ||||
| rubber.  This can be performed by alloying the latex with coal dust. | ||||
| To obtain rubber from latex, alloy latex with coal dust. | ||||
|  | ||||
| ### metal ### | ||||
| ## 3.0 Metal processing | ||||
| Generally, each metal can exist in five forms: | ||||
|  | ||||
| Many of the substances important in technic are metals, and there is | ||||
| a common pattern in how metals are handled.  Generally, each metal can | ||||
| exist in five forms: ore, lump, dust, ingot, and block.  With a couple of | ||||
| tricky exceptions in mods outside technic, metals are only *used* in dust, | ||||
| ingot, and block forms.  Metals can be readily converted between these | ||||
| three forms, but can't be converted from them back to ore or lump forms. | ||||
|  * ore -> stone containing the lump | ||||
|  * lump -> draw metal obtained by digging ("nuggets") | ||||
|  * dust -> grinder output | ||||
|  * ingot -> melted/cooked lump or dust | ||||
|  * block -> placeable node | ||||
|  | ||||
| As in the basic Minetest game, a "lump" of metal is acquired directly by | ||||
| digging ore, and will then be processed into some other form for use. | ||||
| A lump is thus more akin to ore than to refined metal.  (In real life, | ||||
| metal ore rarely yields lumps ("nuggets") of pure metal directly. | ||||
| More often the desired metal is chemically bound into the rock as an | ||||
| oxide or some other compound, and the ore must be chemically processed | ||||
| to yield pure metal.) | ||||
| Metals can be converted between dust, ingot and block, but can't be converted | ||||
| from them back to ore or lump forms. | ||||
|  | ||||
| Not all metals occur directly as ore.  Generally, elemental metals (those | ||||
| consisting of a single chemical element) occur as ore, and alloys (those | ||||
| consisting of a mixture of multiple elements) do not.  In fact, if the | ||||
| fictional mithril is taken to be elemental, this pattern is currently | ||||
| followed perfectly.  (It is not clear in the Middle-Earth setting whether | ||||
| mithril is elemental or an alloy.)  This might change in the future: | ||||
| in real life some alloys do occur as ore, and some elemental metals | ||||
| rarely occur naturally outside such alloys.  Metals that do not occur | ||||
| as ore also lack the "lump" form. | ||||
| ### Grinding | ||||
| Ores can be processed as follows: | ||||
|  | ||||
| The basic Minetest game offers a single way to refine metals: cook a lump | ||||
| in a furnace to produce an ingot.  With technic this refinement method | ||||
| still exists, but is rarely used outside the early part of the game, | ||||
| because technic offers a more efficient method once some machines have | ||||
| been built.  The grinder, available only in electrically-powered forms, | ||||
| can grind a metal lump into two piles of metal dust.  Each dust pile | ||||
| can then be cooked into an ingot, yielding two ingots from one lump. | ||||
| This doubling of material value means that you should only cook a lump | ||||
| directly when you have no choice, mainly early in the game when you | ||||
| haven't yet built a grinder. | ||||
|  * ore -> lump (digging) -> ingot (melting) | ||||
|  * ore -> lump (digging) -> 2x dust (grinding) -> 2x ingot (melting) | ||||
|  | ||||
| An ingot can also be ground back to (one pile of) dust.  Thus it is always | ||||
| possible to convert metal between ingot and dust forms, at the expense | ||||
| of some energy consumption.  Nine ingots of a metal can be crafted into | ||||
| a block, which can be used for building.  The block can also be crafted | ||||
| back to nine ingots.  Thus it is possible to freely convert metal between | ||||
| ingot and block forms, which is convenient to store the metal compactly. | ||||
| Every metal has dust, ingot, and block forms. | ||||
| 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 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.  For example, brass can be produced | ||||
| by alloying two copper ingots with one zinc ingot to make three brass | ||||
| ingots, or by alloying two piles of copper dust with one pile of zinc | ||||
| dust to make three piles of brass dust.  The two ways of alloying produce | ||||
| equivalent results. | ||||
| ### Alloying | ||||
| Input: two ingredients of the same form - lump or dust | ||||
|  | ||||
| ### iron and its alloys ### | ||||
| Output: resulting alloy, as an ingot | ||||
|  | ||||
| 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. | ||||
| Example: 2x copper ingots + 1x zinc ingot -> 3x brass ingot (alloying) | ||||
|  | ||||
| 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. | ||||
| Note that grinding before alloying is the preferred method to gain more output. | ||||
|  | ||||
| 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. | ||||
| #### iron and its 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. | ||||
| 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. | ||||
|  | ||||
| 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. | ||||
| Notable alloys: | ||||
|  | ||||
| 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. | ||||
|  * 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.) | ||||
|  | ||||
| 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. | ||||
| Technic introduces a distinction based on the carbon content, and renames some | ||||
| items of the basic game accordingly. Iron and Steel are now distinguished. | ||||
|  | ||||
| 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. | ||||
| Notable references: | ||||
|  | ||||
| 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. | ||||
|  * https://en.wikipedia.org/wiki/Iron | ||||
|  * https://en.wikipedia.org/wiki/Stainless_steel | ||||
|  * ... plus many more. | ||||
|  | ||||
| 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. | ||||
| 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. | ||||
|  * 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) | ||||
|  | ||||
| ### uranium enrichment ### | ||||
| Reversible processes: | ||||
|  | ||||
|  * Cast iron -> Wrought iron (melting) | ||||
|  * Carbon steel -> Wrought iron (melting) | ||||
|  | ||||
| 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 | ||||
| @@ -523,35 +410,15 @@ a post and adjacent concrete block. | ||||
| 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 | ||||
| @@ -625,57 +492,17 @@ metal alloys.  This can only be done using the dust form of the alloy. | ||||
| 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 | ||||
| ------------- | ||||
| @@ -813,115 +640,44 @@ so the positioning of holes in each layer must still be considered. | ||||
| 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 | ||||
|   | ||||
| @@ -1 +1,3 @@ | ||||
| name = technic | ||||
| description = technic | ||||
| min_minetest_version = 5.0 | ||||
|   | ||||
							
								
								
									
										9
									
								
								settingtypes.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,9 @@ | ||||
| #    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 | ||||
| @@ -1,21 +1,23 @@ | ||||
| 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 | ||||
|   * technic_corium_flowing_animated.png | ||||
|   * technic_corium_source_animated.png | ||||
|  | ||||
| celeron55 (Perttu Ahola) modified by Zefram (CC BY-SA 3.0): | ||||
| celeron55 (Perttu Ahola) modified by Zefram modified by The4codeblocks (The4spaceconstants elsewhere) (CC BY-SA 3.0): | ||||
|   * technic_bucket_corium.png | ||||
|  | ||||
| sdzen (Elise Staudter) (CC BY-SA 3.0): | ||||
| @@ -24,15 +26,29 @@ sdzen (Elise Staudter) (CC BY-SA 3.0): | ||||
| 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/ | ||||
|   | ||||
| @@ -7,6 +7,13 @@ minetest.clear_craft({ | ||||
| 	type = "shapeless", | ||||
| 	output = "default:bronze_ingot" | ||||
| }) | ||||
| -- Restore recipe for bronze block to ingots | ||||
| minetest.register_craft({ | ||||
| 	output = "default:bronze_ingot 9", | ||||
| 	recipe = { | ||||
| 		{"default:bronzeblock"} | ||||
| 	} | ||||
| }) | ||||
|  | ||||
| -- Accelerator tube | ||||
| if pipeworks.enable_accelerator_tube then | ||||
| @@ -167,7 +174,6 @@ minetest.register_craft({ | ||||
| 	}, | ||||
| }) | ||||
|  | ||||
|  | ||||
| minetest.register_craft({ | ||||
| 	output = "default:dirt 2", | ||||
| 	type = "shapeless", | ||||
| @@ -179,3 +185,25 @@ minetest.register_craft({ | ||||
| 		"group:sand", | ||||
| 	}, | ||||
| }) | ||||
|  | ||||
| minetest.register_craft({ | ||||
| 	output = "technic:rubber_goo", | ||||
| 	type = "shapeless", | ||||
| 	recipe = { | ||||
| 		"technic:raw_latex", | ||||
| 		"default:coal_lump", | ||||
| 		"default:coal_lump", | ||||
| 		"default:coal_lump", | ||||
| 		"default:coal_lump", | ||||
| 		"default:coal_lump", | ||||
| 		"default:coal_lump", | ||||
| 		"default:coal_lump", | ||||
| 		"default:coal_lump", | ||||
| 	}, | ||||
| }) | ||||
|  | ||||
| minetest.register_craft({ | ||||
| 	output = "technic:rubber", | ||||
| 	type = "cooking", | ||||
| 	recipe = "technic:rubber_goo", | ||||
| }) | ||||
|   | ||||
| @@ -1,14 +0,0 @@ | ||||
| default | ||||
| pipeworks | ||||
| technic_worldgen | ||||
| basic_materials | ||||
| bucket? | ||||
| screwdriver? | ||||
| mesecons? | ||||
| mesecons_mvps? | ||||
| digilines? | ||||
| digiline_remote? | ||||
| intllib? | ||||
| unified_inventory? | ||||
| vector_extras? | ||||
| dye? | ||||
| @@ -1,41 +1,208 @@ | ||||
| This file is fairly incomplete. Help is welcome. | ||||
| # technic API | ||||
|  | ||||
| Tiers | ||||
| ----- | ||||
| The tier is a string, currently `"LV"`, `"MV"` and `"HV"` are supported. | ||||
| This file documents the functions within the technic modpack for use in mods. | ||||
|  | ||||
| Network | ||||
| ------- | ||||
| The network is the cable with the connected machine nodes. Currently the | ||||
| switching station handles the network activity. | ||||
| [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: | ||||
|  | ||||
| * `"LV"`, Low Voltage | ||||
| * `"MV"`, Medium Voltage | ||||
| * `"HV"`, High Voltage | ||||
|  | ||||
| Available functions: | ||||
|  | ||||
| * `technic.register_tier(tier, description)` | ||||
| 	* Registers a network type (tier) | ||||
| 	* `tier`: string, short name (ex. `LV`) | ||||
| 	* `description`: string, long name (ex. `Low Voltage`) | ||||
| 	* See also `tiers` | ||||
|  | ||||
|  | ||||
| ## Cables | ||||
| * `technic.register_cable(tier, size)` | ||||
| 	* Registers an existing node as cable | ||||
| 	* `tier`: string | ||||
| 	* `size`: number, visual size of the wire | ||||
| * `technic.get_cable_tier(nodename)` | ||||
| 	* Retrieves the tier assigned to the provided node name | ||||
| 	* `nodename`: string, name of the node | ||||
| 	* Returns the tier (string) or `nil` | ||||
| * `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"`: consumes energy. e.g. grinder | ||||
| * `technic.producer = "PR"`: provides energy. e.g. solar panel | ||||
| * `technic.producer_receiver = "PR_RE"` supply converter | ||||
| * `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`: string, see #Tiers | ||||
| 	* `nodename`: string, node name | ||||
| 	* `machine_type`: string, following options are possible: | ||||
| 		* `technic.receiver = "RE"`: Consumes energy | ||||
| 		* `technic.producer = "PR"`: Provides energy | ||||
| 		* `technic.battery = "BA"`: Energy storage | ||||
| 	* See also `Machine types` | ||||
| * `technic.handle_machine_upgrades(meta)` | ||||
| 	* Retrieves the count of `upgrade1` and `upgrade2` items. | ||||
| 	* Use the returned values to improve the capabilities of a machine. | ||||
| 	  As a rule of thumb, each upgrade should result in a 10% improvement. | ||||
| 	* Return values: | ||||
| 		* `EU_upgrade`: integer, to improve power consumption or capacity | ||||
| 		* `tube_upgrade`: integer, to speed up pipeworks item actions | ||||
|  | ||||
| ### Inventory actions and lists | ||||
|  | ||||
| If a node is registered as a technic machine, the following node inventory | ||||
| lists have a defined purpose because stack movement functions depend on them. | ||||
|  | ||||
| * `src`: input slot of any size | ||||
| * `dst`: output slot of any size | ||||
| * `upgrade1`: optional, 1x1 slot for machine upgrades | ||||
| * `upgrade2`: optional, same as `upgrade1`. | ||||
|  | ||||
| These functions protect access to the aforementioned inventory lists: | ||||
|  | ||||
| * `technic.machine_inventory_put(...)` | ||||
| 	* Helper for `<nodedef>.allow_metadata_inventory_put` | ||||
| * `technic.machine_inventory_take(...)` | ||||
| 	* Helper for `<nodedef>.allow_metadata_inventory_take` | ||||
| * `technic.machine_inventory_move(...)` | ||||
| 	* Helper for `<nodedef>.allow_metadata_inventory_move` | ||||
|  | ||||
| ### pipeworks helper functions | ||||
|  | ||||
| * `technic.default_can_insert(pos, node, stack, direction)` | ||||
| 	* Returns boolean, whether the stack fits. | ||||
| * `technic.can_insert_unique_stack(pos, node, stack, direction)` | ||||
| 	* Is based on `technic.default_can_insert` | ||||
| * `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. | ||||
|  | ||||
| ### 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 | ||||
| * `technic.register_power_tool(itemname, max_charge)` | ||||
| 	* Register or configure the maximal charge held by an existing item | ||||
| 	* `craftitem`: string, item or node name | ||||
| 	* `max_charge`: number, maximal EU capacity | ||||
|  | ||||
|  | ||||
| ## Helper functions | ||||
| Unsorted functions: | ||||
|  | ||||
| Helper functions | ||||
| ---------------- | ||||
| * `technic.EU_string(num)` | ||||
| 	* Converts num to a human-readable string (see pretty_num) | ||||
| 	* Converts num to a human-readable string (see `pretty_num`) | ||||
| 	  and adds the `EU` unit | ||||
| 	* Use this function when showing players energy values | ||||
| * `technic.pretty_num(num)` | ||||
| 	* Converts the number `num` to a human-readable string with SI prefixes | ||||
| * `technic.swap_node(pos, nodename)` | ||||
| 	* Same as `mintest.swap_node` but it only changes the nodename. | ||||
| 	* It uses `minetest.get_node` before swapping to ensure the new nodename | ||||
| 	  is not the same as the current one. | ||||
| * `technic.get_or_load_node(pos)` | ||||
| 	* If the mapblock is loaded, it returns the node at pos, | ||||
| 	  else it loads the chunk and returns `nil`. | ||||
| * `technic.config:get(name)` | ||||
| 	* Some configuration function | ||||
| * `technic.tube_inject_item(pos, start_pos, velocity, item)` | ||||
| 	* Same as `pipeworks.tube_inject_item` | ||||
|  | ||||
| ### Energy modifiers | ||||
| * `technic.set_RE_wear(itemstack, item_load, max_charge)` | ||||
| 	* If the `wear_represents` field in the item's nodedef is | ||||
| 	  `"technic_RE_charge"`, this function does nothing. | ||||
| 	* Modifies the power tool wear of the given itemstack | ||||
| 	* `itemstack`: ItemStack to modify | ||||
| 	* `item_load`: number, used energy in EU | ||||
| 	* `max_charge`: number, maximal EU capacity of the tool | ||||
| 	* The itemdef field `wear_represents` must be set to `"technic_RE_charge"`, | ||||
| 	  otherwise this function will do nothing. | ||||
| 	* Returns the modified itemstack | ||||
| * `technic.refill_RE_charge(itemstack)` | ||||
| 	* This function fully recharges an RE chargeable item. | ||||
| 	* 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.is_tier_cable(nodename, tier)` | ||||
| 	* Tells whether the node `nodename` is the cable of the tier `tier`. | ||||
| * `technic.get_cable_tier(nodename)` | ||||
| 	* Returns the tier of the cable `nodename` or `nil`. | ||||
| * `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 manipulation | ||||
| * `technic.get_or_load_node(pos)` | ||||
| 	* If the mapblock is loaded, it returns the node at pos, | ||||
| 	  else it loads the chunk and returns `nil`. | ||||
| * `technic.swap_node(pos, nodename)` | ||||
| 	* Same as `mintest.swap_node` but it only changes the nodename. | ||||
| 	* It uses `minetest.get_node` before swapping to ensure the new nodename | ||||
| 	  is not the same as the current one. | ||||
| * `technic.trace_node_ray(pos, dir, range)` | ||||
| 	* Returns an iteration function (usable in the for loop) to iterate over the | ||||
| 	  node positions along the specified ray. | ||||
| @@ -43,95 +210,111 @@ Helper functions | ||||
| * `technic.trace_node_ray_fat(pos, dir, range)` | ||||
| 	* Like `technic.trace_node_ray` but includes extra positions near the ray. | ||||
| 	* The node ray functions are used for mining lasers. | ||||
| * `technic.config:get(name)` | ||||
| 	* Some configuration function | ||||
| * `technic.tube_inject_item(pos, start_pos, velocity, item)` | ||||
| 	* Same as `pipeworks.tube_inject_item` | ||||
|  | ||||
| Registration functions | ||||
| ---------------------- | ||||
| * `technic.register_power_tool(itemname, max_charge)` | ||||
| 	* Same as `technic.power_tools[itemname] = max_charge` | ||||
| 	* This function makes the craftitem `itemname` chargeable. | ||||
| * `technic.register_machine(tier, nodename, machine_type)` | ||||
| 	* Same as `technic.machines[tier][nodename] = machine_type` | ||||
| 	* Currently this is requisite to make technic recognize your node. | ||||
| 	* See also `Machine types` | ||||
| * `technic.register_tier(tier)` | ||||
| 	* Same as `technic.machines[tier] = {}` | ||||
| 	* See also `tiers` | ||||
|  | ||||
| ### Specific machines | ||||
| * `technic.register_solar_array(data)` | ||||
| 	* data is a table | ||||
| * `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. | ||||
| ## Item Definition fields | ||||
| Groups: | ||||
|  | ||||
| Used itemdef fields | ||||
| ------------------- | ||||
| * groups: | ||||
| 	* `technic_<ltier> = 1` ltier is a tier in small letters; this group makes | ||||
| 	  the node connect to the cable(s) of the right tier. | ||||
| 	* `technic_machine = 1` Currently used for | ||||
| * `connect_sides` | ||||
| 	* In addition to the default use (see lua_api.txt), this tells where the | ||||
| 	  machine can be connected. | ||||
| # | ||||
| # | ||||
| * `technic_run(pos, node)` | ||||
| 	* This function is currently used to update the node. | ||||
| * `technic_<tier> = 1` | ||||
| 	* Makes the node connect to the cables of the matching tier name | ||||
| 	* `<tier>`: name of the tier, in lowercase (ex. `lv`) | ||||
| * `technic_machine = 1` | ||||
| 	* UNRELIABLE. Indicates whether the item or node belongs to technic | ||||
| * `connect_sides = {"top", "left", ...}` | ||||
| 	* Extends the Luanti API. Indicates where the machine can be connected. | ||||
|  | ||||
| Additional definition fields: | ||||
|  | ||||
| * `<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 = 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` | ||||
|  | ||||
| Machine types | ||||
| ------------- | ||||
| There are currently following types: | ||||
| * `technic.receiver = "RE"` e.g. grinder | ||||
| * `technic.producer = "PR"` e.g. solar panel | ||||
| * `technic.producer_receiver = "PR_RE"` supply converter | ||||
| * `technic.battery  = "BA"` e.g. LV batbox | ||||
|  | ||||
| Switching Station | ||||
| ----------------- | ||||
| The switching station is the center of all power distribution on an electric | ||||
| network. | ||||
|  | ||||
| The station 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. | ||||
|  | ||||
| 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. | ||||
|  | ||||
| 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. | ||||
|  | ||||
| ### Node meta usage | ||||
| ## Node Metadata fields | ||||
| Nodes connected to the network will have one or more of these parameters as meta | ||||
| data: | ||||
| 	* `<LV|MV|HV>_EU_supply` : Exists for PR and BA node types. | ||||
| 	This is the EU value supplied by the node. Output | ||||
| 	* `<LV|MV|HV>_EU_demand` : Exists for RE and BA node types. | ||||
| 	This is the EU value the node requires to run. Output | ||||
| 	* `<LV|MV|HV>_EU_input`  : Exists for RE and BA node types. | ||||
| 	This is the actual EU value the network can give the node. Input | ||||
|  | ||||
| The reason the LV|MV|HV type is prepended to meta data is because some machine | ||||
| could require several supplies to work. | ||||
| This way the supplies are separated per network. | ||||
| * `<tier>_EU_supply` - direction: output | ||||
| 	* For nodes registered as `PR` or `BA` tier | ||||
| 	* This is the EU value supplied by the node. | ||||
| * `<tier>_EU_demand` - direction: output | ||||
| 	* For nodes registered as `RE` or `BA` tier | ||||
| 	* This is the EU value the node requires to run. | ||||
| * `<tier>_EU_input` - direction: input | ||||
| 	* For nodes registered as `RE` or `BA` tier | ||||
| 	* This is the actual EU value the network can give the node. | ||||
|  | ||||
| `<tier>` corresponds to the tier name registered using | ||||
| `technic.register_tier` (ex. `LV`). It is possible for the machine to depend on | ||||
| multiple tiers (or networks). | ||||
|  | ||||
| Furthermore, the following fields are reserved for machines: | ||||
|  | ||||
| * `public`: integer, optional. | ||||
| 	* Controls the behaviour of the `technic.machine_inventory_*` helper functions. | ||||
| 	* `0` (default): Inventory lists are protected according to `core.is_protected`. | ||||
| 	* `1`: Inventory lists are accessible to everyone. | ||||
| 	  Except for: `upgrade1`, `upgrade2`. | ||||
| * `splitstacks`: integer, optional. | ||||
|     * Defines the behaviour of technic-specific insertion functions, commonly used | ||||
|       for pipeworks compatibility. | ||||
|     * `0` (default): entire stacks will be inserted. | ||||
|     * `1`: Insert one item (i.e. stack size 1) at a time. | ||||
| * `tube_time`: internal counter for outgoing tube items. | ||||
|  | ||||
|  | ||||
| ## Manual: Network basics | ||||
|  | ||||
| The switching station is the center of all power distribution on an electric | ||||
| network. This node is used to calculate the power supply of the network and | ||||
| to distribute the power across nodes. | ||||
|  | ||||
| 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). | ||||
|  | ||||
| As a thumb of rule, "EU" (energy unit) values are expressed in kW. | ||||
|  | ||||
| Network functionality: | ||||
|  | ||||
| 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 | ||||
|  | ||||
| Following functions are either no longer used by technic, or are planned to | ||||
| be removed soon. Please update mods depending on technic accordingly. | ||||
|  | ||||
|  * `technic.get_RE_item_load` | ||||
|     * Scales the tool wear to a certain numeric range | ||||
|  * `technic.set_RE_item_load` | ||||
|     * Scales a certain numeric range to the tool wear | ||||
|   | ||||
| @@ -65,15 +65,26 @@ function technic.swap_node(pos, name) | ||||
| 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 | ||||
|  | ||||
| @@ -83,7 +94,7 @@ function technic.get_or_load_node(pos) | ||||
| 	local node = minetest.get_node_or_nil(pos) | ||||
| 	if node then return node end | ||||
| 	local vm = VoxelManip() | ||||
| 	local MinEdge, MaxEdge = vm:read_from_map(pos, pos) | ||||
| 	local _, _ = vm:read_from_map(pos, pos) | ||||
| 	return nil | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,11 @@ | ||||
| -- 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() | ||||
|  | ||||
| technic = rawget(_G, "technic") or {} | ||||
| @@ -16,7 +20,17 @@ technic.modpath = modpath | ||||
| 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 | ||||
|  | ||||
|   | ||||
| @@ -134,6 +134,11 @@ minetest.register_node("technic:machine_casing", { | ||||
| 	sounds = default.node_sound_stone_defaults(), | ||||
| }) | ||||
|  | ||||
| minetest.register_craftitem("technic:rubber_goo", { | ||||
| 	description = S("Rubber Goo"), | ||||
| 	inventory_image = "technic_rubber_goo.png", | ||||
| }) | ||||
|  | ||||
| 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 | ||||
|   | ||||
| @@ -39,3 +39,40 @@ for i = 0, 64 do | ||||
| 	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 | ||||
|   | ||||
| @@ -112,10 +112,13 @@ local function set_forcefield_formspec(meta) | ||||
| 	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 | ||||
|   | ||||
| @@ -31,24 +31,26 @@ minetest.register_craft({ | ||||
| }) | ||||
|  | ||||
| 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 | ||||
| @@ -140,8 +142,11 @@ of a lead layer it will be converted to a lead layer. | ||||
| --]] | ||||
| 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}) | ||||
| @@ -157,16 +162,19 @@ local function reactor_structure_badness(pos) | ||||
| 	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 | ||||
| @@ -175,6 +183,7 @@ local function reactor_structure_badness(pos) | ||||
| 		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 | ||||
| @@ -184,6 +193,8 @@ local function reactor_structure_badness(pos) | ||||
| 	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 | ||||
| @@ -206,6 +217,7 @@ local function reactor_structure_badness(pos) | ||||
| 	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 | ||||
|  | ||||
| @@ -217,24 +229,33 @@ end | ||||
|  | ||||
|  | ||||
| local function start_reactor(pos, meta) | ||||
| 	local correct_fuel_count = 6 | ||||
| 	local msg_fuel_missing = "Error: You need to insert " .. correct_fuel_count .. " pieces of Uranium Fuel." | ||||
|  | ||||
| 	if minetest.get_node(pos).name ~= "technic:hv_nuclear_reactor_core" then | ||||
| 		return false | ||||
| 		return msg_fuel_missing | ||||
| 	end | ||||
| 	local inv = meta:get_inventory() | ||||
| 	if inv:is_empty("src") then | ||||
| 		return false | ||||
| 		return msg_fuel_missing | ||||
| 	end | ||||
| 	local src_list = inv:get_list("src") | ||||
| 	local correct_fuel_count = 0 | ||||
| 	local fuel_count = 0 | ||||
| 	for _, src_stack in pairs(src_list) do | ||||
| 		if src_stack and src_stack:get_name() == fuel_type then | ||||
| 			correct_fuel_count = correct_fuel_count + 1 | ||||
| 			fuel_count = fuel_count + 1 | ||||
| 		end | ||||
| 	end | ||||
| 	-- Check that the reactor is complete and has the correct fuel | ||||
| 	if correct_fuel_count ~= 6 or reactor_structure_badness(pos) ~= 0 then | ||||
| 		return false | ||||
| 	-- Check that the has the correct fuel | ||||
| 	if fuel_count ~= correct_fuel_count then | ||||
| 		return msg_fuel_missing | ||||
| 	end | ||||
|  | ||||
| 	-- Check that the reactor is complete | ||||
| 	if reactor_structure_badness(pos) ~= 0 then | ||||
| 		return "Error: The power plant seems to be built incorrectly." | ||||
| 	end | ||||
|  | ||||
| 	meta:set_int("burn_time", 1) | ||||
| 	technic.swap_node(pos, "technic:hv_nuclear_reactor_core_active") | ||||
| 	meta:set_int("HV_EU_supply", power_supply) | ||||
| @@ -242,7 +263,8 @@ local function start_reactor(pos, meta) | ||||
| 		src_stack:take_item() | ||||
| 		inv:set_stack("src", idx, src_stack) | ||||
| 	end | ||||
| 	return true | ||||
|  | ||||
| 	return nil | ||||
| end | ||||
|  | ||||
|  | ||||
| @@ -281,13 +303,13 @@ local function run(pos, node) | ||||
| 					"fuel used", 6, true) | ||||
| 		end | ||||
| 		if meta:get_string("autostart") == "true" then | ||||
| 			if start_reactor(pos, meta) then | ||||
| 			if not start_reactor(pos, meta) then | ||||
| 				return | ||||
| 			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) | ||||
| @@ -313,11 +335,11 @@ local nuclear_reactor_receive_fields = function(pos, formname, fields, sender) | ||||
| 		meta:set_string("remote_channel", fields.remote_channel) | ||||
| 	end | ||||
| 	if fields.start then | ||||
| 		local b = start_reactor(pos, meta) | ||||
| 		if b then | ||||
| 		local start_error_msg = start_reactor(pos, meta) | ||||
| 		if not start_error_msg then | ||||
| 			minetest.chat_send_player(player_name, "Start successful") | ||||
| 		else | ||||
| 			minetest.chat_send_player(player_name, "Error") | ||||
| 			minetest.chat_send_player(player_name, start_error_msg) | ||||
| 		end | ||||
| 	end | ||||
| 	if fields.autostart then | ||||
| @@ -385,11 +407,11 @@ local digiline_remote_def = function(pos, channel, msg) | ||||
| 			melt_down_reactor(pos) | ||||
| 		end | ||||
| 	elseif msg.command == "start" then | ||||
| 		local b = start_reactor(pos, meta) | ||||
| 		if b then | ||||
| 		local start_error_msg = start_reactor(pos, meta) | ||||
| 		if not start_error_msg then | ||||
| 			digiline_remote.send_to_node(pos, channel, "Start successful", 6, true) | ||||
| 		else | ||||
| 			digiline_remote.send_to_node(pos, channel, "Error", 6, true) | ||||
| 			digiline_remote.send_to_node(pos, channel, start_error_msg, 6, true) | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
| @@ -455,7 +477,7 @@ minetest.register_node("technic:hv_nuclear_reactor_core_active", { | ||||
| 	technic_run = run, | ||||
| 	technic_on_disable = function(pos, node) | ||||
| 		local timer = minetest.get_node_timer(pos) | ||||
|         	timer:start(1) | ||||
| 		timer:start(1) | ||||
|         end, | ||||
| 	on_timer = function(pos, node) | ||||
| 		local meta = minetest.get_meta(pos) | ||||
|   | ||||
| @@ -47,14 +47,19 @@ local function set_quarry_demand(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 | ||||
| @@ -105,6 +110,40 @@ local function quarry_handle_purge(pos) | ||||
| 	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() | ||||
| @@ -148,35 +187,11 @@ local function quarry_run(pos, node) | ||||
| 				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 | ||||
|   | ||||
| @@ -27,7 +27,7 @@ minetest.register_craftitem("technic:geothermal", { | ||||
| local check_node_around = function(pos) | ||||
| 	local node = minetest.get_node(pos) | ||||
| 	if node.name == "default:water_source" or node.name == "default:water_flowing" then return 1 end | ||||
| 	if node.name == "default:lava_source"  or node.name == "default:lava_flowing"  then return 2 end	 | ||||
| 	if node.name == "default:lava_source"  or node.name == "default:lava_flowing"  then return 2 end | ||||
| 	return 0 | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -9,5 +9,25 @@ minetest.register_craft({ | ||||
| 	} | ||||
| }) | ||||
|  | ||||
| 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}) | ||||
|  | ||||
|   | ||||
| @@ -22,3 +22,6 @@ dofile(path.."/extractor.lua") | ||||
| dofile(path.."/compressor.lua") | ||||
|  | ||||
| dofile(path.."/music_player.lua") | ||||
| -- NEW LV LAMPS | ||||
| dofile(path.."/led.lua") | ||||
| dofile(path.."/lamp.lua") | ||||
|   | ||||
							
								
								
									
										156
									
								
								technic/machines/LV/lamp.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,156 @@ | ||||
|  | ||||
| -- 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"}, | ||||
| 	} | ||||
| }) | ||||
							
								
								
									
										96
									
								
								technic/machines/LV/led.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,96 @@ | ||||
| -- 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"}, | ||||
| 		{"", "basic_materials:silver_wire", ""}, | ||||
| 	}, | ||||
| 	replacements = { {"basic_materials:silver_wire", "basic_materials:empty_spool"}, }, | ||||
| }) | ||||
| @@ -24,7 +24,6 @@ local run = function(pos, node) | ||||
| 	local meta         = minetest.get_meta(pos) | ||||
| 	local eu_input     = meta:get_int("LV_EU_input") | ||||
| 	local machine_name = S("%s Music Player"):format("LV") | ||||
| 	local machine_node = "technic:music_player" | ||||
| 	local demand       = 150 | ||||
|  | ||||
| 	local current_track = meta:get_int("current_track") | ||||
|   | ||||
| @@ -51,7 +51,7 @@ minetest.register_node("technic:solar_panel", { | ||||
| 		technic_machine=1, technic_lv=1}, | ||||
| 	connect_sides = {"bottom"}, | ||||
| 	sounds = default.node_sound_wood_defaults(), | ||||
|     	description = S("Small Solar %s Generator"):format("LV"), | ||||
| 	description = S("Small Solar %s Generator"):format("LV"), | ||||
| 	active = false, | ||||
| 	drawtype = "nodebox", | ||||
| 	paramtype = "light", | ||||
|   | ||||
| @@ -29,8 +29,8 @@ end | ||||
| local run = function(pos, node) | ||||
| 	local meta             = minetest.get_meta(pos) | ||||
| 	local water_flow       = 0 | ||||
| 	local production_level = 0 | ||||
| 	local eu_supply        = 0 | ||||
| 	local production_level | ||||
| 	local eu_supply | ||||
| 	local max_output       = 4 * 45 -- keeping it around 180, little more than previous 150 :) | ||||
|  | ||||
| 	local positions = { | ||||
|   | ||||
| @@ -30,8 +30,8 @@ end | ||||
| local run = function(pos, node) | ||||
| 	local meta             = minetest.get_meta(pos) | ||||
| 	local water_flow       = 0 | ||||
| 	local production_level = 0 | ||||
| 	local eu_supply        = 0 | ||||
| 	local production_level | ||||
| 	local eu_supply | ||||
| 	local max_output       = 40 * 45 -- Generates 1800EU/s | ||||
|  | ||||
| 	local positions = { | ||||
|   | ||||
| @@ -14,20 +14,7 @@ end | ||||
|  | ||||
| function technic_homedecor_node_is_owned(pos, placer) | ||||
|         local ownername = false | ||||
|         if type(IsPlayerNodeOwner) == "function" then -- node_ownership mod | ||||
|                 if HasOwner(pos, placer) then | ||||
|                         if not IsPlayerNodeOwner(pos, placer:get_player_name()) then | ||||
|                                 if type(getLastOwner) == "function" then -- ...is an old version | ||||
|                                         ownername = getLastOwner(pos) | ||||
|                                 elseif type(GetNodeOwnerName) == "function" then -- ...is a recent version | ||||
|                                         ownername = GetNodeOwnerName(pos) | ||||
|                                 else | ||||
|                                         ownername = S("someone") | ||||
|                                 end | ||||
|                         end | ||||
|                 end | ||||
|  | ||||
|         elseif type(isprotect) == "function" then -- glomie's protection mod | ||||
|         if type(isprotect) == "function" then -- glomie's protection mod | ||||
|                 if not isprotect(5, pos, placer) then | ||||
|                         ownername = S("someone") | ||||
|                 end | ||||
| @@ -45,7 +32,6 @@ function technic_homedecor_node_is_owned(pos, placer) | ||||
|         end | ||||
| end | ||||
|  | ||||
| local dirs1 = {20, 23, 22, 21} | ||||
| local dirs2 = {9,  18,  7, 12} | ||||
|  | ||||
| local technic_homedecor_rotate_and_place = function(itemstack, placer, pointed_thing) | ||||
| @@ -58,7 +44,6 @@ local technic_homedecor_rotate_and_place = function(itemstack, placer, pointed_t | ||||
| 			local under = pointed_thing.under | ||||
| 			local pitch = placer:get_look_pitch() | ||||
| 			local pname = minetest.get_node(under).name | ||||
| 			local node = minetest.get_node(above) | ||||
| 			local fdir = minetest.dir_to_facedir(placer:get_look_dir()) | ||||
| 			local wield_name = itemstack:get_name() | ||||
|  | ||||
| @@ -159,7 +144,7 @@ minetest.register_node('technic:homedecor_glowlight_half_yellow_active', { | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	walkable = true, | ||||
| 	light_source = LIGHT_MAX, | ||||
| 	light_source = minetest.LIGHT_MAX, | ||||
| 	sounds = default.node_sound_wood_defaults(), | ||||
|  | ||||
| 	groups = { snappy = 3, not_in_creative_inventory=1}, | ||||
| @@ -240,7 +225,7 @@ minetest.register_node('technic:homedecor_glowlight_quarter_yellow_active', { | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	walkable = true, | ||||
| 	light_source = LIGHT_MAX-1, | ||||
| 	light_source = minetest.LIGHT_MAX-1, | ||||
| 	sounds = default.node_sound_wood_defaults(), | ||||
|  | ||||
| 	groups = { snappy = 3, not_in_creative_inventory=1}, | ||||
| @@ -322,7 +307,7 @@ minetest.register_node('technic:homedecor_glowlight_half_white_active', { | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	walkable = true, | ||||
| 	light_source = LIGHT_MAX, | ||||
| 	light_source = minetest.LIGHT_MAX, | ||||
| 	sounds = default.node_sound_wood_defaults(), | ||||
|  | ||||
| 	groups = { snappy = 3, not_in_creative_inventory=1}, | ||||
| @@ -403,7 +388,7 @@ minetest.register_node('technic:homedecor_glowlight_quarter_white_active', { | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	walkable = true, | ||||
| 	light_source = LIGHT_MAX-1, | ||||
| 	light_source = minetest.LIGHT_MAX-1, | ||||
| 	sounds = default.node_sound_wood_defaults(), | ||||
|  | ||||
| 	groups = { snappy = 3, not_in_creative_inventory=1}, | ||||
| @@ -484,7 +469,7 @@ minetest.register_node('technic:homedecor_glowlight_small_cube_yellow_active', { | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	walkable = true, | ||||
| 	light_source = LIGHT_MAX-1, | ||||
| 	light_source = minetest.LIGHT_MAX-1, | ||||
| 	sounds = default.node_sound_wood_defaults(), | ||||
|  | ||||
| 	groups = { snappy = 3, not_in_creative_inventory=1}, | ||||
| @@ -565,7 +550,7 @@ minetest.register_node('technic:homedecor_glowlight_small_cube_white_active', { | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	walkable = true, | ||||
| 	light_source = LIGHT_MAX-1, | ||||
| 	light_source = minetest.LIGHT_MAX-1, | ||||
| 	sounds = default.node_sound_wood_defaults(), | ||||
|  | ||||
| 	groups = { snappy = 3, not_in_creative_inventory=1}, | ||||
|   | ||||
| @@ -36,7 +36,8 @@ technic.register_inductive_machine = function(name) | ||||
| 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 | ||||
| @@ -177,8 +178,6 @@ minetest.register_abm({ | ||||
| 			-- The supply radius | ||||
| 			local rad = power_radius | ||||
|  | ||||
| 			local meta1            = nil | ||||
| 			local pos1             = {} | ||||
| 			local used_charge      = 0 | ||||
|  | ||||
| 			-- Index all nodes within supply range | ||||
|   | ||||
| @@ -39,7 +39,6 @@ local run = function(pos, node) | ||||
| 	local inv          = meta:get_inventory() | ||||
| 	local eu_input     = meta:get_int("MV_EU_input") | ||||
| 	local machine_name = S("%s Tool Workshop"):format("MV") | ||||
| 	local machine_node = "technic:tool_workshop" | ||||
|  | ||||
| 	-- Setup meta data if it does not exist. | ||||
| 	if not eu_input then | ||||
| @@ -71,7 +70,7 @@ local run = function(pos, node) | ||||
| 		meta:set_int("MV_EU_demand", 0) | ||||
| 		return | ||||
| 	end | ||||
| 	 | ||||
|  | ||||
| 	if eu_input < workshop_demand[EU_upgrade+1] then | ||||
| 		meta:set_string("infotext", S("%s Unpowered"):format(machine_name)) | ||||
| 	elseif eu_input >= workshop_demand[EU_upgrade+1] then | ||||
| @@ -105,7 +104,7 @@ minetest.register_node("technic:tool_workshop", { | ||||
| 		inv:set_size("src", 1) | ||||
| 		inv:set_size("upgrade1", 1) | ||||
| 		inv:set_size("upgrade2", 1) | ||||
| 	end,	 | ||||
| 	end, | ||||
| 	can_dig = technic.machine_can_dig, | ||||
| 	allow_metadata_inventory_put = technic.machine_inventory_put, | ||||
| 	allow_metadata_inventory_take = technic.machine_inventory_take, | ||||
|   | ||||
| @@ -48,20 +48,23 @@ local function forceload_on(pos, meta) | ||||
| 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", { | ||||
| @@ -80,7 +83,8 @@ 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) | ||||
| @@ -99,7 +103,11 @@ minetest.register_node("technic:admin_anchor", { | ||||
| 			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 | ||||
|   | ||||
| @@ -77,14 +77,12 @@ minetest.register_abm({ | ||||
| 	action = function(pos, node, active_object_count, active_object_count_wider) | ||||
| 		local meta = minetest.get_meta(pos) | ||||
| 		local inv    = meta:get_inventory() | ||||
| 		 | ||||
|  | ||||
| 		if inv:get_size("src") == 1 then -- Old furnace -> convert it | ||||
| 			inv:set_size("src", 2) | ||||
| 			inv:set_stack("src", 2, inv:get_stack("src2", 1)) | ||||
| 			inv:set_size("src2", 0) | ||||
| 		end | ||||
| 		 | ||||
| 		local recipe = nil | ||||
|  | ||||
| 		for i, name in pairs({ | ||||
| 				"fuel_totaltime", | ||||
|   | ||||
| @@ -88,6 +88,7 @@ minetest.register_craft({ | ||||
| local function make_on(mark, length) | ||||
| 	return function(pos, node) | ||||
| 		local meta = minetest.get_meta(pos) | ||||
| 		local owner = meta:get_string("owner") | ||||
| 		local inv = meta:get_inventory() | ||||
| 		local dir = vector.new() | ||||
| 		if node.param2 == 3 then dir.x = 1 end | ||||
| @@ -102,6 +103,9 @@ local function make_on(mark, length) | ||||
| 			minetest.check_for_falling(pos) | ||||
| 			for i = 1, length do | ||||
| 				place_pos = vector.add(place_pos, dir) | ||||
| 				if owner ~= "" and minetest.is_protected(place_pos, owner) then | ||||
| 					return | ||||
| 				end | ||||
| 				local place_node = minetest.get_node(place_pos) | ||||
| 				deploy_node(inv, "slot"..i, place_pos, place_node, node) | ||||
| 			end | ||||
| @@ -156,6 +160,11 @@ local function make_constructor(mark, length) | ||||
| 			for i = 1, length do | ||||
| 				inv:set_size("slot"..i, 1) | ||||
| 			end | ||||
| 			meta:set_string("owner", "?") | ||||
| 		end, | ||||
| 		after_place_node = function(pos, placer) | ||||
| 			local meta = minetest.get_meta(pos) | ||||
| 			meta:set_string("owner", (placer and placer:get_player_name() or "?")) | ||||
| 		end, | ||||
| 		can_dig = function(pos, player) | ||||
| 			local meta = minetest.get_meta(pos) | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| local S = technic.getter | ||||
|  | ||||
| frames = {} | ||||
|  | ||||
| local infinite_stacks = minetest.settings:get_bool("creative_mode") | ||||
| 	and minetest.get_modpath("unified_inventory") == nil | ||||
|  | ||||
| @@ -90,22 +88,22 @@ local function pos_in_list(l, pos) | ||||
| 	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 | ||||
| 		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) | ||||
| @@ -261,8 +259,8 @@ for zp = 0, 1 do | ||||
| 		sunlight_propagates = true, | ||||
|  | ||||
| 		frame_connect_all = function(nodename) | ||||
| 			l2 = {} | ||||
| 			l1 = { | ||||
| 			local l2 = {} | ||||
| 			local l1 = { | ||||
| 				{ x = -1, y = 0, z = 0 }, { x = 1, y = 0, z = 0 }, | ||||
| 				{ x = 0, y = -1, z = 0 }, { x = 0, y = 1, z = 0 }, | ||||
| 				{ x = 0, y = 0, z = -1 }, { x = 0, y = 0, z = 1 } | ||||
| @@ -311,7 +309,7 @@ for zp = 0, 1 do | ||||
| 			local node = minetest.get_node(pos) | ||||
| 			if node.name ~= "air" then | ||||
| 				if is_supported_node(node.name) then | ||||
| 					obj = minetest.add_entity(pos, "technic:frame_entity") | ||||
| 					local obj = minetest.add_entity(pos, "technic:frame_entity") | ||||
| 					obj:get_luaentity():set_node({ name = itemstack:get_name() }) | ||||
| 				end | ||||
| 			else | ||||
| @@ -326,6 +324,7 @@ for zp = 0, 1 do | ||||
|  | ||||
| 		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() | ||||
| @@ -349,7 +348,6 @@ for zp = 0, 1 do | ||||
| 				end | ||||
|  | ||||
| 				-- Run script hook | ||||
| 				local _, callback | ||||
| 				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 } | ||||
| @@ -364,7 +362,7 @@ for zp = 0, 1 do | ||||
| 					itemstack:take_item() | ||||
| 				end | ||||
|  | ||||
| 				obj = minetest.add_entity(pos, "technic:frame_entity") | ||||
| 				local obj = minetest.add_entity(pos, "technic:frame_entity") | ||||
| 				obj:get_luaentity():set_node({ name = node.name }) | ||||
|  | ||||
| 				return itemstack | ||||
| @@ -400,21 +398,7 @@ minetest.register_entity("technic:frame_entity", { | ||||
| 		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 | ||||
| 		prop = { | ||||
| 		local prop = { | ||||
| 			is_visible = true, | ||||
| 			textures = { node.name }, | ||||
| 		} | ||||
| @@ -589,7 +573,7 @@ local function connected(pos, c, adj) | ||||
| end | ||||
|  | ||||
| local function get_connected_nodes(pos) | ||||
| 	c = { pos } | ||||
| 	local c = { pos } | ||||
| 	local nodename = minetest.get_node(pos).name | ||||
| 	if frames_pos[pos_to_string(pos)] then | ||||
| 		nodename = frames_pos[pos_to_string(pos)] | ||||
| @@ -695,7 +679,7 @@ local function swap_template(pos, new) | ||||
| 	local saved_node = meta:get_string("saved_node") | ||||
| 	meta:set_string("saved_node", "") | ||||
| 	technic.swap_node(pos, new) | ||||
| 	local meta = minetest.get_meta(pos) | ||||
| 	meta = minetest.get_meta(pos) | ||||
| 	meta:set_string("saved_node", saved_node) | ||||
| end | ||||
|  | ||||
| @@ -857,7 +841,7 @@ minetest.register_node("technic:template_disabled", { | ||||
| 	on_destruct = template_on_destruct, | ||||
| 	after_dig_node = template_drops, | ||||
| 	on_punch = function(pos, node, puncher) | ||||
| 	local meta = minetest.get_meta(pos) | ||||
| 	local _ = minetest.get_meta(pos) | ||||
| 		swap_template(pos, "technic:template_connector") | ||||
| 	end | ||||
| }) | ||||
|   | ||||
| @@ -16,7 +16,7 @@ local function inject_items (pos) | ||||
| 				if stack then | ||||
| 				local item0=stack:to_table() | ||||
| 				if item0 then | ||||
| 					item0["count"] = "1" | ||||
| 					item0["count"] = 1 | ||||
| 					technic.tube_inject_item(pos, pos, vector.new(0, -1, 0), item0) | ||||
| 					stack:take_item(1) | ||||
| 					inv:set_stack("main", i, stack) | ||||
| @@ -40,7 +40,7 @@ local function inject_items (pos) | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
| 		 | ||||
|  | ||||
| end | ||||
|  | ||||
| minetest.register_craft({ | ||||
| @@ -61,6 +61,9 @@ local function set_injector_formspec(meta) | ||||
| 		(is_stack and | ||||
| 			"button[0,1;2,1;mode_item;"..S("Stackwise").."]" or | ||||
| 			"button[0,1;2,1;mode_stack;"..S("Itemwise").."]").. | ||||
| 		(meta:get_int("public") == 1 and | ||||
| 			"button[2,1;2,1;mode_private;"..S("Public").."]" or | ||||
| 			"button[2,1;2,1;mode_public;"..S("Private").."]").. | ||||
| 		"list[current_name;main;0,2;8,2;]".. | ||||
| 		"list[current_player;main;0,5;8,4;]".. | ||||
| 		"listring[]".. | ||||
| @@ -117,10 +120,15 @@ minetest.register_node("technic:injector", { | ||||
| 		return inv:is_empty("main") | ||||
| 	end, | ||||
| 	on_receive_fields = function(pos, formanme, fields, sender) | ||||
| 		if minetest.is_protected(pos, sender:get_player_name()) then return end | ||||
|  | ||||
| 		local meta = minetest.get_meta(pos) | ||||
| 		if fields.mode_item then meta:set_string("mode", "single items") end | ||||
| 		if fields.mode_stack then meta:set_string("mode", "whole stacks") end | ||||
|  | ||||
| 		if fields.mode_private then meta:set_int("public", 0) end | ||||
| 		if fields.mode_public then meta:set_int("public", 1) end | ||||
|  | ||||
| 		if fields["fs_helpers_cycling:0:splitstacks"] | ||||
| 		  or fields["fs_helpers_cycling:1:splitstacks"] then | ||||
| 			if not pipeworks.may_configure(pos, sender) then return end | ||||
|   | ||||
| @@ -12,14 +12,14 @@ function technic.register_alloy_recipe(data) | ||||
| end | ||||
|  | ||||
| local recipes = { | ||||
| 	{"technic:copper_dust 3",         "technic:tin_dust",           "technic:bronze_dust 4"}, | ||||
| 	{"default:copper_ingot 3",        "default:tin_ingot",          "default:bronze_ingot 4"}, | ||||
| 	{"technic:wrought_iron_dust",     "technic:coal_dust",          "technic:carbon_steel_dust", 3}, | ||||
| 	{"technic:wrought_iron_ingot",    "technic:coal_dust",          "technic:carbon_steel_ingot", 3}, | ||||
| 	{"technic:carbon_steel_dust",     "technic:coal_dust",          "technic:cast_iron_dust", 3}, | ||||
| 	{"technic:carbon_steel_ingot",    "technic:coal_dust",          "technic:cast_iron_ingot", 3}, | ||||
| 	{"technic:carbon_steel_dust 3",   "technic:chromium_dust",      "technic:stainless_steel_dust 4"}, | ||||
| 	{"technic:carbon_steel_ingot 3",  "technic:chromium_ingot",     "technic:stainless_steel_ingot 4"}, | ||||
| 	{"technic:copper_dust 7",         "technic:tin_dust",           "technic:bronze_dust 8", 12}, | ||||
| 	{"default:copper_ingot 7",        "default:tin_ingot",          "default:bronze_ingot 8", 12}, | ||||
| 	{"technic:wrought_iron_dust 2",   "technic:coal_dust",          "technic:carbon_steel_dust 2", 6}, | ||||
| 	{"technic:wrought_iron_ingot 2",  "technic:coal_dust",          "technic:carbon_steel_ingot 2", 6}, | ||||
| 	{"technic:carbon_steel_dust 2",   "technic:coal_dust",          "technic:cast_iron_dust 2", 6}, | ||||
| 	{"technic:carbon_steel_ingot 2",  "technic:coal_dust",          "technic:cast_iron_ingot 2", 6}, | ||||
| 	{"technic:carbon_steel_dust 4",   "technic:chromium_dust",      "technic:stainless_steel_dust 5", 7.5}, | ||||
| 	{"technic:carbon_steel_ingot 4",  "technic:chromium_ingot",     "technic:stainless_steel_ingot 5", 7.5}, | ||||
| 	{"technic:copper_dust 2",         "technic:zinc_dust",          "technic:brass_dust 3"}, | ||||
| 	{"default:copper_ingot 2",        "technic:zinc_ingot",         "basic_materials:brass_ingot 3"}, | ||||
| 	{"default:sand 2",                "technic:coal_dust 2",        "technic:silicon_wafer"}, | ||||
|   | ||||
| @@ -92,7 +92,7 @@ local dirtab = { | ||||
|  | ||||
| local tube = { | ||||
| 	insert_object = function(pos, node, stack, direction) | ||||
| 		print(minetest.pos_to_string(direction), dirtab[direction.x+2+(direction.z+2)*2], node.param2) | ||||
| 		--print(minetest.pos_to_string(direction), dirtab[direction.x+2+(direction.z+2)*2], node.param2) | ||||
| 		if direction.y == 1 | ||||
| 			or (direction.y == 0 and dirtab[direction.x+2+(direction.z+2)*2] == node.param2) then | ||||
| 			return stack | ||||
| @@ -106,7 +106,7 @@ local tube = { | ||||
| 		end | ||||
| 	end, | ||||
| 	can_insert = function(pos, node, stack, direction) | ||||
| 		print(minetest.pos_to_string(direction), dirtab[direction.x+2+(direction.z+2)*2], node.param2) | ||||
| 		--print(minetest.pos_to_string(direction), dirtab[direction.x+2+(direction.z+2)*2], node.param2) | ||||
| 		if direction.y == 1 | ||||
| 			or (direction.y == 0 and dirtab[direction.x+2+(direction.z+2)*2] == node.param2) then | ||||
| 			return false | ||||
| @@ -192,10 +192,10 @@ function technic.register_battery_box(data) | ||||
| 	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 | ||||
| @@ -304,15 +304,14 @@ function technic.register_battery_box(data) | ||||
| 			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") | ||||
| 				local cpercent = math.floor(charge / max_charge * 100) | ||||
| 				local inv = meta:get_inventory() | ||||
| 				local node = minetest.get_node(pos) | ||||
| 				meta:set_string("infotext", S("%s Battery Box"):format(tier)) | ||||
| 				meta:set_string("formspec", formspec..add_on_off_buttons(meta, ltier, cpercent)) | ||||
| 				meta:set_string("channel", ltier.."_battery_box"..minetest.pos_to_string(pos)) | ||||
| @@ -335,7 +334,6 @@ function technic.register_battery_box(data) | ||||
| 			after_dig_node = technic.machine_after_dig_node, | ||||
| 			on_receive_fields = function(pos, formname, fields, sender) | ||||
| 				local meta = minetest.get_meta(pos) | ||||
| 				local nodename = minetest.get_node(pos).name | ||||
| 				if fields.edit_channel then | ||||
| 					minetest.show_formspec(sender:get_player_name(), | ||||
| 						"technic:battery_box_edit_channel"..minetest.pos_to_string(pos), | ||||
| @@ -344,12 +342,12 @@ function technic.register_battery_box(data) | ||||
| 				  or   fields["fs_helpers_cycling:0:split_dst_stacks"] | ||||
| 				  or   fields["fs_helpers_cycling:1:split_src_stacks"] | ||||
| 				  or   fields["fs_helpers_cycling:1:split_dst_stacks"] then | ||||
| 					local meta = minetest.get_meta(pos) | ||||
| 					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") | ||||
| @@ -411,6 +409,25 @@ minetest.register_on_player_receive_fields( | ||||
| 	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 | ||||
| @@ -418,18 +435,18 @@ function technic.charge_tools(meta, batt_charge, charge_step) | ||||
| 	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 | ||||
| @@ -439,9 +456,7 @@ function technic.charge_tools(meta, batt_charge, charge_step) | ||||
| 	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 | ||||
| @@ -452,21 +467,20 @@ function technic.discharge_tools(meta, batt_charge, charge_step, max_charge) | ||||
| 	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 | ||||
| @@ -476,10 +490,8 @@ function technic.discharge_tools(meta, batt_charge, charge_step, max_charge) | ||||
| 	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 | ||||
|  | ||||
|   | ||||
| @@ -11,6 +11,13 @@ function technic.get_cable_tier(name) | ||||
| 	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 = {} | ||||
| @@ -36,84 +43,106 @@ local function check_connections(pos) | ||||
| 	return connections | ||||
| end | ||||
|  | ||||
| local function clear_networks(pos) | ||||
| local clear_networks | ||||
|  | ||||
| local function clear_network(network_id) | ||||
| 	if not network_id then | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	for _,v in pairs(technic.networks[network_id].all_nodes) do | ||||
| 		local pos1 = minetest.hash_node_position(v) | ||||
| 		technic.cables[pos1] = nil | ||||
| 	end | ||||
| 	local network_bckup = technic.networks[network_id] | ||||
| 	technic.networks[network_id] = nil | ||||
|  | ||||
| 	for _,n_pos in pairs(network_bckup.PR_nodes) do | ||||
| 		clear_networks(n_pos) | ||||
| 	end | ||||
| 	for _,n_pos in pairs(network_bckup.RE_nodes) do | ||||
| 		clear_networks(n_pos) | ||||
| 	end | ||||
| 	for _,n_pos in pairs(network_bckup.BA_nodes) do | ||||
| 		clear_networks(n_pos) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| clear_networks = function(pos) | ||||
| 	local node = minetest.get_node(pos) | ||||
| 	local meta = minetest.get_meta(pos) | ||||
| 	local placed = node.name ~= "air" | ||||
| 	local positions = check_connections(pos) | ||||
|  | ||||
| 	if #positions < 1 then return end | ||||
| 	local dead_end = #positions == 1 | ||||
| 	for _,connected_pos in pairs(positions) do | ||||
| 		local net = technic.cables[minetest.hash_node_position(connected_pos)] | ||||
| 		if net and technic.networks[net] then | ||||
| 			if dead_end and placed then | ||||
| 				-- Dead end placed, add it to the network | ||||
| 				-- Get the network | ||||
| 				local network_id = technic.cables[minetest.hash_node_position(positions[1])] | ||||
| 				if not network_id then | ||||
| 					-- We're evidently not on a network, nothing to add ourselves to | ||||
| 					return | ||||
| 				end | ||||
| 				local sw_pos = minetest.get_position_from_hash(network_id) | ||||
| 				sw_pos.y = sw_pos.y + 1 | ||||
| 				local network = technic.networks[network_id] | ||||
| 				local tier = network.tier | ||||
|  | ||||
| 				-- Actually add it to the (cached) network | ||||
| 				-- This is similar to check_node_subp | ||||
| 	if #positions == 1 then | ||||
| 		if placed then | ||||
| 			-- Dead end placed, add it to the network | ||||
| 			-- Get the network | ||||
| 			local network_id = technic.cables[minetest.hash_node_position(positions[1])] | ||||
| 			if not network_id then | ||||
| 				-- We're evidently not on a network, nothing to add ourselves to | ||||
| 				return | ||||
| 			end | ||||
| 			local network = technic.networks[network_id] | ||||
| 			local tier = network.tier | ||||
|  | ||||
| 			-- Actually add it to the (cached) network | ||||
| 			-- !! IMPORTANT: ../switching_station.lua -> check_node_subp() must be kept in sync | ||||
| 			if technic.is_tier_cable(node.name, tier) then | ||||
| 				technic.cables[minetest.hash_node_position(pos)] = network_id | ||||
| 				pos.visited = 1 | ||||
| 				if technic.is_tier_cable(name, tier) then | ||||
| 					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) | ||||
| 					end | ||||
| 				table.insert(network.all_nodes,pos) | ||||
| 			elseif technic.machines[tier][node.name] then | ||||
| 				-- Found a machine | ||||
| 				local eu_type = technic.machines[tier][node.name] | ||||
| 				meta:set_string(tier.."_network", string.format("%.20g", network_id)) | ||||
| 				meta:set_int(tier.."_EU_timeout", 2) | ||||
| 				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 | ||||
| 			elseif dead_end and not placed then | ||||
| 				-- Dead end removed, remove it from the network | ||||
| 				-- Get the network | ||||
| 				local network_id = technic.cables[minetest.hash_node_position(positions[1])] | ||||
| 				if not network_id then | ||||
| 					-- We're evidently not on a network, nothing to add ourselves to | ||||
| 					return | ||||
| 				end | ||||
| 				local network = technic.networks[network_id] | ||||
| 				-- Note: SPECIAL (i.e. switching station) is not traversed! | ||||
| 			end | ||||
| 		else | ||||
| 			-- Dead end removed, remove it from the network | ||||
| 			-- Get the network | ||||
| 			local network_id = technic.cables[minetest.hash_node_position(positions[1])] | ||||
| 			if not network_id then | ||||
| 				-- We're evidently not on a network, nothing to add ourselves to | ||||
| 				return | ||||
| 			end | ||||
| 			local network = technic.networks[network_id] | ||||
|  | ||||
| 				-- Search for and remove machine | ||||
| 				technic.cables[minetest.hash_node_position(pos)] = nil | ||||
| 				for tblname,table in pairs(network) do | ||||
| 					if tblname ~= "tier" then | ||||
| 						for machinenum,machine in pairs(table) do | ||||
| 							if machine.x == pos.x | ||||
| 							and machine.y == pos.y | ||||
| 							and machine.z == pos.z then | ||||
| 								table[machinenum] = nil | ||||
| 							end | ||||
| 			-- Search for and remove machine | ||||
| 			technic.cables[minetest.hash_node_position(pos)] = nil | ||||
| 			for tblname,table in pairs(network) do | ||||
| 				if tblname ~= "tier" then | ||||
| 					for machinenum,machine in pairs(table) do | ||||
| 						if machine.x == pos.x | ||||
| 						and machine.y == pos.y | ||||
| 						and machine.z == pos.z then | ||||
| 							table[machinenum] = nil | ||||
| 						end | ||||
| 					end | ||||
| 				end | ||||
| 			else | ||||
| 				-- Not a dead end, so the whole network needs to be recalculated | ||||
| 				for _,v in pairs(technic.networks[net].all_nodes) do | ||||
| 					local pos1 = minetest.hash_node_position(v) | ||||
| 					technic.cables[pos1] = nil | ||||
| 				end | ||||
| 				technic.networks[net] = nil | ||||
| 			end | ||||
| 		end | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	clear_network(technic.cables[minetest.hash_node_position(pos)]) | ||||
|  | ||||
| 	for _,connected_pos in pairs(positions) do | ||||
| 		local network_id = technic.cables[minetest.hash_node_position(connected_pos)] | ||||
| 		-- Not a dead end, so the whole network needs to be recalculated | ||||
| 		clear_network(network_id) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| @@ -163,7 +192,7 @@ function technic.register_cable(tier, size) | ||||
| 		connects_to = {"group:technic_"..ltier.."_cable", | ||||
| 			"group:technic_"..ltier, "group:technic_all_tiers"}, | ||||
| 		on_construct = clear_networks, | ||||
| 		on_destruct = clear_networks, | ||||
| 		after_destruct = clear_networks, | ||||
| 	}) | ||||
|  | ||||
| 	local xyz = { | ||||
| @@ -203,7 +232,7 @@ function technic.register_cable(tier, size) | ||||
| 			connects_to = {"group:technic_"..ltier.."_cable", | ||||
| 				"group:technic_"..ltier, "group:technic_all_tiers"}, | ||||
| 			on_construct = clear_networks, | ||||
| 			on_destruct = clear_networks, | ||||
| 			after_destruct = clear_networks, | ||||
| 		} | ||||
| 		def.node_box.fixed = { | ||||
| 			{-size, -size, -size, size, size, size}, | ||||
|   | ||||
| @@ -11,8 +11,8 @@ function technic.register_separating_recipe(data) | ||||
| end | ||||
|  | ||||
| local recipes = { | ||||
| 	{ "technic:bronze_dust 4",             "technic:copper_dust 3",       "technic:tin_dust"      }, | ||||
| 	{ "technic:stainless_steel_dust 4",    "technic:wrought_iron_dust 3", "technic:chromium_dust" }, | ||||
| 	{ "technic:bronze_dust 8",             "technic:copper_dust 7",       "technic:tin_dust"      }, | ||||
| 	{ "technic:stainless_steel_dust 5",    "technic:wrought_iron_dust 4", "technic:chromium_dust" }, | ||||
| 	{ "technic:brass_dust 3",              "technic:copper_dust 2",       "technic:zinc_dust"     }, | ||||
| 	{ "technic:chernobylite_dust",         "default:sand",                "technic:uranium3_dust" }, | ||||
| 	{ "default:dirt 4",                    "default:sand",                "default:gravel",       "default:clay_lump 2"     }, | ||||
|   | ||||
| @@ -65,7 +65,7 @@ function technic.send_items(pos, x_velocity, z_velocity, output_name) | ||||
| 	if output_name == nil then | ||||
| 		output_name = "dst" | ||||
| 	end | ||||
| 	 | ||||
|  | ||||
| 	local meta = minetest.get_meta(pos) | ||||
| 	local inv = meta:get_inventory() | ||||
| 	local i = 0 | ||||
| @@ -74,7 +74,7 @@ function technic.send_items(pos, x_velocity, z_velocity, output_name) | ||||
| 		if stack then | ||||
| 			local item0 = stack:to_table() | ||||
| 			if item0 then | ||||
| 				item0["count"] = "1" | ||||
| 				item0["count"] = 1 | ||||
| 				technic.tube_inject_item(pos, pos, vector.new(x_velocity, 0, z_velocity), item0) | ||||
| 				stack:take_item(1) | ||||
| 				inv:set_stack(output_name, i, stack) | ||||
| @@ -84,7 +84,6 @@ function technic.send_items(pos, x_velocity, z_velocity, output_name) | ||||
| 	end | ||||
| end | ||||
|  | ||||
|  | ||||
| function technic.smelt_item(meta, result, speed) | ||||
| 	local inv = meta:get_inventory() | ||||
| 	meta:set_int("cook_time", meta:get_int("cook_time") + 1) | ||||
| @@ -109,10 +108,9 @@ function technic.handle_machine_pipeworks(pos, tube_upgrade, send_function) | ||||
| 	if send_function == nil then | ||||
| 		send_function = technic.send_items | ||||
| 	end | ||||
| 	 | ||||
|  | ||||
| 	local node = minetest.get_node(pos) | ||||
| 	local meta = minetest.get_meta(pos) | ||||
| 	local inv = meta:get_inventory() | ||||
| 	local pos1 = vector.new(pos) | ||||
| 	local x_velocity = 0 | ||||
| 	local z_velocity = 0 | ||||
|   | ||||
| @@ -8,6 +8,71 @@ function technic.register_compressor_recipe(data) | ||||
| 	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"}, | ||||
| @@ -21,27 +86,36 @@ local recipes = { | ||||
| 	{"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 | ||||
|  | ||||
|   | ||||
| @@ -41,9 +41,9 @@ function technic.register_generator(data) | ||||
| 		"image[4,1;1,1;default_furnace_fire_bg.png]".. | ||||
| 		"list[current_player;main;0,5;8,4;]".. | ||||
| 		"listring[]" | ||||
| 	 | ||||
|  | ||||
| 	local desc = S("Fuel-Fired %s Generator"):format(tier) | ||||
| 	 | ||||
|  | ||||
| 	local run = function(pos, node) | ||||
| 		local meta = minetest.get_meta(pos) | ||||
| 		local burn_time = meta:get_int("burn_time") | ||||
| @@ -162,7 +162,6 @@ function technic.register_generator(data) | ||||
| 			fs_helpers.on_receive_fields(pos, fields) | ||||
| 			local meta = minetest.get_meta(pos) | ||||
| 			local node = minetest.get_node(pos) | ||||
| 			local form = generator_formspec | ||||
| 			local form_buttons = "" | ||||
| 			if not string.find(node.name, ":lv_") then | ||||
| 				form_buttons = fs_helpers.cycling_button( | ||||
| @@ -204,15 +203,15 @@ function technic.register_generator(data) | ||||
| 		technic_run = run, | ||||
| 		technic_on_disable = function(pos, node) | ||||
| 			local timer = minetest.get_node_timer(pos) | ||||
|         		timer:start(1) | ||||
|         	end, | ||||
| 			timer:start(1) | ||||
| 		end, | ||||
| 		on_timer = function(pos, node) | ||||
| 			local meta = minetest.get_meta(pos) | ||||
| 			local node = minetest.get_node(pos) | ||||
|  | ||||
| 			-- Connected back? | ||||
| 			if meta:get_int(tier.."_EU_timeout") > 0 then return false end | ||||
| 			 | ||||
|  | ||||
| 			local burn_time = meta:get_int("burn_time") or 0 | ||||
|  | ||||
| 			if burn_time <= 0 then | ||||
|   | ||||
| @@ -23,6 +23,8 @@ local recipes = { | ||||
| 	{"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"}, | ||||
| @@ -34,49 +36,73 @@ local recipes = { | ||||
| 	{"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, ' ', '_') | ||||
| @@ -94,33 +120,57 @@ local function register_dust(name, ingot) | ||||
| 	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 | ||||
| @@ -156,6 +206,7 @@ for pa = 0, 34 do | ||||
| 	end | ||||
| end | ||||
|  | ||||
| -- Fuels | ||||
| minetest.register_craft({ | ||||
| 	type = "fuel", | ||||
| 	recipe = "technic:coal_dust", | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| local S = technic.getter | ||||
| local moretrees = minetest.get_modpath("moretrees") | ||||
| local mesecons_materials = minetest.get_modpath("mesecons_materials") | ||||
| local dye = minetest.get_modpath("dye") | ||||
|  | ||||
| -- sawdust, the finest wood/tree grinding | ||||
|   | ||||
| @@ -39,6 +39,8 @@ function technic.register_base_machine(data) | ||||
| 	local tier = data.tier | ||||
| 	local ltier = string.lower(tier) | ||||
|  | ||||
| 	data.modname = data.modname or minetest.get_current_modname() | ||||
|  | ||||
| 	local groups = {cracky = 2, technic_machine = 1, ["technic_"..ltier] = 1} | ||||
| 	if data.tube then | ||||
| 		groups.tubedevice = 1 | ||||
| @@ -82,7 +84,7 @@ function technic.register_base_machine(data) | ||||
| 		local eu_input = meta:get_int(tier.."_EU_input") | ||||
|  | ||||
| 		local machine_desc_tier = machine_desc:format(tier) | ||||
| 		local machine_node      = "technic:"..ltier.."_"..machine_name | ||||
| 		local machine_node      = data.modname..":"..ltier.."_"..machine_name | ||||
| 		local machine_demand    = data.demand | ||||
|  | ||||
| 		-- Setup meta data if it does not exist. | ||||
| @@ -157,15 +159,15 @@ function technic.register_base_machine(data) | ||||
| 		tentry = "" | ||||
| 	end | ||||
|  | ||||
| 	minetest.register_node("technic:"..ltier.."_"..machine_name, { | ||||
| 	minetest.register_node(data.modname..":"..ltier.."_"..machine_name, { | ||||
| 		description = machine_desc:format(tier), | ||||
| 		tiles = { | ||||
| 			"technic_"..ltier.."_"..machine_name.."_top.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_bottom.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_front.png" | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_top.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_bottom.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_front.png" | ||||
| 		}, | ||||
| 		paramtype2 = "facedir", | ||||
| 		groups = groups, | ||||
| @@ -207,9 +209,10 @@ function technic.register_base_machine(data) | ||||
| 		after_place_node = data.tube and pipeworks.after_place, | ||||
| 		after_dig_node = technic.machine_after_dig_node, | ||||
| 		on_receive_fields = function(pos, formname, fields, sender) | ||||
| 			local node = minetest.get_node(pos) | ||||
| 			if fields.quit then return end | ||||
| 			if not pipeworks.may_configure(pos, sender) then return end | ||||
| 			fs_helpers.on_receive_fields(pos, fields) | ||||
| 			local node = minetest.get_node(pos) | ||||
| 			local meta = minetest.get_meta(pos) | ||||
| 			local form_buttons = "" | ||||
| 			if not string.find(node.name, ":lv_") then | ||||
| @@ -227,18 +230,18 @@ function technic.register_base_machine(data) | ||||
| 		end, | ||||
| 	}) | ||||
|  | ||||
| 	minetest.register_node("technic:"..ltier.."_"..machine_name.."_active",{ | ||||
| 	minetest.register_node(data.modname..":"..ltier.."_"..machine_name.."_active",{ | ||||
| 		description = machine_desc:format(tier), | ||||
| 		tiles = { | ||||
| 			"technic_"..ltier.."_"..machine_name.."_top.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_bottom.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			"technic_"..ltier.."_"..machine_name.."_front_active.png" | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_top.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_bottom.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_side.png"..tentry, | ||||
| 			data.modname.."_"..ltier.."_"..machine_name.."_front_active.png" | ||||
| 		}, | ||||
| 		paramtype2 = "facedir", | ||||
| 		drop = "technic:"..ltier.."_"..machine_name, | ||||
| 		drop = data.modname..":"..ltier.."_"..machine_name, | ||||
| 		groups = active_groups, | ||||
| 		connect_sides = data.connect_sides or connect_default, | ||||
| 		legacy_facedir_simple = true, | ||||
| @@ -249,11 +252,12 @@ function technic.register_base_machine(data) | ||||
| 		allow_metadata_inventory_take = technic.machine_inventory_take, | ||||
| 		allow_metadata_inventory_move = technic.machine_inventory_move, | ||||
| 		technic_run = run, | ||||
| 		technic_disabled_machine_name = "technic:"..ltier.."_"..machine_name, | ||||
| 		technic_disabled_machine_name = data.modname..":"..ltier.."_"..machine_name, | ||||
| 		on_receive_fields = function(pos, formname, fields, sender) | ||||
| 			local node = minetest.get_node(pos) | ||||
| 			if fields.quit then return end | ||||
| 			if not pipeworks.may_configure(pos, sender) then return end | ||||
| 			fs_helpers.on_receive_fields(pos, fields) | ||||
| 			local node = minetest.get_node(pos) | ||||
| 			local meta = minetest.get_meta(pos) | ||||
| 			local form_buttons = "" | ||||
| 			if not string.find(node.name, ":lv_") then | ||||
| @@ -271,8 +275,8 @@ function technic.register_base_machine(data) | ||||
| 		end, | ||||
| 	}) | ||||
|  | ||||
| 	technic.register_machine(tier, "technic:"..ltier.."_"..machine_name,            technic.receiver) | ||||
| 	technic.register_machine(tier, "technic:"..ltier.."_"..machine_name.."_active", technic.receiver) | ||||
| 	technic.register_machine(tier, data.modname..":"..ltier.."_"..machine_name,            technic.receiver) | ||||
| 	technic.register_machine(tier, data.modname..":"..ltier.."_"..machine_name.."_active", technic.receiver) | ||||
|  | ||||
| end -- End registration | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| local have_ui = minetest.get_modpath("unified_inventory") | ||||
| local have_cg = minetest.get_modpath("craftguide") | ||||
| local have_i3 = minetest.get_modpath("i3") | ||||
|  | ||||
| technic.recipes = { cooking = { input_size = 1, output_size = 1 } } | ||||
| function technic.register_recipe_type(typename, origdata) | ||||
| @@ -6,19 +8,34 @@ function technic.register_recipe_type(typename, origdata) | ||||
| 	for k, v in pairs(origdata) do data[k] = v end | ||||
| 	data.input_size = data.input_size or 1 | ||||
| 	data.output_size = data.output_size or 1 | ||||
| 	if have_ui and unified_inventory.register_craft_type and data.output_size == 1 then | ||||
| 		unified_inventory.register_craft_type(typename, { | ||||
| 			description = data.description, | ||||
| 			width = data.input_size, | ||||
| 			height = 1, | ||||
| 		}) | ||||
| 	if data.output_size == 1 then | ||||
| 		if have_ui and unified_inventory.register_craft_type then | ||||
| 			unified_inventory.register_craft_type(typename, { | ||||
| 				description = data.description, | ||||
| 				width = data.input_size, | ||||
| 				height = 1, | ||||
| 			}) | ||||
| 		end | ||||
| 		if have_cg and craftguide.register_craft_type then | ||||
| 			craftguide.register_craft_type(typename, { | ||||
| 				description = data.description, | ||||
| 			}) | ||||
| 		end | ||||
| 		if have_i3 then | ||||
| 			i3.register_craft_type(typename, { | ||||
| 				description = data.description, | ||||
| 			}) | ||||
| 		end | ||||
| 	end | ||||
| 	data.recipes = {} | ||||
| 	technic.recipes[typename] = data | ||||
| end | ||||
|  | ||||
| local function get_recipe_index(items) | ||||
| 	if not items or type(items) ~= "table" then return false end | ||||
| 	if type(items) ~= "table" then | ||||
| 		return false | ||||
| 	end | ||||
|  | ||||
| 	local l = {} | ||||
| 	for i, stack in ipairs(items) do | ||||
| 		l[i] = ItemStack(stack):get_name() | ||||
| @@ -39,7 +56,7 @@ local function register_recipe(typename, data) | ||||
| 	else | ||||
| 		data.output = ItemStack(data.output):to_string() | ||||
| 	end | ||||
| 	 | ||||
|  | ||||
| 	local recipe = {time = data.time, input = {}, output = data.output} | ||||
| 	local index = get_recipe_index(data.input) | ||||
| 	if not index then | ||||
| @@ -49,7 +66,7 @@ local function register_recipe(typename, data) | ||||
| 	for _, stack in ipairs(data.input) do | ||||
| 		recipe.input[ItemStack(stack):get_name()] = ItemStack(stack):get_count() | ||||
| 	end | ||||
| 	 | ||||
|  | ||||
| 	technic.recipes[typename].recipes[index] = recipe | ||||
| 	if have_ui and technic.recipes[typename].output_size == 1 then | ||||
| 		unified_inventory.register_craft({ | ||||
| @@ -59,6 +76,26 @@ local function register_recipe(typename, data) | ||||
| 			width = 0, | ||||
| 		}) | ||||
| 	end | ||||
| 	if (have_cg or have_i3) and technic.recipes[typename].output_size == 1 then | ||||
| 		local result = data.output | ||||
| 		if type(result) == "table" then | ||||
| 			result = result[1] | ||||
| 		end | ||||
| 		if have_cg and craftguide.register_craft then | ||||
| 			craftguide.register_craft({ | ||||
| 				type = typename, | ||||
| 				result = result, | ||||
| 				items = data.input, | ||||
| 			}) | ||||
| 		end | ||||
| 		if have_i3 then | ||||
| 			i3.register_craft({ | ||||
| 				type = typename, | ||||
| 				result = result, | ||||
| 				items = data.input, | ||||
| 			}) | ||||
| 		end | ||||
| 	end | ||||
| end | ||||
|  | ||||
| function technic.register_recipe(typename, data) | ||||
|   | ||||
| @@ -56,7 +56,6 @@ function technic.register_solar_array(data) | ||||
| 		}, | ||||
| 		on_construct = function(pos) | ||||
| 			local meta = minetest.get_meta(pos) | ||||
| 			local name = minetest.get_node(pos).name | ||||
| 			meta:set_int(tier.."_EU_supply", 0) | ||||
| 		end, | ||||
| 		technic_run = run, | ||||
|   | ||||
| @@ -120,7 +120,7 @@ local run = function(pos, node, run_stage) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	local remain = 0.9 | ||||
| 	local efficiency = 0.9 | ||||
| 	-- Machine information | ||||
| 	local machine_name  = S("Supply Converter") | ||||
| 	local meta          = minetest.get_meta(pos) | ||||
| @@ -133,7 +133,6 @@ local run = function(pos, node, run_stage) | ||||
| 		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} | ||||
| @@ -144,14 +143,37 @@ local run = function(pos, node, run_stage) | ||||
| 	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 | ||||
|   | ||||
| @@ -45,14 +45,12 @@ minetest.register_node("technic:switching_station",{ | ||||
| 		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) | ||||
| @@ -99,10 +97,14 @@ local function flatten(map) | ||||
| 	return list | ||||
| end | ||||
|  | ||||
| -- Add a wire node to the LV/MV/HV network | ||||
| -- Add a node to the LV/MV/HV network | ||||
| -- Returns: indicator whether the node 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) | ||||
| 	technic.cables[node_id] = network_id | ||||
| 	local node_id = hash_node_position(pos) | ||||
| 	if network_id then | ||||
| 		technic.cables[node_id] = network_id | ||||
| 	end | ||||
| 	if nodes[node_id] then | ||||
| 		return false | ||||
| 	end | ||||
| @@ -117,39 +119,58 @@ local function add_cable_node(nodes, pos, network_id, queue) | ||||
| 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) | ||||
| 	local network_str = string.format("%.20g", network_id) | ||||
| 	local network_key = network.tier.."_network" | ||||
| 	local m_network_str = meta:get_string(network_key) | ||||
|  | ||||
| 	if m_network_str == "" then | ||||
| 		meta:set_string(network_key, network_str) | ||||
| 	else | ||||
| 		if m_network_str ~= network_str then | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| 	if     eu_type == technic.producer then | ||||
| 		add_network_node(network.PR_nodes, pos) | ||||
| 	elseif eu_type == technic.receiver then | ||||
| 		add_network_node(network.RE_nodes, pos) | ||||
| 	elseif eu_type == technic.producer_receiver then | ||||
| 		add_network_node(network.PR_nodes, pos) | ||||
| 		add_network_node(network.RE_nodes, pos) | ||||
| 	elseif eu_type == technic.battery then | ||||
| 		add_network_node(network.BA_nodes, pos) | ||||
| 	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) | ||||
| 		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}, | ||||
| @@ -158,7 +179,7 @@ local traverse_network = function(PR_nodes, RE_nodes, BA_nodes, SP_nodes, all_no | ||||
| 		{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 | ||||
|  | ||||
| @@ -169,43 +190,50 @@ local touch_nodes = function(list, tier) | ||||
| 	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 | ||||
|  | ||||
| ----------------------------------------------- | ||||
| @@ -215,19 +243,17 @@ 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) | ||||
| @@ -243,32 +269,23 @@ end | ||||
|  | ||||
| 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 meta1            = nil | ||||
| 		local pos1             = {} | ||||
| 		local PR_EU            = 0 -- EUs from PR nodes | ||||
| 		local BA_PR_EU         = 0 -- EUs from BA nodes (discharching) | ||||
| 		local BA_RE_EU         = 0 -- EUs to BA nodes (charging) | ||||
| 		local RE_EU            = 0 -- EUs to RE nodes | ||||
|  | ||||
| 		local tier      = "" | ||||
| 		local PR_nodes | ||||
| 		local BA_nodes | ||||
| 		local RE_nodes | ||||
| 		local meta = minetest.get_meta(pos) | ||||
| 		local meta1 | ||||
| 		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) | ||||
| @@ -280,18 +297,18 @@ minetest.register_abm({ | ||||
| 			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 | ||||
|  | ||||
| @@ -344,20 +361,16 @@ minetest.register_abm({ | ||||
| 		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", | ||||
| @@ -378,8 +391,8 @@ minetest.register_abm({ | ||||
| 		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 | ||||
| @@ -453,6 +466,7 @@ local function switching_station_timeout_count(pos, tier) | ||||
| 	local meta = minetest.get_meta(pos) | ||||
| 	local timeout = meta:get_int(tier.."_EU_timeout") | ||||
| 	if timeout <= 0 then | ||||
| 		meta:set_string(tier.."_network", "") | ||||
| 		meta:set_int(tier.."_EU_input", 0) -- Not needed anymore <-- actually, it is for supply converter | ||||
| 		return true | ||||
| 	else | ||||
| @@ -466,21 +480,29 @@ minetest.register_abm({ | ||||
| 	interval   = 1, | ||||
| 	chance     = 1, | ||||
| 	action = function(pos, node, active_object_count, active_object_count_wider) | ||||
| 		local has_network = false | ||||
| 		local technic_machine = false | ||||
| 		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)) | ||||
| 			if machines[node.name] then | ||||
| 				technic_machine = true | ||||
| 				if not switching_station_timeout_count(pos, tier) then | ||||
| 					has_network = true | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		if technic_machine and not has_network then | ||||
| 			local nodedef = minetest.registered_nodes[node.name] | ||||
| 			local meta = minetest.get_meta(pos) | ||||
| 			meta:set_string("infotext", S("%s Has No Network"):format(nodedef.description)) | ||||
| 			if nodedef.technic_disabled_machine_name then | ||||
| 				node.name = nodedef.technic_disabled_machine_name | ||||
| 				minetest.swap_node(pos, node) | ||||
| 			end | ||||
| 			if nodedef.technic_on_disable then | ||||
| 				nodedef.technic_on_disable(pos, node) | ||||
| 			end | ||||
| 		end | ||||
| 	end, | ||||
| }) | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,3 @@ | ||||
| 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 | ||||
| optional_depends = bucket, screwdriver, mesecons, mesecons_mvps, digilines, digiline_remote, intllib, unified_inventory, vector_extras, dye, craftguide, i3, everness, nether | ||||
|   | ||||
| @@ -244,7 +244,6 @@ to be safe, and limits the range at which source/player interactions | ||||
| need to be considered. | ||||
| --]] | ||||
| local abdomen_offset = 1 | ||||
| local cache_scaled_shielding = {} | ||||
| local rad_dmg_cutoff = 0.2 | ||||
| local radiated_players = {} | ||||
|  | ||||
| @@ -429,7 +428,7 @@ for _, state in pairs({"flowing", "source"}) do | ||||
| 		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}, | ||||
|   | ||||
| @@ -44,7 +44,10 @@ end | ||||
|  | ||||
| -- 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 | ||||
|   | ||||
| Before Width: | Height: | Size: 23 KiB | 
| Before Width: | Height: | Size: 675 B | 
| Before Width: | Height: | Size: 75 KiB | 
| Before Width: | Height: | Size: 2.1 KiB | 
| Before Width: | Height: | Size: 7.1 KiB | 
| Before Width: | Height: | Size: 405 B | 
| Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 203 B | 
| Before Width: | Height: | Size: 2.1 KiB | 
| Before Width: | Height: | Size: 275 B | 
| Before Width: | Height: | Size: 736 B | 
| Before Width: | Height: | Size: 670 B | 
| Before Width: | Height: | Size: 523 B | 
| Before Width: | Height: | Size: 778 B | 
| Before Width: | Height: | Size: 778 B | 
| Before Width: | Height: | Size: 772 B | 
| Before Width: | Height: | Size: 743 B | 
| Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 181 B | 
| Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 251 B | 
| Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 168 B | 
| Before Width: | Height: | Size: 194 B After Width: | Height: | Size: 194 B | 
| Before Width: | Height: | Size: 2.1 KiB | 
| Before Width: | Height: | Size: 2.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_lv_lamp_bottom.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 995 B | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_lv_lamp_side.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1014 B | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_lv_lamp_top.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 466 B | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_lv_led.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 738 B | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_lv_led_inv.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 429 B | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_lv_led_side.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 245 B | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_lv_led_side2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 253 B | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_lv_led_top.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 466 B | 
| Before Width: | Height: | Size: 916 B After Width: | Height: | Size: 775 B | 
							
								
								
									
										
											BIN
										
									
								
								technic/textures/technic_nether_dust.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 207 B | 
| Before Width: | Height: | Size: 533 B | 
| Before Width: | Height: | Size: 33 KiB | 
| Before Width: | Height: | Size: 457 B | 
| Before Width: | Height: | Size: 450 B | 
| Before Width: | Height: | Size: 551 B | 
| Before Width: | Height: | Size: 501 B | 
| Before Width: | Height: | Size: 37 KiB | 
| Before Width: | Height: | Size: 33 KiB | 
| Before Width: | Height: | Size: 517 B |