Compare commits

..

514 Commits

Author SHA1 Message Date
Joachim Stolberg
8183b05675 Fix russian translation (https://github.com/joe7575/techage_modpack/pull/28) 2024-11-03 10:39:09 +01:00
Joachim Stolberg
009ea6f3fd
Merge pull request #185 from Niklp09/flowers
Don't spawn water plants on garden soil
2024-10-06 16:24:10 +02:00
Niklp
46b176805d
Don't spawn water plants on garden soil 2024-10-06 11:44:57 +02:00
Joachim Stolberg
d7be11a8aa Bug fix 2024-08-21 20:41:25 +02:00
Joachim Stolberg
8f255ec545 Fix bug 'TA2 boiler work without requiring boiler' 2024-07-21 20:57:03 +02:00
Joachim Stolberg
ec982b0de0 Remove the reset feature again 2024-07-18 06:44:51 +02:00
Joachim Stolberg
9a699a361f Add pre-assignment menu to the furnace 2024-07-14 22:26:54 +02:00
Joachim Stolberg
a1485b6eab Improve recording for move/fly/turn controllers 2024-07-13 11:41:19 +02:00
Joachim Stolberg
895b7895e6
Merge pull request #179 from Eternal-Study/Eternal-Study-patch-2
Add replacement to Electric Meter recipe
2024-07-11 18:19:07 +02:00
Eternal-Study
3453392c56
Add replacement to electricmeter recipe
Adds a replacement value to the electric meter recipe so as to return an empty spool to replace the gold wire.
2024-07-09 23:34:18 -04:00
Joachim Stolberg
25b087232d Fix injector bug 2024-07-08 18:56:47 +02:00
Joachim Stolberg
885d25a4a9
Merge pull request #178 from Niklp09/fix_flower_detection
Fix flowers detection when using ethereal
2024-07-03 21:19:27 +02:00
Niklp
abd945d5bc
Fix flowers detection when using ethereal 2024-07-03 20:53:06 +02:00
Joachim Stolberg
b1a338c8d4 Fix issue #175 (TA3 Furnace Does not implement replacements in recipes) 2024-06-30 14:00:34 +02:00
Joachim Stolberg
d7c31f9865 Fix bug #162 (Industrial Furnace Standby mode doesn't work as expected when connected to a pump) 2024-06-30 12:54:50 +02:00
Joachim Stolberg
c98b9a3b79
Merge pull request #176 from Eternal-Study/Eternal-Study-Salt-Patch
Water to Salt + River Water Reactor Recipe
2024-06-30 10:53:10 +02:00
Joachim Stolberg
923164c17c
Merge pull request #173 from Eternal-Study/Eternal-Study-patch-1
Add or minetest.registered_nodes[name] to Silo powder check.
2024-06-30 10:50:37 +02:00
Joachim Stolberg
ee3b19dd10
Merge pull request #172 from Niklp09/fix_deprecated_calls
Replace deprecated `meta:set_string(*, nil)` calls
2024-06-30 10:49:23 +02:00
Joachim Stolberg
11585b2f86
Merge pull request #171 from Niklp09/flb_list_del_if_empty
Don't serialize empty tables when saving flb lists
2024-06-30 10:47:50 +02:00
Eternal-Study
a3d77f5ff1
Add Salt.lua
Add new reactor recipes for salt and adds salt to powdered group.
2024-06-29 20:31:37 -04:00
Eternal-Study
46cd8b111d
Water to Salt + River Water Recipe
This pull requests adds a Water to River Water reactor recipe. If it detects a farming:salt node (as found in the Farming Redo mod) then it adds salt to the powder group, allowing it to be stored in silos, and changes the recipe to Water → Salt with River Water as a waste product.

It should be noted that issue [insert issue number here] must be resolved to implement this pull request, as otherwise nodes cannot be loaded into the silo, even if they are in the powder group. This pull request was tested with pull request [insert pull request number] implemented. Using another solution to issue [insert issue number here] may require updates to the pull request.

I release this code under the terms of AGPL v3, and transfer copyright to Joachim Stolberg.
2024-06-29 20:28:22 -04:00
Eternal-Study
0b84d478d7
Add or minetest.registered_nodes[name] to Silo powder check.
This pull request adds “or minetest.registered_nodes[name]” to the Silo powder check in line 131, permitting items in the powder group registered as nodes to be stored in the Silo. This improves interoperability with other mods by expanding the scope of items that can be stored, while still limiting it to the powder group.

It should be noted the powder check in lines 31-33 are noted affected by this pull request.

I release this code under the terms of AGPL v3, and transfer copyright to Joachim Stolberg.
2024-06-29 19:55:00 -04:00
Niklp
33c045fafb
Replace deprecated meta:set_string(*, nil) calls 2024-06-29 17:16:22 +02:00
Niklp
747bd7bfac
Don't serialize empty tables when saving flb lists 2024-06-29 16:07:49 +02:00
Joachim Stolberg
653e76c165 Add new button commands 2024-05-31 20:36:44 +02:00
Joachim Stolberg
a62f883d36 Improve command interface 2024-05-30 20:22:59 +02:00
Joachim Stolberg
bf5c5bb919 Enable recipes with input items with metadata as templates 2024-05-25 21:45:41 +02:00
Joachim Stolberg
9eb8e75efb Fix bug with injector and a full 8x2000 chest 2024-05-20 09:40:42 +02:00
Joachim Stolberg
1489fc26f3
Merge pull request #169 from Niklp09/flb_fs_list
Fix forceload block formspec list
2024-05-20 09:33:37 +02:00
Niklp
eed4d46d87
Fix forceload block formspec list 2024-05-20 00:13:13 +02:00
Joachim Stolberg
ac286776e3
Merge pull request #168 from Niklp09/nbox_low_power_box
Improve `techage:ta4_power_box` node_box
2024-05-01 11:06:10 +02:00
Niklp
c2c0686d07
Improve techage:ta4_power_box node_box 2024-04-30 21:43:48 +02:00
Joachim Stolberg
ab66660b32 Fix bug with detectors and full chests 2024-04-30 18:13:30 +02:00
Joachim Stolberg
5f0ddb211c Fix bug with detectors and full chests 2024-04-28 20:02:22 +02:00
Joachim Stolberg
bd7368a412 Fix bug with shop and injectors 2024-04-28 19:14:26 +02:00
Joachim Stolberg
a181f9524f Allow to move the TA4 terminal with the assembly tool (#165) 2024-04-20 15:44:56 +02:00
Joachim Stolberg
db28d18137
Merge pull request #166 from jfanjoy/feature/techpack-aluminum
add aluminum recipes for techpack_stairway items
2024-04-10 17:40:53 +02:00
John Fanjoy
368544046f add aluminum recipes for techpack_stairway items 2024-04-05 11:11:14 -04:00
Joachim Stolberg
064e9d0f26
Merge pull request #164 from Niklp09/replace_blanktile
Replace `techage_invisible.png` w/ engine provided `blank.png`
2024-04-03 18:38:09 +02:00
Joachim Stolberg
69cc7bff27
Merge pull request #163 from jfanjoy/feature/verify-forceload-blocks
adds a new chat command and column to forceload formspec
2024-04-03 18:37:54 +02:00
Niklp
65c6d0adbc
Replace techage_invisible.png w/ engine provided blank.png 2024-04-02 22:16:57 +02:00
John Fanjoy
6bfc943b01 adds a new chat command and column to forceload formspec 2024-04-01 16:41:02 -04:00
Joachim Stolberg
0b50136116 Fix bug #24 (Energy Storage respawn red gravel infinit) 2024-03-24 10:14:11 +01:00
Joachim Stolberg
aa7cdfba6e Error on load image on manual pt-BR #158 2024-03-24 10:02:00 +01:00
Joachim Stolberg
8b80ddab24
Merge pull request #159 from Niklp09/screwdriver_anvil
Allow TA3 screwdriver to get repaired by anvil
2024-03-24 09:48:46 +01:00
Niklp
66a3977c9f
Allow TA3 screwdriver to get repaired by anvil 2024-03-16 21:41:38 +01:00
Joachim Stolberg
77ee9928b7 Add translations and fix bug with growlight 2024-02-24 17:07:51 +01:00
Joachim Stolberg
ad2fa9d756 Add manual for pt-BR language 2024-02-04 21:39:16 +01:00
Joachim Stolberg
8ab2835141 Add reverse mode for ta5 pump 2024-01-21 12:36:44 +01:00
Joachim Stolberg
6b07399bf3 Fix issue #125 (Improve forceload formspec) 2024-01-21 11:55:48 +01:00
Joachim Stolberg
ccd017b665 Fix texture issoes 2024-01-21 11:55:48 +01:00
Joachim Stolberg
eea5c1a4ef Fix texture issoes 2024-01-21 11:55:48 +01:00
Joachim Stolberg
bb749c5eb2 Fix texture issoes 2024-01-21 11:55:48 +01:00
Joachim Stolberg
4e4445ff4e
Merge pull request #155 from Niklp09/master
Generate new randomseed after use
2023-12-30 11:32:32 +01:00
Niklp
a9c842897c Generate new randomseed after use 2023-12-28 22:00:12 +01:00
Joachim Stolberg
44720ca6ae Add some line breaks 2023-12-26 17:05:57 +01:00
Joachim Stolberg
63310ed33d Fix assembly tool bug with non-empty chests 2023-12-25 21:55:45 +01:00
Joachim Stolberg
7bb16c6a73 Typo 2023-11-11 18:58:34 +01:00
Joachim Stolberg
fad059c1bf Fix #151 (crash on 'test X') 2023-11-11 18:38:08 +01:00
Joachim Stolberg
11c3dea912 Techage v1.18 2023-11-05 13:11:32 +01:00
Joachim Stolberg
4e77cfab70
Merge pull request #150 from alwayshopeless/patch-2
Water mill river water bug fix
2023-11-05 00:43:07 +01:00
alwayshopeless
a5634c7a75
Water mill river water bug fix 2023-11-04 13:44:04 +02:00
Joachim Stolberg
f5becb1eb8 Fix #148 (Collider documentation is hard to follow) 2023-11-01 18:17:18 +01:00
Joachim Stolberg
2a157dc825 Fix #148 (Collider documentation is hard to follow) by means of:
- Remove the gas connection on the back of the magnets
- Add code to turn legacy magnets to the right direction
- Improve manual
2023-11-01 18:12:00 +01:00
Joachim Stolberg
2c16b9d01f Fix #147 (Sea level might not be y==1 for water inlets) 2023-11-01 18:10:58 +01:00
Joachim Stolberg
c81f62fd39 Fix concentrator blocking bug 2023-10-22 16:33:09 +02:00
Joachim Stolberg
6042a9d30a Allow further types of cobblestone for the coalburner 2023-10-22 11:25:14 +02:00
Joachim Stolberg
4ed5d7494f Improve description 2023-10-14 14:24:44 +02:00
Joachim Stolberg
d0e9d0b656 Improve description 2023-10-13 13:50:25 +02:00
Joachim Stolberg
1838507521 Fix burn time issue 2023-10-13 13:49:57 +02:00
Joachim Stolberg
7a99d7c0ad Add function to allow to disable a block from being removed by the assembly tool 2023-09-29 19:40:25 +02:00
Joachim Stolberg
a347405150 Add storesize command 2023-09-27 19:27:49 +02:00
Joachim Stolberg
5b94e40243
Merge pull request #146 from Niklp09/creative_check
Use proper player creative check
2023-09-24 10:01:11 +02:00
Niklp09
ae9458aa45 Use proper player creative check 2023-09-23 21:54:10 +02:00
Joachim Stolberg
bc6697a8cc Optimize recipe command 2023-09-17 18:47:48 +02:00
Joachim Stolberg
cb11941f30
Merge pull request #144 from Niklp09/converter_fix
Fix converter stores mesecon signals
2023-09-17 13:48:20 +02:00
Niklp09
ae52a9242d Fix converter stores mesecon signals 2023-09-17 10:26:12 +02:00
Joachim Stolberg
908678e840 Add new assembly tool 2023-09-16 21:03:46 +02:00
Joachim Stolberg
5a0aadc063 Add flush command 2023-09-16 12:04:43 +02:00
Joachim Stolberg
18bd475a5d Add flush command 2023-09-16 12:04:17 +02:00
Joachim Stolberg
38946d6d84 Add flush command 2023-09-16 12:03:57 +02:00
Joachim Stolberg
957466f2e1 Unify wrench menu for generators 2023-09-05 21:26:15 +02:00
Joachim Stolberg
b32d22b0c8 Add arrow on the bottom 2023-09-05 21:26:15 +02:00
Joachim Stolberg
4f4c370358 Add Beduino command interface 2023-09-05 21:26:15 +02:00
Joachim Stolberg
a946658b3b
Merge pull request #143 from Niklp09/tr_fix
Escape equal sign in german translation
2023-09-01 20:03:21 +02:00
Niklp09
73fadb4fc3 Escape equal sign in german translation 2023-09-01 11:48:24 +02:00
Joachim Stolberg
7871b81c2a Allow rotation with a screwdriver 2023-08-28 17:03:17 +02:00
Joachim Stolberg
14440f0cad Improve manual 2023-08-28 10:35:55 +02:00
Joachim Stolberg
aee918d025 Improve TA2 clutch 2023-08-27 20:18:55 +02:00
Joachim Stolberg
9111d7287c Add TA2 clutch 2023-08-26 21:27:56 +02:00
Joachim Stolberg
92039b3a83 Add TA2 clutch 2023-08-26 21:26:22 +02:00
Joachim Stolberg
ae8d2d3d09 Add TA2 clutch 2023-08-26 19:37:03 +02:00
Joachim Stolberg
c7ac277d40 Add TA2 clutch 2023-08-26 17:55:12 +02:00
Joachim Stolberg
b258057317 Add generator menu to TA5 generator 2023-08-26 10:25:18 +02:00
Joachim Stolberg
a740837b30
Merge pull request #142 from debiankaios/inv_name_prefix
Added inv_name_prefix
2023-08-24 17:50:08 +02:00
debiankaios
fffc542ac6
Added inv_name_prefix 2023-08-23 21:26:53 +02:00
Joachim Stolberg
4a5ad68054 format issue 2023-08-21 20:32:53 +02:00
Joachim Stolberg
d6157087f1 Adapt to lcdlib 1.03 2023-08-20 21:46:31 +02:00
Joachim Stolberg
2dc3f24f1c Fix manual issues, increase version to v1.17 2023-08-20 14:22:40 +02:00
Joachim Stolberg
6b77916afa Fix minor bugs and adapt mod to the new lcdlib mod 2023-08-19 17:58:58 +02:00
Joachim Stolberg
56b8e2bef6 Fix image format bug 2023-08-19 15:26:07 +02:00
Joachim Stolberg
6189fde452 Fix texture issues 2023-08-18 17:53:48 +02:00
Joachim Stolberg
56197d229b Add support for doclib 2023-08-18 17:30:55 +02:00
Joachim Stolberg
366913ac58 Fix LICENCSE file bug 2023-07-31 21:05:17 +02:00
Joachim Stolberg
e12ba852cf Fix texture bug 2023-07-20 18:59:24 +02:00
Joachim Stolberg
f737be9a38 Remove needless code 2023-07-20 18:57:40 +02:00
Joachim Stolberg
7947d23719
Merge pull request #138 from Niklp09/quarry_log
log position of coroutine errors
2023-07-20 18:43:53 +02:00
Niklp09
0f8846d6f6 log position of coroutine errors 2023-07-15 13:09:29 +02:00
Joachim Stolberg
ec34c87b97 Add digging depth 7 2023-07-02 19:23:29 +02:00
Joachim Stolberg
a2cba47c63
Merge pull request #136 from realmicu/master
Add beduino support for TA3 repeater
2023-07-02 18:39:39 +02:00
Michal Cieslakiewicz
cf3b525529 Add beduino support for TA3 repeater 2023-07-01 21:26:04 +02:00
Joachim Stolberg
f68260310b v1.16 2023-06-30 15:12:36 +02:00
Joachim Stolberg
d85de971a7 Add TA4 node detector 2023-06-30 14:30:15 +02:00
Joachim Stolberg
cbd8b0ca52 Add wrench menu to TA3 button 2023-06-30 10:25:50 +02:00
Joachim Stolberg
39d13286d9 Add arrows to the pump bottom and allow to turn the pump with the Techage Screwdriver 2023-06-30 10:15:11 +02:00
Joachim Stolberg
5b0be32db3 Fix bug with configurred TA4 chest and TA5 teleport tubes 2023-06-30 09:57:08 +02:00
Joachim Stolberg
4206875f23 Fix the possible server crash error 2023-06-30 09:56:13 +02:00
Joachim Stolberg
3b51e1d557 Fix water placement issue 2023-06-24 09:47:17 +02:00
Joachim Stolberg
e262cccdfe Undo last bug fix 2023-06-24 08:03:38 +02:00
Joachim Stolberg
b1efedb55f Improve gaze sensor 2023-06-23 21:54:39 +02:00
Joachim Stolberg
356e8310d8 Fix typo 2023-06-23 15:31:50 +02:00
Joachim Stolberg
780b39d23c Enable the use as elevator winch 2023-06-23 15:31:20 +02:00
Joachim Stolberg
af5038387a Fix typo 2023-06-23 15:30:40 +02:00
Joachim Stolberg
99645642c2 Add dirt blocks to the list of simple nodes 2023-06-20 21:43:56 +02:00
Joachim Stolberg
f9035e4aea Fix quarry depth bug 2023-06-20 21:41:30 +02:00
Joachim Stolberg
f602a502bb Add chat message if block can't be moved 2023-06-13 19:23:44 +02:00
Joachim Stolberg
f7863333d5 Prevent triggering when player has open-end wrench in hand 2023-06-10 16:59:46 +02:00
Joachim Stolberg
947a31f350 Prevent triggering when player has open-end wrench in hand 2023-06-10 16:53:09 +02:00
Joachim Stolberg
4d33f5f034 Improve the behaviour 2023-06-10 16:49:15 +02:00
Joachim Stolberg
d6be0812c4 Add flip-flop 2023-06-09 16:31:22 +02:00
Joachim Stolberg
9210bce637 Add TA3 Command Converter and TA4 Gaze Sensor 2023-06-09 15:43:48 +02:00
Joachim Stolberg
e9ddfee834 Fix flycontroller bug #134 2023-06-09 13:26:54 +02:00
Joachim Stolberg
a7449c86ab Add TA3 Command Converter and TA4 Gaze Sensor 2023-06-08 21:41:27 +02:00
Joachim Stolberg
7872915be3 Add TA3 Command Converter and TA4 Gaze Sensor 2023-06-08 21:16:22 +02:00
Joachim Stolberg
d758751ee0 Add TA3 Command Converter and TA4 Gaze Sensor 2023-06-08 21:09:27 +02:00
Joachim Stolberg
4b164afca3 Change event behavior 2023-05-29 16:52:07 +02:00
Joachim Stolberg
84971f05b3 Fix node state bug 2023-05-29 16:51:07 +02:00
Joachim Stolberg
97936102c3 Add 'current' command to the TA4 Electric Meter 2023-05-21 17:54:38 +02:00
Joachim Stolberg
301d20aaf1 Fix some typos (Thanks to Gorm) 2023-05-20 13:49:32 +02:00
Joachim Stolberg
6a92a72e14 Fix runtime error, occuring when top of a TA5 heat exchanger is removed 2023-05-20 13:36:14 +02:00
Joachim Stolberg
1e007f2f0e Add hint to the water consumption of the steam engine 2023-05-18 19:58:00 +02:00
Joachim Stolberg
9d48746093 Make manual corrections 2023-05-18 19:28:41 +02:00
Joachim Stolberg
3669ef0f96 Improve fusion reactor checks 2023-05-18 18:32:08 +02:00
Joachim Stolberg
0f7814034d Add energy storage charge detector 2023-05-17 22:02:17 +02:00
Joachim Stolberg
dac5872e8c Fix issue with dst inventory 2023-05-17 22:02:17 +02:00
Joachim Stolberg
3cc2a01779 Fix bug with pump limit via commands 2023-05-17 22:02:16 +02:00
Joachim Stolberg
11944f7aba
Update ta4_lua_controller_EN.md 2023-05-15 20:54:14 +02:00
Joachim Stolberg
14136ff363
Update ta4_lua_controller_EN.md
Fix link bug
2023-05-15 20:53:50 +02:00
Joachim Stolberg
37a3e1398e Add some num/string corrections 2023-05-15 20:51:04 +02:00
Joachim Stolberg
240ab79203 Fix typo 2023-05-14 18:01:27 +02:00
Joachim Stolberg
6e2ed8071b Add lua example for TA4 4x Button 2023-05-14 15:41:49 +02:00
Joachim Stolberg
d5c63a8e56 Fix controller stop command bug 2023-05-14 15:40:45 +02:00
Joachim Stolberg
d8caf09cf7 Reduce the waiting time for experience points 2023-05-14 15:40:04 +02:00
Joachim Stolberg
125e5ad689 Reduce the waiting time for experience points 2023-05-14 15:39:48 +02:00
Joachim Stolberg
2d39171b1f Fix minor manual issues 2023-05-09 18:40:37 +02:00
Joachim Stolberg
5b5d5b57ac Fix minor manual issues 2023-05-06 19:11:12 +02:00
Joachim Stolberg
d2cd7fff27 Change the recipe to prevent an infinite cobble source 2023-05-06 19:10:39 +02:00
Joachim Stolberg
6ee7306e90 Fix the bug with hyperloop dependency 2023-05-06 18:40:15 +02:00
Joachim Stolberg
65852f2035 Set version to 1.15 2023-05-05 21:55:20 +02:00
Joachim Stolberg
a7cbf6924d Add further energy storage sizes 2023-05-05 21:41:23 +02:00
Joachim Stolberg
a93ef1db2c Add bucket register function 2023-05-05 20:58:04 +02:00
Joachim Stolberg
1c86092894 Add hyperloop chest only if the hyperloop mod is available 2023-05-05 19:41:16 +02:00
Joachim Stolberg
dabccff9b0 Add missing 'minetest.formspec_escape' (#131) 2023-04-30 12:56:08 +02:00
Joachim Stolberg
9de42a5a66 Fix bug "Trouble with flycontroller #130" 2023-04-27 19:43:40 +02:00
Joachim Stolberg
86ff66684c
Merge pull request #129 from orwell96/patch-1
Add optional dependency on farming mod
2023-04-25 18:59:33 +02:00
orwell96
9ebb3a9f6f
Add optional dependency on farming mod
While trying out techage_modpack, I noticed that the TA1 mill doesn't have any recipes registered. I could eventually track it down to the following:
- At load time, if techage gets loaded before farming, the registration for the wheat recipes (in the mill) is skipped
- Changing the global_exists() to a get_modpack() doesn't remedy the issue as add_grinder_recipe() checks for item existence
Soft-depending on farming remedies the issue and the mill works normally.
2023-04-24 22:20:45 +02:00
Joachim Stolberg
dbae9bd8e4
Merge pull request #127 from Niklp09/ffs
fix forceload formspec receiver
2023-04-23 11:30:35 +02:00
Niklp09
7bdd00c019 fix forceload formspec receiver 2023-04-18 13:11:53 +02:00
Joachim Stolberg
09e48c4084 Update version to v1.14 2023-04-16 15:12:55 +02:00
Joachim Stolberg
fc80a90ff2 Add API manual 2023-04-16 15:08:05 +02:00
Joachim Stolberg
05670352c6 Add API function register_ore_for_gravelsieve 2023-04-16 15:07:29 +02:00
Joachim Stolberg
9e1ae22bf4 Add support for the game Asuna (#126) 2023-04-13 20:20:58 +02:00
Joachim Stolberg
9e226d6d8a Remove teleport mode for move controller 2023-04-11 12:49:56 +02:00
Joachim Stolberg
66a4c3ae7f Fix manual issue #123 2023-04-11 11:05:15 +02:00
Joachim Stolberg
a3079dae78
Merge pull request #124 from Niklp09/drops
fix unknown item drops
2023-04-11 11:00:42 +02:00
Niklp09
f0c0ee3d75 fix unknown item drops 2023-04-11 10:44:21 +02:00
Joachim Stolberg
109c5c371e Fix keep node number issue 2023-04-10 16:52:24 +02:00
Joachim Stolberg
a932296420 Add "Teleport mode" to ta4 move and ta5 fly controller 2023-04-10 16:32:41 +02:00
Joachim Stolberg
b2ad9f3058 Fix use of deprecated field name in some tile definitions #12 2023-04-07 10:51:33 +02:00
Joachim Stolberg
bf33f47b2c Fix texture flipping issues 2023-04-03 19:39:39 +02:00
Joachim Stolberg
7051da903e v1.12 2023-04-01 19:19:53 +02:00
Joachim Stolberg
e5fc8a4b8a Add version command 2023-04-01 19:19:29 +02:00
Joachim Stolberg
062b3f5fef fix overload bug, fix missing dominant 'on' issue 2023-04-01 19:10:14 +02:00
Joachim Stolberg
2e24ccbdcd Disable inventory access on client side due to minetest core issues 2023-04-01 19:09:04 +02:00
Joachim Stolberg
1fcadc9ff7 Fix bug with reset button 2023-03-28 18:34:54 +02:00
Joachim Stolberg
c3a492cb89 Add craftable and invisible move block 2023-03-28 18:33:43 +02:00
Joachim Stolberg
6159ccaa96 Add craftable and invisible move block 2023-03-21 20:00:26 +01:00
Joachim Stolberg
d92c2a7b91 Fix ta4 pusher counting bug 2023-03-20 20:09:58 +01:00
Joachim Stolberg
774d0d2e42 Add running state 2023-03-19 17:05:03 +01:00
Joachim Stolberg
f84b040346 Increase player inventory to 8x4 for the filler 2023-03-19 11:53:27 +01:00
Joachim Stolberg
15e021e2ed fix bug with ta3 node_detector and wielded_light nodes 2023-03-19 11:46:23 +01:00
Joachim Stolberg
279b876087
Merge pull request #120 from Niklp09/aliases
add an option to disable stair aliases
2023-03-19 10:52:22 +01:00
Niklp09
45357e2980 add an option to disable stair aliases 2023-03-13 14:11:08 +01:00
Joachim Stolberg
41b82454c4 Improve transformer and electricmeter:
Transformer:
- add wrench menu for 'max. power passed through'
- Increase max. power passed through from 100 to 300 ku

Electricmeter:
- add wrench menu for 'max. power passed through' and 'power countdown'
- add commands to read the countdown value (Lua and Beduino controller)
2023-03-05 22:06:48 +01:00
Joachim Stolberg
37f6462673 Improve transformer and electricmeter 2023-03-05 21:44:35 +01:00
Joachim Stolberg
e95949ae04 Update history 2023-03-05 11:51:03 +01:00
Joachim Stolberg
6e193f57ae Fix paramtype/use_texture_alpha issue 2023-03-05 11:39:01 +01:00
Joachim Stolberg
b40447ed95 fix issue #119 (Possible Bug in techage:ta4_display) 2023-03-05 11:34:34 +01:00
Joachim Stolberg
57f5a3594b Reduce the number of necessary exp points 2023-02-28 21:12:57 +01:00
Joachim Stolberg
4c3e73b3f9 Try to fix kernel crashes 2023-02-27 19:57:56 +01:00
Joachim Stolberg
460cc7eefd Fix another chest chain bug 2023-02-27 19:57:36 +01:00
Joachim Stolberg
1a861c7f15 Try to fix kernel crashes 2023-02-27 19:57:28 +01:00
Joachim Stolberg
71a024649a Try to fix kernel crashes 2023-02-27 19:57:24 +01:00
Joachim Stolberg
93c004132f Rework doorcontroller 2023-02-26 21:01:50 +01:00
Joachim Stolberg
30b0a51209 Rework doorcontroller 2023-02-26 19:56:14 +01:00
Joachim Stolberg
82d9d6de55 Increase tank cart storage size to 200 2023-02-20 20:57:42 +01:00
Joachim Stolberg
e068a39c4d Fix paramtype/use_texture_alphaissue 2023-02-20 20:57:07 +01:00
Joachim Stolberg
2826423e5b Add command 'load' to the TA4 power terminal 2023-02-19 21:29:07 +01:00
Joachim Stolberg
a53ab04ca2 Add beduino tank commands 2023-02-19 19:23:38 +01:00
Joachim Stolberg
354dcf2684 Fix command on/off bug 2023-02-19 19:07:28 +01:00
Joachim Stolberg
6d9c9bb51f Improve power terminal 2023-02-19 16:47:06 +01:00
Joachim Stolberg
66937f5743 Fix power consumption bug for a stopped collider 2023-02-19 15:11:43 +01:00
Joachim Stolberg
77181cbc3b Fix electrolyzer formspec bug 2023-02-19 10:54:13 +01:00
Joachim Stolberg
633e1e987d
Merge pull request #118 from Niklp09/autocrafter
fix sigsegv's due autocrafter
2023-02-16 16:53:34 +01:00
Niklp09
c7c61d05fb fix sigsegv's due autocrafter 2023-02-15 18:17:00 +01:00
Joachim Stolberg
68a8555825 Fix doser goes blocked bug 2023-02-12 21:30:12 +01:00
Joachim Stolberg
83b2bd483f Add missing translations 2023-02-12 17:56:38 +01:00
Joachim Stolberg
d82ae0c86e Add Rack and pinion node 2023-02-12 17:53:46 +01:00
Joachim Stolberg
b8009dd2ab Add Rack and pinion node 2023-02-12 17:46:03 +01:00
Joachim Stolberg
b759386016 Expand sequencer wrench menu 2023-02-12 11:53:09 +01:00
Joachim Stolberg
228b2d39cc Expand sequencer wrench menu 2023-02-12 11:50:43 +01:00
Joachim Stolberg
8fcd4ef70b Expand sequencer wrench menu 2023-02-12 11:50:31 +01:00
Joachim Stolberg
50d9816fa7 Expand sequencer wrench menu 2023-02-12 11:50:21 +01:00
Joachim Stolberg
7ac25a098d Add cement block to the saw 2023-02-11 18:41:21 +01:00
Joachim Stolberg
f8e47ed4b1 Allow to move objects 'without' a move block 2023-02-11 18:00:27 +01:00
Joachim Stolberg
4a09dc785f Add empty_spool as fab output 2023-02-11 17:15:46 +01:00
Joachim Stolberg
b85e325cd5 Fix doser goes blocked bug 2023-02-11 11:45:04 +01:00
Joachim Stolberg
8c5adfdd50 Flip texture (issue #116) 2023-02-08 18:33:54 +01:00
Joachim Stolberg
f141588818 Fix bug 'nvmstack' (a nil value) 2023-02-07 20:04:59 +01:00
Joachim Stolberg
078069baf6 Fix movecontroller bug when carts are running in both directions 2023-02-06 17:42:25 +01:00
Joachim Stolberg
07fcfafedf Remove handover description 2023-02-06 16:33:23 +01:00
Joachim Stolberg
c95e3e7b50 Accept mincart carts for the move controller 2023-02-05 19:34:08 +01:00
Joachim Stolberg
46d2ae91aa Accept mincart carts for the move controller 2023-02-05 18:14:01 +01:00
Joachim Stolberg
39cbeea15e Update to v1.10 2023-02-04 15:43:26 +01:00
Joachim Stolberg
7cfc5c3840 Improve flycontroller, remove handover for movecontroller 2023-02-04 15:32:05 +01:00
Joachim Stolberg
baea3f137f Fix 2 flycontroller bugs 2023-02-02 19:22:37 +01:00
Joachim Stolberg
14f7c8718c Fast fix for #115: bad argument #1 to 'pairs' (table expected, got nil) 2023-01-29 16:47:07 +01:00
Joachim Stolberg
8bb62a4abc Fix the 'lpos1 (a nil value)' bug 2023-01-28 11:12:04 +01:00
Joachim Stolberg
9a03cd86d2 Fix node number register issue 2023-01-27 17:24:05 +01:00
Joachim Stolberg
d8d655e516 Use repairkit to reactivate broken techage nodes 2023-01-24 21:24:14 +01:00
Joachim Stolberg
436fec17d2 Fix beduino command issue 2023-01-24 19:10:31 +01:00
Joachim Stolberg
2d71d06dc5 Fix bug #107 (Blocks not rendering properly) 2023-01-23 17:17:37 +01:00
Joachim Stolberg
80d4edb99c Update manual 2023-01-23 17:14:52 +01:00
Joachim Stolberg
11f4cf6eeb Rename to color lamp 2023-01-23 17:12:10 +01:00
Joachim Stolberg
29a2e404ed Rename to color lamp 2023-01-23 17:11:44 +01:00
Joachim Stolberg
aa466d3827 Rename to color lamp 2023-01-23 17:10:52 +01:00
Joachim Stolberg
8592d65589 Rename to color lamp 2023-01-23 17:09:42 +01:00
Joachim Stolberg
ab9e7040d5 Add state command 2023-01-23 17:07:45 +01:00
Joachim Stolberg
39b7ca719d Fix bakedclay recipe conflict 2023-01-14 20:49:48 +01:00
Joachim Stolberg
26558ce1eb Fix some beduino command issues 2023-01-08 14:00:47 +01:00
Joachim Stolberg
71d0d6f012 Fix unremovable ta4_chest_dummy bug 2023-01-08 14:00:47 +01:00
Joachim Stolberg
a88a07e421
Merge pull request #110 from Niklp09/dump
disable flowers table dump
2023-01-07 17:45:44 +01:00
Niklp09
c858c56ec9 disable flowers table dump 2023-01-07 15:24:08 +01:00
Joachim Stolberg
b92e746e18 Add countdown mode to TA4 Detector 2023-01-05 12:57:26 +01:00
Joachim Stolberg
7b2f10e915 Add some missing recipes 2023-01-05 09:52:09 +01:00
Joachim Stolberg
c042115cbb
Merge pull request #108 from Niklp09/growlight
glowlight: register flowers only once
2023-01-04 22:34:21 +01:00
Joachim Stolberg
51c71d499f Adapt to new beduino and minecart versions 2023-01-04 22:28:32 +01:00
Niklp09
4d73d3fdf2 glowlight: register flowers only once 2023-01-04 13:38:08 +01:00
Joachim Stolberg
638993b49b Fix sound bug 2023-01-04 10:12:20 +01:00
Joachim Stolberg
b59567aab1 Replace blanks with tabs 2023-01-03 17:24:27 +01:00
Joachim Stolberg
8b1a4f8dcf Add missing recipe 2023-01-03 17:23:21 +01:00
Joachim Stolberg
74593fa150 Fix sound bug 2023-01-03 17:22:57 +01:00
Joachim Stolberg
c69cb294a0 Add wafer recipe with 'mesecons_materials:silicon' 2022-12-31 10:49:25 +01:00
Joachim Stolberg
c1645fc9b9 Add TA5 AI Chip II to the manual 2022-12-30 19:05:30 +01:00
Joachim Stolberg
d78004cef3 Fix movecontroller wrench menu bug 2022-12-11 09:49:00 +01:00
Joachim Stolberg
b9072c7940 Improve chemical reactor description 2022-12-10 13:47:09 +01:00
Joachim Stolberg
4cb7ffe718 Improve player detector wrench menu 2022-12-10 12:38:15 +01:00
Joachim Stolberg
ac01df763d Fix 'count' command bug: default value is 0 again 2022-12-10 11:09:27 +01:00
Joachim Stolberg
dc899e1bd1 Allow moving blocks through unloaded areas 2022-12-09 21:19:22 +01:00
Joachim Stolberg
c6afb4a173 Remove EOL blanks 2022-12-09 21:17:21 +01:00
Joachim Stolberg
446de79704 Allow moving blocks through unloaded areas 2022-12-09 21:17:01 +01:00
Joachim Stolberg
902fabd148 Allow moving blocks through unloaded areas 2022-12-06 18:43:10 +01:00
Joachim Stolberg
29e542eb74 Add wrench menu to configure search radius 2022-12-02 20:30:00 +01:00
Joachim Stolberg
2b541d0197 Place unloaded flying blocks to dest pos 2022-12-02 20:29:38 +01:00
Joachim Stolberg
c83da97df5 Add wrench menu to configure search radius 2022-12-02 20:24:19 +01:00
Joachim Stolberg
7a4a446d82 Furnace: Don't use items filled from the top as fuel 2022-11-21 21:50:37 +01:00
Joachim Stolberg
c98258238b Manual improvements for the move controller 2022-11-19 21:44:38 +01:00
Joachim Stolberg
c47c6aa54c Make a use for cotton seeds #104 2022-11-19 21:20:29 +01:00
Joachim Stolberg
fca2faaeef
Merge pull request #102 from Niklp09/mvps2
fix broken mesecons detection
2022-11-16 12:54:41 +01:00
Niklp
c127297254
fix broken mesecons detection 2022-11-14 20:00:00 +01:00
Joachim Stolberg
f14e93e17a Fix bug with TA1 hammer used by pipeworks nodebreaker 2022-11-13 12:01:58 +01:00
Joachim Stolberg
99b2f8f0c5 Fix bug with TA1 hammer used by pipeworks nodebreaker 2022-11-07 21:38:18 +01:00
Joachim Stolberg
41c4492ca6
Merge pull request #99 from Niklp09/mvps
register mvps stopper for complex techage nodes
2022-11-06 11:39:49 +01:00
Niklp
554d79b740
use global_exist to check if mesecons is available 2022-11-06 11:19:15 +01:00
Niklp09
75dca89737 register mvps stopper for complex techage nodes 2022-11-05 14:54:00 +01:00
Joachim Stolberg
18d06994bc
Merge pull request #98 from Niklp09/glow_gravel
add not in creative inv group to grow gravel
2022-11-01 20:28:39 +01:00
Joachim Stolberg
f70c58d356 Fix hammer bauxite bug 2022-10-29 20:51:33 +02:00
Joachim Stolberg
f9a582af5e fix server crash 2022-10-29 20:50:06 +02:00
Niklp
e849077e52
add not in creative inv group to grow gravel 2022-10-23 16:25:16 +02:00
Joachim Stolberg
416126f80c fix mesecons_materials bug 2022-10-18 16:39:26 +02:00
Joachim Stolberg
2dedba04b1 add cracking recipe for isobutane 2022-10-18 14:12:51 +02:00
Joachim Stolberg
7e7642a96f
Merge pull request #96 from Niklp09/ethereal
grind ethereal leaves to leave powder
2022-10-12 17:25:16 +02:00
Niklp
6bebc47f84
grind ethereal leaves to leave powder 2022-10-01 18:04:55 +02:00
Joachim Stolberg
6cc1f75d15 Improve manual, fix bug in electrolyzer menu description 2022-10-01 15:49:28 +02:00
Joachim Stolberg
4469dd128c Add 'on button' mode to the button 2022-09-18 11:53:51 +02:00
Joachim Stolberg
742fc51dc0 Add wrench menu to ta4_sequencer 2022-09-17 19:30:56 +02:00
Joachim Stolberg
90f4e4da3f Add wrench menu to ta4_sequencer 2022-09-17 18:51:26 +02:00
Joachim Stolberg
0305ab20f4 Fix pusher and chest bugs 2022-09-17 16:21:57 +02:00
Joachim Stolberg
e2f72ca57e Improve TA4 button wrench menu 2022-09-16 19:30:49 +02:00
Joachim Stolberg
d3126bff70 Fix pusher bug 2022-09-14 18:24:49 +02:00
Joachim Stolberg
79cf2ba7af Fix TA4 pusher and flycontroller bugs 2022-09-13 21:13:09 +02:00
Joachim Stolberg
3ce0af9a3d Fix signallamp color bug 2022-09-12 17:15:51 +02:00
Joachim Stolberg
c57724dbd0 Add command to ta4_doser to change recipe, add pusher/hopper support for ta4_reactor inventory 2022-09-11 14:32:59 +02:00
Joachim Stolberg
2ea430d054 Update networks dependency 2022-09-10 20:46:25 +02:00
Joachim Stolberg
9f38cef427 Improve repairkit for pumps 2022-09-10 20:42:31 +02:00
Joachim Stolberg
680f411e04 Add chat command ta_color 2022-09-10 18:13:20 +02:00
Joachim Stolberg
70febea204 Add chat command ta_color 2022-09-10 18:06:41 +02:00
Joachim Stolberg
4f0cacb224 Add new signal lamp with color commands 2022-09-10 16:04:45 +02:00
Joachim Stolberg
4702f46b07 Fix issue #93 (slow down TA1 gravel sieve) 2022-09-10 16:03:42 +02:00
Joachim Stolberg
4378e42ef1 Fix issue #93 (slow down TA1 gravel sieve) 2022-09-10 15:51:43 +02:00
Joachim Stolberg
2b43e8a913 Remove test blocks 2022-09-04 21:49:00 +02:00
Joachim Stolberg
713f3675ab Fix move command bug in move controller 2022-09-04 20:05:18 +02:00
Joachim Stolberg
69aac18dc5 Add Flow Limiter mode to TA4 pusher 2022-09-04 18:25:03 +02:00
Joachim Stolberg
873a51e3db Add Flow Limiter mode to TA4 pusher 2022-09-04 18:05:37 +02:00
Joachim Stolberg
15a4765b6f Add Flow Limiter mode to TA4 pump 2022-09-03 19:22:43 +02:00
Joachim Stolberg
3426712006 Change behavior of push_items function 2022-09-02 21:12:25 +02:00
Joachim Stolberg
1182912724 Improve readme 2022-08-19 21:39:56 +02:00
Joachim Stolberg
e997fe797d Add distance check to ta4 movecontroller 2022-08-18 18:09:07 +02:00
Joachim Stolberg
ede42eefbd Add distance check to ta4 movecontroller 2022-08-18 18:06:55 +02:00
Joachim Stolberg
22495ad741 Improve readme 2022-08-18 14:38:10 +02:00
Joachim Stolberg
65e951a7ee Fix issue #90 (Disappearing tank contents) 2022-08-18 14:29:33 +02:00
Joachim Stolberg
25d5ca0a02 Fix issue #8 (techage uses 'mesecon' as a dependency instead of 'mesecons') 2022-08-18 14:27:02 +02:00
Joachim Stolberg
16c152e475
Merge pull request #89 from asl97/patch-1
Move box under textarea, fixes overlay blocking scrollbar
2022-08-16 15:40:16 +02:00
asl97
71380ffdf8
Move box under textarea, fixes overlay blocking scrollbar
Fixes #87
2022-08-12 16:31:14 +08:00
Joachim Stolberg
0c3f1f56a4 Fix node state request bug 2022-08-09 21:15:28 +02:00
Joachim Stolberg
c78ea7eb66 Fix ICTA controller bugs 2022-08-09 20:27:33 +02:00
Joachim Stolberg
c0a11e2477 Fix use_texture_alpha issues 2022-08-07 16:03:33 +02:00
Joachim Stolberg
1652b154b4 Add testblock 2022-08-05 17:48:47 +02:00
Joachim Stolberg
493422fb1b Fix minor issues 2022-08-03 22:19:46 +02:00
Joachim Stolberg
d61517ee3c Change beduino/move_controller limits 2022-08-02 13:28:32 +02:00
Joachim Stolberg
87dfe8e651 Fix use_texture_alpha issues 2022-07-11 20:20:00 +02:00
Joachim Stolberg
79ad815ed6 Fix use_texture_alpha issues 2022-07-11 20:16:23 +02:00
Joachim Stolberg
1219deb83d Fix beduino.counting bug 2022-07-08 22:24:37 +02:00
Joachim Stolberg
904d6559d3 Fix ICTA controller bug 2022-07-08 20:59:22 +02:00
Joachim Stolberg
7082e1ab0d Add time & name commands to the TA4 button 2022-07-03 16:07:38 +02:00
Joachim Stolberg
df6a526a99 Fix door controller issue 2022-06-25 10:28:32 +02:00
Joachim Stolberg
137e61b6ce Fix division with zero bug 2022-06-24 20:59:08 +02:00
Joachim Stolberg
b936024113 Minor improvements 2022-06-23 20:36:36 +02:00
Joachim Stolberg
998689aafd Fiy beduino command bug 2022-06-21 20:21:16 +02:00
Joachim Stolberg
3a593ff56f Add new config & get commands 2022-06-12 18:35:32 +02:00
Joachim Stolberg
ce839fead3 Add new config & get commands 2022-06-12 18:35:06 +02:00
Joachim Stolberg
07a7f2fffa Fix chest chain bug 2022-06-12 18:34:06 +02:00
Joachim Stolberg
e69e30bad8 Fix bug so that blocks don't respawn after an on/off command 2022-06-12 11:02:05 +02:00
Joachim Stolberg
5056a4a4fb Add 'get name' command to the door controller 2022-06-10 11:48:59 +02:00
Joachim Stolberg
f7d12dd79a Implement fly/door controller improvements 2022-06-10 10:59:59 +02:00
Joachim Stolberg
deb9678b54 Add key/value store for the beduino controller 2022-06-09 21:46:56 +02:00
Joachim Stolberg
6a71892799 Fix beduino command bugs 2022-06-09 12:59:17 +02:00
Joachim Stolberg
ff7e30a1c0 Improve TA4 movecontroller 2022-06-08 18:14:42 +02:00
Joachim Stolberg
acb54d7e8d Improve TA3 doorcontroller2 2022-06-07 22:32:03 +02:00
Joachim Stolberg
e2bd472408 Minor improvements 2022-06-07 19:14:43 +02:00
Joachim Stolberg
7bc1221249 Add support for beduino commands 2022-06-06 20:43:52 +02:00
Joachim Stolberg
24e91edc7e Add support for beduino commands 2022-06-06 20:39:55 +02:00
Joachim Stolberg
a0b637e4e9 Add support for beduino commands 2022-06-06 15:59:12 +02:00
Joachim Stolberg
abac1cce98 Add support for beduino commands 2022-06-05 21:23:17 +02:00
Joachim Stolberg
b6eeef358a Add support for beduino commands 2022-06-05 21:20:43 +02:00
Joachim Stolberg
ac33080404 Fix command interface bugs 2022-05-22 15:20:42 +02:00
Joachim Stolberg
90dd1c3bbe Make collider expoint waiting time adjustable 2022-05-07 17:05:19 +02:00
Joachim Stolberg
54ed4e60c5 Fix wind turbine and concentrator bugs 2022-05-06 23:02:22 +02:00
Joachim Stolberg
4570a10241 Fix bugs for ta5 heat exchanger and ta4 electronic fab 2022-05-03 21:08:35 +02:00
Joachim Stolberg
192d46c682
Merge pull request #83 from Thomas--S/sequencer-on-off
TA4 Sequencer: Add 'on' and 'off' commands
2022-05-03 20:34:40 +02:00
Thomas--S
806af873b4 TA4 Sequencer: Add 'on' and 'off' commands
Allows the sequencer to be used with buttons, for example.
2022-05-02 17:12:52 +02:00
Joachim Stolberg
47c391c679 Fix bug with unconfigured turncontroller 2022-04-26 22:35:28 +02:00
Joachim Stolberg
3309316b18 Fix bug #81 2022-04-25 18:58:08 +02:00
Joachim Stolberg
094d448386 Fix bug #82 2022-04-25 18:00:26 +02:00
Joachim Stolberg
2df3d3a523 Fix bug #81 2022-04-24 20:39:26 +02:00
Joachim Stolberg
8b0d340344 Fix collider remove bug 2022-03-21 20:49:22 +01:00
Joachim Stolberg
e0269da493 Fix ta3 lightdetector drop bug 2022-03-11 21:46:36 +01:00
Joachim Stolberg
3488bdfed1 Fix bug after server crash 2022-02-25 23:00:17 +01:00
Joachim Stolberg
622a26d575
Merge pull request #77 from joe7575/wizardofgcc/master
Wizardofgcc/master
2022-02-23 19:07:00 +01:00
Joachim Stolberg
e3cdb47f9e Add German translation 2022-02-23 19:01:38 +01:00
Konstantin Logashenko
dfa9f2c7cb Update md manual file for light detector (lua file not generated) and add item entry to doc/items.lua 2022-02-22 11:50:35 +03:00
Konstantin Logashenko
598b0b9b11 Revert "Add Construction Board documentation for light detector"
This reverts commit 93deeb33d6.

Revert manual documentation, to add automatically generated one instead
2022-02-22 11:33:52 +03:00
Konstantin Logashenko
93deeb33d6 Add Construction Board documentation for light detector 2022-02-21 21:48:58 +03:00
Konstantin Logashenko
1306c9a0ba Revert "Add documentation for light detector (only English)"
This reverts commit 39cb0e150a.
2022-02-21 21:37:07 +03:00
Konstantin Logashenko
155d926479 Merge branch 'master' of https://github.com/wizardofgcc/techage 2022-02-21 21:31:30 +03:00
Konstantin Logashenko
39cb0e150a Add documentation for light detector (only English) 2022-02-21 21:29:43 +03:00
wizardofgcc
a5ca593b02
Merge branch 'joe7575:master' into master 2022-02-21 21:15:34 +03:00
Konstantin Logashenko
877d754c6a Textures for light detector 2022-02-07 16:53:56 +03:00
Konstantin Logashenko
3837e5a22b Make sure to update the init too 2022-02-07 16:50:44 +03:00
Konstantin Logashenko
94389990ed Implement the light detector (detects light level of the node above) 2022-02-07 16:50:06 +03:00
Joachim Stolberg
bdc6074790 Fix teleport pipe pump bug 2022-02-01 19:11:00 +01:00
Joachim Stolberg
7281ec7af7 Fix 'controller will not start' bug 2022-01-30 11:31:58 +01:00
Joachim Stolberg
c60b242c5d Fix FR controller command interface error 2022-01-24 17:54:50 +01:00
Joachim Stolberg
7ef1a81420 Merge branch 'fusion_reactor' 2022-01-23 17:19:15 +01:00
Joachim Stolberg
532677020a Fix ceramic recipe and TA5 generator bugs 2022-01-23 16:44:11 +01:00
Joachim Stolberg
ce970279bf Fix ceramic recipe and TA5 generator bugs 2022-01-23 15:51:20 +01:00
Joachim Stolberg
5195bf23f4 Improve FR construction plan 2022-01-21 23:32:21 +01:00
Joachim Stolberg
53a0cfaa38 Improve FR construction plan 2022-01-21 23:15:02 +01:00
Joachim Stolberg
7f786860a1 Improve FR construction plan 2022-01-21 23:11:05 +01:00
Joachim Stolberg
59e2e630ee Improve FR construction plan 2022-01-21 21:44:04 +01:00
Joachim Stolberg
67ff7af651 Adapt manual for FR 2022-01-21 19:12:22 +01:00
Joachim Stolberg
428662e78d Adapt manual for FR 2022-01-21 18:55:32 +01:00
Joachim Stolberg
f6d4eba130 Add FR item recipes 2022-01-19 21:24:14 +01:00
Joachim Stolberg
4b98b92eef Add TA5 heat exchanger for the FR 2022-01-18 21:38:57 +01:00
Joachim Stolberg
76e83db072 Add TA5 heat exchanger for the FR 2022-01-12 20:50:18 +01:00
Joachim Stolberg
e9e5527516 Add TA5 heat exchanger for the FR 2022-01-10 21:39:36 +01:00
Joachim Stolberg
d010256b05 Fix two fly/move controller bugs 2022-01-10 21:36:54 +01:00
Joachim Stolberg
859be9954d Add first items of the fusion reactor 2022-01-07 22:35:12 +01:00
Joachim Stolberg
0f14d504d5 Fix fly controller 'move' bug 2022-01-07 17:29:56 +01:00
Joachim Stolberg
bea3f617d5 Add ta5 gas pipes 2022-01-07 17:25:28 +01:00
Joachim Stolberg
aedf234ae5 Allow to turn the concentrator with the new screwdriver 2022-01-06 10:13:18 +01:00
Joachim Stolberg
ca8929fa9d Allow to turn the pusher with the new screwdriver 2022-01-05 21:41:30 +01:00
Joachim Stolberg
d7f0dbc50d Add screwdriver tool 2022-01-05 13:43:22 +01:00
Joachim Stolberg
861a36f45c Add screwdriver tool 2022-01-05 12:48:36 +01:00
Joachim Stolberg
f8ca493a6b Fix ta5 hyperloop tank bug, EOF blank added 2022-01-04 19:40:27 +01:00
Joachim Stolberg
f96abd97b7 Improve manual 2022-01-04 10:46:55 +01:00
Joachim Stolberg
8a21364d4b delete EOL blanks 2022-01-03 21:40:31 +01:00
Joachim Stolberg
ae35581c61 Improve manual 2022-01-03 21:22:40 +01:00
Joachim Stolberg
950086aefb Rename teleport blocks 2022-01-03 11:40:45 +01:00
Joachim Stolberg
dab2199a58 Rename teleport blocks 2022-01-03 11:37:17 +01:00
Joachim Stolberg
8752abbf7c Add ta5 teleport pipes 2022-01-02 23:05:31 +01:00
Joachim Stolberg
4f41c338ff Add ta5 teleport pipes 2022-01-02 23:00:21 +01:00
Joachim Stolberg
577a4e8bd3 Add ta5 teleport tubes 2022-01-02 21:00:46 +01:00
Joachim Stolberg
9b02954efd Fix ta5 tank recipe bug 2022-01-02 10:33:02 +01:00
Joachim Stolberg
f2cf3934d7 Isobutane bugfix 2021-12-31 17:54:31 +01:00
Joachim Stolberg
91f5e8dfe7 update docu 2021-12-31 17:42:40 +01:00
Joachim Stolberg
fcc325a36a ta5 hyperloop tank addded 2021-12-31 17:28:12 +01:00
Joachim Stolberg
e2834a20ff ta5 hyperloop tank addded 2021-12-31 17:25:37 +01:00
Joachim Stolberg
8f037a4ec0 Add ta5 chest for hyperloop transfer 2021-12-30 15:05:20 +01:00
Joachim Stolberg
33cf08f136 Fix tank/chest ta5 menu bug 2021-12-29 12:36:42 +01:00
Joachim Stolberg
9200dc35e4 Improve manual and tank/chest menu 2021-12-29 11:55:04 +01:00
Joachim Stolberg
3bd07893dd Use isobutan instead of hydrogen for the collider 2021-12-28 14:16:47 +01:00
Joachim Stolberg
45479bf153 Support for i3 added 2021-12-25 17:18:34 +01:00
Joachim Stolberg
2fb526f54b Activate TA5, improve move/fly controller 2021-12-25 16:33:51 +01:00
Joachim Stolberg
79890c1c1b Activate TA5, improve move/fly controller 2021-12-25 16:12:09 +01:00
Joachim Stolberg
fd5b33e025 Improve move/fly controller 2021-12-24 16:05:04 +01:00
Joachim Stolberg
b75a9277b5 Improve collider, add further nodes to manual 2021-12-18 20:36:46 +01:00
Joachim Stolberg
7d76cd4717 Improve collider, add further nodes to manual 2021-12-18 20:11:34 +01:00
Joachim Stolberg
4c7e75279e Collider system added 2021-12-12 20:47:30 +01:00
Joachim Stolberg
cef31ea0cf Collider system added 2021-12-12 20:41:49 +01:00
Joachim Stolberg
dee6c47555 Collider system added 2021-12-11 20:15:55 +01:00
Joachim Stolberg
0e3a4d4bc7 Add new commands 2021-12-06 21:12:06 +01:00
Joachim Stolberg
fea1a6981c Add recipeblock and mba_detector, improve ta4 pump and ta4 autocrafter 2021-11-28 14:42:18 +01:00
Joachim Stolberg
a2d39706cf status command changed to state 2021-11-17 18:55:54 +01:00
Joachim Stolberg
8ba2eae70e status command changed to state 2021-11-17 18:55:42 +01:00
Joachim Stolberg
27fa1ee26e Improvements on move-, fly-, and turn controllers 2021-11-16 20:54:25 +01:00
Joachim Stolberg
793ef84a8c Improvements on move-, fly-, and turn controllers 2021-11-16 20:07:52 +01:00
Joachim Stolberg
5597836d06 Add fly and turn controllers 2021-11-15 19:26:59 +01:00
Joachim Stolberg
deab00aa07 Improve move-controller, remove 'move' command 2021-11-11 22:04:43 +01:00
Joachim Stolberg
b3ddc91489 Improve area protection check 2021-11-09 20:25:01 +01:00
Joachim Stolberg
82444021a9 Remove debug print lines 2021-11-07 16:02:55 +01:00
Joachim Stolberg
1698985cbc Add 2x-button, 2x- and 4x-signal-lamp 2021-11-06 20:15:17 +01:00
Joachim Stolberg
6e04374f89 Add 2x-button, 2x- and 4x-signal-lamp 2021-11-06 20:09:11 +01:00
Joachim Stolberg
c63ef4d557 Add a state command to the laser emitter 2021-11-05 22:13:08 +01:00
Joachim Stolberg
6a1beeaaec Add TA5 ex points feature for hyperloop tank and chest 2021-11-05 20:26:07 +01:00
Joachim Stolberg
9f645843ff bugfix 2021-11-05 19:25:34 +01:00
Joachim Stolberg
44cfa46e9f bugfix 2021-11-05 19:21:15 +01:00
Joachim Stolberg
cf3415a1d6 Add hyperloop support to ta4 chest and tank 2021-11-02 21:28:22 +01:00
Joachim Stolberg
a961ec8796 Add docu to sequencer and move controller 2021-10-30 16:37:21 +02:00
Joachim Stolberg
c1542a48d1 Fix sequencer bugs 2021-10-26 21:58:28 +02:00
Joachim Stolberg
46aa567ef4 v1.03 2021-10-24 21:26:40 +02:00
Joachim Stolberg
22e9a8eacc
Merge pull request #69 from Thomas--S/tank-assignment
TA4 Tank: Add option to keep assignment
2021-10-24 21:16:35 +02:00
Joachim Stolberg
6e9906aac4
Merge pull request #67 from realmicu/master
4x Button: add switch mode
2021-10-24 21:16:19 +02:00
Joachim Stolberg
ad25882ca1 Activate ta4 movecontroller, ta4 sequencer and command counting 2021-10-24 21:15:19 +02:00
Joachim Stolberg
3505751f16 Improve ta4 sequencer 2021-10-23 16:59:50 +02:00
Joachim Stolberg
0ffb786a57 Finish movecontroller 2021-10-23 16:12:09 +02:00
Michal Cieslakiewicz
56b2479f92 4x Button: add switch mode
Make 4x Button able to act like switch node, sending on/off
commands only (custom command string is ignored in this mode).
Works identically to its standard single version.
2021-10-23 13:33:38 +02:00
Joachim Stolberg
43bb2705cf Fix valve protection and tank cart bugs, add command payload to buttons 2021-10-22 19:03:02 +02:00
Thomas--S
7a60792066 TA4 Tank: Add option to keep assignment 2021-10-15 20:42:08 +02:00
Joachim Stolberg
58b1be93ca Add draft version of ta4 sequencer and other minor improvements 2021-10-12 19:57:22 +02:00
Joachim Stolberg
9e91e1e709 Add block height to movecontroller menu 2021-10-12 19:57:22 +02:00
Joachim Stolberg
546e9e8349 Add ta4 movecontroller 2021-10-12 19:57:22 +02:00
Joachim Stolberg
b643482c02
Merge pull request #68 from Thomas--S/repair-nodenumber
Allow to repair node number
2021-10-12 19:40:24 +02:00
Thomas--S
803c6b80f6 Allow to repair node number 2021-10-12 16:35:26 +02:00
Joachim Stolberg
90815845f9 Fix bugs for injector and electric cable 2021-10-01 14:26:17 +02:00
Joachim Stolberg
76cf6abeea Improve injector and detector 2021-09-27 22:10:30 +02:00
Joachim Stolberg
801d2f5492 Improve injector and detector 2021-09-27 21:34:24 +02:00
Joachim Stolberg
d2002ce2cd
Merge pull request #66 from Thomas--S/explorer-mapblock
Oil Explorer: Mark mapblock after dig
2021-09-26 16:02:11 +02:00
Joachim Stolberg
d1d549bbff
Merge pull request #65 from Thomas--S/4x-button-crash
4x Button: Fix crash
2021-09-26 13:58:41 +02:00
Thomas--S
24a3df1127 Oil Explorer: Mark mapblock after dig
This allows to find the next mapblock more easily
2021-09-26 12:24:55 +02:00
Thomas--S
888701c27c 4x Button: Fix crash
Previously, the server crashed when multiple numbers were entered in one field (separated by space)
2021-09-26 12:06:19 +02:00
Joachim Stolberg
05027a3ae0 Add label field to button menu 2021-09-25 21:42:28 +02:00
Joachim Stolberg
98b2626365 Add label field to button menu 2021-09-25 21:40:05 +02:00
Joachim Stolberg
48f0235f3b Add missing ta4_button_4x recipe 2021-09-25 20:51:26 +02:00
Joachim Stolberg
032f59c11a Add ta4 fourfold button 2021-09-24 22:19:36 +02:00
Joachim Stolberg
9218c3097b Improve detector, fix filler bug 2021-09-19 20:02:24 +02:00
Joachim Stolberg
1e36775c18 Allow pushing of items 'into' a techage:ta4_chest_dummy 2021-09-19 12:56:03 +02:00
Joachim Stolberg
86855ee6b7 Update README 2021-09-18 13:11:24 +02:00
Joachim Stolberg
50590d923c Update version check for networks v0.10 2021-09-18 13:06:33 +02:00
Joachim Stolberg
e7cde49228 Update README for v1.02 2021-09-18 12:45:13 +02:00
Joachim Stolberg
3ff6ca909f fix ta4_injector and detector issues 2021-09-17 18:57:14 +02:00
Joachim Stolberg
9cc6b93f58 fix concentrator bug 2021-09-14 20:07:41 +02:00
Joachim Stolberg
4fcf259445
Merge pull request #64 from Thomas--S/ta4-chest-max-count-fix
TA4 Chest: Fix items disappearing
2021-09-14 20:02:12 +02:00
Thomas--S
6a9ccd34e5 TA4 Chest: Fix items disappearing 2021-09-14 13:23:17 +02:00
Joachim Stolberg
e73124fd38 Fix 'delivered' command for ta4 heat exchanger 2021-09-10 20:23:39 +02:00
Joachim Stolberg
17a39387b7
Merge pull request #63 from Thomas--S/colored-cables
Add support for colored cables
2021-09-10 20:20:51 +02:00
Joachim Stolberg
f48ebf1b67 Fix aluminum powder recipe bug 2021-09-10 15:43:48 +02:00
Thomas--S
4770885e5f Add support for colored cables
As requested by player "anju64".
2021-09-08 13:02:11 +02:00
Joachim Stolberg
3918f61437 Fix the glowing gravel bug 2021-08-21 22:45:45 +02:00
Joachim Stolberg
c4247a4434 Add debug output to logic block, fix some bugs 2021-08-20 19:27:23 +02:00
Joachim Stolberg
692777ec6f Fix next sluice bug 2021-08-18 19:48:37 +02:00
Joachim Stolberg
83d9991ffb Increase max_tube_length of TA1 axle 2021-08-18 17:04:14 +02:00
Joachim Stolberg
9b6dab9aeb Fix sluice remove bug 2021-08-18 16:49:07 +02:00
Joachim Stolberg
d68105cf21 Simplify the use of the watermill 2021-08-18 16:10:33 +02:00
Joachim Stolberg
5f48e026c4 Improve manuals 2021-08-17 21:50:40 +02:00
Joachim Stolberg
e28f9de02c Add TA1 watermill 2021-08-16 22:22:48 +02:00
Joachim Stolberg
b491ff70ce Add TA1 watermill 2021-08-16 20:40:09 +02:00
Joachim Stolberg
55fccd5245
Merge pull request #62 from realmicu/master
Allow picking TA3 Tiny Generator with fuel
2021-08-16 18:05:29 +02:00
Joachim Stolberg
019d9c96b5
Merge pull request #61 from Thomas--S/protected-button
Allow sharing the button based on protection
2021-08-16 18:04:11 +02:00
Joachim Stolberg
58d8142495 Add TA1 watermill 2021-08-16 17:57:54 +02:00
Michal Cieslakiewicz
753ca42605 Allow picking TA3 Tiny Generator with fuel
TA3 Tiny Generator can now be collected and deployed with non-empty fuel
tank. Item description provides information about fuel level. Engine cycles
are not preserved, it would make empty generators with different cycle
values to quickly clog player's inventory.

Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
2021-08-16 10:19:40 +02:00
Thomas--S
b0c6911638 Allow sharing the button based on protection
Should be fully backwards compatible.
2021-08-15 09:26:42 +02:00
Joachim Stolberg
fd729b512b
Merge pull request #60 from Thomas--S/sequencer-pause
Allow to pause the sequencer with a TechAge command
2021-08-09 20:55:07 +02:00
Thomas--S
4cf3f6434d Allow to pause the sequencer with a TechAge command
Has the same effect as turning the sequencer off by hand.

Use case: You use a sequencer in combination with a TA Signal Lamp to build a flashing warning light.
You then want to turn this warning light on and off with a TechAge command.
Using the "off" command would result in unsetting the "Run endless" checkbox.
2021-08-08 16:32:46 +02:00
Joachim Stolberg
428a3d552f Allow singleplayer to place lava on y>0. Logic block: allow to use output numbers for the expression 2021-08-02 20:18:29 +02:00
Joachim Stolberg
fe37465f65 Reactivate grinder recipes 2021-08-01 16:32:52 +02:00
Joachim Stolberg
e2421b01cd Fix ta2_winch bug 2021-08-01 11:27:37 +02:00
Joachim Stolberg
9de48d8259 Fix ta2_winch bug 2021-08-01 11:13:13 +02:00
Joachim Stolberg
70b909ef5b Fix ta4_doser bug 2021-08-01 10:33:25 +02:00
Joachim Stolberg
4dbf460715 Add minor improvements 2021-07-29 21:08:44 +02:00
Joachim Stolberg
875c3dc9de Convert liquid filter and blackhole 2021-07-24 11:26:13 +02:00
Joachim Stolberg
a330070c54 Some bugfixes 2021-07-23 19:51:51 +02:00
Joachim Stolberg
8e249248dc Merge branch 'networks' 2021-07-23 19:47:43 +02:00
Joachim Stolberg
60487a232f Add grinder bugfix from Micu 2021-06-14 23:23:56 +02:00
475 changed files with 38337 additions and 8675 deletions

View File

@ -7,7 +7,7 @@
GPL v3
See LICENSE.txt for more information
Demo for a electrical power consuming node
]]--
@ -62,7 +62,7 @@ end
minetest.register_node("techage:sink", {
description = "Sink",
tiles = {'techage_electric_button.png^[colorize:#000000:50'},
on_timer = function(pos, elapsed)
local consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED)
if consumed == PWR_NEEDED then
@ -76,7 +76,7 @@ minetest.register_node("techage:sink", {
after_dig_node = after_dig_node,
paramtype = "light",
light_source = 0,
light_source = 0,
paramtype2 = "facedir",
groups = {choppy = 2, cracky = 2, crumbly = 2},
is_ground_content = false,
@ -100,7 +100,7 @@ minetest.register_node("techage:sink_on", {
after_dig_node = after_dig_node,
paramtype = "light",
light_source = minetest.LIGHT_MAX,
light_source = minetest.LIGHT_MAX,
paramtype2 = "facedir",
diggable = false,
drop = "",

43
.test/testblock.lua Normal file
View File

@ -0,0 +1,43 @@
local M = minetest.get_meta
minetest.register_node("techage:testblock", {
description = "Testblock",
tiles = {
"techage_top_ta4.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
},
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
is_ground_content = false,
after_place_node = function(pos, placer)
local nvm = techage.get_nvm(pos)
nvm.test_val = 1
M(pos):set_int("test_val", 1)
M(pos):set_string("infotext", "Value = " .. 1)
end,
})
minetest.register_lbm({
label = "Update testblock",
name = "techage:update_testblock",
nodenames = {
"techage:testblock",
},
run_at_every_load = true,
action = function(pos, node)
local nvm = techage.get_nvm(pos)
if M(pos):get_int("test_val") == nvm.test_val then
nvm.test_val = nvm.test_val + 1
M(pos):set_int("test_val", nvm.test_val)
M(pos):set_string("infotext", "Value = " .. nvm.test_val)
else
minetest.log("error", "[techage] Memory error at " .. minetest.pos_to_string(pos))
M(pos):set_string("infotext", "Error")
end
end,
})

View File

@ -629,8 +629,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
TechAge, a mod to go through 5 tech ages in search of wealth and power.
Copyright (C) 2019-2023 Joachim Stolberg
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by

215
README.md
View File

@ -1,41 +1,44 @@
# Tech Age [techage] (Minetest 5.0+)
# Tech Age [techage] (Minetest 5.4+)
Tech Age, a mod to go through 4 tech ages in search of wealth and power.
**Tech Age (techage) is the successor to TechPack V2, at first glance similar and yet completely different!**
Tech Age, a mod to go through 5 tech ages in search of wealth and power.
![screenshot](https://github.com/joe7575/techage/blob/master/screenshot.png)
Important facts:
- techage is not backwards compatible and cannot be installed on a server together with TechPack
- techage is significantly more extensive, since additional mods are integrated
- techage represents 4 technological ages:
- techage represents 5 technological ages:
- Iron Age (TA1) - simple tools like coal pile, coal burner, gravel sieve, hammer for getting ores and making goods
- Steam Age (TA2) - Simple machines that are powered by steam engines and drive axles
- Oil Age (TA3) - More modern machines that are powered by electricity.
The electricity is generated by coal & oil power plants. The oil must be explored, extracted and transported.
- Future Age (TA4) - Electricity from renewable energy sources such as sun and wind.
Environmentally friendly electricity storage, intelligent machines and means of transport of the future
- Present (TA4) - Electricity from renewable energy sources such as sun and wind.
- Future (TA5) - Machines to overcome space and time, new sources of energy and other achievements.
- Since the levels build on each other, all ages have to be run through one after the other
In contrast to TechPack, the resources are more limited and it is much more difficult to pass all levels.
(no endless ore generation by means of cobble generators)
**Techage blocks store information outside of the block. This is for performance reasons.
If you move, place, or remove blocks with any tool, at best, only the information is lost.
In the worst case, the server crashes.**
[Manuals](https://github.com/joe7575/techage/wiki)
### License
Copyright (C) 2019-2021 Joachim Stolberg
Copyright (C) 2019-2023 Joachim Stolberg
Code: Licensed under the GNU AGPL version 3 or later. See LICENSE.txt
Textures: CC BY-SA 3.0
Many thanks to Thomas-S and others for their contributions
The TA1 mill sound is from https://freesound.org/people/JustinBW/sounds/70200/
The TA1 watermill sound is from https://freesound.org/people/bmoreno/sounds/164182/
Many thanks to Thomas-S, niklp09, and others for their contributions
### Dependencies
Required: default, doors, bucket, stairs, screwdriver, basic_materials, tubelib2, networks, minecart, lcdlib, safer_lua
Required: default, doors, bucket, stairs, screwdriver, basic_materials, tubelib2, networks, minecart, lcdlib, safer_lua, doclib
Recommended: signs_bot, hyperloop, compost, techpack_stairway, autobahn
Optional: unified_inventory, wielded_light, unifieddyes, lua-mashal, lsqlite3, moreores, ethereal, mesecon
@ -50,6 +53,7 @@ The following mods in the newest version have to be downloaded directly from Git
* [minecart](https://github.com/joe7575/minecart)
* [lcdlib](https://github.com/joe7575/lcdlib)
* [safer_lua](https://github.com/joe7575/safer_lua)
* [doclib](https://github.com/joe7575/doclib)
It is highly recommended that you install the following mods, too:
@ -58,27 +62,192 @@ It is highly recommended that you install the following mods, too:
* [compost](https://github.com/joe7575/compost): The garden soil is needed for the TA4 LED Grow Light based flower bed
* [techpack_stairway](https://github.com/joe7575/techpack_stairway): Ladders, stairways, and bridges for your machines
* [autobahn](https://github.com/joe7575/autobahn): Street blocks and slopes with stripes for faster traveling
* [[ta4_jetpack](https://github.com/joe7575/ta4_jetpack): A Jetpack with hydrogen as fuel and TA4 recipe
* [ta4_jetpack](https://github.com/joe7575/ta4_jetpack): A Jetpack with hydrogen as fuel and TA4 recipe
For large servers with many player `lsqlite3` is recommended.
The package has to be installed via [luarocks](https://luarocks.org/):
More recommended Techage related mods by other authors:
luarocks install lsqlite3
* [ta4_addons](https://github.com/Thomas--S/ta4_addons) from Thomas--S: A Touchscreen for the Lua controller
* [ts_vehicles](https://github.com/Thomas--S/ts_vehicles) from Thomas--S: A mod to provide cars and other vehicles for Minetest.
* [ta_apiary](https://gitlab.com/lesya_minetest_mods/ta_apiary) from Olesya Sibidanova: TechAge Machines for beekeeping
To enable this `unsafe` package, add 'techage' to the list of trusted mods in minetest.conf:
For large servers with many players, the following packages are recommended:
secure.trusted_mods = techage
* lua-mashal for faster serialization/deserialization of data
* lsqlite3 for storing node and network data
For the installation of 'luarocks' (if not already available), see [luarocks](https://luarocks.org/)
The packages have to be installed via [luarocks](https://luarocks.org/):
luarocks --lua-version 5.1 install lsqlite3
luarocks --lua-version 5.1 install lua-marshal
To enable these `unsafe` packages, add 'techage' and 'lua-marshal'
to the list of trusted mods in `minetest.conf`:
secure.trusted_mods = techage,lua-marshal
and add the following line to your `world.mt` or `minetest.conf`:
techage_use_sqlite = true
Available worlds will be converted to 'lsqlite3', but there is no way back, so:
** Never disable 'lsqlite3' for a world that has already been used!**
**Never disable 'lsqlite3' for a world that has already been used!**
### History
**2021-07-18 V1.00**
**2023-11-05 V1.18**
- Add TA2 clutch
- TA5 Generator: Add generator menu
- TA4 Injector: Allow rotation with a screwdriver
- Escape equal sign in german translation (Niklp09)
- Autocrafter: Add Beduino command interface
- Autocrafter: Add flush command
- Fix converter stores mesecon signals (Niklp09)
- TA1 Gravel Sieve: Use proper player creative check (Niklp09)
- TA4 Chest: Add storesize command
- Improve Assembly Tool
- Furnace: Fix burn time issue
- Allow further types of cobblestone for the coalburner
- Fix water mill river water bug (alwayshopeless)
- Improve manual
- Further improvements
**2023-08-25 V1.17**
- Add support for doclib / remove techage internal doc support
**The mod doclib is a new hard depenency !**
- Fix LICENCSE file bug
- Add beduino support for TA3 repeater (realmicu)
- Add inv_name_prefix to `techage.register_consumer` (debiankaios)
- Add generator menu to TA5 generator (fusion reactor)
- Adapt mod to the new lcdlib mod
- Fix some bugs
**2023-06-30 V1.16**
- Add TA4 node detector
- Add wrench menu to TA3 button
- Add arrows to the pump bottom and allow to turn the pump with the Techage Screwdriver
- Fix bug with configurred TA4 chest and TA5 teleport tubes
- Add gaze sensor
- Many bugfixes and improvements
**2023-05-05 V1.15**
- Allow energy storage with up to 13x13x13 concrete blocks
- Allow registration of other buckets
- Add hyperloop chest only if the hyperloop mod is available
- Add missing 'minetest.formspec_escape' #131
- Fix bug "Trouble with flycontroller #130"
- Add optional dependency on farming mod (orwell96)
- Fix forceload formspec receiver (Niklp09)
**2023-04-16 V1.14**
- Add file "api.md"
- Add API function `register_ore_for_gravelsieve`
- Add support for the game Asuna
- Merge pull request #124 from Niklp09/drops
- Fix keep node number issue
- Fix manual issue #123
**2023-04-10 V1.13**
- Add "Teleport mode" to the ta5 fly controller
**2023-04-01 V1.12**
- Improve Transformer:
- add wrench menu for 'max. power passed through'
- Increase max. power passed through from 100 to 300 ku
- Improve Electricmeter:
- add wrench menu for 'max. power passed through' and 'power countdown' 2458
- add commands to read the countdown value (Lua and Beduino controller)
- Improve TA3 Mesecons Converter:
- fix overload bug
- fix missing dominant 'on' issue
- Add version command to TA3/TA4 Terminal
- TA5 Hyperloop Chest: Disable inventory access on client side due to minetest core issues
**2023-03-05 V1.11**
- Reduce the number of necessary exp points for TA5 Hyperloop Chest,
TA5 Hyperloop Tank, and TA5 AI Chip II
- Fix possible kernel crashes with TA5 Hyperloop Chest and autocrafter
- Rework doorcontroller (menu changed)
- Increase tank cart storage size to 200 units
- Fix several paramtype/use_texture_alpha issues
- Add command 'load' to the TA4 power terminal
- Add beduino tank commands
- Fix power consumption bug for a stopped collider
- Fix electrolyzer formspec bug
- Add Rack and pinion node
- Expand ta4 sequencer wrench menu
- Accept mincart carts for the move controller
- movecontroller: Allow to move objects 'without' a move block
- Add empty_spool as fab output
- Fix doser goes blocked bug
**2023-02-04 V1.10**
- Improve flycontroller
- Remove handover for movecontroller
- Rename "techage:signal_lamp" to "techage:color_lamp"
- Rename "techage:signal_lamp2" to "techage:color_lamp2"
- Add countdown mode to TA4 Detector
- Adapt to new beduino and minecart versions
- Improve manuals
- flycontroller/movecontroller: Allow moving blocks through unloaded areas
- playerdetector: Add wrench menu to configure search radius
- Default furnace: Don't use items filled from the top as fuel
- Many further improvements and bug fixes from joe7575 and Niklp09
**2022-09-03 V1.09**
- Change the way items are pushed
- Add "Flow Limiter" mode to TA4 pump and TA4 pusher
**2022-06-06 V1.08**
- Native support for the mod Beduino added
**2022-01-22 V1.07**
- TA5 fusion reactor added
**2022-01-03 V1.06**
- TA5 teleport blocks added
- Many improvements
**2021-12-25 V1.05**
- Support for the mod i3 added (thanks to ghaydn)
- TA5 enabled
- Many improvements
**2021-12-12 V1.04**
- TA4 Collider added (experimental)
- move, turn, sound, and fly blocks added
- TA5 (future) introduced (TA4 is now the "present")
**2021-10-24 V1.03**
- Add TA4 Sequencer for time controlled command sequences
- Add TA4 Move Controller for moving blocks
- Add techage command counting function to be able to limit the amount of commands/min.
- Pull request #67: Add switch mode for 4x Button (by realmicu)
- Pull request #69: Add option to keep assignment for TA4 Tank (by Thomas-S)
**2021-09-18 V1.02**
- TA4 Chest: Fix items disappearing (PR #64 by Thomas--S)
- Add support for colored cables (PR #63 by Thomas--S)
**2021-08-16 V1.01**
- Allow singleplayer to place lava on y>0.
- Logic block: allow to use output numbers for the expression
- Pull request #60: Allow to pause the sequencer with a TechAge command (by Thomas-S)
- Pull request #61: Allow sharing the button based on protection (by Thomas-S)
- Pull request #62: Allow picking TA3 Tiny Generator with fuel (by realmicu)
- Add TA1 watermill
- Fix TA4 LED Grow Light bug
- Fix grinder recipe bu
**2021-07-23 V1.00**
- Change the way, power distribution works
- Add TA2 storage system
- Add TA4 Isolation Transformer
@ -87,7 +256,7 @@ Available worlds will be converted to 'lsqlite3', but there is no way back, so:
- Many improvements on power producing/consuming nodes
- See Construction Board for some hints on moving to v1
**2021-05-14 V0.25**
**2021-05-14 V0.26**
- Add concentrator tubes
- Add ta4 cable wall entry
- Pull request #57: Distributor improvements (from Thomas-S)

225
api.md Normal file
View File

@ -0,0 +1,225 @@
# Techage API Functions
Techage API function to adapt/prepare techage for other mods/games.
## Move/Fly Controller
Register node names for nodes allowed to be moved by fly/move controllers.
This is only necessary for undiggable/intelligent nodes with one of the following attributes:
- ```drop = ""```
- ```diggable = false```
- ```after_dig_node ~= nil```
```lua
techage.register_simple_nodes(node_names, is_valid)
```
- `is_valid = true` - Add node to the list of simple nodes
- `is_valid = false` - Remove node from the list of simple nodes
Example:
```lua
techage.register_simple_nodes({"techage:power_lineS"}, true)
```
For door nodes used as sliding doors by means of the move controller, call in addition:
```lua
techage.flylib.protect_door_from_being_opened(node_name)
```
## TA1 Hammer
Register stone/gravel name pair for the hammer blow:
```lua
techage.register_stone_gravel_pair(stone_name, gravel_name)
```
Example:
```lua
techage.register_stone_gravel_pair("default:stone", "default:gravel")
```
## TA1 Melting Pot
Register a pot recipe:
```lua
techage.ironage_register_recipe(recipe)
```
Examples:
```lua
techage.ironage_register_recipe({
output = "default:obsidian",
recipe = {"default:cobble"},
heat = 10, -- Corresponds to the tower height
time = 8, -- Cooking time in seconds
})
techage.ironage_register_recipe({
output = "default:bronze_ingot 4",
recipe = {"default:copper_ingot", "default:copper_ingot", "default:copper_ingot", "default:tin_ingot"},
heat = 4, -- Corresponds to the tower height
time = 8, -- Cooking time in seconds
})
```
## TA2/TA3/TA4 Autocrafter
Register any nodes/items that should not be crafted via the autocrafter.
```lua
techage.register_uncraftable_items(item_name)
```
## TA2/TA3/TA4 Gravel Sieve
Change the probability of ores or register new ores for sieving.
```lua
techage.register_ore_for_gravelsieve(ore_name, probability)
```
Example:
```lua
techage.register_ore_for_gravelsieve("default:iron_lump", 30)
```
Default values for MTG are:
```lua
-- higher value means less frequent occurrence
techage:baborium_lump 100000 -- hardly ever
default:mese_crystal 548 -- every 548th time
default:gold_lump 439
default:tin_lump 60
default:diamond 843
default:copper_lump 145
default:coal_lump 11
default:iron_lump 15
```
## TA2/TA3/TA4 Gravel Rinser
Add a rinser recipe.
```lua
techage.add_rinser_recipe(recipe)
```
Example:
```lua
techage.add_rinser_recipe({input = "techage:sieved_gravel", output = "techage:usmium_nuggets", probability = 30})
```
## TA2/TA3/TA4 Grinder
Add a grinder recipe.
```lua
techage.add_grinder_recipe(recipe, ta1_permitted)
```
Examples:
```lua
echage.add_grinder_recipe({input = "default:cobble", output = "default:gravel"})
techage.add_grinder_recipe({input = "default:sandstone", output = "default:sand 4"})
```
## TA3/TA4 Electronic Fab, TA4 Doser
Add recipes to an electronic fab or doser (chemical reactor):
```lua
techage.recipes.add(rtype, recipe)
```
`rtype` is one of: `ta2_electronic_fab` , `ta4_doser`
A recipe look like:
```
{
output = "<item-name> <units>", -- units = 1..n
waste = "<item-name> <units>", -- units = 1..n
input = { -- up to 4 items
"<item-name> <units>",
"<item-name> <units>",
},
}
```
Examples:
```lua
techage.recipes.add("ta2_electronic_fab", {
output = "techage:vacuum_tube 2",
waste = "basic_materials:empty_spool 1",
input = {"default:glass 1", "basic_materials:copper_wire 1", "basic_materials:plastic_sheet 1", "techage:usmium_nuggets 1"}
})
techage.recipes.add("ta4_doser", {
output = "techage:naphtha 1",
input = {
"techage:fueloil 1",
},
catalyst = "techage:gibbsite_powder",
})
```
## TA3 Furnace
Register recipe:
```lua
techage.furnace.register_recipe(recipe)
```
Example:
```lua
techage.furnace.register_recipe({
output = "default:bronze_ingot 4",
recipe = {"default:copper_ingot", "default:copper_ingot", "default:copper_ingot", "default:tin_ingot"},
time = 2, -- in seconds
})
```
## Assembly Tool
Disable a block from being removed by the assembly tool:
```lua
techage.disable_block_for_assembly_tool(block_name)
```

View File

@ -3,16 +3,16 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
The autocrafter is derived from pipeworks:
The autocrafter is derived from pipeworks:
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> WTFPL
TA2/TA3/TA4 Autocrafter
]]--
-- for lazy programmers
@ -68,8 +68,23 @@ local function count_index(invlist)
return index
end
local function flush_input_inventory(pos)
local inv = M(pos):get_inventory()
if not inv:is_empty("src") then
for idx = 1, 16 do
local stack = inv:get_stack("src", idx)
if not inv:room_for_item("dst", stack) then
return false
end
inv:add_item("dst", stack)
inv:set_stack("src", idx, nil)
end
end
return true
end
-- caches some recipe data
local autocrafterCache = {}
local autocrafterCache = {}
local function get_craft(pos, inventory, hash)
hash = hash or minetest.hash_node_position(pos)
@ -78,13 +93,13 @@ local function get_craft(pos, inventory, hash)
local recipe = inventory:get_list("recipe")
local output, decremented_input = minetest.get_craft_result(
{method = "normal", width = 3, items = recipe})
-- check if registered item
if UncraftableItems[output.item:get_name()] then
if UncraftableItems[output.item:get_name()] then
output.item = ItemStack()
end
craft = {recipe = recipe, consumption = count_index(recipe),
craft = {recipe = recipe, consumption = count_index(recipe),
output = output, decremented_input = decremented_input}
autocrafterCache[hash] = craft
end
@ -93,18 +108,18 @@ end
local function autocraft(pos, crd, nvm, inv)
local craft = get_craft(pos, inv)
if not craft then
if not craft then
crd.State:idle(pos, nvm)
return
end
local output_item = craft.output.item
if output_item:get_name() == "" then
crd.State:idle(pos, nvm)
return
return
end
-- check if we have enough room in dst
if not inv:room_for_item("dst", output_item) then
if not inv:room_for_item("dst", output_item) then
crd.State:blocked(pos, nvm)
return
end
@ -112,9 +127,9 @@ local function autocraft(pos, crd, nvm, inv)
local inv_index = count_index(inv:get_list("src"))
-- check if we have enough material available
for itemname, number in pairs(consumption) do
if (not inv_index[itemname]) or inv_index[itemname] < number then
if (not inv_index[itemname]) or inv_index[itemname] < number then
crd.State:idle(pos, nvm)
return
return
end
end
-- consume material
@ -129,7 +144,7 @@ local function autocraft(pos, crd, nvm, inv)
for i = 1, 9 do
inv:add_item("dst", craft.decremented_input.items[i])
end
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
@ -189,6 +204,17 @@ local function normalize(item_list)
return item_list
end
local function get_input_from_recipeblock(pos, number, idx)
local own_num = M(pos):get_string("node_number")
local owner = M(pos):get_string("owner")
if techage.check_numbers(number, owner) then
local input = techage.send_single(own_num, number, "input", idx)
if input and type(input) == "string" then
return input
end
end
end
local function on_output_change(pos, inventory, stack)
if not stack then
inventory:set_list("output", {})
@ -212,8 +238,53 @@ local function on_output_change(pos, inventory, stack)
after_recipe_change(pos, inventory)
end
local function determine_recipe_items(pos, input)
local num, idx
if input and type(input) == "string" then -- Lua controller
-- Test if "<node-number>.<recipe-number>" input
num, idx = unpack(string.split(input, ".", false, 1))
elseif input and type(input) == "table" then -- Beduino
num = tostring(input[1] * 65536 + input[2])
idx = tostring(input[3])
end
if num and idx then
input = get_input_from_recipeblock(pos, num, idx)
if input then
-- "<item>,<item>,..." input
local items = string.split(input, ",", true, 8)
if items and type(items) == "table" and next(items) then
return items
end
end
end
end
local function on_new_recipe(pos, input)
local items = determine_recipe_items(pos, input)
local inv = M(pos):get_inventory()
if items then
for i = 1, 9 do
inv:set_stack("recipe", i, items[i])
end
else
inv:set_list("recipe", {})
end
local hash = minetest.hash_node_position(pos)
autocrafterCache[hash] = nil
local craft = get_craft(pos, inv, hash)
if craft.output and craft.output.item then
inv:set_stack("output", 1, craft.output.item)
else
inv:set_stack("output", 1, nil)
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if listname == "output" then
return 0
end
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
@ -233,6 +304,9 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player)
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if listname == "output" then
return 0
end
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
@ -250,6 +324,9 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if from_list == "output" or "to_list" == "output" then
return 0
end
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
@ -312,7 +389,7 @@ tiles.pas = {
tiles.act = {
-- up, down, right, left, back, front
{
image = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#_top.png",
name = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -325,7 +402,7 @@ tiles.act = {
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
image = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#.png",
name = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -335,7 +412,7 @@ tiles.act = {
},
},
{
image = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#.png",
name = "techage_filling4_ta#.png^techage_appl_autocrafter4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -346,6 +423,8 @@ tiles.act = {
},
}
local INFO = [[Commands: 'state', 'recipe']]
local tubing = {
on_inv_request = function(pos, in_dir, access_type)
if access_type == "push" then
@ -378,14 +457,44 @@ local tubing = {
end
end,
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
if topic == "recipe" and CRD(pos).stage == 4 then
if payload and payload ~= "" then
on_new_recipe(pos, payload)
return true
else
local inv = M(pos):get_inventory()
return inv:get_stack("output", 1):get_name()
end
elseif topic == "flush" and CRD(pos).stage == 4 then
return flush_input_inventory(pos)
elseif topic == "info" and CRD(pos).stage == 4 then
return INFO
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 10 and CRD(pos).stage == 4 then
on_new_recipe(pos, payload)
return 1, ""
elseif topic == 11 and CRD(pos).stage == 4 then
if flush_input_inventory(pos) then
return 1, ""
else
return 0, ""
end
end
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("autocrafter", S("Autocrafter"), tiles, {
drawtype = "normal",
cycle_time = CYCLE_TIME,
@ -410,7 +519,7 @@ local node_name_ta2, node_name_ta3, node_name_ta4 =
num_items = {0,1,2,4},
power_consumption = {0,4,6,9},
},
{false, true, true, false}) -- TA2/TA3
{false, true, true, true}) -- TA2/TA3/TA4
minetest.register_craft({
output = node_name_ta2,
@ -430,3 +539,18 @@ minetest.register_craft({
},
})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:diamond", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})
local Cable = techage.ElectricCable
local power = networks.power
techage.register_node_for_v1_transition({"techage:ta3_autocrafter_pas", "techage:ta4_autocrafter_pas"}, function(pos, node)
power.update_network(pos, nil, Cable)
end)

View File

@ -9,12 +9,12 @@
See LICENSE.txt for more information
All items and liquids disappear.
]]--
local S = techage.S
local Pipe = techage.LiquidPipe
local liquid = techage.liquid
local liquid = networks.liquid
local function take_liquid(pos, indir, name, amount)
return 0, name
@ -28,13 +28,6 @@ local function peek_liquid(pos, indir)
return nil
end
local networks_def = {
pipe2 = {
sides = {R=1}, -- Pipe connection sides
ntype = "tank",
},
}
minetest.register_node("techage:blackhole", {
description = S("TechAge Black Hole"),
tiles = {
@ -57,22 +50,12 @@ minetest.register_node("techage:blackhole", {
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
end,
tubelib2_on_update2 = function(pos, outdir, tlib2, node)
liquid.update_network(pos, outdir)
end,
on_rotate = screwdriver.disallow,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
liquid = {
capa = 999999,
peek = peek_liquid,
put = put_liquid,
take = take_liquid,
},
networks = networks_def,
})
minetest.register_craft({
@ -87,7 +70,7 @@ minetest.register_craft({
techage.register_node({"techage:blackhole"}, {
on_pull_item = nil, -- not needed
on_unpull_item = nil, -- not needed
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir then
@ -96,4 +79,11 @@ techage.register_node({"techage:blackhole"}, {
end,
})
Pipe:add_secondary_node_names({"techage:blackhole"})
liquid.register_nodes({"techage:blackhole"},
Pipe, "tank", {"R"}, {
capa = 9999999,
peek = peek_liquid,
put = put_liquid,
take = take_liquid,
}
)

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Chest
]]--
-- for lazy programmers
@ -45,6 +45,7 @@ end
local function after_dig_node(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end
local function formspec2()
@ -75,7 +76,7 @@ minetest.register_node("techage:chest_ta2", {
local inv = meta:get_inventory()
inv:set_size('main', 32)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
@ -85,7 +86,7 @@ minetest.register_node("techage:chest_ta2", {
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, S("TA2 Protected Chest"))
end,
can_dig = can_dig,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = allow_metadata_inventory_put,
@ -125,7 +126,7 @@ minetest.register_node("techage:chest_ta3", {
local inv = meta:get_inventory()
inv:set_size('main', 40)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local number = techage.add_node(pos, "techage:chest_ta3")
@ -138,7 +139,7 @@ minetest.register_node("techage:chest_ta3", {
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, S("TA3 Protected Chest"))
end,
can_dig = can_dig,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = allow_metadata_inventory_put,
@ -179,7 +180,16 @@ techage.register_node({"techage:chest_ta2", "techage:chest_ta3"}, {
return "unsupported"
end
end,
})
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return 0, {techage.get_inv_state_num(inv, "main")}
else
return 2, ""
end
end,
})
local function formspec4(pos)
@ -226,7 +236,7 @@ local function ta4_allow_metadata_inventory_put(pos, listname, index, stack, pla
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "main" then
return stack:get_count()
else
@ -239,7 +249,7 @@ local function ta4_allow_metadata_inventory_take(pos, listname, index, stack, pl
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if listname == "main" then
return stack:get_count()
else
@ -252,7 +262,7 @@ local function ta4_allow_metadata_inventory_move(pos, from_list, from_index, to_
if not public and minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if from_list == "main" then
return count
else
@ -278,7 +288,7 @@ minetest.register_node("techage:chest_ta4", {
inv:set_size('main', 50)
inv:set_size('conf', 50)
end,
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local number = techage.add_node(pos, "techage:chest_ta4")
@ -292,7 +302,7 @@ minetest.register_node("techage:chest_ta4", {
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local meta = minetest.get_meta(pos)
local mem = techage.get_mem(pos)
if fields.tab == "1" then
@ -319,11 +329,11 @@ minetest.register_node("techage:chest_ta4", {
meta:set_string("formspec", formspec4_cfg(pos))
end
end,
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, S("TA4 Protected Chest"))
end,
can_dig = can_dig,
after_dig_node = after_dig_node,
allow_metadata_inventory_put = ta4_allow_metadata_inventory_put,
@ -346,14 +356,14 @@ techage.register_node({"techage:chest_ta4"}, {
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local mem = techage.get_mem(pos)
mem.filter = mem.filter or mConf.item_filter(pos, TA4_INV_SIZE)
mem.chest_configured = mem.chest_configured or not inv:is_empty("conf")
if inv:is_empty("main") then
return nil
end
if item_name then
if mem.filter[item_name] or not mem.chest_configured then
local taken = inv:remove_item("main", {name = item_name, count = num})
@ -373,10 +383,10 @@ techage.register_node({"techage:chest_ta4"}, {
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local mem = techage.get_mem(pos)
mem.filter = mem.filter or mConf.item_filter(pos, TA4_INV_SIZE)
mem.chest_configured = mem.chest_configured or not inv:is_empty("conf")
if mem.chest_configured then
local name = item:get_name()
local stacks = mem.filter[name] or mem.filter["unconfigured"]
@ -389,10 +399,10 @@ techage.register_node({"techage:chest_ta4"}, {
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local mem = techage.get_mem(pos)
mem.filter = mem.filter or mConf.item_filter(pos, TA4_INV_SIZE)
mem.chest_configured = mem.chest_configured or not inv:is_empty("conf")
if mem.chest_configured then
local name = item:get_name()
local stacks = mem.filter[name] or mem.filter["unconfigured"]
@ -401,7 +411,7 @@ techage.register_node({"techage:chest_ta4"}, {
return techage.put_items(inv, "main", item)
end
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "state" then
local meta = minetest.get_meta(pos)
@ -411,7 +421,16 @@ techage.register_node({"techage:chest_ta4"}, {
return "unsupported"
end
end,
})
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return 0, {techage.get_inv_state_num(inv, "main")}
else
return 2, ""
end
end,
})
minetest.register_craft({
type = "shapeless",

View File

@ -3,7 +3,7 @@
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
@ -39,6 +39,7 @@ local names = networks.register_junction("techage:concentrator", 2/8, Boxes, Tub
"techage_tube_junction.png^techage_appl_arrow2.png^[transformR270",
},
paramtype2 = "facedir", -- important!
use_texture_alpha = techage.CLIP,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, techage_trowel = 1},
sounds = default.node_sound_defaults(),
@ -53,18 +54,32 @@ local names = networks.register_junction("techage:concentrator", 2/8, Boxes, Tub
local name = "techage:concentrator"..networks.junction_type(pos, Tube, "R", node.param2)
minetest.swap_node(pos, {name = name, param2 = node.param2})
end,
ta_rotate_node = function(pos, node, new_param2)
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
M(pos):set_int("push_dir", techage.side_to_outdir("R", new_param2))
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_node(pos)
end,
}, 27)
for _, name in ipairs(names) do
Tube:set_valid_sides(name, {"B", "R", "F", "L", "D", "U"})
end
techage.register_node(names, {
on_push_item = function(pos, in_dir, stack)
local push_dir = M(pos):get_int("push_dir")
return techage.push_items(pos, push_dir, stack)
if networks.Flip[push_dir] ~= in_dir then
return techage.safe_push_items(pos, push_dir, stack)
else
return stack
end
end,
is_pusher = true, -- is a pulling/pushing node
})
})
names = networks.register_junction("techage:ta4_concentrator", 2/8, Boxes, Tube, {
description = S("TA4 Tube Concentrator"),
@ -77,6 +92,7 @@ names = networks.register_junction("techage:ta4_concentrator", 2/8, Boxes, Tube,
"techage_tubeta4_junction.png^techage_appl_arrow2.png^[transformR270",
},
paramtype2 = "facedir", -- important!
use_texture_alpha = techage.CLIP,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, techage_trowel = 1},
sounds = default.node_sound_defaults(),
@ -91,18 +107,32 @@ names = networks.register_junction("techage:ta4_concentrator", 2/8, Boxes, Tube,
local name = "techage:ta4_concentrator"..networks.junction_type(pos, Tube, "R", node.param2)
minetest.swap_node(pos, {name = name, param2 = node.param2})
end,
ta_rotate_node = function(pos, node, new_param2)
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
M(pos):set_int("push_dir", techage.side_to_outdir("R", new_param2))
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_node(pos)
end,
}, 27)
for _, name in ipairs(names) do
Tube:set_valid_sides(name, {"B", "R", "F", "L", "D", "U"})
end
techage.register_node(names, {
on_push_item = function(pos, in_dir, stack)
local push_dir = M(pos):get_int("push_dir")
return techage.push_items(pos, push_dir, stack)
if networks.Flip[push_dir] ~= in_dir then
return techage.safe_push_items(pos, push_dir, stack)
else
return stack
end
end,
is_pusher = true, -- is a pulling/pushing node
})
})
minetest.register_craft({

View File

@ -3,14 +3,14 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Consumer node basis functionality.
It handles:
- up to 3 stages of nodes (TA2/TA3/TA4)
- up to 4 stages of nodes (TA2/TA3/TA4/TA5)
- power consumption
- node state handling
- registration of passive and active nodes
@ -54,7 +54,7 @@ end
local function node_timer_pas(pos, elapsed)
local crd = CRD(pos)
local nvm = techage.get_nvm(pos)
-- handle power consumption
if crd.power_netw and techage.needs_power(nvm) then
local consumed = power.consume_power(pos, crd.power_netw, nil, crd.power_consumption)
@ -62,7 +62,7 @@ local function node_timer_pas(pos, elapsed)
crd.State:start(pos, nvm)
end
end
-- call the node timer routine
if techage.is_operational(nvm) then
nvm.node_timer_call_cyle = (nvm.node_timer_call_cyle or 0) + 1
@ -77,7 +77,7 @@ end
local function node_timer_act(pos, elapsed)
local crd = CRD(pos)
local nvm = techage.get_nvm(pos)
-- handle power consumption
if crd.power_netw and techage.needs_power(nvm) then
local consumed = power.consume_power(pos, crd.power_netw, nil, crd.power_consumption)
@ -85,7 +85,7 @@ local function node_timer_act(pos, elapsed)
crd.State:nopower(pos, nvm)
end
end
-- call the node timer routine
if techage.is_operational(nvm) then
nvm.node_timer_call_cyle = (nvm.node_timer_call_cyle or 0) + 1
@ -104,25 +104,30 @@ local function prepare_tiles(tiles, stage, power_png)
tbl[#tbl+1] = item:gsub("#", stage):gsub("{power}", power_png):gsub("@@", '#')
else
local temp = table.copy(item)
temp.image = temp.image:gsub("#", stage):gsub("{power}", power_png):gsub("@@", '#')
temp.name = temp.name:gsub("#", stage):gsub("{power}", power_png):gsub("@@", '#')
tbl[#tbl+1] = temp
end
end
return tbl
end
-- 'validStates' is optional and can be used to e.g. enable
-- 'validStates' is optional and can be used to e.g. enable
-- only one TA2 node {false, true, false, false}
function techage.register_consumer(base_name, inv_name, tiles, tNode, validStates, node_name_prefix)
function techage.register_consumer(base_name, inv_name, tiles, tNode, validStates, node_name_prefix, inv_name_prefix)
local names = {}
validStates = validStates or {true, true, true, true}
if not node_name_prefix then
node_name_prefix = "techage:ta"
node_name_prefix = node_name_prefix or "techage:ta"
if inv_name_prefix then
inv_name_prefix = inv_name_prefix.." "
else
inv_name_prefix = ""
end
for stage = 2,4 do
for stage = 2,5 do
local name_pas = node_name_prefix..stage.."_"..base_name.."_pas"
local name_act = node_name_prefix..stage.."_"..base_name.."_act"
local name_inv = "TA"..stage.." "..inv_name
local name_inv = inv_name_prefix.."TA"..stage.." "..inv_name
names[#names+1] = name_pas
if validStates[stage] then
@ -152,6 +157,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
formspec_func = tNode.formspec,
on_state_change = tNode.on_state_change,
can_start = tNode.can_start,
quick_start = tNode.quick_start,
has_power = tNode.has_power or power_used and has_power or nil,
start_node = power_used and start_node or nil,
stop_node = power_used and stop_node or nil,
@ -162,7 +168,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
State = tState,
-- number of items to be processed per cycle
num_items = tNode.num_items and tNode.num_items[stage],
power_consumption = power_used and
power_consumption = power_used and
tNode.power_consumption[stage] or 0,
node_timer = tNode.node_timer,
cycle_time = tNode.cycle_time,
@ -177,6 +183,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
local node = minetest.get_node(pos)
meta:set_int("push_dir", techage.side_to_indir("L", node.param2))
meta:set_int("pull_dir", techage.side_to_indir("R", node.param2))
meta:set_string("owner", placer:get_player_name())
-- Delete existing node number. Needed for Digtron compatibility.
if (meta:contains("node_number")) then
meta:set_string("node_number", "")
@ -202,7 +209,7 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end
tNode.groups.not_in_creative_inventory = 0
local def_pas = {
@ -227,6 +234,9 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
on_metadata_inventory_move = tNode.on_metadata_inventory_move,
on_metadata_inventory_put = tNode.on_metadata_inventory_put,
on_metadata_inventory_take = tNode.on_metadata_inventory_take,
ta_rotate_node = tNode.ta_rotate_node,
ta3_formspec = stage == 3 and tNode.ta3_formspec,
ta4_formspec = stage == 4 and tNode.ta4_formspec,
paramtype = tNode.paramtype,
paramtype2 = "facedir",
@ -267,6 +277,9 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
on_metadata_inventory_move = tNode.on_metadata_inventory_move,
on_metadata_inventory_put = tNode.on_metadata_inventory_put,
on_metadata_inventory_take = tNode.on_metadata_inventory_take,
ta_rotate_node = tNode.ta_rotate_node,
ta3_formspec = stage == 3 and tNode.ta3_formspec,
ta4_formspec = stage == 4 and tNode.ta4_formspec,
paramtype = tNode.paramtype,
paramtype2 = "facedir",
@ -283,19 +296,19 @@ function techage.register_consumer(base_name, inv_name, tiles, tNode, validState
def_act[k] = v
end
end
minetest.register_node(name_act, def_act)
if power_used then
power.register_nodes({name_pas, name_act}, power_network, "con", sides)
end
techage.register_node({name_pas, name_act}, tNode.tubing)
if tNode.tube_sides then
Tube:set_valid_sides(name_pas, get_keys(tNode.tube_sides))
Tube:set_valid_sides(name_act, get_keys(tNode.tube_sides))
end
end
end
return names[1], names[2], names[3]
return names[1], names[2], names[3], names[4]
end

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Distributor
]]--
-- for lazy programmers
@ -34,7 +34,8 @@ local INFO = [[Turn port on/off or read its state: command = 'port', payload = r
--local Side2Color = {B="red", L="green", F="blue", R="yellow"}
local SlotColors = {"red", "green", "blue", "yellow"}
local Num2Ascii = {"B", "L", "F", "R"}
local SlotNumbers = {red = 1, green = 2, blue = 3, yellow = 4}
local Num2Ascii = {"B", "L", "F", "R"}
local FilterCache = {} -- local cache for filter settings
local function filter_settings(pos)
@ -72,9 +73,9 @@ local function filter_settings(pos)
end
end
end
FilterCache[minetest.hash_node_position(pos)] = {
ItemFilter = ItemFilter,
ItemFilter = ItemFilter,
OpenPorts = OpenPorts,
}
end
@ -88,7 +89,7 @@ local function get_filter_settings(pos)
-- }
-- local OpenPorts = {3}
-- return ItemFilter, OpenPorts
local hash = minetest.hash_node_position(pos)
if FilterCache[hash] == nil then
filter_settings(pos)
@ -111,8 +112,8 @@ local function blocking_checkbox(pos, filter, is_hp)
M(pos):set_int("blocking", 0) -- disable blocking
end
return ""
end
end
local function formspec(self, pos, nvm)
local filter = minetest.deserialize(M(pos):get_string("filter")) or {false,false,false,false}
local is_hp = nvm.high_performance == true
@ -185,7 +186,7 @@ end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
@ -247,7 +248,7 @@ local function tubelib2_on_update2(pos, outdir, tlib2, node)
is_ta4_tube = is_ta4_tube and techage.TA4tubes[node.name]
end
end
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
if CRD(pos).stage == 4 and not is_ta4_tube then
@ -276,10 +277,17 @@ local function push_item(pos, base_filter, itemstack, num_items, nvm)
num_of_trials = num_of_trials + 1
local push_dir = filter[idx]
local num_to_push = math.min(amount, num_items - num_pushed)
if techage.push_items(pos, push_dir, itemstack:peek_item(num_to_push)) then
num_pushed = num_pushed + num_to_push
nvm.port_counter[push_dir] = (nvm.port_counter[push_dir] or 0) + num_to_push
local leftover = techage.push_items(pos, push_dir, itemstack:peek_item(num_to_push))
local pushed
if not leftover then
pushed = 0
elseif leftover ~= true then
pushed = num_to_push - leftover:get_count()
else -- leftover == true
pushed = num_to_push
end
num_pushed = num_pushed + pushed
nvm.port_counter[push_dir] = (nvm.port_counter[push_dir] or 0) + pushed
-- filter start offset
idx = idx + 1
if idx > num_ports then
@ -295,10 +303,10 @@ local function distributing(pos, inv, crd, nvm)
local sum_num_pushed = 0
local num_pushed = 0
local blocking_mode = M(pos):get_int("blocking") == 1
-- start searching after last position
local offs = nvm.last_index or 1
for i = 1, SRC_INV_SIZE do
local idx = ((i + offs - 1) % 8) + 1
local stack = inv:get_stack("src", idx)
@ -308,7 +316,7 @@ local function distributing(pos, inv, crd, nvm)
local stack_to_push = stack:peek_item(num_to_push)
local filter = item_filter[item_name]
num_pushed = 0
if filter and #filter > 0 then
-- Push items based on filter
num_pushed = push_item(pos, filter, stack_to_push, num_to_push, nvm)
@ -320,16 +328,16 @@ local function distributing(pos, inv, crd, nvm)
-- Push items based on open ports
num_pushed = push_item(pos, open_ports, stack_to_push, num_to_push, nvm)
end
sum_num_pushed = sum_num_pushed + num_pushed
stack:take_item(num_pushed)
inv:set_stack("src", idx, stack)
if sum_num_pushed >= (nvm.num_items or crd.num_items) then
if sum_num_pushed >= (nvm.num_items or crd.num_items) then
nvm.last_index = idx
break
break
end
end
if sum_num_pushed == 0 then
crd.State:blocked(pos, nvm)
else
@ -370,9 +378,9 @@ local function on_receive_fields(pos, formname, fields, player)
meta:set_int("blocking", fields.blocking == "true" and 1 or 0)
end
meta:set_string("filter", minetest.serialize(filter))
filter_settings(pos)
local nvm = techage.get_nvm(pos)
if fields.state_button ~= nil then
crd.State:state_button_event(pos, nvm, fields)
@ -383,17 +391,17 @@ end
-- techage command to turn on/off filter channels
local function change_filter_settings(pos, slot, val)
local slots = {["red"] = 1, ["green"] = 2, ["blue"] = 3, ["yellow"] = 4}
local meta = M(pos)
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
local num = slots[slot] or 1
local num = SlotNumbers[slot] or 1
if num >= 1 and num <= 4 then
filter[num] = val == "on"
end
meta:set_string("filter", minetest.serialize(filter))
filter_settings(pos)
local hash = minetest.hash_node_position(pos)
FilterCache[hash] = nil
local nvm = techage.get_nvm(pos)
meta:set_string("formspec", formspec(CRD(pos).State, pos, nvm))
return true
@ -401,9 +409,45 @@ end
-- techage command to read filter channel status (on/off)
local function read_filter_settings(pos, slot)
local slots = {["red"] = 1, ["green"] = 2, ["blue"] = 3, ["yellow"] = 4}
local filter = minetest.deserialize(M(pos):get_string("filter")) or {false,false,false,false}
return filter[slots[slot]] and "on" or "off"
return filter[SlotNumbers[slot]] and "on" or "off"
end
local function get_payload_values(payload)
local color
local idx = 0
local items = {ItemStack(""), ItemStack(""), ItemStack(""), ItemStack(""), ItemStack(""), ItemStack("")}
for s in payload:gmatch("[^%s]+") do --- white spaces
if not color then
if SlotNumbers[s] then
color = s
else
return "red", {}
end
else
idx = idx + 1
if idx <= 6 then
items[idx] = ItemStack(s)
end
end
end
return color, items
end
local function str_of_inv_items(pos, color)
color = SlotColors[color] or color
if SlotNumbers[color] then
local inv = M(pos):get_inventory()
local t = {}
for idx = 1, 6 do
local item = inv:get_stack(color, idx)
if item:get_count() > 0 then
t[#t + 1] = item:get_name()
end
end
return table.concat(t, " ")
end
return ""
end
local function can_dig(pos, player)
@ -431,7 +475,7 @@ local get_tiles = function(is_hp)
tiles.act = {
-- up, down, right, left, back, front
{
image = "techage_filling4_ta#.png^techage_appl_distri4.png^techage_frame4_ta#_top"..variant..".png^techage_appl_color_top4.png",
name = "techage_filling4_ta#.png^techage_appl_distri4.png^techage_frame4_ta#_top"..variant..".png^techage_appl_color_top4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -474,10 +518,47 @@ local tubing = {
else
return change_filter_settings(pos, slot, val)
end
else
elseif topic == "config" then
local color, items = get_payload_values(payload)
local inv = M(pos):get_inventory()
for idx,item in ipairs(items) do
inv:set_stack(color, idx, item)
end
local hash = minetest.hash_node_position(pos)
FilterCache[hash] = nil
return true
elseif topic == "get" then
return str_of_inv_items(pos, payload)
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 4 then
local slot = SlotColors[payload[1]]
local state = payload[2] == 1 and "on" or "off"
change_filter_settings(pos, slot, state)
return 0
elseif topic == 67 then
local color, items = get_payload_values(payload)
local inv = M(pos):get_inventory()
for idx,item in ipairs(items) do
inv:set_stack(color, idx, item)
end
local hash = minetest.hash_node_position(pos)
FilterCache[hash] = nil
return 0
else
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 148 then
return 0, str_of_inv_items(pos, payload[1])
else
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Electronic Fab
]]--
-- for lazy programmers
@ -26,27 +26,25 @@ local recipes = techage.recipes
local RecipeType = {
[2] = "ta2_electronic_fab",
[3] = "ta3_electronic_fab",
[3] = "ta3_electronic_fab",
[4] = "ta4_electronic_fab",
}
local function formspec(self, pos, nvm)
local rtype = RecipeType[CRD(pos).stage]
local owner = M(pos):get_string("owner")
return "size[8.4,8.4]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;0,0;2,4;]"..
recipes.formspec(2.2, 0, rtype, nvm)..
"list[context;dst;6.4,0;2,4;]"..
"image_button[3.7,3.3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3.7,3.3;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[current_player;main;0.2,4.5;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0.2, 4.5)
"list[context;src;0,0;2,4;]"..
recipes.formspec(2.2, 0, rtype, nvm, owner)..
"list[context;dst;6.4,0;2,4;]"..
"image_button[3.7,3.3;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3.7,3.3;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[current_player;main;0.2,4.5;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0.2, 4.5)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
@ -75,11 +73,26 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player
return stack:get_count()
end
local function get_original_waste(inv, waste)
-- Waste has meta data, so we need to find the original waste item
for i = 1, 8 do
local stack = inv:get_stack("src", i)
if stack:get_count() == 1 then
if stack:get_name() == waste:get_name() then
return stack
end
end
end
return waste
end
local function making(pos, crd, nvm, inv)
local owner = M(pos):get_string("owner")
local rtype = RecipeType[crd.stage]
local recipe = recipes.get(nvm, rtype)
local output = ItemStack(recipe.output.name.." "..recipe.output.num)
if inv:room_for_item("dst", output) then
local recipe = recipes.get(nvm, rtype, owner)
local output = ItemStack(recipe.output.name .. " " .. recipe.output.num)
local waste = recipe.waste and ItemStack(recipe.waste.name .. " " .. recipe.waste.num)
if inv:room_for_item("dst", output) and (not waste or inv:room_for_item("dst", waste)) then
for _,item in ipairs(recipe.input) do
local input = ItemStack(item.name.." "..item.num)
if not inv:contains_item("src", input) then
@ -87,11 +100,25 @@ local function making(pos, crd, nvm, inv)
return
end
end
-- For some recipes, an item customized via metadata is used as a copy template.
-- This allows specially programmed items such as ROM chips to be produced.
-- The metadata of the copy template must be passed to the on_production function.
-- At the same time, the metadata of the copy template must not be lost when moving
-- as 'waste' to the output inventory.
local idef = minetest.registered_items[recipe.output.name]
if waste and idef and idef.on_production then
waste = get_original_waste(inv, waste)
local metadata = waste:get_meta():to_table().fields or {}
output = idef.on_production(output, metadata)
end
for _,item in ipairs(recipe.input) do
local input = ItemStack(item.name.." "..item.num)
inv:remove_item("src", input)
end
inv:add_item("dst", output)
if waste then
inv:add_item("dst", waste)
end
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
return
end
@ -111,14 +138,14 @@ local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
if not nvm.running then
if not nvm.running then
recipes.on_receive_fields(pos, formname, fields, player)
end
crd.State:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", formspec(crd.State, pos, nvm))
end
@ -149,7 +176,7 @@ tiles.act = {
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
image = "techage_filling4_ta#.png^techage_appl_electronic_fab4.png^techage_frame4_ta#.png",
name = "techage_filling4_ta#.png^techage_appl_electronic_fab4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -159,7 +186,7 @@ tiles.act = {
},
},
{
image = "techage_filling4_ta#.png^techage_appl_electronic_fab4.png^techage_frame4_ta#.png",
name = "techage_filling4_ta#.png^techage_appl_electronic_fab4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -204,12 +231,18 @@ local tubing = {
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("electronic_fab", S("Electronic Fab"), tiles, {
drawtype = "normal",
cycle_time = CYCLE_TIME,
@ -261,24 +294,21 @@ minetest.register_craft({
},
})
if minetest.global_exists("unified_inventory") then
unified_inventory.register_craft_type("ta2_electronic_fab", {
description = S("TA2 Ele Fab"),
icon = 'techage_filling_ta2.png^techage_appl_electronic_fab.png^techage_frame_ta2.png',
width = 2,
height = 2,
})
unified_inventory.register_craft_type("ta3_electronic_fab", {
description = S("TA3 Ele Fab"),
icon = 'techage_filling_ta3.png^techage_appl_electronic_fab.png^techage_frame_ta3.png',
width = 2,
height = 2,
})
unified_inventory.register_craft_type("ta4_electronic_fab", {
description = S("TA4 Ele Fab"),
icon = 'techage_filling_ta4.png^techage_appl_electronic_fab.png^techage_frame_ta4.png',
width = 2,
height = 2,
})
end
techage.recipes.register_craft_type("ta2_electronic_fab", {
description = S("TA2 Ele Fab"),
icon = 'techage_filling_ta2.png^techage_appl_electronic_fab.png^techage_frame_ta2.png',
width = 2,
height = 2,
})
techage.recipes.register_craft_type("ta3_electronic_fab", {
description = S("TA3 Ele Fab"),
icon = 'techage_filling_ta3.png^techage_appl_electronic_fab.png^techage_frame_ta3.png',
width = 2,
height = 2,
})
techage.recipes.register_craft_type("ta4_electronic_fab", {
description = S("TA4 Ele Fab"),
icon = 'techage_filling_ta4.png^techage_appl_electronic_fab.png^techage_frame_ta4.png',
width = 2,
height = 2,
})

View File

@ -9,7 +9,7 @@
See LICENSE.txt for more information
Forceload block
]]--
-- for lazy programmers
@ -38,7 +38,7 @@ end
local function remove_list_elem(list, x)
local n = nil
for idx, v in ipairs(list) do
if vector.equals(v, x) then
if vector.equals(v, x) then
n = idx
break
end
@ -59,12 +59,12 @@ local function postload_area(pos)
minetest.after(60, postload_area, pos)
end
end
local function add_pos(pos, player)
local meta = player:get_meta()
local lPos = minetest.deserialize(meta:get_string("techage_forceload_blocks")) or {}
if not in_list(lPos, pos) and (#lPos < techage.max_num_forceload_blocks or
creative and creative.is_enabled_for and
minetest.global_exists("creative") and creative.is_enabled_for and
creative.is_enabled_for(player:get_player_name())) then
lPos[#lPos+1] = pos
local meta = player:get_meta()
@ -73,12 +73,16 @@ local function add_pos(pos, player)
end
return false
end
local function del_pos(pos, player)
local meta = player:get_meta()
local lPos = minetest.deserialize(meta:get_string("techage_forceload_blocks")) or {}
lPos = remove_list_elem(lPos, pos)
meta:set_string("techage_forceload_blocks", minetest.serialize(lPos))
if next(lPos) then
meta:set_string("techage_forceload_blocks", minetest.serialize(lPos))
else
meta:set_string("techage_forceload_blocks", "")
end
end
local function get_pos_list(player)
@ -88,16 +92,20 @@ end
local function set_pos_list(player, lPos)
local meta = player:get_meta()
meta:set_string("techage_forceload_blocks", minetest.serialize(lPos))
if next(lPos) then
meta:set_string("techage_forceload_blocks", minetest.serialize(lPos))
else
meta:set_string("techage_forceload_blocks", "")
end
end
local function shoe_flbs(pos, name, range)
local function show_flbs(pos, name, range)
local pos1 = {x=pos.x-range, y=pos.y-range, z=pos.z-range}
local pos2 = {x=pos.x+range, y=pos.y+range, z=pos.z+range}
for _,npos in ipairs(minetest.find_nodes_in_area(pos1, pos2, {"techage:forceload", "techage:forceloadtile"})) do
local _pos1, _pos2 = calc_area(npos)
local owner = M(npos):get_string("owner")
techage.mark_region(name, _pos1, _pos2, owner)
techage.mark_region(name, _pos1, _pos2, owner .. " " .. P2S(npos))
end
end
@ -114,21 +122,26 @@ local function formspec(name)
if player then
local lPos = get_pos_list(player)
local tRes = {}
for idx,pos in ipairs(lPos) do
tRes[#tRes+1] = "#"
tRes[#tRes+1] = S("Block at pos")
tRes[#tRes+1] = S("Area from")
tRes[#tRes+1] = S("Area to")
tRes[#tRes+1] = S("Status")
for idx,pos in ipairs(lPos) do
local pos1, pos2 = calc_area(pos)
local ypos = 0.2 + idx * 0.4
tRes[#tRes+1] = idx
tRes[#tRes+1] = minetest.formspec_escape(P2S(pos))
tRes[#tRes+1] = minetest.formspec_escape(P2S(pos1))
tRes[#tRes+1] = "to"
tRes[#tRes+1] = minetest.formspec_escape(P2S(pos2))
tRes[#tRes+1] = minetest.forceload_block(pos, true) and 'Loaded' or 'Unloaded'
end
return "size[7,9]"..
return "size[9,9]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"label[0,0;"..S("List of your Forceload Blocks:").."]"..
"tablecolumns[text,width=1.2;text,width=12;text,width=1.6;text,width=12]"..
"table[0,0.6;6.8,8.4;output;"..table.concat(tRes, ",")..";1]"
"tablecolumns[text,width=1.8;text,width=12;text,width=12;text,width=12;text,width=12]"..
"table[0,0.6;8.8,8.4;output;"..table.concat(tRes, ",")..";1]"
end
end
@ -170,7 +183,7 @@ local function on_rightclick(pos, node, clicker, itemstack, pointed_thing)
if name == owner or minetest.check_player_privs(name, "server") then
local s = formspec(owner)
if s then
minetest.show_formspec(owner, "techage:forceload", s)
minetest.show_formspec(name, "techage:forceload", s)
end
end
end
@ -187,7 +200,7 @@ minetest.register_node("techage:forceload", {
'techage_filling_ta2.png^techage_frame_ta2_top.png',
'techage_filling_ta2.png^techage_frame_ta2_top.png',
{
image = "techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_forceload.png",
name = "techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_forceload.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -202,10 +215,11 @@ minetest.register_node("techage:forceload", {
after_dig_node = after_dig_node,
on_rightclick = on_rightclick,
on_punch = on_punch,
paramtype = "light",
sunlight_propagates = true,
groups = {choppy=2, cracky=2, crumbly=2,
use_texture_alpha = techage.CLIP,
groups = {choppy=2, cracky=2, crumbly=2,
digtron_protected = 1,
not_in_creative_inventory = techage.max_num_forceload_blocks == 0 and 1 or 0},
is_ground_content = false,
@ -217,7 +231,7 @@ minetest.register_node("techage:forceloadtile", {
tiles = {
-- up, down, right, left, back, front
{
image = "techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_forceload.png",
name = "techage_filling_ta2.png^techage_frame_ta2_top.png^techage_appl_forceload.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -236,17 +250,17 @@ minetest.register_node("techage:forceloadtile", {
{-4/16, -8/16, -4/16, 4/16, -15/32, 4/16},
},
},
on_place = on_place,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
on_rightclick = on_rightclick,
on_punch = on_punch,
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
groups = {choppy=2, cracky=2, crumbly=2,
groups = {choppy=2, cracky=2, crumbly=2,
not_in_creative_inventory = techage.max_num_forceload_blocks == 0 and 1 or 0},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
@ -266,6 +280,11 @@ if techage.max_num_forceload_blocks > 0 then
output = "techage:forceloadtile",
recipe = {"techage:forceload"},
})
minetest.register_craft({
type = "shapeless",
output = "techage:forceload",
recipe = {"techage:forceloadtile"},
})
end
minetest.register_on_joinplayer(function(player)
@ -293,15 +312,29 @@ minetest.register_chatcommand("forceload", {
params = "",
description = S("Show all forceload blocks in a 64x64x64 range"),
func = function(name, param)
if minetest.check_player_privs(name, "superminer") then
local player = minetest.get_player_by_name(name)
if player then
local pos = player:get_pos()
pos = vector.round(pos)
shoe_flbs(pos, name, 64)
end
else
return false, S("Priv missing")
local player = minetest.get_player_by_name(name)
if player then
local pos = player:get_pos()
pos = vector.round(pos)
show_flbs(pos, name, 64)
end
end,
})
minetest.register_chatcommand("forceload_verify", {
params = "",
description = "Checks each forceload block and returns a count of active/placed blocks",
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then
local loaded = {}
local wanted = get_pos_list(player)
for _,pos in ipairs(wanted) do
if minetest.forceload_block(pos, true) then
loaded[#loaded+1] = pos
end
end
minetest.chat_send_player(name, "Found "..#loaded.." out of ".. #wanted .. " force loads")
end
end,
})

View File

@ -7,16 +7,16 @@
AGPL v3
See LICENSE.txt for more information
Tube support for default chests and furnace
]]--
local OwnerCache = {
}
-- Check if the chest is in the protected area of the owner
local function is_owner(pos, meta)
local function is_owner(pos, meta)
local owner = meta:get_string("owner")
local key = minetest.hash_node_position(pos)
-- If successfull, store info in cache
@ -27,7 +27,7 @@ local function is_owner(pos, meta)
end
return OwnerCache[key] == owner
end
techage.register_node({"default:chest", "default:chest_open"}, {
on_inv_request = function(pos, in_dir, access_type)
@ -49,7 +49,7 @@ techage.register_node({"default:chest", "default:chest_open"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
})
techage.register_node({"default:chest_locked", "default:chest_locked_open"}, {
on_inv_request = function(pos, in_dir, access_type)
@ -75,13 +75,17 @@ techage.register_node({"default:chest_locked", "default:chest_locked_open"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
})
techage.register_node({"shop:shop"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
if is_owner(pos, meta) then
return meta:get_inventory(), "main"
if access_type == "push" then
return meta:get_inventory(), "stock"
elseif access_type == "pull" then
return meta:get_inventory(), "register"
end
end
end,
on_pull_item = function(pos, in_dir, num)
@ -101,7 +105,7 @@ techage.register_node({"shop:shop"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "register", stack)
end,
})
})
techage.register_node({"default:furnace", "default:furnace_active"}, {
on_pull_item = function(pos, in_dir, num)
@ -109,22 +113,24 @@ techage.register_node({"default:furnace", "default:furnace_active"}, {
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "dst", num)
end,
on_push_item = function(pos, side, stack)
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
minetest.get_node_timer(pos):start(1.0)
if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
if in_dir == 5 then
return techage.put_items(inv, "src", stack)
elseif minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
return techage.put_items(inv, "fuel", stack)
else
return techage.put_items(inv, "src", stack)
end
end,
on_unpull_item = function(pos, side, stack)
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "dst", stack)
end,
})
})
techage.register_node({"mobs:beehive"}, {
on_pull_item = function(pos, in_dir, num)
@ -137,7 +143,7 @@ techage.register_node({"mobs:beehive"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "beehive", stack)
end,
})
})
techage.register_node({"xdecor:hive"}, {
on_pull_item = function(pos, in_dir, num)
@ -150,4 +156,4 @@ techage.register_node({"xdecor:hive"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "honey", stack)
end,
})
})

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2 Gravel Rinser, washing sieved gravel to find more ores
]]--
-- for lazy programmers
@ -146,25 +146,26 @@ local function washing(pos, crd, nvm, inv)
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
return
end
local src = ItemStack("techage:sieved_gravel")
local dst = ItemStack("default:sand")
if inv:contains_item("src", src) then
if not inv:room_for_item("dst", dst) then
crd.State:blocked(pos, nvm)
return
end
local ore = get_random_gravel_ore()
if ore then
add_object({x=pos.x, y=pos.y+1, z=pos.z}, ore)
end
inv:add_item("dst", dst)
inv:remove_item("src", src)
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
return
else
crd.State:idle(pos, nvm)
return
end
if not inv:room_for_item("dst", dst) then
crd.State:idle(pos, nvm)
return
end
inv:add_item("dst", dst)
inv:remove_item("src", src)
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
local function keep_running(pos, elapsed)
@ -206,7 +207,7 @@ tiles.pas = {
tiles.act = {
-- up, down, right, left, back, front
{
image = "techage_appl_rinser4_top.png^techage_frame4_ta#_top.png",
name = "techage_appl_rinser4_top.png^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -248,13 +249,19 @@ local tubing = {
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
remove_objects({x=pos.x, y=pos.y+1, z=pos.z})
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("rinser", S("Gravel Rinser"), tiles, {
drawtype = "nodebox",
paramtype = "light",
@ -316,24 +323,19 @@ minetest.register_craft({
})
if minetest.global_exists("unified_inventory") then
unified_inventory.register_craft_type("rinsing", {
description = S("Rinsing"),
icon = "techage_appl_rinser_top.png^techage_frame_ta2_top.png",
width = 2,
height = 2,
})
end
techage.recipes.register_craft_type("rinsing", {
description = S("Rinsing"),
icon = "techage_appl_rinser_top.png^techage_frame_ta2_top.png",
width = 2,
height = 2,
})
function techage.add_rinser_recipe(recipe)
Probability[recipe.output] = recipe.probability
if minetest.global_exists("unified_inventory") then
recipe.items = {recipe.input}
recipe.type = "rinsing"
unified_inventory.register_craft(recipe)
end
end
recipe.items = {recipe.input}
recipe.type = "rinsing"
techage.recipes.register_craft(recipe)
end
techage.add_rinser_recipe({input="techage:sieved_gravel", output="techage:usmium_nuggets", probability=30})
techage.add_rinser_recipe({input="techage:sieved_gravel", output="default:copper_lump", probability=15})

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Gravel Sieve, sieving gravel to find ores
]]--
-- for lazy programmers
@ -133,7 +133,7 @@ tiles.pas = {
tiles.act = {
-- up, down, right, left, back, front
{
image = "techage_appl_sieve4_top.png^techage_frame4_ta#_top.png",
name = "techage_appl_sieve4_top.png^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -174,12 +174,18 @@ local tubing = {
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("gravelsieve", S("Gravel Sieve"), tiles, {
drawtype = "nodebox",
paramtype = "light",
@ -246,38 +252,36 @@ minetest.register_craft({
},
})
if minetest.global_exists("unified_inventory") then
unified_inventory.register_craft_type("ta2_gravelsieve", {
description = S("TA2 Gravel Sieve"),
icon = 'techage_sieve_sieve_ta1.png',
width = 1,
height = 1,
})
unified_inventory.register_craft_type("ta3_gravelsieve", {
description = S("TA3 Gravel Sieve"),
icon = 'techage_filling_ta3.png^techage_appl_sieve.png^techage_frame_ta3.png',
width = 1,
height = 1,
})
unified_inventory.register_craft_type("ta4_gravelsieve", {
description = S("TA4 Gravel Sieve"),
icon = 'techage_filling_ta4.png^techage_appl_sieve.png^techage_frame_ta4.png',
width = 1,
height = 1,
})
unified_inventory.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta2_gravelsieve",
})
unified_inventory.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta3_gravelsieve",
})
unified_inventory.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta4_gravelsieve",
})
end
techage.recipes.register_craft_type("ta2_gravelsieve", {
description = S("TA2 Gravel Sieve"),
icon = 'techage_sieve_sieve_ta1.png',
width = 1,
height = 1,
})
techage.recipes.register_craft_type("ta3_gravelsieve", {
description = S("TA3 Gravel Sieve"),
icon = 'techage_filling_ta3.png^techage_appl_sieve.png^techage_frame_ta3.png',
width = 1,
height = 1,
})
techage.recipes.register_craft_type("ta4_gravelsieve", {
description = S("TA4 Gravel Sieve"),
icon = 'techage_filling_ta4.png^techage_appl_sieve.png^techage_frame_ta4.png',
width = 1,
height = 1,
})
techage.recipes.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta2_gravelsieve",
})
techage.recipes.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta3_gravelsieve",
})
techage.recipes.register_craft({
output = "techage:sieved_basalt_gravel",
items = {"techage:basalt_gravel"},
type = "ta4_gravelsieve",
})

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Grinder, grinding Cobble/Basalt to Gravel
]]--
-- for lazy programmers
@ -17,14 +17,15 @@ local M = minetest.get_meta
local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer or {} end
local STANDBY_TICKS = 3
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 4
-- Grinder recipes
-- Grinder recipes TA1
local RecipesTa1 = {}
-- Grinder recipes TA2 - TA4
local Recipes = {}
local function formspec(self, pos, nvm)
@ -55,7 +56,10 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player)
return 0
end
if listname == "src" then
CRD(pos).State:start_if_standby(pos)
local state = CRD(pos).State
if state then
state:start_if_standby(pos)
end
end
return stack:get_count()
end
@ -97,9 +101,9 @@ local function src_to_dst(src_stack, idx, src_name, num_items, inp_num, inv, dst
end
return false
end
local function grinding(pos, crd, nvm, inv)
local num_items = 0
local blocked = false -- idle
for idx,stack in ipairs(inv:get_list("src")) do
if not stack:is_empty() then
local name = stack:get_name()
@ -107,16 +111,21 @@ local function grinding(pos, crd, nvm, inv)
local recipe = Recipes[name]
if src_to_dst(stack, idx, name, crd.num_items, recipe.inp_num, inv, recipe.output) then
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
return
else
crd.State:blocked(pos, nvm)
blocked = true
end
else
crd.State:fault(pos, nvm)
return
end
return
end
end
crd.State:idle(pos, nvm)
if blocked then
crd.State:blocked(pos, nvm)
else
crd.State:idle(pos, nvm)
end
end
local function keep_running(pos, elapsed)
@ -158,7 +167,7 @@ tiles.pas = {
tiles.act = {
-- up, down, right, left, back, front
{
image = "techage_appl_grinder4.png^techage_frame4_ta#_top.png",
name = "techage_appl_grinder4.png^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -200,12 +209,18 @@ local tubing = {
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("grinder", S("Grinder"), tiles, {
drawtype = "nodebox",
paramtype = "light",
@ -245,6 +260,79 @@ local node_name_ta2, node_name_ta3, node_name_ta4 =
tube_sides = {L=1, R=1, U=1},
})
-------------------------------------------------------------------------------
-- TA1 Mill (watermill)
-------------------------------------------------------------------------------
local formspecStr = "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"list[context;src;1,1;1,1;]"..
"item_image[1,1;1,1;farming:wheat]"..
"image[1,1;1,1;techage_form_mask.png]"..
"image[3.5,1;1,1;techage_form_arrow.png]"..
"list[context;dst;6,1;1,1;]"..
"item_image[6,1;1,1;farming:flour]"..
"image[6,1;1,1;techage_form_mask.png]"..
"list[current_player;main;0,4;8,4;]"..
"listring[context;dst]"..
"listring[current_player;main]"..
"listring[context;src]"..
"listring[current_player;main]"..
default.get_hotbar_bg(0, 4)
local function node_timer(pos, elapsed)
if techage.ta1_mill_has_power(pos, 2) then
local inv = M(pos):get_inventory()
local stack = inv:get_stack("src", 1)
if not stack:is_empty() then
local name = stack:get_name()
if RecipesTa1[name] then
local recipe = RecipesTa1[name]
src_to_dst(stack, 1, name, 1, recipe.inp_num, inv, recipe.output)
end
end
end
return true
end
minetest.register_node("techage:ta1_mill_base", {
description = S("TA1 Mill Base"),
tiles = {
"techage_mill_base.png",
"default_stone_brick.png",
},
after_place_node = function(pos, placer)
M(pos):set_string("formspec", formspecStr)
local inv = M(pos):get_inventory()
inv:set_size('src', 1)
inv:set_size('dst', 1)
minetest.get_node_timer(pos):start(4)
end,
can_dig = can_dig,
on_timer = node_timer,
allow_metadata_inventory_put = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
allow_metadata_inventory_take = allow_metadata_inventory_take,
is_ground_content = false,
groups = {cracky = 2, crumbly = 2, choppy = 2},
})
techage.register_node({"techage:ta1_mill_base"}, {
on_node_load = function(pos, node)
minetest.get_node_timer(pos):start(4)
end,
})
minetest.register_craft({
output = "techage:ta1_mill_base",
recipe = {
{"default:stonebrick", "", "default:stonebrick"},
{"", "techage:iron_ingot", ""},
{"default:stonebrick", "", "default:stonebrick"},
},
})
minetest.register_craft({
output = node_name_ta2,
recipe = {
@ -254,43 +342,55 @@ minetest.register_craft({
},
})
--minetest.register_craft({
-- output = node_name_ta3,
-- recipe = {
-- {"", "default:mese_crystal", ""},
-- {"", node_name_ta2, ""},
-- {"", "techage:vacuum_tube", ""},
-- },
--})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta2, ""},
{"", "techage:vacuum_tube", ""},
},
})
--minetest.register_craft({
-- output = node_name_ta4,
-- recipe = {
-- {"", "default:mese_crystal", ""},
-- {"", node_name_ta3, ""},
-- {"", "techage:ta4_wlanchip", ""},
-- },
--})
minetest.register_craft({
output = node_name_ta4,
recipe = {
{"", "default:mese_crystal", ""},
{"", node_name_ta3, ""},
{"", "techage:ta4_wlanchip", ""},
},
})
if minetest.global_exists("unified_inventory") then
unified_inventory.register_craft_type("grinding", {
description = S("Grinding"),
icon = 'techage_appl_grinder.png',
width = 2,
height = 2,
})
end
techage.recipes.register_craft_type("grinding", {
description = S("Grinding"),
icon = 'techage_appl_grinder.png',
width = 2,
height = 2,
})
techage.recipes.register_craft_type("milling", {
description = S("Milling"),
icon = 'techage_mill_inv.png',
width = 2,
height = 2,
})
function techage.add_grinder_recipe(recipe)
function techage.add_grinder_recipe(recipe, ta1_permitted)
local name, num = unpack(string.split(recipe.input, " ", false, 1))
Recipes[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output}
if minetest.global_exists("unified_inventory") then
if minetest.registered_items[name] then
if ta1_permitted then
RecipesTa1[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output}
recipe.items = {recipe.input}
recipe.type = "milling"
techage.recipes.register_craft(table.copy(recipe))
end
Recipes[name] = {input = name,inp_num = tonumber(num) or 1, output = recipe.output}
recipe.items = {recipe.input}
recipe.type = "grinding"
unified_inventory.register_craft(recipe)
techage.recipes.register_craft(recipe)
end
end
end
techage.add_grinder_recipe({input="default:cobble", output="default:gravel"})
@ -321,14 +421,15 @@ techage.add_grinder_recipe({input="default:acacia_tree", output="default:acacia_
techage.add_grinder_recipe({input="default:aspen_tree", output="default:aspen_leaves 8"})
if minetest.global_exists("farming") then
techage.add_grinder_recipe({input="farming:wheat 3", output="farming:flour"})
techage.add_grinder_recipe({input="farming:seed_wheat 6", output="farming:flour"})
techage.add_grinder_recipe({input="farming:barley 3", output="farming:flour"})
techage.add_grinder_recipe({input="farming:seed_barley 6", output="farming:flour"})
techage.add_grinder_recipe({input="farming:rye 3", output="farming:flour"})
techage.add_grinder_recipe({input="farming:seed_rye 6", output="farming:flour"})
techage.add_grinder_recipe({input="farming:rice 3", output="farming:rice_flour"})
techage.add_grinder_recipe({input="farming:seed_rice 6", output="farming:rice_flour"})
techage.add_grinder_recipe({input="farming:oat 3", output="farming:flour"})
techage.add_grinder_recipe({input="farming:seed_oat 6", output="farming:flour"})
techage.add_grinder_recipe({input="farming:wheat 3", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_wheat 6", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:barley 3", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_barley 6", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:rye 3", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_rye 6", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:rice 3", output="farming:rice_flour"}, true)
techage.add_grinder_recipe({input="farming:seed_rice 6", output="farming:rice_flour"}, true)
techage.add_grinder_recipe({input="farming:oat 3", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_oat 6", output="farming:flour"}, true)
techage.add_grinder_recipe({input="farming:seed_cotton 3", output="basic_materials:oil_extract"}, true)
end

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Item Source Block
]]--
@ -16,7 +16,7 @@ local M = minetest.get_meta
local S = techage.S
local CYCLE_TIME = 30
local function formspec()
return "size[8,7.2]"..
default.gui_bg..
@ -32,7 +32,7 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
@ -40,7 +40,7 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
@ -73,15 +73,21 @@ minetest.register_node("techage:itemsource", {
local stack = inv:get_stack('main', 1)
if stack:get_count() > 0 then
local push_dir = meta:get_int("push_dir")
if techage.push_items(pos, push_dir, stack) then
local cnt = meta:get_int("counter") + stack:get_count()
meta:set_int("counter", cnt)
meta:set_string("infotext", "Techage Item Source: "..cnt)
local leftover = techage.push_items(pos, push_dir, stack)
local pushed
if not leftover then
pushed = 0
elseif leftover ~= true then
pushed = stack:get_count() - leftover:get_count()
else -- leftover == true
pushed = stack:get_count()
end
meta:set_int("counter", pushed)
meta:set_string("infotext", "Techage Item Source: "..pushed)
end
return true
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
@ -97,4 +103,4 @@ techage.register_node({"techage:itemsource"}, {
on_node_load = function(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})
})

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3 Bucket based Liquid Sampler
]]--
-- for lazy programmers
@ -96,7 +96,7 @@ end
local function keep_running(pos, elapsed)
--if tubelib.data_not_corrupted(pos) then
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
sample_liquid(pos, crd, nvm, inv)
end
@ -136,7 +136,7 @@ tiles.act = {
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
image = "techage_filling4_ta#.png^techage_liquidsampler4.png^techage_frame4_ta#.png",
name = "techage_filling4_ta#.png^techage_liquidsampler4.png^techage_frame4_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -173,9 +173,15 @@ local tubing = {
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
}
local node_name_ta2, node_name_ta3, _ =
local node_name_ta2, node_name_ta3, _ =
techage.register_consumer("liquidsampler", S("Liquid Sampler"), tiles, {
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
@ -220,4 +226,3 @@ minetest.register_craft({
{"", "techage:vacuum_tube", ""},
},
})

View File

@ -7,9 +7,9 @@
AGPL v3
See LICENSE.txt for more information
Tube support for digtron and protector chests
]]--
@ -20,7 +20,7 @@ local CacheForFuelNodeNames = {}
local function is_fuel(stack)
local name = stack:get_name()
if CacheForFuelNodeNames[name] then
if CacheForFuelNodeNames[name] then
return true
end
if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
@ -53,7 +53,7 @@ techage.register_node({"digtron:inventory"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
})
techage.register_node({"digtron:fuelstore"}, {
on_inv_request = function(pos, in_dir, access_type)
@ -75,7 +75,7 @@ techage.register_node({"digtron:fuelstore"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "fuel", stack)
end,
})
})
techage.register_node({"digtron:combined_storage"}, {
on_inv_request = function(pos, in_dir, access_type)
@ -102,7 +102,7 @@ techage.register_node({"digtron:combined_storage"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
})
------------------------------------------------------------------------------
-- protector
@ -128,6 +128,4 @@ techage.register_node({"protector:chest"}, {
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
})

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA2/TA3/TA4 Pusher
Nodes for push/pull operation of StackItems from chests or other
inventory/server nodes to tubes or other inventory/server nodes.
@ -33,7 +33,17 @@ local Tube = techage.Tube
local STANDBY_TICKS = 2
local COUNTDOWN_TICKS = 4
local CYCLE_TIME = 2
local WRENCH_MENU = {
{
type = "number",
name = "limit",
label = S("Number of items"),
tooltip = S("Number of items that are allowed to be pushed"),
default = "0",
},
}
local function ta4_formspec(self, pos, nvm)
if CRD(pos).stage == 4 then -- TA4 node?
return "size[8,7.2]"..
@ -42,7 +52,8 @@ local function ta4_formspec(self, pos, nvm)
default.gui_slots..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[3,-0.1;"..minetest.colorize("#000000", S("Pusher")).."]"..
techage.question_mark_help(8, S("Optionally configure\nthe pusher with one item"))..
techage.question_mark_help(7.5, S("Optionally configure\nthe pusher with one item"))..
techage.wrench_image(7.4, -0.05) ..
"list[context;main;3.5,0.8;1,1;]"..
"image_button[3.5,2;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[3.5,2;1,1;"..self:get_state_tooltip(nvm).."]"..
@ -56,12 +67,12 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) ~= techage.STOPPED then
return 0
end
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
if list[index]:get_count() == 0 then
@ -76,41 +87,83 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) ~= techage.STOPPED then
return 0
end
local inv = M(pos):get_inventory()
inv:set_stack(listname, index, nil)
return 0
end
local function set_limit(pos, nvm, val)
val = tonumber(val) or 0
if val > 0 then
nvm.limit = val
nvm.num_items = 0
M(pos):set_int("limit", val)
else
nvm.limit = nil
nvm.num_items = nil
M(pos):set_string("limit", "")
end
end
-- Function returns the number of pushed items
local function push(pos, crd, meta, nvm, pull_dir, push_dir, num)
local items = techage.pull_items(pos, pull_dir, num, nvm.item_name)
if items ~= nil then
local taken = items:get_count()
local leftover = techage.push_items(pos, push_dir, items)
if not leftover then
-- place item back
techage.unpull_items(pos, pull_dir, items)
crd.State:blocked(pos, nvm)
return 0
elseif leftover ~= true then
-- place item back
taken = taken - leftover:get_count()
techage.unpull_items(pos, pull_dir, leftover)
crd.State:blocked(pos, nvm)
return taken
end
return taken
end
crd.State:idle(pos, nvm)
return 0
end
local function pushing(pos, crd, meta, nvm)
local pull_dir = meta:get_int("pull_dir")
local push_dir = meta:get_int("push_dir")
local num = nvm.item_count or nvm.num_items or crd.num_items
local items = techage.pull_items(pos, pull_dir, num, nvm.item_name)
if items ~= nil then
if techage.push_items(pos, push_dir, items) ~= true then
-- place item back
techage.unpull_items(pos, pull_dir, items)
crd.State:blocked(pos, nvm)
return
end
if nvm.item_count then -- remote job?
nvm.item_count = nil
nvm.item_name = nil
crd.State:stop(pos, nvm)
local number = M(pos):get_string("node_number")
techage.send_single(number, nvm.rmt_num, "off")
else
if not nvm.limit then
local num = nvm.item_count or nvm.num_items or crd.num_items
num = push(pos, crd, meta, nvm, pull_dir, push_dir, num)
if num > 0 then
if nvm.item_count then
nvm.item_count = nvm.item_count - num
if nvm.item_count <= 0 then
crd.State:stop(pos, nvm)
nvm.item_count = nil
end
end
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
return
elseif nvm.num_items < nvm.limit then
local num = math.min(crd.num_items, nvm.limit - nvm.num_items)
num = push(pos, crd, meta, nvm, pull_dir, push_dir, num)
if num > 0 then
nvm.num_items = nvm.num_items + num
if nvm.num_items >= nvm.limit then
crd.State:stop(pos, nvm)
else
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
end
end
crd.State:idle(pos, nvm)
end
local function keep_running(pos, elapsed)
@ -118,7 +171,7 @@ local function keep_running(pos, elapsed)
local crd = CRD(pos)
pushing(pos, crd, M(pos), nvm)
crd.State:is_active(nvm)
end
end
local function on_rightclick(pos, node, clicker)
if CRD(pos).stage ~= 4 then -- Not TA4 node?
@ -148,14 +201,14 @@ local function tubelib2_on_update2(pos, outdir, tlib2, node)
local pull_dir = M(pos):get_int("pull_dir")
local push_dir = M(pos):get_int("push_dir")
local is_ta4_tube = true
for i, pos, node in Tube:get_tube_line(pos, pull_dir) do
is_ta4_tube = is_ta4_tube and techage.TA4tubes[node.name]
end
for i, pos, node in Tube:get_tube_line(pos, push_dir) do
is_ta4_tube = is_ta4_tube and techage.TA4tubes[node.name]
end
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
if CRD(pos).stage == 4 and not is_ta4_tube then
@ -180,14 +233,34 @@ local function can_start(pos, nvm, state)
return true
end
local function ta_after_formspec(pos, fields, playername)
local nvm = techage.get_nvm(pos)
set_limit(pos, nvm, fields.limit)
end
local function on_state_change(pos, old_state, new_state)
if old_state == techage.STOPPED and new_state == techage.RUNNING then
local nvm = techage.get_nvm(pos)
set_limit(pos, nvm, M(pos):get_int("limit"))
end
end
local function config_item(pos, payload)
local name, count = unpack(payload:split(" "))
if name and (minetest.registered_nodes[name] or minetest.registered_items[name]
or minetest.registered_craftitems[name]) then
count = tonumber(count) or 1
local inv = M(pos):get_inventory()
inv:set_stack("main", 1, {name = name, count = 1})
return count
if type(payload) == "string" then
if payload == "" then
local inv = M(pos):get_inventory()
inv:set_stack("main", 1, nil)
return 0
else
local name, count = unpack(payload:split(" "))
if name and (minetest.registered_nodes[name] or minetest.registered_items[name]
or minetest.registered_craftitems[name]) then
count = tonumber(count) or 1
local inv = M(pos):get_inventory()
inv:set_stack("main", 1, {name = name, count = 1})
return count
end
end
end
return 0
end
@ -197,7 +270,7 @@ local tiles = {}
-- '{power}' will be replaced by the power PNG
tiles.pas = {
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#_bottom.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_appl_pusher.png^[transformR180]^techage_frame_ta#.png",
@ -206,11 +279,11 @@ tiles.pas = {
tiles.act = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#_bottom.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
image = "techage_appl_pusher14.png^[transformR180]^techage_frame14_ta#.png",
name = "techage_appl_pusher14.png^[transformR180]^techage_frame14_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -220,7 +293,7 @@ tiles.act = {
},
},
{
image = "techage_appl_pusher14.png^techage_frame14_ta#.png",
name = "techage_appl_pusher14.png^techage_frame14_ta#.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -230,41 +303,76 @@ tiles.act = {
},
},
}
local tubing = {
-- push item through the pusher in opposit direction
on_push_item = function(pos, in_dir, stack)
return in_dir == M(pos):get_int("pull_dir") and techage.push_items(pos, in_dir, stack)
return in_dir == M(pos):get_int("pull_dir") and techage.safe_push_items(pos, in_dir, stack)
end,
is_pusher = true, -- is a pulling/pushing node
on_recv_message = function(pos, src, topic, payload)
if topic == "pull" then
if topic == "pull" then -- Deprecated command, use config/limit/start instead
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
nvm.item_count = math.min(config_item(pos, payload), 12)
nvm.rmt_num = src
CRD(pos).State:start(pos, nvm)
return true
elseif topic == "config" then
elseif topic == "config" then -- Set item type
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
config_item(pos, payload)
CRD(pos).State:start(pos, nvm)
return true
elseif topic == "limit" then -- Set push limit
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
set_limit(pos, nvm, payload)
return true
elseif topic == "count" then -- Get number of push items
local nvm = techage.get_nvm(pos)
return nvm.num_items or 0
else
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
if topic == 65 then -- Set item type
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
config_item(pos, payload)
return 0
elseif topic == 68 or topic == 20 then -- Set push limit
local nvm = techage.get_nvm(pos)
CRD(pos).State:stop(pos, nvm)
set_limit(pos, nvm, payload[1])
return 0
else
local nvm = techage.get_nvm(pos)
if nvm.limit then
nvm.num_items = 0
end
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 150 then -- Get number of pushed items
local nvm = techage.get_nvm(pos)
return 0, {nvm.num_items or 0}
else
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("pusher", S("Pusher"), tiles, {
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = ta4_formspec,
tubing = tubing,
can_start = can_start,
on_state_change = on_state_change,
after_place_node = function(pos, placer)
local meta = M(pos)
local node = minetest.get_node(pos)
@ -277,7 +385,14 @@ local node_name_ta2, node_name_ta3, node_name_ta4 =
M(pos):set_string("formspec", ta4_formspec(CRD(pos).State, pos, nvm))
end
end,
ta_rotate_node = function(pos, node, new_param2)
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
local meta = M(pos)
meta:set_int("pull_dir", techage.side_to_outdir("L", new_param2))
meta:set_int("push_dir", techage.side_to_outdir("R", new_param2))
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
on_rightclick = on_rightclick,
@ -285,7 +400,9 @@ local node_name_ta2, node_name_ta3, node_name_ta4 =
node_timer = keep_running,
on_rotate = screwdriver.disallow,
tubelib2_on_update2 = tubelib2_on_update2,
ta4_formspec = WRENCH_MENU,
ta_after_formspec = ta_after_formspec,
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
@ -319,4 +436,3 @@ minetest.register_craft({
{"", "techage:ta4_wlanchip", ""},
},
})

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Quarry machine to dig stones and other ground blocks.
The Quarry digs a hole (default) 5x5 blocks large and up to 80 blocks deep.
It starts at the given level (0 is same level as the quarry block,
1 is one level higher and so on)) and goes down to the given depth number.
@ -26,16 +26,16 @@ local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm
local S = techage.S
local CYCLE_TIME = 3
local CYCLE_TIME = 4
local STANDBY_TICKS = 4
local COUNTDOWN_TICKS = 4
local Side2Facedir = {F=0, R=1, B=2, L=3, D=4, U=5}
local Depth2Idx = {[1]=1 ,[2]=2, [3]=3, [5]=4, [10]=5, [15]=6, [20]=7, [25]=8, [40]=9, [60]=10, [80]=11}
local Depth2Idx = {[1]=1 ,[2]=2, [3]=3, [5]=4, [7]=5, [10]=6, [15]=7, [20]=8, [25]=9, [40]=10, [60]=11, [80]=12}
local Holesize2Idx = {["3x3"] = 1, ["5x5"] = 2, ["7x7"] = 3, ["9x9"] = 4, ["11x11"] = 5}
local Holesize2Diameter = {["3x3"] = 3, ["5x5"] = 5, ["7x7"] = 7, ["9x9"] = 9, ["11x11"] = 11}
local Level2Idx = {[2]=1, [1]=2, [0]=3, [-1]=4, [-2]=5, [-3]=6,
[-5]=7, [-10]=8, [-15]=9, [-20]=10}
local Level2Idx = {[2]=1, [1]=2, [0]=3, [-1]=4, [-2]=5, [-3]=6,
[-5]=7, [-10]=8, [-15]=9, [-20]=10}
local function formspec(self, pos, nvm)
local tooltip = S("Start level = 0\nmeans the same level\nas the quarry is placed")
@ -46,14 +46,16 @@ local function formspec(self, pos, nvm)
local hsize_list = "5x5"
if CRD(pos).stage == 4 then
hsize_list = "3x3,5x5,7x7,9x9,11x11"
elseif CRD(pos).stage == 3 then
hsize_list = "3x3,5x5,7x7"
end
local depth_list = "1,2,3,5,10,15,20,25,40,60,80"
local depth_list = "1,2,3,5,7,10,15,20,25,40,60,80"
if CRD(pos).stage == 3 then
depth_list = "1,2,3,5,10,15,20,25,40"
depth_list = "1,2,3,5,7,10,15,20,25,40"
elseif CRD(pos).stage == 2 then
depth_list = "1,2,3,5,10,15,20"
depth_list = "1,2,3,5,7,10,15,20"
end
return "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
@ -61,11 +63,11 @@ local function formspec(self, pos, nvm)
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[3.5,-0.1;"..minetest.colorize( "#000000", S("Quarry")).."]"..
techage.question_mark_help(8, tooltip)..
"dropdown[0,0.8;1.5;level;2,1,0,-1,-2,-3,-5,-10,-15,-20;"..level_idx.."]"..
"dropdown[0,0.8;1.5;level;2,1,0,-1,-2,-3,-5,-10,-15,-20;"..level_idx.."]"..
"label[1.6,0.9;"..S("Start level").."]"..
"dropdown[0,1.8;1.5;depth;"..depth_list..";"..depth_idx.."]"..
"dropdown[0,1.8;1.5;depth;"..depth_list..";"..depth_idx.."]"..
"label[1.6,1.9;"..S("Digging depth").." ("..level..")]"..
"dropdown[0,2.8;1.5;hole_size;"..hsize_list..";"..hsize_idx.."]"..
"dropdown[0,2.8;1.5;hole_size;"..hsize_list..";"..hsize_idx.."]"..
"label[1.6,2.9;"..S("Hole size").."]"..
"list[context;main;5,0.8;3,3;]"..
"image[4,0.8;1,1;"..techage.get_power_image(pos, nvm).."]"..
@ -80,7 +82,7 @@ local function play_sound(pos)
local mem = techage.get_mem(pos)
if not mem.handle or mem.handle == -1 then
mem.handle = minetest.sound_play("techage_quarry", {
pos = pos,
pos = pos,
gain = 1.5,
max_hear_distance = 15,
loop = true})
@ -114,7 +116,7 @@ local function get_pos(pos, facedir, side, steps)
facedir = (facedir + Side2Facedir[side]) % 4
local dir = vector.multiply(minetest.facedir_to_dir(facedir), steps or 1)
return vector.add(pos, dir)
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
@ -147,7 +149,7 @@ local function get_corner_positions(pos, facedir, hole_diameter)
return pos1, pos2
end
local function is_air_level(pos1, pos2, hole_diameter)
local function is_air_level(pos1, pos2, hole_diameter)
return #minetest.find_nodes_in_area(pos1, pos2, {"air"}) == hole_diameter * hole_diameter
end
@ -189,24 +191,28 @@ local function quarry_task(pos, crd, nvm)
end
return at_least_one_added
end
local pos1, pos2 = get_corner_positions(pos, facedir, nvm.hole_diameter)
nvm.level = 1
for y_curr = y_first, y_last, -1 do
pos1.y = y_curr
pos2.y = y_curr
-- Restarting the server can detach the coroutine data.
-- Therefore, read nvm again.
nvm = techage.get_nvm(pos)
nvm.level = y_first - y_curr
if minetest.is_area_protected(pos1, pos2, owner, 5) then
crd.State:fault(pos, nvm, S("area is protected"))
return
end
if not is_air_level(pos1, pos2, nvm.hole_diameter) then
mark_area(pos1, pos2, owner)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
coroutine.yield()
for zoffs = 1, nvm.hole_diameter do
for xoffs = 1, nvm.hole_diameter do
local qpos = get_quarry_pos(pos1, xoffs, zoffs)
@ -226,20 +232,20 @@ local function quarry_task(pos, crd, nvm)
end
crd.State:stop(pos, nvm, S("finished"))
end
local function keep_running(pos, elapsed)
local mem = techage.get_mem(pos)
if not mem.co then
mem.co = coroutine.create(quarry_task)
end
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local _, err = coroutine.resume(mem.co, pos, crd, nvm)
if err then
minetest.log("error", "[TA4 Quarry Coroutine Error]" .. err)
minetest.log("error", "[TA4 Quarry Coroutine Error] at pos " .. minetest.pos_to_string(pos) .. " " .. err)
end
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(crd.State, pos, nvm))
end
@ -268,7 +274,7 @@ local function on_receive_fields(pos, formname, fields, player)
end
local nvm = techage.get_nvm(pos)
local mem = techage.get_mem(pos)
if fields.depth then
if tonumber(fields.depth) ~= nvm.quarry_depth then
nvm.quarry_depth = tonumber(fields.depth)
@ -281,7 +287,7 @@ local function on_receive_fields(pos, formname, fields, player)
CRD(pos).State:stop(pos, nvm)
end
end
if fields.level then
if tonumber(fields.level) ~= nvm.start_level then
nvm.start_level = tonumber(fields.level)
@ -298,6 +304,13 @@ local function on_receive_fields(pos, formname, fields, player)
mem.co = nil
CRD(pos).State:stop(pos, nvm)
end
elseif CRD(pos).stage == 3 then
if fields.hole_size ~= nvm.hole_size then
nvm.hole_size = fields.hole_size
nvm.hole_diameter = Holesize2Diameter[fields.hole_size or "7x7"] or 7
mem.co = nil
CRD(pos).State:stop(pos, nvm)
end
else
nvm.hole_size = "5x5"
nvm.hole_diameter = 5
@ -324,7 +337,7 @@ tiles.act = {
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
{
image = "techage_frame14_ta#.png^techage_quarry_left14.png",
name = "techage_frame14_ta#.png^techage_quarry_left14.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -368,12 +381,28 @@ local tubing = {
return CRD(pos).State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 133 then -- Quarry Depth
local nvm = techage.get_nvm(pos)
return 0, {nvm.level or 0}
else
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
local nvm = techage.get_nvm(pos)
if nvm.techage_state == techage.RUNNING then
stop_sound(pos)
play_sound(pos)
end
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("quarry", S("Quarry"), tiles, {
drawtype = "normal",
cycle_time = CYCLE_TIME,

View File

@ -0,0 +1,243 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Recipe Block for the TA4 Autocrafter
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local M = minetest.get_meta
local S = techage.S
local MAX_RECIPE = 10
local function recipes_formspec(x, y, idx)
return "container[" .. x .. "," .. y .. "]" ..
"background[0,0;8,3.2;techage_form_grey.png]" ..
"list[context;input;0.1,0.1;3,3;]" ..
"image[3,1.1;1,1;techage_form_arrow.png]" ..
"list[context;output;3.9,1.1;1,1;]" ..
"button[5.5,1.1;1,1;priv;<<]" ..
"button[6.5,1.1;1,1;next;>>]" ..
"label[5.5,0.5;"..S("Recipe") .. ": " .. idx .. "/" .. MAX_RECIPE .. "]" ..
"container_end[]"
end
local function formspec(pos, nvm)
return "size[8,7.4]"..
recipes_formspec(0, 0, nvm.recipe_idx or 1) ..
"list[current_player;main;0,3.6;8,4;]" ..
"listring[current_player;main]"..
"listring[context;src]" ..
"listring[current_player;main]"..
"listring[context;dst]" ..
"listring[current_player;main]"
end
local function determine_new_input(pos, inv)
local output = inv:get_stack("output", 1):get_name()
if output and output ~= "" then
local recipe = minetest.get_craft_recipe(output)
if recipe.items and recipe.type == "normal" then
for i = 1, 9 do
local name = recipe.items[i]
if name then
if minetest.registered_items[name] then
inv:set_stack("input", i, name)
end
end
end
inv:set_stack("output", 1, recipe.output)
end
else
for i = 1, 9 do
inv:set_stack("input", i, nil)
end
end
end
local function determine_new_output(pos, inv)
local items = {}
for i = 1, 9 do
items[i] = inv:get_stack("input", i):get_name()
end
local input = {
method = "normal",
width = 3,
items = items,
}
local output, _ = minetest.get_craft_result(input)
inv:set_stack("output", 1, output.item)
end
local function get_recipe(inv)
local items = {}
local last_idx = 0
for i = 1, 9 do
local name = inv:get_stack("input", i):get_name()
if name ~= "" then
last_idx = i
end
items[i] = name
end
local input = table.concat(items, ",", 1, last_idx)
local stack = inv:get_stack("output", 1)
return {
input = input,
output = stack:get_name() .. " " .. stack:get_count()
}
end
local function after_recipe_change(pos, inv, listname)
if listname == "input" then
determine_new_output(pos, inv)
else
determine_new_input(pos, inv)
end
local nvm = techage.get_nvm(pos)
nvm.recipes = nvm.recipes or {}
nvm.recipes[nvm.recipe_idx or 1] = get_recipe(inv)
end
local function update_inventor(pos, inv, idx)
local nvm = techage.get_nvm(pos)
nvm.recipes = nvm.recipes or {}
local recipe = nvm.recipes[idx]
if recipe then
local items = string.split(recipe.input, ",", true)
for i = 1, 9 do
inv:set_stack("input", i, items[i] or "")
end
inv:set_stack("output", 1, recipe.output)
else
for i = 1, 9 do
inv:set_stack("input", i, nil)
end
inv:set_stack("output", 1, nil)
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
stack:set_count(1)
inv:set_stack(listname, index, stack)
after_recipe_change(pos, inv, listname)
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = M(pos):get_inventory()
inv:set_stack(listname, index, nil)
after_recipe_change(pos, inv, listname)
return 0
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local inv = M(pos):get_inventory()
if from_list == to_list then
minetest.after(0.1, after_recipe_change, pos, inv, from_list)
return 1
end
return 0
end
minetest.register_node("techage:ta4_recipeblock", {
description = S("TA4 Recipe Block"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4_top.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_recipeblock.png",
},
on_construct = function(pos)
local inv = M(pos):get_inventory()
inv:set_size('input', 9)
inv:set_size('output', 1)
end,
after_place_node = function(pos, placer, itemstack)
local nvm = techage.get_nvm(pos)
local number = techage.add_node(pos, "techage:ta4_chest")
M(pos):set_string("owner", placer:get_player_name())
M(pos):set_string("node_number", number)
M(pos):set_string("formspec", formspec(pos, nvm))
M(pos):set_string("infotext", S("TA4 Recipe Block") .. " " .. number)
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
nvm.recipe_idx = nvm.recipe_idx or 1
if fields.next == ">>" then
nvm.recipe_idx = techage.in_range(nvm.recipe_idx + 1, 1, MAX_RECIPE)
elseif fields.priv == "<<" then
nvm.recipe_idx = techage.in_range(nvm.recipe_idx - 1, 1, MAX_RECIPE)
end
local inv = M(pos):get_inventory()
update_inventor(pos, inv, nvm.recipe_idx or 1)
M(pos):set_string("formspec", formspec(pos, nvm))
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:ta4_recipeblock"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "input" and payload and payload ~= "" then
nvm.recipes = nvm.recipes or {}
local recipe = nvm.recipes[tonumber(payload) or 1]
if recipe then
return recipe.input
end
else
return "unsupported"
end
end,
})
minetest.register_craft({
output = "techage:ta4_recipeblock",
recipe = {
{"techage:ta4_carbon_fiber", "dye:blue", "techage:aluminum"},
{"", "basic_materials:ic", ""},
{"default:steel_ingot", "techage:ta4_wlanchip", "default:steel_ingot"},
},
})

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Recycler, recycling techage machines
]]--
-- for lazy programmers
@ -26,40 +26,44 @@ local CYCLE_TIME = 8
local Recipes = {}
local SpecialItems = {
["techage:sieved_gravel"] = "default:sand",
["basic_materials:heating_element"] = "default:copper_ingot",
["techage:ta4_wlanchip"] = "",
["techage:basalt_cobble"] = "default:sand",
["default:stone"] = "techage:sieved_gravel",
["default:wood"] = "default:stick 5",
["basic_materials:concrete_block"] = "techage:sieved_gravel",
["dye:green"] = "",
["dye:red"] = "",
["dye:white"] = "",
["dye:blue"] = "",
["dye:brown"] = "",
["techage:sieved_gravel"] = "default:sand",
["basic_materials:heating_element"] = "default:copper_ingot",
["techage:ta4_wlanchip"] = "",
["techage:basalt_cobble"] = "default:sand",
["default:stone"] = "techage:sieved_gravel",
["default:wood"] = "default:stick 5",
["basic_materials:concrete_block"] = "techage:sieved_gravel",
["dye:green"] = "",
["dye:red"] = "",
["dye:white"] = "",
["dye:blue"] = "",
["dye:brown"] = "",
["dye:cyan"] = "",
["dye:yellow"] = "",
["dye:grey"] = "",
["dye:orange"] = "",
["dye:black"] = "",
["techage:basalt_glass_thin"] = "",
["group:stone"] = "techage:sieved_gravel",
["basic_materials:plastic_sheet"] = "",
["group:wood"] = "default:stick 5",
["techage:basalt_glass"] = "",
["default:junglewood"] = "default:stick 5",
["techage:ta4_silicon_wafer"] = "",
["default:cobble"] = "techage:sieved_gravel",
["default:pick_diamond"] = "default:stick",
["techage:hammer_steel"] = "default:stick",
["default:paper"] = "",
["stairs:slab_basalt_glass2"] = "",
["techage:basalt_stone"] = "techage:sieved_gravel",
["techage:ta4_ramchip"] = "",
["dye:black"] = "",
["techage:basalt_glass_thin"] = "",
["group:stone"] = "techage:sieved_gravel",
--["basic_materials:plastic_sheet"] = "",
["group:wood"] = "default:stick 5",
["techage:basalt_glass"] = "",
["default:junglewood"] = "default:stick 5",
["techage:ta4_silicon_wafer"] = "",
["default:cobble"] = "techage:sieved_gravel",
["default:pick_diamond"] = "default:stick",
["techage:hammer_steel"] = "default:stick",
["default:paper"] = "",
["stairs:slab_basalt_glass2"] = "",
["techage:basalt_stone"] = "techage:sieved_gravel",
["techage:ta4_ramchip"] = "",
["protector:chest"] = "default:chest",
["techage:ta4_rotor_blade"] = "",
["techage:ta4_carbon_fiber"] = "",
["techage:ta4_round_ceramic"] = "",
["techage:ta4_furnace_ceramic"] = "",
["techage:ta5_aichip"] = "",
["techage:ta4_leds"] = "",
}
local function formspec(self, pos, nvm)
@ -108,17 +112,17 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player
return stack:get_count()
end
local function cook_reverse(stack, inv, idx, recipe)
local function cook_reverse(stack, inv, idx, recipe)
-- check space
for _,item in ipairs(recipe.items) do
if not inv:room_for_item("dst", stack) then
for _,item in ipairs(recipe.items) do
if not inv:room_for_item("dst", item) then
return false
end
end
-- take item
inv:remove_item("src", ItemStack(recipe.output))
-- add items
for _,item in ipairs(recipe.items) do
for _,item in ipairs(recipe.items) do
inv:add_item("dst", item)
end
return true
@ -189,7 +193,7 @@ tiles.pas = {
tiles.act = {
-- up, down, right, left, back, front
{
image = "techage_appl_grinder4.png^[colorize:@@000000:100^techage_frame4_ta#_top.png",
name = "techage_appl_grinder4.png^[colorize:@@000000:100^techage_frame4_ta#_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -231,12 +235,18 @@ local tubing = {
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local _, _, node_name_ta4 =
local _, _, node_name_ta4 =
techage.register_consumer("recycler", S("Recycler"), tiles, {
drawtype = "nodebox",
paramtype = "light",
@ -288,13 +298,13 @@ minetest.register_craft({
-------------------------------------------------------------------------------
-- Prepare recipes
-------------------------------------------------------------------------------
-- Nodes from mods that can be recycled
-- Nodes from mods that can be recycled
local ModNames = {
techage = true,
techage = true,
hyperloop = true,
}
local function get_item_list(inputs)
local function get_item_list(inputs)
local lst = {}
for _,input in pairs(inputs or {}) do
if SpecialItems[input] then
@ -313,7 +323,7 @@ local function get_special_recipe(name)
if SpecialItems[name] then
return {
output = name,
items = {SpecialItems[name]}
items = {SpecialItems[name]}
}
end
end
@ -321,22 +331,22 @@ end
local function collect_recipes()
local add = function(name, ndef)
local _, _, mod, _ = string.find(name, "([%w_]+):([%w_]+)")
local recipe = get_special_recipe(name) or
techage.recipes.get_recipe(name) or
local recipe = get_special_recipe(name) or
techage.recipes.get_recipe(name) or
minetest.get_craft_recipe(name)
local items = get_item_list(recipe.items)
if ModNames[mod]
and ndef.groups.not_in_creative_inventory ~= 1
if ModNames[mod]
and ndef.groups.not_in_creative_inventory ~= 1
and not ndef.tool_capabilities
and recipe.output
and recipe.output
and next(items) then
local s = table.concat(items, ", ")
--print(string.format("%-36s {%s}", recipe.output, s))
Recipes[name] = {output = recipe.output, items = items}
end
end
for name, ndef in pairs(minetest.registered_nodes) do
add(name, ndef)
end

View File

@ -9,7 +9,7 @@
See LICENSE.txt for more information
TA2/TA3 Power Test Source
]]--
-- for lazy programmers
@ -55,7 +55,7 @@ local function stop_node2(pos, nvm, state)
end
local function start_node3(pos, nvm, state)
local meta = M(pos)
local meta = M(pos)
nvm.running = true
nvm.provided = 0
techage.evaluate_charge_termination(nvm, meta)
@ -241,7 +241,7 @@ techage.register_node({"techage:t4_source"}, {
return State3:on_receive_message(pos, topic, payload)
end
end,
})
})
control.register_nodes({"techage:t4_source"}, {
on_receive = function(pos, tlib2, topic, payload)
@ -256,11 +256,10 @@ control.register_nodes({"techage:t4_source"}, {
running = nvm.running or false,
available = PWR_PERF,
provided = nvm.provided or 0,
termpoint = meta:get_string("termpoint"),
termpoint = meta:get_string("termpoint"),
}
end
return false
end,
}
)

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 8x2000 Chest
]]--
-- for lazy programmers
@ -22,6 +22,7 @@ local STACK_SIZE = 2000
local function gen_stack(inv, idx)
inv[idx] = {name = "", count = 0}
return inv[idx]
end
local function gen_inv(nvm)
@ -36,7 +37,7 @@ local function repair_inv(nvm)
nvm.inventory = nvm.inventory or {}
for i = 1,8 do
local item = nvm.inventory[i]
if not item or type(item) ~= "table"
if not item or type(item) ~= "table"
or not item.name or type(item.name) ~= "string" or item.name == ""
or not item.count or type(item.count) ~= "number" or item.count < 1
then
@ -92,6 +93,18 @@ local function inv_state(nvm)
return "loaded"
end
local function inv_state_num(nvm)
local num = 0
for _,item in ipairs(nvm.inventory or {}) do
if item.count and item.count > 0 then
num = num + 1
end
end
if num == 0 then return 0 end
if num == 8 then return 2 end
return 1
end
local function max_stacksize(item_name)
-- It is sufficient to use minetest.registered_items as all registration
-- functions (node, craftitems, tools) add the definitions there.
@ -102,8 +115,8 @@ end
local function get_stacksize(pos)
local size = M(pos):get_int("stacksize")
if size == 0 then
return STACK_SIZE
if size == 0 then
return STACK_SIZE
end
return size
end
@ -121,7 +134,7 @@ local function doesItemStackMatchNvmStack(itemstack, nvmstack)
-- The following seems to be the most reliable approach to compare meta.
local nvm_meta = ItemStack():get_meta()
nvm_meta:from_table(minetest.deserialize(nvmstack.meta))
nvm_meta:from_table(minetest.deserialize(nvmstack.meta or ""))
if not nvm_meta:equals(itemstack:get_meta()) then
return false, "Mismatching meta"
end
@ -170,7 +183,7 @@ local function take_from_chest(pos, idx, output_stack, max_total_count, keep_ass
local nvm_stack = get_stack(nvm, idx)
output_stack = output_stack or ItemStack()
local assignment_count = keep_assignment and M(pos):get_int("assignment") == 1 and 1 or 0
local count = math.min(nvm_stack.count - assignment_count, max_stacksize(nvm_stack.name))
local count = math.min(nvm_stack.count - assignment_count, max_stacksize(nvm_stack.name) - output_stack:get_count())
if max_total_count then
count = math.min(count, max_total_count - output_stack:get_count())
end
@ -185,7 +198,7 @@ local function take_from_chest(pos, idx, output_stack, max_total_count, keep_ass
count = count,
wear = nvm_stack.wear,
}))
output_stack:get_meta():from_table(minetest.deserialize(nvm_stack.meta))
output_stack:get_meta():from_table(minetest.deserialize(nvm_stack.meta or ""))
nvm_stack.count = nvm_stack.count - count
if nvm_stack.count == 0 then
gen_stack(nvm.inventory or {}, idx)
@ -198,21 +211,14 @@ local function tube_add_to_chest(pos, input_stack)
local nvm = techage.get_nvm(pos)
nvm.inventory = nvm.inventory or {}
-- Backup some values needed for restoring the old
-- state if items can't fully be added to chest.
local orig_count = input_stack:get_count()
local backup = table.copy(nvm.inventory)
for idx = 1,8 do
input_stack:take_item(add_to_chest(pos, input_stack, idx))
end
if input_stack:get_count() > 0 then
nvm.inventory = backup -- Restore old nvm inventory
input_stack:set_count(orig_count) -- Restore input_stack
return false -- No items were added to chest
return input_stack -- Not all items were added to chest
else
return true -- Items were added successfully
return true -- All items were added
end
end
@ -324,37 +330,77 @@ local function count_number_of_chests(pos)
local node = techage.get_node_lvm(pos)
local dir = techage.side_to_outdir("B", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
local param2 = node.param2
local cnt = 1
while cnt < 50 do
node = techage.get_node_lvm(pos1)
if node.name ~= "techage:ta4_chest_dummy" then
break
end
local meta = M(pos1)
if meta:contains("param2") and meta:get_int("param2") ~= param2 then
break
end
pos1 = tubelib2.get_pos(pos1, dir)
cnt = cnt + 1
end
M(pos):set_int("stacksize", STACK_SIZE * cnt)
end
local function dummy_chest_behind(pos, node)
local dir = techage.side_to_outdir("B", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
node = techage.get_node_lvm(pos1)
return node.name == "techage:ta4_chest_dummy"
end
local function part_of_a_chain(pos, node)
local dir = techage.side_to_outdir("F", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
node = techage.get_node_lvm(pos1)
return node.name == "techage:ta4_chest_dummy" or node.name == "techage:ta4_chest"
end
local function search_chest_in_front(pos, node)
local dir = techage.side_to_outdir("F", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
local param2 = node.param2
local cnt = 1
while cnt < 50 do
node = techage.get_node_lvm(pos1)
if node.name ~= "techage:ta4_chest_dummy" then
break
end
local meta = M(pos1)
if meta:contains("param2") and meta:get_int("param2") ~= param2 then
break
end
pos1 = tubelib2.get_pos(pos1, dir)
cnt = cnt + 1
end
if node.name == "techage:ta4_chest" then
if node.name == "techage:ta4_chest" and node.param2 == param2 then
minetest.after(1, count_number_of_chests, pos1)
local nvm = techage.get_nvm(pos)
nvm.front_chest_pos = pos1
return true
end
return false
end
local function get_front_chest_pos(pos)
local nvm = techage.get_nvm(pos)
if nvm.front_chest_pos then
return nvm.front_chest_pos
end
local node = techage.get_node_lvm(pos)
if search_chest_in_front(pos, node) then
return nvm.front_chest_pos
end
return pos
end
local function convert_to_chest_again(pos, node, player)
local dir = techage.side_to_outdir("B", node.param2)
local pos1 = tubelib2.get_pos(pos, dir)
@ -373,8 +419,8 @@ local function convert_to_chest_again(pos, node, player)
M(pos1):set_string("formspec", formspec(pos1))
M(pos1):set_string("infotext", DESCRIPTION.." "..number)
end
end
end
local function unlock_chests(pos, player)
local nvm = techage.get_nvm(pos)
for idx = 1,8 do
@ -434,7 +480,7 @@ local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
for i = 1,8 do
if fields["get"..i] ~= nil then
inv_take_from_chest(pos, i)
@ -453,7 +499,7 @@ local function on_receive_fields(pos, formname, fields, player)
if fields.priority then
M(pos):set_int("priority", fields.priority == "true" and 1 or 0)
end
M(pos):set_string("formspec", formspec(pos))
end
@ -495,12 +541,17 @@ minetest.register_node("techage:ta4_chest", {
local inv = M(pos):get_inventory()
inv:set_size('main', 8)
end,
after_place_node = function(pos, placer)
local node = minetest.get_node(pos)
if dummy_chest_behind(pos, node) then
minetest.remove_node(pos)
return true
end
if search_chest_in_front(pos, node) then
node.name = "techage:ta4_chest_dummy"
minetest.swap_node(pos, node)
M(pos):set_int("param2", node.param2)
else
local nvm = techage.get_nvm(pos)
gen_inv(nvm)
@ -514,7 +565,7 @@ minetest.register_node("techage:ta4_chest", {
techage_set_numbers = function(pos, numbers, player_name)
return techage.logic.set_numbers(pos, numbers, player_name, DESCRIPTION)
end,
on_rotate = on_rotate,
on_rightclick = on_rightclick,
on_receive_fields = on_receive_fields,
@ -522,7 +573,7 @@ minetest.register_node("techage:ta4_chest", {
after_dig_node = after_dig_node,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
on_metadata_inventory_put = on_metadata_inventory_put,
on_metadata_inventory_move = on_metadata_inventory_move,
on_metadata_inventory_take = on_metadata_inventory_take,
@ -577,14 +628,16 @@ techage.register_node({"techage:ta4_chest"}, {
end
return res
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "count" then
local nvm = techage.get_nvm(pos)
return get_count(nvm, tonumber(payload) or 0)
return get_count(nvm, tonumber(payload or 0) or 0)
elseif topic == "itemstring" then
local nvm = techage.get_nvm(pos)
return get_itemstring(nvm, tonumber(payload) or 0)
return get_itemstring(nvm, tonumber(payload or 0) or 0)
elseif topic == "storesize" then
return get_stacksize(pos)
elseif topic == "state" then
local nvm = techage.get_nvm(pos)
return inv_state(nvm)
@ -592,7 +645,62 @@ techage.register_node({"techage:ta4_chest"}, {
return "unsupported"
end
end,
})
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 140 and payload[1] == 1 then -- Inventory Item Count
local nvm = techage.get_nvm(pos)
return 0, {get_count(nvm, tonumber(payload[2] or 0) or 0)}
elseif topic == 140 and payload[1] == 2 then -- Inventory Item Name
local nvm = techage.get_nvm(pos)
return 0, get_itemstring(nvm, tonumber(payload[2] or 0) or 0)
elseif topic == 140 and payload[1] == 3 then -- storesize
return 0, {get_stacksize(pos)}
elseif topic == 131 then -- Chest State
local nvm = techage.get_nvm(pos)
return 0, {inv_state_num(nvm)}
else
return 2, ""
end
end,
})
techage.register_node({"techage:ta4_chest_dummy"}, {
on_pull_item = function(pos, in_dir, num, item_name)
local fc_pos = get_front_chest_pos(pos)
local res = tube_take_from_chest(fc_pos, item_name, num)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end,
on_push_item = function(pos, in_dir, stack)
local fc_pos = get_front_chest_pos(pos)
local res = tube_add_to_chest(fc_pos, stack)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end,
on_unpull_item = function(pos, in_dir, stack)
local fc_pos = get_front_chest_pos(pos)
local res = tube_add_to_chest(fc_pos, stack)
if techage.is_activeformspec(fc_pos) then
M(fc_pos):set_string("formspec", formspec(fc_pos))
end
return res
end
})
minetest.register_lbm({
label = "Repair Dummy Chests",
name = "techage:chest_dummy",
nodenames = {"techage:ta4_chest_dummy"},
run_at_every_load = true,
action = function(pos, node)
if not part_of_a_chain(pos, node) then
minetest.swap_node(pos, {name = "techage:ta4_chest", param2 = node.param2})
end
end,
})
minetest.register_craft({
type = "shapeless",

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2020 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Injector
]]--
@ -19,6 +19,7 @@ local S = techage.S
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local tooltip = S("Switch to pull mode \nto pull items out of inventory slots \naccording the injector configuration")
local Tube = techage.Tube
local STANDBY_TICKS = 2
local COUNTDOWN_TICKS = 3
@ -47,12 +48,12 @@ local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) ~= techage.STOPPED then
return 0
end
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
local cdr = CRD(pos)
@ -69,12 +70,12 @@ local function allow_metadata_inventory_take(pos, listname, index, stack, player
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) ~= techage.STOPPED then
return 0
end
local inv = M(pos):get_inventory()
inv:set_stack(listname, index, nil)
return 0
@ -121,8 +122,23 @@ local function push_items(pos, out_dir, idx, items)
return true
end
end
return false
else
return techage.push_items(pos, out_dir, items, idx)
local taken = items:get_count()
local leftover = techage.push_items(pos, out_dir, items, idx)
if not leftover or leftover == false then
return false -- No items placed
elseif leftover ~= true then
-- One or more items placed?
if leftover:get_count() < taken then
-- place the rest back
local pull_dir = M(pos):get_int("pull_dir")
techage.unpull_items(pos, pull_dir, leftover)
return true -- Some items placed
end
return false -- No items placed
end
return true -- All items placed
end
end
@ -148,7 +164,7 @@ local function pushing(pos, crd, meta, nvm)
local filter = inv:get_list("filter")
local pushed = false
local pulled = false
for idx, item in ipairs(filter) do
local name = item:get_name()
local num = math.min(item:get_count(), crd.num_items)
@ -165,7 +181,7 @@ local function pushing(pos, crd, meta, nvm)
end
end
end
if not pulled then
crd.State:idle(pos, nvm)
elseif not pushed then
@ -175,11 +191,11 @@ local function pushing(pos, crd, meta, nvm)
end
end
local function keep_running(pos, elapsed)
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
pushing(pos, crd, M(pos), nvm)
end
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
@ -188,7 +204,7 @@ local function on_receive_fields(pos, formname, fields, player)
local nvm = techage.get_nvm(pos)
if fields.pull_mode then
nvm.pull_mode = fields.pull_mode == "true"
end
end
CRD(pos).State:state_button_event(pos, nvm, fields)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
@ -198,7 +214,7 @@ local tiles = {}
-- '{power}' will be replaced by the power PNG
tiles.pas = {
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
"techage_appl_pusher.png^[transformR180]^techage_frame_ta#.png^techage_appl_injector.png",
@ -207,11 +223,11 @@ tiles.pas = {
tiles.act = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_arrow.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png",
{
image = "techage_appl_pusher14.png^[transformR180]^techage_frame14_ta#.png^techage_appl_injector14.png",
name = "techage_appl_pusher14.png^[transformR180]^techage_frame14_ta#.png^techage_appl_injector14.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -221,7 +237,7 @@ tiles.act = {
},
},
{
image = "techage_appl_pusher14.png^techage_frame14_ta#.png^techage_appl_injector14.png",
name = "techage_appl_pusher14.png^techage_frame14_ta#.png^techage_appl_injector14.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -231,28 +247,35 @@ tiles.act = {
},
},
}
local tubing = {
-- push item through the injector in opposit direction
on_push_item = function(pos, in_dir, stack)
return in_dir == M(pos):get_int("pull_dir") and techage.push_items(pos, in_dir, stack)
return in_dir == M(pos):get_int("pull_dir") and techage.safe_push_items(pos, in_dir, stack)
end,
is_pusher = true, -- is a pulling/pushing node
on_recv_message = function(pos, src, topic, payload)
return CRD(pos).State:on_receive_message(pos, topic, payload)
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return CRD(pos).State:on_beduino_request_data(pos, topic, payload)
end,
on_node_load = function(pos)
CRD(pos).State:on_node_load(pos)
end,
}
local _, node_name_ta3, node_name_ta4 =
local _, node_name_ta3, node_name_ta4 =
techage.register_consumer("injector", S("Injector"), tiles, {
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
quick_start = node_timer,
after_place_node = function(pos, placer)
local meta = M(pos)
local node = minetest.get_node(pos)
@ -263,14 +286,26 @@ local _, node_name_ta3, node_name_ta4 =
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end,
ta_rotate_node = function(pos, node, new_param2)
local nvm = techage.get_nvm(pos)
if CRD(pos).State:get_state(nvm) == techage.STOPPED then
Tube:after_dig_node(pos)
minetest.swap_node(pos, {name = node.name, param2 = new_param2})
Tube:after_place_node(pos)
local meta = M(pos)
meta:set_int("pull_dir", techage.side_to_outdir("L", new_param2))
meta:set_int("push_dir", techage.side_to_outdir("R", new_param2))
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = function() return 0 end,
on_receive_fields = on_receive_fields,
node_timer = keep_running,
node_timer = node_timer,
on_rotate = screwdriver.disallow,
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),

View File

@ -0,0 +1,248 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA5 Hyperloop Chest
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local S = techage.S
local TA4_INV_SIZE = 32
local EX_POINTS = 15
local hyperloop = techage.hyperloop
local remote_pos = techage.hyperloop.remote_pos
local shared_inv = techage.shared_inv
local menu = techage.menu
local function formspec(pos)
local ndef = minetest.registered_nodes["techage:ta5_hl_chest"]
local status = M(pos):get_string("conn_status")
if hyperloop.is_server(pos) then
local title = ndef.description .. " " .. status
return "size[8,9]"..
"box[0,-0.1;7.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"list[context;main;0,1;8,4;]"..
"list[current_player;main;0,5.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
elseif hyperloop.is_client(pos) then
local title = ndef.description .. " " .. status
return "size[8,9]"..
"box[0,-0.1;7.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"label[0.2,2;Inventory access on this node is disabled\ndue to minetest engine issues!]" ..
"list[current_player;main;0,5.3;8,4;]"
else
return menu.generate_formspec(pos, ndef, hyperloop.SUBMENU)
end
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if techage.hyperloop.is_client(pos) then
return 0
end
shared_inv.before_inv_access(pos, listname)
local inv = minetest.get_inventory({type="node", pos=pos})
if inv and inv:room_for_item(listname, stack) then
return stack:get_count()
end
return 0
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
if techage.hyperloop.is_client(pos) then
return 0
end
shared_inv.before_inv_access(pos, listname)
local inv = minetest.get_inventory({type="node", pos=pos})
if inv and inv:contains_item(listname, stack) then
return stack:get_count()
end
return 0
end
local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if shared_inv.before_inv_access(pos, "main") then
return 0
end
if techage.hyperloop.is_client(pos) then
return 0
end
return count
end
minetest.register_node("techage:ta5_hl_chest", {
description = S("TA5 Hyperloop Chest"),
tiles = {
-- up, down, right, left, back, front
"techage_filling_ta4.png^techage_frame_ta5_top.png",
"techage_filling_ta4.png^techage_frame_ta5.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_chest_back_ta4.png",
"techage_filling_ta4.png^techage_frame_ta5.png^techage_appl_chest_front_ta4.png",
},
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size('main', 32)
local number = techage.add_node(pos, "techage:ta5_hl_chest")
meta:set_string("node_number", number)
meta:set_string("owner", placer:get_player_name())
meta:set_string("formspec", formspec(pos))
meta:set_string("infotext", S("TA5 Hyperloop Chest").." "..number)
hyperloop.after_place_node(pos, placer, "chest")
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
if techage.get_expoints(player) >= EX_POINTS then
if techage.menu.eval_input(pos, hyperloop.SUBMENU, fields) then
hyperloop.after_formspec(pos, fields)
shared_inv.on_rightclick(pos, player, "main")
M(pos):set_string("formspec", formspec(pos))
end
end
end,
on_timer = shared_inv.node_timer,
on_rightclick = function(pos, node, clicker)
shared_inv.on_rightclick(pos, clicker, "main")
M(pos):set_string("formspec", formspec(pos))
end,
can_dig = function(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
shared_inv.before_inv_access(pos, "main")
local inv = minetest.get_meta(pos):get_inventory()
return inv:is_empty("main")
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
techage.remove_node(pos, oldnode, oldmetadata)
hyperloop.after_dig_node(pos, oldnode, oldmetadata, digger)
techage.del_mem(pos)
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
allow_metadata_inventory_move = allow_metadata_inventory_move,
on_metadata_inventory_put = shared_inv.after_inv_access,
on_metadata_inventory_take = shared_inv.after_inv_access,
paramtype2 = "facedir",
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
})
techage.register_node({"techage:ta5_hl_chest"}, {
on_inv_request = function(pos, in_dir, access_type)
pos = remote_pos(pos)
if pos then
local meta = minetest.get_meta(pos)
if meta then
return meta:get_inventory(), "main"
end
end
end,
on_pull_item = function(pos, in_dir, num, item_name)
pos = remote_pos(pos)
if pos then
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return techage.get_items(pos, inv, "main", num)
end
end
end
return false
end,
on_push_item = function(pos, in_dir, stack)
if techage.hyperloop.is_paired(pos) then
pos = remote_pos(pos)
if pos then
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return techage.put_items(inv, "main", stack)
end
end
end
end
return false
end,
on_unpull_item = function(pos, in_dir, stack)
pos = remote_pos(pos)
if pos then
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return techage.put_items(inv, "main", stack)
end
end
end
return false
end,
on_recv_message = function(pos, src, topic, payload)
if topic == "state" then
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return techage.get_inv_state(inv, "main")
end
end
return "error"
else
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then -- Chest State
local meta = minetest.get_meta(pos)
if meta then
local inv = meta:get_inventory()
if inv then
return 0, {techage.get_inv_state_num(inv, "main")}
end
end
else
return 2, ""
end
end,
})
minetest.register_craft({
type = "shapeless",
output = "techage:ta5_hl_chest",
recipe = {"techage:chest_ta4", "techage:ta5_aichip"}
})
minetest.register_on_mods_loaded(function()
if not minetest.global_exists("hyperloop") then
minetest.clear_craft({output = "techage:ta5_hl_chest"})
end
end)

View File

@ -9,7 +9,7 @@
See LICENSE.txt for more information
Assemble routines
]]--
-- for lazy programmers
@ -28,7 +28,7 @@ local Face2Dir = {[0]=
{x=0, y=1, z=0}
}
-- Determine the destination position based on the base position,
-- Determine the destination position based on the base position,
-- param2, and a route table like : {0,3}
-- 0 = forward, 1 = right, 2 = backward, 3 = left
local function dest_pos(pos, param2, route, y_offs)
@ -54,8 +54,8 @@ local function build(pos, param2, AssemblyPlan, idx)
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end
end
end
-- timer based function
local function remove(pos, param2, AssemblyPlan, idx)
local item = AssemblyPlan[idx]
@ -68,7 +68,7 @@ local function remove(pos, param2, AssemblyPlan, idx)
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end
end
end
local function check_space(pos, param2, AssemblyPlan, player_name)
for _,item in ipairs(AssemblyPlan) do
@ -78,7 +78,7 @@ local function check_space(pos, param2, AssemblyPlan, player_name)
minetest.chat_send_player(player_name, S("[TA] Area is protected!"))
return false
end
local node = techage.get_node_lvm(pos1)
local ndef = minetest.registered_nodes[node.name]
if not ndef or not ndef.buildable_to and node.name ~= node_name then
@ -97,7 +97,7 @@ function techage.assemble.build(pos, AssemblyPlan, player_name)
-- check protection
if minetest.is_protected(pos, player_name) then
return
end
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked then
return
@ -114,7 +114,7 @@ function techage.assemble.remove(pos, AssemblyPlan, player_name)
-- check protection
if minetest.is_protected(pos, player_name) then
return
end
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked then
return
@ -124,3 +124,119 @@ function techage.assemble.remove(pos, AssemblyPlan, player_name)
remove(pos, node.param2, AssemblyPlan, #AssemblyPlan)
nvm.assemble_build = false
end
--------------------------------------------------------------------------------
-- Assembly functions based on nodes from node inventory
--------------------------------------------------------------------------------
local function play_sound(pos, sound)
minetest.sound_play(sound, {
pos = pos,
gain = 1,
max_hear_distance = 10,
})
end
local function build_inv(pos, inv, param2, AssemblyPlan, player_name, idx)
local item = AssemblyPlan[idx]
if item ~= nil then
local y, path, fd_offs, node_name = item[1], item[2], item[3], item[4]
local pos1 = dest_pos(pos, param2, path, y)
if not minetest.is_protected(pos1, player_name) then
local node = minetest.get_node(pos1)
if techage.is_air_like(node.name) then
local stack = inv:remove_item("src", ItemStack(node_name))
if stack:get_count() == 1 then
minetest.add_node(pos1, {name=node_name, param2=(param2 + fd_offs) % 4})
play_sound(pos, "default_place_node_hard")
local ndef = minetest.registered_nodes[node_name]
if ndef and ndef.after_place_node then
local placer = minetest.get_player_by_name(player_name)
ndef.after_place_node(pos1, placer, ItemStack(node_name))
end
end
end
end
minetest.after(0.5, build_inv, pos, inv, param2, AssemblyPlan, player_name, idx + 1)
else
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end
end
local function remove_inv(pos, inv, param2, AssemblyPlan, player_name, idx)
local item = AssemblyPlan[idx]
if item ~= nil then
local y, path, fd_offs, node_name = item[1], item[2], item[3], item[4]
local pos1 = dest_pos(pos, param2, path, y)
if not minetest.is_protected(pos1, player_name) then
local stack = ItemStack(node_name)
if inv:room_for_item("src", stack) then
local node = minetest.get_node(pos1)
if node.name == node_name then
local meta = M(pos1):to_table()
minetest.remove_node(pos1)
inv:add_item("src", stack)
play_sound(pos, "default_dig_cracky")
local ndef = minetest.registered_nodes[node_name]
if ndef and ndef.after_dig_node then
local digger = minetest.get_player_by_name(player_name)
ndef.after_dig_node(pos1, node, meta, digger)
end
end
end
end
minetest.after(0.5, remove_inv, pos, inv, param2, AssemblyPlan, player_name, idx - 1)
else
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end
end
function techage.assemble.build_inv(pos, inv, AssemblyPlan, player_name)
-- check protection
if minetest.is_protected(pos, player_name) then
return
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked then
return
end
local node = minetest.get_node(pos)
nvm.assemble_locked = true
build_inv(pos, inv, node.param2, AssemblyPlan, player_name, 1)
end
function techage.assemble.remove_inv(pos, inv, AssemblyPlan, player_name)
-- check protection
if minetest.is_protected(pos, player_name) then
return
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked then
return
end
local node = minetest.get_node(pos)
nvm.assemble_locked = true
remove_inv(pos, inv, node.param2, AssemblyPlan, player_name, #AssemblyPlan)
end
function techage.assemble.count_items(AssemblyPlan)
local t = {}
for _, item in ipairs(AssemblyPlan) do
local node_name = item[4]
local ndef = minetest.registered_nodes[node_name]
local name = ndef.description
if not t[name] then
t[name] = 1
else
t[name] = t[name] + 1
end
end
return t
end
-- Determine the destination position based on the given route
-- param2, and a route table like : {0,3}
-- 0 = forward, 1 = right, 2 = backward, 3 = left
-- techage.assemble.get_pos(pos, param2, route, y_offs)
techage.assemble.get_pos = dest_pos

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Boiler common functions
]]--
@ -24,13 +24,10 @@ local BLOCKING_TIME = 0.3 -- 300ms
techage.boiler = {}
local IsWater = {
["bucket:bucket_river_water"] = true,
["bucket:bucket_water"] = true,
["bucket:bucket_river_water"] = "bucket:bucket_empty",
}
local IsBucket = {
["bucket:bucket_empty"] = true,
}
local IsBucket = {}
local function node_description(name)
name = string.split(name, " ")[1]
@ -74,7 +71,7 @@ function techage.boiler.water_temperature(pos, nvm)
nvm.temperature = math.max(nvm.temperature - HEAT_STEP, 20)
end
nvm.fire_trigger = false
if nvm.water_level == 0 then
if nvm.num_water > 0 then
nvm.num_water = nvm.num_water - 1
@ -119,19 +116,19 @@ function techage.boiler.on_punch(pos, node, puncher, pointed_thing)
if mem.blocking_time > techage.SystemTime then
return
end
nvm.num_water = nvm.num_water or 0
local wielded_item = puncher:get_wielded_item():get_name()
local item_count = puncher:get_wielded_item():get_count()
if IsWater[wielded_item] and nvm.num_water < MAX_WATER then
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
nvm.num_water = nvm.num_water + 1
puncher:set_wielded_item(ItemStack("bucket:bucket_empty"))
puncher:set_wielded_item(ItemStack(IsWater[wielded_item]))
M(pos):set_string("formspec", techage.boiler.formspec(pos, nvm))
elseif IsBucket[wielded_item] and nvm.num_water > 0 then
if item_count > 1 then
local inv = puncher:get_inventory()
local item = ItemStack("bucket:bucket_water")
local item = ItemStack(IsBucket[wielded_item])
if inv:room_for_item("main", item) then
inv:add_item("main", item)
puncher:set_wielded_item({name=wielded_item, count = item_count - 1})
@ -141,9 +138,13 @@ function techage.boiler.on_punch(pos, node, puncher, pointed_thing)
else
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
nvm.num_water = nvm.num_water - 1
puncher:set_wielded_item(ItemStack("bucket:bucket_water"))
puncher:set_wielded_item(ItemStack(IsBucket[wielded_item]))
end
M(pos):set_string("formspec", techage.boiler.formspec(pos, nvm))
end
end
function techage.register_water_bucket(empty_bucket, full_bucket)
IsWater[full_bucket] = empty_bucket
IsBucket[empty_bucket] = full_bucket
end

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Basis functions for inter-node communication
]]--
@ -16,6 +16,7 @@
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
--local P = minetest.string_to_pos
--local M = minetest.get_meta
local has_mesecons = minetest.global_exists("mesecon")
local NodeInfoCache = {}
local NumbersToBeRecycled = {}
@ -27,6 +28,8 @@ local string_split = string.split
local NodeDef = techage.NodeDef
local Tube = techage.Tube
local is_cart_available = minecart.is_nodecart_available
local techage_counting_hit = techage.counting_hit
local tubelib2_side_to_dir = tubelib2.side_to_dir
-------------------------------------------------------------------
-- Database
@ -58,7 +61,7 @@ local function delete_nodeinfo_entry(number)
return number
end
-- Keep the cache size small by deleting entries randomly
-- Keep the cache size small by deleting entries randomly
local function keep_small(number)
number = delete_nodeinfo_entry(number)
minetest.after(10, keep_small, number)
@ -81,13 +84,13 @@ end
-- Determine position related node number for addressing purposes
local function get_number(pos, new)
local meta = minetest.get_meta(pos)
if meta:contains("node_number") then
return meta:get_string("node_number")
if meta:contains("node_number") then
return meta:get_string("node_number")
end
-- generate new number
if new then
local num = backend.add_nodepos(pos)
meta:set_string("node_number", num)
meta:set_string("node_number", num)
return num
end
end
@ -124,11 +127,7 @@ end
local SideToDir = {B=1, R=2, F=3, L=4, D=5, U=6}
local function side_to_dir(side, param2)
local dir = SideToDir[side]
if dir < 5 then
dir = (((dir - 1) + (param2 % 4)) % 4) + 1
end
return dir
return tubelib2_side_to_dir(side, param2)
end
techage.side_to_outdir = side_to_dir
@ -140,15 +139,15 @@ end
local function get_next_node(pos, out_dir)
local res, npos, node = Tube:compatible_node(pos, out_dir)
local in_dir = tubelib2.Turn180Deg[out_dir]
return res, npos, in_dir, node.name
return res, npos, in_dir, node.name
end
local function get_dest_node(pos, out_dir)
local spos, in_dir = Tube:get_connected_node_pos(pos, out_dir)
local _,node = Tube:get_node(spos)
return spos, in_dir, node.name
return spos, in_dir, node.name
end
local function item_handling_node(name)
local node_def = name and NodeDef[name]
if node_def then
@ -173,24 +172,32 @@ end)
techage.dug_node = {}
minetest.register_on_dignode(function(pos, oldnode, digger)
if not digger then return end
-- store pos for tools without own 'register_on_dignode'
-- store the position of the dug block for tools like the TA1 hammer
techage.dug_node[digger:get_player_name()] = pos
end)
-------------------------------------------------------------------
-- API helper functions
-------------------------------------------------------------------
-- Check if both strings are the same or one string starts with the other string.
function techage.string_compare(s1, s2)
if s1 and s2 then
local minLength = math.min(#s1, #s2)
return string.sub(s1, 1, minLength) == string.sub(s2, 1, minLength)
end
end
-- Function returns { pos, name } for the node referenced by number
function techage.get_node_info(dest_num)
return NodeInfoCache[dest_num] or update_nodeinfo(dest_num)
end
end
-- Function returns the node number from the given position or
-- nil, if no node number for this position is assigned.
function techage.get_node_number(pos)
return get_number(pos)
end
end
function techage.get_pos(pos, side)
local node = techage.get_node_lvm(pos)
@ -199,11 +206,11 @@ function techage.get_pos(pos, side)
dir = side_to_dir(side, node.param2)
end
return tubelib2.get_pos(pos, dir)
end
end
-- Function is used for available nodes with lost numbers, only.
function techage.get_new_number(pos, name)
-- store position
-- store position
return get_number(pos, true)
end
@ -216,7 +223,7 @@ end
-------------------------------------------------------------------
-- Node construction/destruction functions
-------------------------------------------------------------------
-- Add node to the techage lists.
-- Function determines and returns the node position number,
-- needed for message communication.
@ -226,12 +233,13 @@ function techage.add_node(pos, name, is_ta2)
if item_handling_node(name) then
Tube:after_place_node(pos)
end
if is_ta2 then
if is_ta2 then
return "-"
end
local key = minetest.hash_node_position(pos)
local num = NumbersToBeRecycled[key]
if num then
NodeInfoCache[num] = nil
backend.set_nodepos(num, pos)
NumbersToBeRecycled[key] = nil
return num
@ -253,6 +261,48 @@ function techage.remove_node(pos, oldnode, oldmetadata)
end
end
-- Repairs the node number after it was erased by `backend.delete_invalid_entries`
function techage.repair_number(pos)
local number = techage.get_node_number(pos)
if number then
backend.set_nodepos(number, pos)
end
end
-- Like techage.add_node, but use the old number again
function techage.unpack_node(pos, name, number)
if item_handling_node(name) then
Tube:after_place_node(pos)
end
local key = minetest.hash_node_position(pos)
NumbersToBeRecycled[key] = nil
if number then
backend.set_nodepos(number, pos)
end
end
-- Like techage.remove_node but don't store the number for this position
function techage.pack_node(pos, oldnode, number)
if number then
NodeInfoCache[number] = nil
end
if oldnode and item_handling_node(oldnode.name) then
Tube:after_dig_node(pos)
end
end
-------------------------------------------------------------------
-- Used by the assembly tool
-------------------------------------------------------------------
function techage.pre_add_node(pos, number)
local key = minetest.hash_node_position(pos)
NumbersToBeRecycled[key] = number
end
function techage.post_remove_node(pos)
local key = minetest.hash_node_position(pos)
NumbersToBeRecycled[key] = nil
end
-------------------------------------------------------------------
-- Node register function
@ -276,10 +326,10 @@ function techage.register_node(names, node_definition)
for _,n in ipairs(names) do
NodeDef[n] = node_definition
end
if node_definition.on_pull_item or node_definition.on_push_item or
if node_definition.on_pull_item or node_definition.on_push_item or
node_definition.is_pusher then
Tube:add_secondary_node_names(names)
for _,n in ipairs(names) do
techage.KnownNodes[n] = true
end
@ -288,6 +338,13 @@ function techage.register_node(names, node_definition)
if node_definition.on_node_load then
register_lbm(names[1], names)
end
-- register mvps stopper
if has_mesecons then
for _, name in ipairs(names) do
mesecon.register_mvps_stopper(name)
end
end
end
-------------------------------------------------------------------
@ -302,6 +359,19 @@ function techage.not_protected(number, placer_name, clicker_name)
return false
end
-- Check the given number value.
-- Returns true if the number is valid, point to real node and
-- and the node is not protected for the given player_name.
function techage.check_number(number, placer_name)
if number then
if not techage.not_protected(number, placer_name, nil) then
return false
end
return true
end
return false
end
-- Check the given list of numbers.
-- Returns true if number(s) is/are valid, point to real nodes and
-- and the nodes are not protected for the given player_name.
@ -315,7 +385,7 @@ function techage.check_numbers(numbers, placer_name)
return true
end
return false
end
end
function techage.send_multi(src, numbers, topic, payload)
--print("send_multi", src, numbers, topic)
@ -324,11 +394,12 @@ function techage.send_multi(src, numbers, topic, payload)
if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_recv_message then
techage_counting_hit()
ndef.on_recv_message(ninfo.pos, src, topic, payload)
end
end
end
end
end
function techage.send_single(src, number, topic, payload)
--print("send_single", src, number, topic)
@ -336,11 +407,12 @@ function techage.send_single(src, number, topic, payload)
if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_recv_message then
techage_counting_hit()
return ndef.on_recv_message(ninfo.pos, src, topic, payload)
end
end
return false
end
end
-- The destination node location is either:
-- A) a destination position, specified by pos
@ -374,7 +446,36 @@ function techage.transfer(pos, outdir, topic, payload, network, nodenames)
return ndef.on_transfer(dpos, indir, topic, payload)
end
return false
end
end
-------------------------------------------------------------------
-- Beduino functions (see "bep-005_ta_cmnd.md")
-------------------------------------------------------------------
function techage.beduino_send_cmnd(src, number, topic, payload)
--print("beduino_send_cmnd", src, number, topic)
local ninfo = NodeInfoCache[number] or update_nodeinfo(number)
if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_beduino_receive_cmnd then
techage_counting_hit()
return ndef.on_beduino_receive_cmnd(ninfo.pos, src, topic, payload or {})
end
end
return 1, ""
end
function techage.beduino_request_data(src, number, topic, payload)
--print("beduino_request_data", src, number, topic)
local ninfo = NodeInfoCache[number] or update_nodeinfo(number)
if ninfo and ninfo.name and ninfo.pos then
local ndef = NodeDef[ninfo.name]
if ndef and ndef.on_beduino_request_data then
techage_counting_hit()
return ndef.on_beduino_request_data(ninfo.pos, src, topic, payload or {})
end
end
return 1, ""
end
-------------------------------------------------------------------
-- Client side Push/Pull item functions
@ -397,12 +498,37 @@ end
function techage.push_items(pos, out_dir, stack, idx)
local npos, in_dir, name = get_dest_node(pos, out_dir)
if npos and NodeDef[name] and NodeDef[name].on_push_item then
return NodeDef[name].on_push_item(npos, in_dir, stack, idx)
return NodeDef[name].on_push_item(npos, in_dir, stack, idx)
elseif is_air_like(name) or is_cart_available(npos) then
minetest.add_item(npos, stack)
return true
return true
end
return false
return stack
end
-- Check for recursion and too long distances
local start_pos
function techage.safe_push_items(pos, out_dir, stack, idx)
local mem = techage.get_mem(pos)
if not mem.pushing then
if not start_pos then
start_pos = pos
mem.pushing = true
local res = techage.push_items(pos, out_dir, stack, idx)
mem.pushing = nil
start_pos = nil
return res
else
local npos, in_dir, name = get_dest_node(pos, out_dir)
if vector.distance(start_pos, npos) < (Tube.max_tube_length or 100) then
mem.pushing = true
local res = techage.push_items(pos, out_dir, stack, idx)
mem.pushing = nil
return res
end
end
end
return stack
end
function techage.unpull_items(pos, out_dir, stack)
@ -412,37 +538,6 @@ function techage.unpull_items(pos, out_dir, stack)
end
return false
end
-------------------------------------------------------------------
-- Client side Push/Pull item functions for hopper like nodes
-- (nodes with no tube support)
-------------------------------------------------------------------
function techage.neighbour_pull_items(pos, out_dir, num)
local res, npos, in_dir, name = get_next_node(pos, out_dir)
if res and NodeDef[name] and NodeDef[name].on_pull_item then
return NodeDef[name].on_pull_item(npos, in_dir, num)
end
end
function techage.neighbour_push_items(pos, out_dir, stack)
local res, npos, in_dir, name = get_next_node(pos, out_dir)
if res and NodeDef[name] and NodeDef[name].on_push_item then
return NodeDef[name].on_push_item(npos, in_dir, stack)
elseif name == "air" then
minetest.add_item(npos, stack)
return true
end
return false
end
function techage.neighbour_unpull_items(pos, out_dir, stack)
local res, npos, in_dir, name = get_next_node(pos, out_dir)
if res and NodeDef[name] and NodeDef[name].on_unpull_item then
return NodeDef[name].on_unpull_item(npos, in_dir, stack)
end
return false
end
-------------------------------------------------------------------
-- Server side helper functions
@ -471,23 +566,33 @@ function techage.get_items(pos, inv, listname, num)
return nil
end
-- Put the given stack into the given ItemList.
-- Function returns false if ItemList is full.
-- Put the given stack into the given ItemList/inventory.
-- Function returns:
-- - true, if all items are moved
-- - false, if no item is moved
-- - leftover, if less than all items are moved
-- (true/false is the legacy mode and can't be removed)
function techage.put_items(inv, listname, item, idx)
local leftover
if idx and inv and idx <= inv:get_size(listname) then
local stack = inv:get_stack(listname, idx)
if stack:item_fits(item) then
stack:add_item(item)
inv:set_stack(listname, idx, stack)
return true
end
leftover = stack:add_item(item)
inv:set_stack(listname, idx, stack)
elseif inv then
leftover = inv:add_item(listname, item)
else
if inv and inv:room_for_item(listname, item) then
inv:add_item(listname, item)
return true
end
return false
end
return false
local cnt = leftover:get_count()
if cnt == item:get_count() then
return false
elseif cnt == 0 then
return true
else
return leftover
end
end
-- Return "full", "loaded", or "empty" depending
@ -508,3 +613,79 @@ function techage.get_inv_state(inv, listname)
end
return state
end
-- Beduino variant
function techage.get_inv_state_num(inv, listname)
local state
if inv:is_empty(listname) then
state = 0
else
local list = inv:get_list(listname)
state = 2
for _, item in ipairs(list) do
if item:is_empty() then
return 1
end
end
end
return state
end
minetest.register_chatcommand("ta_send", {
description = minetest.formspec_escape(
"Send a techage command to the block with the number given: /ta_send <number> <command> [<data>]"),
func = function(name, param)
local num, cmnd, payload = param:match('^([0-9]+)%s+(%w+)%s*(.*)$')
if num and cmnd then
if techage.not_protected(num, name) then
local resp = techage.send_single("0", num, cmnd, payload)
if type(resp) == "string" then
return true, resp
else
return true, dump(resp)
end
else
return false, "Destination block is protected"
end
end
return false, "Syntax: /ta_send <number> <command> [<data>]"
end
})
minetest.register_chatcommand("expoints", {
privs = {
server = true
},
func = function(name, param)
local player_name, points = param:match("^(%S+)%s*(%d*)$")
if player_name then
local player = minetest.get_player_by_name(player_name)
if player then
if points and points ~= "" then
if techage.set_expoints(player, tonumber(points)) then
return true, "The player "..player_name.." now has "..points.." experience points."
end
else
points = techage.get_expoints(player)
return true, "The player "..player_name.." has "..points.." experience points."
end
else
return false, "Unknown player "..player_name
end
end
return false, "Syntax error! Syntax: /expoints <name> [<points>]"
end
})
minetest.register_chatcommand("my_expoints", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then
local points = techage.get_expoints(player)
if points then
return true, "You have "..points.." experience points."
end
end
end
})

View File

@ -7,12 +7,15 @@
AGPL v3
See LICENSE.txt for more information
Configured inventory lib
Assuming the inventory has the name "conf"
Otherwise the name has to be provided as argument
]]--
local StackName = ... or "conf"
-- for lazy programmers
local M = minetest.get_meta
@ -22,7 +25,7 @@ function inv_lib.preassigned_stacks(pos, xsize, ysize)
local inv = M(pos):get_inventory()
local tbl = {}
for idx = 1, xsize * ysize do
local item_name = inv:get_stack("conf", idx):get_name()
local item_name = inv:get_stack(StackName, idx):get_name()
if item_name ~= "" then
local x = (idx - 1) % xsize
local y = math.floor((idx - 1) / xsize)
@ -36,9 +39,9 @@ function inv_lib.item_filter(pos, size)
local inv = M(pos):get_inventory()
local filter = {}
for idx = 1, size do
local item_name = inv:get_stack("conf", idx):get_name()
local item_name = inv:get_stack(StackName, idx):get_name()
if item_name == "" then item_name = "unconfigured" end
if not filter[item_name] then
if not filter[item_name] then
filter[item_name] = {}
end
table.insert(filter[item_name], idx)
@ -49,7 +52,7 @@ end
function inv_lib.allow_conf_inv_put(pos, listname, index, stack, player)
local inv = M(pos):get_inventory()
local list = inv:get_list(listname)
if list[index]:get_count() == 0 then
stack:set_count(1)
inv:set_stack(listname, index, stack)
@ -76,16 +79,22 @@ function inv_lib.allow_conf_inv_move(pos, from_list, from_index, to_list, to_ind
end
function inv_lib.put_items(pos, inv, listname, item, stacks, idx)
local name = item:get_name()
local count = item:get_count()
for _, i in ipairs(stacks or {}) do
if not idx or idx == i then
local stack = inv:get_stack(listname, i)
if stack:item_fits(item) then
stack:add_item(item)
inv:set_stack(listname, i, stack)
local leftover = stack:add_item({name = name, count = count})
count = leftover:get_count()
inv:set_stack(listname, i, stack)
if count == 0 then
return true
end
end
end
if count > 0 then
return ItemStack({name = name, count = count})
end
return false
end
@ -104,6 +113,6 @@ function inv_lib.take_item(pos, inv, listname, num, stacks)
end
end
end
return inv_lib
return inv_lib

71
basis/counting.lua Normal file
View File

@ -0,0 +1,71 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Count techage commands player related
]]--
local PlayerName
local PlayerPoints = {}
local LastPlayerPoints = {}
local S = techage.S
local MAX_POINTS = tonumber(minetest.settings:get("techage_command_limit")) or 1200
function techage.counting_start(player_name)
PlayerName = player_name
PlayerPoints[PlayerName] = PlayerPoints[PlayerName] or 0
end
function techage.counting_stop()
PlayerName = nil
end
function techage.counting_hit()
if PlayerName then
PlayerPoints[PlayerName] = PlayerPoints[PlayerName] + 1
end
end
function techage.counting_add(player_name, points)
PlayerPoints[player_name] = (PlayerPoints[player_name] or 0) + points
end
local function output()
for name, val in pairs(PlayerPoints) do
if val > MAX_POINTS then
local obj = minetest.get_player_by_name(name)
if obj then
minetest.chat_send_player(name,
S("[techage] The limit for 'number of commands per minute' has been exceeded.") ..
" " .. string.format(MAX_POINTS .. " " .. S("is allowed. Current value is") .. " " .. val));
minetest.log("action", "[techage] " .. name ..
" exceeds the limit for commands per minute. value = " .. val)
local factor = 100 / (obj:get_armor_groups().fleshy or 100)
obj:punch(obj, 1.0, {full_punch_interval=1.0, damage_groups = {fleshy=factor * 5}})
end
end
end
LastPlayerPoints = table.copy(PlayerPoints)
PlayerPoints = {}
minetest.after(60, output)
end
minetest.after(60, output)
minetest.register_chatcommand("ta_limit", {
description = "Get your current techage command limit value",
func = function(name)
local num = LastPlayerPoints[name] or 0
return true, S("Your current value is") .. " " .. num .. " " .. S("per minute") .. ". " ..
MAX_POINTS .. " " .. S("is allowed")
end
})

View File

@ -10,7 +10,7 @@
See LICENSE.txt for more information
Fake Player
]]--
-- Map method names to their return values
@ -115,4 +115,3 @@ for method_name, return_value in pairs(methods) do
return return_value
end
end

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Firebox basic functions
]]--
@ -20,14 +20,14 @@ local S = techage.S
techage.firebox = {}
techage.firebox.Burntime = {
["techage:charcoal"] = true, -- will be replaced by burntime
["default:coal_lump"] = true,
["default:coalblock"] = true,
["techage:oil_source"] = true,
["techage:gas"] = true,
["techage:gasoline"] = true,
["techage:naphtha"] = true,
["techage:fueloil"] = true,
["techage:charcoal"] = 1, -- will be replaced by burntime
["default:coal_lump"] = 1,
["default:coalblock"] = 1,
["techage:oil_source"] = 1,
["techage:gas"] = 1,
["techage:gasoline"] = 1,
["techage:naphtha"] = 1,
["techage:fueloil"] = 1,
}
techage.firebox.ValidOilFuels = {
@ -43,8 +43,8 @@ local function determine_burntimes()
local fuel,_ = minetest.get_craft_result({method = "fuel", width = 1, items = {k}})
techage.firebox.Burntime[k] = fuel.time
end
end
minetest.after(1, determine_burntimes)
end
minetest.register_on_mods_loaded(determine_burntimes)
function techage.firebox.formspec(nvm)
local fuel_percent = 0
@ -147,5 +147,4 @@ function techage.firebox.set_firehole(pos, on)
minetest.swap_node(pos2, {name="air"})
end
end
end
end

955
basis/fly_lib.lua Normal file
View File

@ -0,0 +1,955 @@
--[[
TechAge
=======
Copyright (C) 2020-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Block fly/move library
]]--
-- for lazy programmers
local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local S = techage.S
local flylib = {}
local function lvect_add_vec(lvect1, offs)
if not lvect1 or not offs then return end
local lvect2 = {}
for _, v in ipairs(lvect1) do
lvect2[#lvect2 + 1] = vector.add(v, offs)
end
return lvect2
end
-- yaw in radiant
local function rotate(v, yaw)
local sinyaw = math.sin(yaw)
local cosyaw = math.cos(yaw)
return {x = v.x * cosyaw - v.z * sinyaw, y = v.y, z = v.x * sinyaw + v.z * cosyaw}
end
-- playername is needed for carts, to attach the player to the cart entity
local function set_node(item, playername)
local dest_pos = item.dest_pos
local name = item.name or "air"
local param2 = item.param2 or 0
local nvm = techage.get_nvm(item.base_pos)
local node = techage.get_node_lvm(dest_pos)
local ndef1 = minetest.registered_nodes[name]
local ndef2 = minetest.registered_nodes[node.name]
nvm.running = false
M(item.base_pos):set_string("status", S("Stopped"))
if ndef1 and ndef2 then
if minecart.is_cart(name) and (minecart.is_rail(dest_pos, node.name) or minecart.is_cart(name)) then
local player = playername and minetest.get_player_by_name(playername)
minecart.place_and_start_cart(dest_pos, {name = name, param2 = param2}, item.cartdef, player)
return
elseif ndef2.buildable_to then
local meta = M(dest_pos)
if name ~= "techage:moveblock" then
minetest.set_node(dest_pos, {name=name, param2=param2})
meta:from_table(item.metadata or {})
meta:set_string("ta_move_block", "")
meta:set_int("ta_door_locked", 1)
end
return
end
local meta = M(dest_pos)
if not meta:contains("ta_move_block") then
meta:set_string("ta_move_block", minetest.serialize({name=name, param2=param2}))
return
end
elseif ndef1 then
if name ~= "techage:moveblock" then
minetest.add_item(dest_pos, ItemStack(name))
end
end
end
-------------------------------------------------------------------------------
-- Entity monitoring
-------------------------------------------------------------------------------
local queue = {}
local first = 0
local last = -1
local function push(item)
last = last + 1
queue[last] = item
end
local function pop()
if first > last then return end
local item = queue[first]
queue[first] = nil -- to allow garbage collection
first = first + 1
return item
end
local function monitoring()
local num = last - first + 1
for _ = 1, num do
local item = pop()
if item.ttl >= techage.SystemTime then
-- still valud
push(item)
elseif item.ttl ~= 0 then
set_node(item)
end
end
minetest.after(1, monitoring)
end
minetest.after(1, monitoring)
minetest.register_on_shutdown(function()
local num = last - first + 1
for _ = 1, num do
local item = pop()
if item.ttl ~= 0 then
set_node(item)
end
end
end)
local function monitoring_add_entity(item)
item.ttl = techage.SystemTime + 1
push(item)
end
local function monitoring_del_entity(item)
-- Mark as timed out
item.ttl = 0
end
local function monitoring_trigger_entity(item)
item.ttl = techage.SystemTime + 1
end
-------------------------------------------------------------------------------
-- to_path function for the fly/move path
-------------------------------------------------------------------------------
local function strsplit(text)
text = text:gsub("\r\n", "\n")
text = text:gsub("\r", "\n")
return string.split(text, "\n", true)
end
local function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function flylib.distance(v)
return math.abs(v.x) + math.abs(v.y) + math.abs(v.z)
end
function flylib.to_vector(s, max_dist)
local x,y,z = unpack(string.split(s, ","))
x = tonumber(x) or 0
y = tonumber(y) or 0
z = tonumber(z) or 0
if x and y and z then
if not max_dist or (math.abs(x) + math.abs(y) + math.abs(z)) <= max_dist then
return {x = x, y = y, z = z}
end
end
end
function flylib.to_path(s, max_dist)
local tPath
local dist = 0
for _, line in ipairs(strsplit(s or "")) do
line = trim(line)
line = string.split(line, "--", true, 1)[1] or ""
if line ~= "" then
local v = flylib.to_vector(line)
if v then
dist = dist + flylib.distance(v)
if not max_dist or dist <= max_dist then
tPath = tPath or {}
tPath[#tPath + 1] = v
else
return tPath, S("Error: Max. length of the flight route exceeded by @1 blocks !!", dist - max_dist)
end
else
return tPath, S("Error: Invalid path !!")
end
end
end
return tPath
end
local function next_path_pos(pos, lpath, idx)
local offs = lpath[idx]
if offs then
return vector.add(pos, offs)
end
end
local function reverse_path(lpath)
local lres = {}
for i = #lpath, 1, -1 do
lres[#lres + 1] = vector.multiply(lpath[i], -1)
end
return lres
end
local function dest_offset(lpath)
local offs = {x=0, y=0, z=0}
for i = 1,#lpath do
offs = vector.add(offs, lpath[i])
end
return offs
end
-------------------------------------------------------------------------------
-- Protect the doors from being opened by hand
-------------------------------------------------------------------------------
local function new_on_rightclick(old_on_rightclick)
return function(pos, node, clicker, itemstack, pointed_thing)
if M(pos):contains("ta_door_locked") then
return itemstack
end
if old_on_rightclick then
return old_on_rightclick(pos, node, clicker, itemstack, pointed_thing)
else
return itemstack
end
end
end
function flylib.protect_door_from_being_opened(name)
-- Change on_rightclick function.
local ndef = minetest.registered_nodes[name]
if ndef then
local old_on_rightclick = ndef.on_rightclick
minetest.override_item(ndef.name, {
on_rightclick = new_on_rightclick(old_on_rightclick)
})
end
end
-------------------------------------------------------------------------------
-- Entity / Move / Attach / Detach
-------------------------------------------------------------------------------
local MIN_SPEED = 0.4
local MAX_SPEED = 8
local CORNER_SPEED = 4
local function calc_speed(v)
return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
end
-- Only the ID ist stored, not the object
local function get_object_id(object)
for id, entity in pairs(minetest.luaentities) do
if entity.object == object then
return id
end
end
end
-- determine exact position of attached entities
local function obj_pos(obj)
local _, _, pos = obj:get_attach()
if pos then
pos = vector.divide(pos, 29)
return vector.add(obj:get_pos(), pos)
end
end
-- Check access conflicts with other mods
local function lock_player(player)
local meta = player:get_meta()
if meta:get_int("player_physics_locked") == 0 then
meta:set_int("player_physics_locked", 1)
meta:set_string("player_physics_locked_by", "ta_flylib")
return true
end
return false
end
local function unlock_player(player)
local meta = player:get_meta()
if meta:get_int("player_physics_locked") == 1 then
if meta:get_string("player_physics_locked_by") == "ta_flylib" then
meta:set_int("player_physics_locked", 0)
meta:set_string("player_physics_locked_by", "")
return true
end
end
return false
end
local function detach_player(player)
local pos = obj_pos(player)
if pos then
player:set_detach()
player:set_properties({visual_size = {x=1, y=1}})
player:set_pos(pos)
end
-- TODO: move to save position
end
-- Attach player/mob to given parent object (block)
local function attach_single_object(parent, obj, distance)
local self = parent:get_luaentity()
local res = obj:get_attach()
if not res then -- not already attached
local yaw
if obj:is_player() then
yaw = obj:get_look_horizontal()
else
yaw = obj:get_rotation().y
end
-- store for later use
local offs = table.copy(distance)
-- Calc entity rotation, which is relative to the parent's rotation
local rot = parent:get_rotation()
if self.param2 >= 20 then
distance = rotate(distance, 2 * math.pi - rot.y)
distance.y = -distance.y
distance.x = -distance.x
rot.y = rot.y - yaw
elseif self.param2 < 4 then
distance = rotate(distance, 2 * math.pi - rot.y)
rot.y = rot.y - yaw
end
distance = vector.multiply(distance, 29)
obj:set_attach(parent, "", distance, vector.multiply(rot, 180 / math.pi))
obj:set_properties({visual_size = {x=2.9, y=2.9}})
if obj:is_player() then
if lock_player(obj) then
table.insert(self.players, {name = obj:get_player_name(), offs = offs})
end
else
table.insert(self.entities, {objID = get_object_id(obj), offs = offs})
end
end
end
-- Attach all objects around to the parent object
-- offs is the search/attach position offset
-- distance (optional) is the attach distance to the center of the entity
local function attach_objects(pos, offs, parent, yoffs, distance)
local pos1 = vector.add(pos, offs)
for _, obj in pairs(minetest.get_objects_inside_radius(pos1, 0.9)) do
-- keep relative object position
distance = distance or vector.subtract(obj:get_pos(), pos)
local entity = obj:get_luaentity()
if entity then
local mod = entity.name:gmatch("(.-):")()
if techage.RegisteredMobsMods[mod] then
distance.y = distance.y + yoffs
attach_single_object(parent, obj, distance)
end
elseif obj:is_player() then
attach_single_object(parent, obj, distance)
end
end
end
-- Detach all attached objects from the parent object
local function detach_objects(pos, self)
for _, item in ipairs(self.entities or {}) do
local entity = minetest.luaentities[item.objID]
if entity then
local obj = entity.object
obj:set_detach()
obj:set_properties({visual_size = {x=1, y=1}})
local pos1 = vector.add(pos, item.offs)
pos1.y = pos1.y - (self.yoffs or 0)
obj:set_pos(pos1)
end
end
for _, item in ipairs(self.players or {}) do
local obj = minetest.get_player_by_name(item.name)
if obj then
obj:set_detach()
obj:set_properties({visual_size = {x=1, y=1}})
local pos1 = vector.add(pos, item.offs)
pos1.y = pos1.y + 0.1
obj:set_pos(pos1)
unlock_player(obj)
end
end
self.entities = {}
self.players = {}
end
local function entity_to_node(pos, obj)
local self = obj:get_luaentity()
if self and self.item then
local playername = self.players and self.players[1] and self.players[1].name
detach_objects(pos, self)
monitoring_del_entity(self.item)
minetest.after(0.1, obj.remove, obj)
set_node(self.item, playername)
end
end
-- Create a node entitiy.
-- * base_pos is controller block related
-- * start_pos and dest_pos are entity positions
local function node_to_entity(base_pos, start_pos, dest_pos)
local meta = M(start_pos)
local node, metadata, cartdef
node = techage.get_node_lvm(start_pos)
if minecart.is_cart(node.name) then
cartdef = minecart.remove_cart(start_pos)
elseif meta:contains("ta_move_block") then
-- Move-block stored as metadata
node = minetest.deserialize(meta:get_string("ta_move_block"))
metadata = {}
meta:set_string("ta_move_block", "")
meta:set_string("ta_block_locked", "true")
elseif not meta:contains("ta_block_locked") then
-- Block with other metadata
node = techage.get_node_lvm(start_pos)
metadata = meta:to_table()
minetest.after(0.1, minetest.remove_node, start_pos)
else
return
end
local obj = minetest.add_entity(start_pos, "techage:move_item")
if obj then
local self = obj:get_luaentity()
local rot = techage.facedir_to_rotation(node.param2)
obj:set_rotation(rot)
obj:set_properties({wield_item=node.name})
obj:set_armor_groups({immortal=1})
-- To be able to revert to node
self.param2 = node.param2
self.item = {
name = node.name,
param2 = node.param2,
metadata = metadata or {},
dest_pos = dest_pos,
base_pos = base_pos,
cartdef = cartdef,
}
monitoring_add_entity(self.item)
-- Prepare for attachments
self.players = {}
self.entities = {}
-- Prepare for path walk
self.path_idx = 1
return obj, self.item.cartdef ~= nil
end
end
-- move block direction
local function determine_dir(pos1, pos2)
local vdist = vector.subtract(pos2, pos1)
local ndist = vector.length(vdist)
if ndist > 0 then
return vector.divide(vdist, ndist)
end
return {x=0, y=0, z=0}
end
local function move_entity(obj, next_pos, dir, is_corner)
local self = obj:get_luaentity()
self.next_pos = next_pos
self.dir = dir
if is_corner then
local vel = vector.multiply(dir, math.min(CORNER_SPEED, self.max_speed))
obj:set_velocity(vel)
end
local acc = vector.multiply(dir, self.max_speed / 2)
obj:set_acceleration(acc)
end
local function moveon_entity(obj, self, pos1)
local pos2 = next_path_pos(pos1, self.lmove, self.path_idx)
if pos2 then
self.path_idx = self.path_idx + 1
local dir = determine_dir(pos1, pos2)
move_entity(obj, pos2, dir, true)
return true
end
end
minetest.register_entity("techage:move_item", {
initial_properties = {
pointable = true,
makes_footstep_sound = true,
static_save = false,
collide_with_objects = false,
physical = false,
visual = "wielditem",
wield_item = "default:dirt",
visual_size = {x=0.67, y=0.67, z=0.67},
selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
on_step = function(self, dtime, moveresult)
local stop_obj = function(obj, self)
local next_pos = self.next_pos
obj:move_to(self.next_pos, true)
obj:set_acceleration({x=0, y=0, z=0})
obj:set_velocity({x=0, y=0, z=0})
self.next_pos = nil
self.old_dist = nil
return next_pos
end
if self.next_pos then
local obj = self.object
local pos = obj:get_pos()
local dist = vector.distance(pos, self.next_pos)
local speed = calc_speed(obj:get_velocity())
self.old_dist = self.old_dist or dist
if self.lmove and self.lmove[self.path_idx] then
local min_dist = math.min(1, self.max_speed / 8)
if dist < min_dist or dist > self.old_dist then
-- change of direction
local next_pos = stop_obj(obj, self)
if not moveon_entity(obj, self, next_pos) then
minetest.after(0.5, entity_to_node, next_pos, obj)
end
return
end
elseif dist < 0.05 or dist > self.old_dist then
-- Landing
local next_pos = stop_obj(obj, self)
local dest_pos = self.item.dest_pos or next_pos
minetest.after(0.5, entity_to_node, dest_pos, obj)
return
end
self.old_dist = dist
-- Braking or limit max speed
if speed > (dist * 2) or speed > self.max_speed then
speed = math.min(speed, math.max(dist * 2, MIN_SPEED))
local vel = vector.multiply(self.dir,speed)
obj:set_velocity(vel)
obj:set_acceleration({x=0, y=0, z=0})
end
monitoring_trigger_entity(self.item)
end
end,
})
local function is_valid_dest(pos)
local node = techage.get_node_lvm(pos)
if techage.is_air_like(node.name) then
return true
end
if minecart.is_rail(pos, node.name) or minecart.is_cart(node.name) then
return true
end
if not M(pos):contains("ta_move_block") then
return true
end
return false
end
local function is_simple_node(pos)
local node = techage.get_node_lvm(pos)
if not minecart.is_rail(pos, node.name) then
local ndef = minetest.registered_nodes[node.name]
return node.name ~= "air" and techage.can_dig_node(node.name, ndef) or minecart.is_cart(node.name)
end
end
-- Move node from 'pos1' to the destination, calculated by means of 'lmove'
-- * pos and meta are controller block related
-- * lmove is the movement as a list of `moves`
-- * height is move block height as value between 0 and 1 and used to calculate the offset
-- for the attached object (player).
local function move_node(pos, meta, pos1, lmove, max_speed, height)
local pos2 = next_path_pos(pos1, lmove, 1)
local offs = dest_offset(lmove)
local dest_pos = vector.add(pos1, offs)
-- optional for non-player objects
local yoffs = meta:get_float("offset")
if pos2 then
local dir = determine_dir(pos1, pos2)
local obj, is_cart = node_to_entity(pos, pos1, dest_pos)
if obj then
if is_cart then
attach_objects(pos1, 0, obj, yoffs, {x = 0, y = -0.4, z = 0})
else
local offs = {x=0, y=height or 1, z=0}
attach_objects(pos1, offs, obj, yoffs)
if dir.y == 0 then
if (dir.x ~= 0 and dir.z == 0) or (dir.x == 0 and dir.z ~= 0) then
attach_objects(pos1, dir, obj, yoffs)
end
end
end
local self = obj:get_luaentity()
self.path_idx = 2
self.lmove = lmove
self.max_speed = max_speed
self.yoffs = yoffs
move_entity(obj, pos2, dir)
return true
else
return false
end
end
end
--
-- Default Move Mode
--
-- Move the nodes from nvm.lpos1 to nvm.lpos2
-- * nvm.lpos1 is a list of nodes
-- * lmove is the movement as a list of `moves`
-- * pos, meta, and nvm are controller block related
--- height is move block height as value between 0 and 1 and used to calculate the offset
-- for the attached object (player).
local function multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2to1)
local owner = meta:get_string("owner")
techage.counting_add(owner, #lmove, #nvm.lpos1 * #lmove)
for idx = 1, #nvm.lpos1 do
local pos1 = nvm.lpos1[idx]
local pos2 = nvm.lpos2[idx]
--print("multi_move_nodes", idx, P2S(pos1), P2S(pos2))
if move2to1 then
pos1, pos2 = pos2, pos1
end
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
if is_simple_node(pos1) and is_valid_dest(pos2) then
if move_node(pos, meta, pos1, lmove, max_speed, height) == false then
meta:set_string("status", S("No valid node at the start position"))
return false
end
else
if not is_simple_node(pos1) then
meta:set_string("status", S("No valid node at the start position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid node at the start position") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("No valid destination position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2))
end
return false
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Start position is protected") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("Destination position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2))
end
return false
end
end
meta:set_string("status", S("Running"))
return true
end
-- Move the nodes from lpos1 to lpos2.
-- * lpos1 is a list of nodes
-- * lpos2 = lpos1 + move
-- * pos and meta are controller block related
-- * height is move block height as value between 0 and 1 and used to calculate the offset
-- for the attached object (player).
local function move_nodes(pos, meta, lpos1, move, max_speed, height)
local owner = meta:get_string("owner")
lpos1 = lpos1 or {}
techage.counting_add(owner, #lpos1)
local lpos2 = {}
for idx = 1, #lpos1 do
local pos1 = lpos1[idx]
local pos2 = vector.add(lpos1[idx], move)
lpos2[idx] = pos2
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
if is_simple_node(pos1) and is_valid_dest(pos2) then
move_node(pos, meta, pos1, {move}, max_speed, height)
else
if not is_simple_node(pos1) then
meta:set_string("status", S("No valid node at the start position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid node at the start position") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("No valid destination position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2))
end
return false, lpos1
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Start position is protected") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("Destination position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2))
end
return false, lpos1
end
end
meta:set_string("status", S("Running"))
return true, lpos2
end
--
-- Teleport Mode
--
local function is_player_available(lpos1)
if #lpos1 == 1 then
for _, obj in pairs(minetest.get_objects_inside_radius(lpos1[1], 0.9)) do
if obj:is_player() then
return true
end
end
end
end
local function teleport(base_pos, pos1, pos2, meta, owner, lmove, max_speed)
if not minetest.is_protected(pos1, owner) and not minetest.is_protected(pos2, owner) then
local node1 = techage.get_node_lvm(pos1)
local node2 = techage.get_node_lvm(pos2)
if techage.is_air_like(node1.name) and techage.is_air_like(node2.name) then
minetest.swap_node(pos1, {name = "techage:moveblock", param2 = 0})
if move_node(base_pos, meta, pos1, lmove, max_speed, 0) == false then
meta:set_string("status", S("No valid start position"))
return false
end
else
if not techage.is_air_like(node1.name) then
meta:set_string("status", S("No valid start position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid start position") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("No valid destination position"))
minetest.chat_send_player(owner, " [techage] " .. S("No valid destination position") .. " at " .. P2S(pos2))
end
return false
end
else
if minetest.is_protected(pos1, owner) then
meta:set_string("status", S("Start position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Start position is protected") .. " at " .. P2S(pos1))
else
meta:set_string("status", S("Destination position is protected"))
minetest.chat_send_player(owner, " [techage] " .. S("Destination position is protected") .. " at " .. P2S(pos2))
end
return false
end
meta:set_string("status", S("Running"))
return true
end
-- Move the player from nvm.lpos1 to nvm.lpos2
-- * nvm.lpos1 is a list of length one(!) with the not to be moved block below the player
-- * lmove is the movement as a list of `moves`
-- * pos, meta, and nvm are controller block related
local function multi_teleport_player(base_pos, meta, nvm, lmove, max_speed, move2to1)
local owner = meta:get_string("owner")
techage.counting_add(owner, #lmove, #nvm.lpos1 * #lmove)
local pos1 = vector.add(nvm.lpos1[1], {x=0, y=1, z=0})
local pos2 = vector.add(nvm.lpos2[1], {x=0, y=1, z=0})
if move2to1 then
pos1, pos2 = pos2, pos1
end
return teleport(base_pos, pos1, pos2, meta, owner, lmove, max_speed)
end
-- Move the player from lpos1 to lpos2.
-- * lpos1 is a list of length one(!) with the not to be moved block below the player
-- * lpos2 = lpos1 + move
-- * pos and meta are controller block related
local function teleport_player(base_pos, meta, lpos1, move, max_speed)
local owner = meta:get_string("owner")
lpos1 = lpos1 or {}
techage.counting_add(owner, #lpos1)
local pos1 = vector.add(lpos1[1], {x=0, y=1, z=0})
local pos2 = vector.add(pos1, move)
return teleport(base_pos, pos1, pos2, meta, owner, {move}, max_speed), nil
end
--------------------------------------------------------------------------------------
-- API
--------------------------------------------------------------------------------------
-- move2to1 is the direction and is true for 'from pos2 to pos1'
-- Move path and other data is stored as meta data of pos
function flylib.move_to_other_pos(pos, move2to1)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local lmove, err = flylib.to_path(meta:get_string("path")) or {}
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
local height = meta:contains("height") and meta:get_float("height") or 1
local teleport_mode = meta:get_string("teleport_mode") == "enable"
if err or nvm.running then return false end
height = techage.in_range(height, 0, 1)
max_speed = techage.in_range(max_speed, MIN_SPEED, MAX_SPEED)
nvm.lpos1 = nvm.lpos1 or {}
local offs = dest_offset(lmove)
if move2to1 then
lmove = reverse_path(lmove)
end
-- calc destination positions
nvm.lpos2 = lvect_add_vec(nvm.lpos1, offs)
local lpos = move2to1 and nvm.lpos2 or nvm.lpos1
if teleport_mode and is_player_available(lpos) then
nvm.running = multi_teleport_player(pos, meta, nvm, lmove, max_speed, move2to1)
elseif not teleport_mode then
nvm.running = multi_move_nodes(pos, meta, nvm, lmove, max_speed, height, move2to1)
end
nvm.moveBA = nvm.running and not move2to1
return nvm.running
end
-- `move` the movement as a vector
function flylib.move_to(pos, move)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1)
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
local teleport_mode = meta:get_string("teleport_mode") == "enable"
if nvm.running then return false end
-- TODO: Not working so far. There is no known 'nvm.lastpos' as start pos.
--if teleport_mode and is_player_available(nvm.lpos1) then
-- nvm.running, nvm.lastpos = teleport_player(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed)
--elseif not teleport_mode then
nvm.running, nvm.lastpos = move_nodes(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height)
--end
return nvm.running
end
function flylib.reset_move(pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
local height = techage.in_range(meta:contains("height") and meta:get_float("height") or 1, 0, 1)
local max_speed = meta:contains("max_speed") and meta:get_int("max_speed") or MAX_SPEED
if nvm.running then return false end
if meta:get_string("teleport_mode") == "enable" then return false end
if nvm.lpos1 and nvm.lpos1[1] then
local move = vector.subtract(nvm.lpos1[1], (nvm.lastpos or nvm.lpos1)[1])
nvm.running, nvm.lastpos = move_nodes(pos, meta, nvm.lastpos or nvm.lpos1, move, max_speed, height)
return nvm.running
end
return false
end
-- pos is the controller block pos
-- lpos is a list of node positions to be moved
-- rot is one of "l", "r", "2l", "2r"
function flylib.rotate_nodes(pos, lpos, rot)
local meta = M(pos)
local owner = meta:get_string("owner")
-- cpos is the center pos
local cpos = meta:contains("center") and flylib.to_vector(meta:get_string("center"))
local lpos2 = techage.rotate_around_center(lpos, rot, cpos)
local param2
local nodes2 = {}
techage.counting_add(owner, #lpos * 2)
for i, pos1 in ipairs(lpos) do
local node = techage.get_node_lvm(pos1)
if rot == "l" then
param2 = techage.param2_turn_right(node.param2)
elseif rot == "r" then
param2 = techage.param2_turn_left(node.param2)
else
param2 = techage.param2_turn_right(techage.param2_turn_right(node.param2))
end
if not minetest.is_protected(pos1, owner) and is_simple_node(pos1) then
minetest.remove_node(pos1)
nodes2[#nodes2 + 1] = {pos = lpos2[i], name = node.name, param2 = param2}
end
end
for _,item in ipairs(nodes2) do
if not minetest.is_protected(item.pos, owner) and is_valid_dest(item.pos) then
minetest.add_node(item.pos, {name = item.name, param2 = item.param2})
end
end
return lpos2
end
function flylib.exchange_node(pos, name, param2)
local meta = M(pos)
local move_block
-- consider stored "objects"
if meta:contains("ta_move_block") then
move_block = meta:get_string("ta_move_block")
end
minetest.swap_node(pos, {name = name, param2 = param2})
if move_block then
meta:set_string("ta_move_block", move_block)
end
end
function flylib.remove_node(pos)
local meta = M(pos)
local move_block
-- consider stored "objects"
if meta:contains("ta_move_block") then
move_block = meta:get_string("ta_move_block")
end
minetest.remove_node(pos)
if move_block then
local node = minetest.deserialize(move_block)
minetest.add_node(pos, node)
meta:set_string("ta_move_block", "")
end
end
minetest.register_on_joinplayer(function(player)
unlock_player(player)
end)
minetest.register_on_leaveplayer(function(player)
if unlock_player(player) then
detach_player(player)
end
end)
minetest.register_on_dieplayer(function(player)
if unlock_player(player) then
detach_player(player)
end
end)
techage.flylib = flylib

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Keep only one formspec active per player
]]--

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Oil fuel burning lib
]]--
@ -51,7 +51,7 @@ function techage.fuel.fuel_container(x, y, nvm)
fuel_percent..":default_furnace_fire_fg.png]"..
techage.item_image(0.1, 1.1, itemname)..
"container_end[]"
end
end
local function help(x, y)
local tooltip = S("To add fuel punch\nthis block\nwith a fuel container")
@ -108,17 +108,17 @@ function techage.fuel.on_punch(pos, node, puncher, pointed_thing)
if mem.blocking_time > techage.SystemTime then
return
end
local wielded_item = puncher:get_wielded_item():get_name()
local item_count = puncher:get_wielded_item():get_count()
local new_item = techage.liquid.fill_on_punch(nvm, wielded_item, item_count, puncher)
local new_item = techage.liquid.fill_on_punch(nvm, wielded_item, item_count, puncher)
if new_item then
puncher:set_wielded_item(new_item)
M(pos):set_string("formspec", techage.fuel.formspec(pos, nvm))
mem.blocking_time = techage.SystemTime + BLOCKING_TIME
return
end
local ldef = techage.liquid.get_liquid_def(wielded_item)
if ldef and ValidOilFuels[ldef.inv_item] then
local lqd = (minetest.registered_nodes[node.name] or {}).liquid
@ -139,7 +139,7 @@ function techage.fuel.get_fuel(nvm)
nvm.liquid.amount = nvm.liquid.amount - 1
return nvm.liquid.name
end
nvm.liquid.name = nil
nvm.liquid.name = nil
end
return nil
end
@ -194,4 +194,4 @@ function techage.fuel.get_liquid_table(valid_fuel, capacity, start_firebox)
return leftover
end
}
end
end

View File

@ -7,9 +7,9 @@
AGPL v3
See LICENSE.txt for more information
Gravel Sieve basis functions
]]--
-- Increase the probability over the natural occurrence
@ -29,19 +29,19 @@ local ProbabilityCorrections = {
-- collect all registered ores and calculate the probability
local function add_ores()
for _,item in pairs(minetest.registered_ores) do
if minetest.registered_nodes[item.ore] then
if not ore_probability[item.ore] and minetest.registered_nodes[item.ore] then
local drop = minetest.registered_nodes[item.ore].drop
if type(drop) == "string"
and drop ~= item.ore
and drop ~= ""
and item.ore_type == "scatter"
and item.wherein == "default:stone"
and item.clust_scarcity ~= nil and item.clust_scarcity > 0
and item.clust_num_ores ~= nil and item.clust_num_ores > 0
and item.clust_scarcity ~= nil and item.clust_scarcity > 0
and item.clust_num_ores ~= nil and item.clust_num_ores > 0
and item.y_max ~= nil and item.y_min ~= nil then
local factor = 0.5
if item.y_max < -250 then
factor = -250 / item.y_max
if item.y_max < -250 then
factor = -250 / item.y_max
end
local probability = (techage.ore_rarity / PROBABILITY_FACTOR) * item.clust_scarcity /
(item.clust_num_ores * factor)
@ -64,10 +64,16 @@ local function add_ores()
overall_probability = overall_probability + 1.0/probability
end
minetest.log("info", string.format("[techage] Overall probability %g", overall_probability))
end
end
minetest.after(1, add_ores)
minetest.register_on_mods_loaded(add_ores)
--
-- Change the probability of ores or register new ores for sieving
--
function techage.register_ore_for_gravelsieve(ore_name, probability)
ore_probability[ore_name] = probability
end
-- determine ore based on the calculated probability
function techage.gravelsieve_get_random_gravel_ore()

240
basis/hyperloop.lua Normal file
View File

@ -0,0 +1,240 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
For chests and tanks with hyperloop support
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local N = techage.get_node_lvm
local S = techage.S
-- Will be initialized when mods are loaded
local Stations = nil
local Tube = nil
local HYPERLOOP = nil
techage.hyperloop = {}
--[[
tStations["(x,y,z)"] = {
conn = {dir = "(200,0,20)", ...},
name = <node_type>, -- chest/tank
owner = "singleplayer",
conn_name = <own name>,
single = true/nil,
}
]]--
minetest.register_on_mods_loaded(function()
if minetest.global_exists("hyperloop") then
Stations = hyperloop.Stations
Tube = hyperloop.Tube
HYPERLOOP = true
Tube:add_secondary_node_names({"techage:ta5_hl_chest", "techage:ta5_hl_tank"})
end
end)
local function get_remote_pos(pos, rmt_name)
local owner = M(pos):get_string("owner")
for key,item in pairs(Stations:get_node_table(pos)) do
if item.owner == owner and item.conn_name == rmt_name then
return S2P(key)
end
end
end
local function get_free_server_list(pos, owner)
if Stations and Stations.get_node_table then
local tbl = {M(pos):get_string("remote_name")}
for key,item in pairs(Stations:get_node_table(pos) or {}) do
if item.single and item.owner == owner then
if M(pos):get_string("node_type") == M(S2P(key)):get_string("node_type") then
tbl[#tbl+1] = item.conn_name
end
end
end
tbl[#tbl+1] = ""
return tbl
end
return {}
end
local function on_lose_connection(pos, node_type)
local name = techage.get_node_lvm(pos).name
local ndef = minetest.registered_nodes[name]
if ndef and ndef.on_lose_connection then
ndef.on_lose_connection(pos, node_type)
end
end
local function on_dropdown(pos)
if pos then
local owner = M(pos):get_string("owner")
return table.concat(get_free_server_list(pos, owner), ",") or ""
end
return ""
end
local function update_node_data(pos, state, conn_name, remote_name, rmt_pos)
local meta = M(pos)
local nvm = techage.get_nvm(pos)
if state == "server_connected" then
Stations:update(pos, {conn_name=conn_name, single="nil"})
meta:set_string("status", "server")
meta:set_string("conn_name", conn_name)
meta:set_string("remote_name", "")
meta:set_string("conn_status", S("connected to") .. " " .. P2S(rmt_pos))
nvm.rmt_pos = rmt_pos
elseif state == "client_connected" then
Stations:update(pos, {conn_name="nil", single="nil"})
meta:set_string("status", "client")
meta:set_string("conn_name", "")
meta:set_string("remote_name", remote_name)
meta:set_string("conn_status", S("connected to") .. " " .. P2S(rmt_pos))
nvm.rmt_pos = rmt_pos
elseif state == "server_not_connected" then
Stations:update(pos, {conn_name=conn_name, single=true})
meta:set_string("status", "server")
meta:set_string("conn_name", conn_name)
meta:set_string("remote_name", "")
meta:set_string("conn_status", S("not connected"))
nvm.rmt_pos = nil
on_lose_connection(pos, "server")
elseif state == "client_not_connected" then
Stations:update(pos, {conn_name="nil", single=nil})
meta:set_string("status", "not connected")
meta:set_string("conn_name", "")
meta:set_string("remote_name", "")
meta:set_string("conn_status", S("not connected"))
nvm.rmt_pos = nil
on_lose_connection(pos, "client")
end
end
techage.hyperloop.SUBMENU = {
{
type = "label",
label = S("Enter a block name or select an existing one"),
tooltip = "",
name = "l1",
},
{
type = "ascii",
name = "conn_name",
label = S("Block name"),
tooltip = S("Connection name for this block"),
default = "",
},
{
type = "dropdown",
choices = "",
on_dropdown = on_dropdown,
name = "remote_name",
label = S("Remote name"),
tooltip = S("Connection name of the remote block"),
},
}
function techage.hyperloop.is_client(pos)
if HYPERLOOP then
local nvm = techage.get_nvm(pos)
if Stations:get(nvm.rmt_pos) then
if M(pos):get_string("status") == "client" then
return true
end
end
end
end
function techage.hyperloop.is_server(pos)
if HYPERLOOP then
if M(pos):get_string("status") == "server" then
return true
end
end
end
function techage.hyperloop.is_paired(pos)
if HYPERLOOP then
local nvm = techage.get_nvm(pos)
if Stations:get(nvm.rmt_pos) then
if M(pos):get_string("status") ~= "not connected" then
return true
end
end
end
end
function techage.hyperloop.remote_pos(pos)
if HYPERLOOP then
local nvm = techage.get_nvm(pos)
if Stations:get(nvm.rmt_pos) then
if M(pos):contains("remote_name") then
return nvm.rmt_pos or pos
end
end
end
return pos
end
function techage.hyperloop.after_place_node(pos, placer, node_type)
if HYPERLOOP then
Stations:set(pos, node_type, {owner=placer:get_player_name()})
M(pos):set_string("node_type", node_type)
Tube:after_place_node(pos)
end
end
function techage.hyperloop.after_dig_node(pos, oldnode, oldmetadata, digger)
if HYPERLOOP then
local conn_name = oldmetadata.fields.conn_name
local remote_name = oldmetadata.fields.remote_name
local loc_pos, rmt_pos = pos, techage.get_nvm(pos).rmt_pos
-- Close connections
if remote_name and rmt_pos then -- Connected client
update_node_data(rmt_pos, "server_not_connected", remote_name, "")
elseif conn_name and rmt_pos then -- Connected server
update_node_data(rmt_pos, "client_not_connected", "", conn_name)
end
Tube:after_dig_node(pos)
Stations:delete(pos)
end
end
function techage.hyperloop.after_formspec(pos, fields)
if HYPERLOOP and fields.save or fields.key_enter_field then
local meta = M(pos)
local conn_name = meta:get_string("conn_name")
local remote_name = meta:get_string("remote_name")
local status = meta:contains("status") and meta:get_string("status") or "not connected"
local loc_pos, rmt_pos = pos, techage.get_nvm(pos).rmt_pos
if status == "not connected" then
if fields.remote_name ~= "" then -- Client
local rmt_pos = get_remote_pos(pos, fields.remote_name)
if rmt_pos then
update_node_data(loc_pos, "client_connected", "", fields.remote_name, rmt_pos)
update_node_data(rmt_pos, "server_connected", fields.remote_name, "", loc_pos)
end
elseif fields.conn_name ~= "" then -- Server
update_node_data(loc_pos, "server_not_connected", fields.conn_name, "")
end
end
end
end

View File

@ -42,7 +42,7 @@ local function get_positions(pos, mem, dir)
return true -- no new values
end
-- return both both laser entities the pos and length
-- return for both laser entities the pos and length
local function get_laser_length_and_pos(pos1, pos2, dir)
local dist = vector.distance(pos1, pos2)
@ -133,5 +133,14 @@ function techage.renew_laser(pos, force)
return res
end
function techage.add_laser(pos, pos1, pos2)
local dir = vector.direction(pos1, pos2)
local param2 = minetest.dir_to_facedir(dir)
local size, pos3, pos4 = get_laser_length_and_pos(pos1, pos2, dir)
if size then
add_laser(pos, pos3, pos4, size, param2)
end
end
-- techage.del_laser(pos)
techage.del_laser = del_laser

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
For the transition from v0.26 to v1.0
]]--

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Helper functions
]]--
@ -27,13 +27,166 @@ local Input = {
20,21,22,23, -- 6
}
-- allowed for digging
local RegisteredNodesToBeDug = {}
-- Input data to turn a "facedir" block to the right/left
local ROTATION = {
{5,14,11,16}, -- x+
{7,12,9,18}, -- x-
{0,1,2,3}, -- y+
{22,21,20,23}, -- y-
{6,15,8,17}, -- z+
{4,13,10,19}, -- z-
}
function techage.register_node_to_be_dug(name)
RegisteredNodesToBeDug[name] = true
local FACEDIR_TO_ROT = {[0] =
{x=0.000000, y=0.000000, z=0.000000},
{x=0.000000, y=4.712389, z=0.000000},
{x=0.000000, y=3.141593, z=0.000000},
{x=0.000000, y=1.570796, z=0.000000},
{x=4.712389, y=0.000000, z=0.000000},
{x=3.141593, y=1.570796, z=1.570796},
{x=1.570796, y=4.712389, z=4.712389},
{x=3.141593, y=4.712389, z=4.712389},
{x=1.570796, y=0.000000, z=0.000000},
{x=0.000000, y=4.712389, z=1.570796},
{x=4.712389, y=1.570796, z=4.712389},
{x=0.000000, y=1.570796, z=4.712389},
{x=0.000000, y=0.000000, z=1.570796},
{x=4.712389, y=0.000000, z=1.570796},
{x=0.000000, y=3.141593, z=4.712389},
{x=1.570796, y=3.141593, z=4.712389},
{x=0.000000, y=0.000000, z=4.712389},
{x=1.570796, y=0.000000, z=4.712389},
{x=0.000000, y=3.141593, z=1.570796},
{x=4.712389, y=0.000000, z=4.712389},
{x=0.000000, y=0.000000, z=3.141593},
{x=0.000000, y=1.570796, z=3.141593},
{x=0.000000, y=3.141593, z=3.141593},
{x=0.000000, y=4.712389, z=3.141593},
}
local RotationViaYAxis = {}
for _,row in ipairs(ROTATION) do
for i = 1,4 do
local val = row[i]
local left = row[i == 1 and 4 or i - 1]
local right = row[i == 4 and 1 or i + 1]
RotationViaYAxis[val] = {left, right}
end
end
function techage.facedir_to_rotation(facedir)
return FACEDIR_TO_ROT[facedir] or FACEDIR_TO_ROT[0]
end
function techage.param2_turn_left(param2)
return (RotationViaYAxis[param2] or RotationViaYAxis[0])[2]
end
function techage.param2_turn_right(param2)
return (RotationViaYAxis[param2] or RotationViaYAxis[0])[1]
end
-- Roll a block in north direction (south is vice versa)
local RollNorth = {
{0,4,22,8},
{1,5,23,9},
{2,6,20,10},
{3,7,21,11},
{12,13,14,15},
{16,19,18,17},
}
-- Roll a block in east direction (west is vice versa)
local RollEast = {
{0,12,20,16},
{1,13,21,17},
{2,14,22,18},
{3,15,23,19},
{4,7,6,5},
{8,9,10,11},
}
-- Generate a table for all facedir and param2 values:
-- TurnUp[facedir][param2] = new_param2
local TurnUp = {[0] = {}, {}, {}, {}}
for i = 1,6 do
for j = 1,4 do
local idx = RollNorth[i][j]
TurnUp[0][idx] = RollNorth[i][j == 4 and 1 or j + 1] -- north
TurnUp[2][idx] = RollNorth[i][j == 1 and 4 or j - 1] -- south
idx = RollEast[i][j]
TurnUp[1][idx] = RollEast[i][j == 4 and 1 or j + 1] -- east
TurnUp[3][idx] = RollEast[i][j == 1 and 4 or j - 1] -- west
end
end
-- facedir is from the players (0..3)
-- param2 is from the node (0..23)
function techage.param2_turn_up(facedir, param2)
return TurnUp[facedir % 4][param2 % 24]
end
-------------------------------------------------------------------------------
-- Rotate nodes around the center
-------------------------------------------------------------------------------
function techage.positions_center(lpos)
local c = {x=0, y=0, z=0}
for _,v in ipairs(lpos) do
c = vector.add(c, v)
end
c = vector.divide(c, #lpos)
c = vector.round(c)
c.y = 0
return c
end
function techage.rotate_around_axis(v, c, turn)
local dx, dz = v.x - c.x, v.z - c.z
if turn == "l" then
return {
x = c.x - dz,
y = v.y,
z = c.z + dx,
}
elseif turn == "r" then
return {
x = c.x + dz,
y = v.y,
z = c.z - dx,
}
elseif turn == "" then
return v
else -- turn 180 degree
return {
x = c.x - dx,
y = v.y,
z = c.z - dz,
}
end
end
-- Function returns a list ẃith the new node positions
-- turn is one of "l", "r", "2l", "2r"
-- cpos is the center pos (optional)
function techage.rotate_around_center(nodes1, turn, cpos)
cpos = cpos or techage.positions_center(nodes1)
local nodes2 = {}
for _,pos in ipairs(nodes1) do
nodes2[#nodes2 + 1] = techage.rotate_around_axis(pos, cpos, turn)
end
return nodes2
end
-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------
-- allowed for digging
local SimpleNodes = {}
-- translation from param2 to dir (out of the node upwards)
local Param2Dir = {}
for idx,val in ipairs(Input) do
@ -90,6 +243,17 @@ function techage.add_to_set(set, x)
end
end
-- techage.tbl_filter({"a", "b", "c", "d"}, function(v, k, t) return v >= "c" end) --> {"c","d"}
techage.tbl_filter = function(t, filterIter)
local out = {}
for k, v in pairs(t) do
if filterIter(v, k, t) then out[k] = v end
end
return out
end
function techage.get_node_lvm(pos)
local node = minetest.get_node_or_nil(pos)
if node then
@ -110,25 +274,6 @@ function techage.get_node_lvm(pos)
return {name="ignore", param2=0}
end
--
-- Functions used to hide electric cable and biogas pipes
--
-- Overridden method of tubelib2!
function techage.get_primary_node_param2(pos, dir)
local npos = vector.add(pos, tubelib2.Dir6dToVector[dir or 0])
local param2 = M(npos):get_int("tl2_param2")
if param2 ~= 0 then
return param2, npos
end
end
-- Overridden method of tubelib2!
function techage.is_primary_node(pos, dir)
local npos = vector.add(pos, tubelib2.Dir6dToVector[dir or 0])
local param2 = M(npos):get_int("tl2_param2")
return param2 ~= 0
end
function techage.is_air_like(name)
local ndef = minetest.registered_nodes[name]
if ndef and ndef.buildable_to then
@ -138,21 +283,54 @@ function techage.is_air_like(name)
end
-- returns true, if node can be dug, otherwise false
function techage.can_node_dig(node, ndef)
if RegisteredNodesToBeDug[node.name] then
return true
end
function techage.can_dig_node(name, ndef)
if not ndef then return false end
if node.name == "ignore" then return false end
if node.name == "air" then return true end
if ndef.buildable_to == true then return true end
if ndef.diggable == false then return false end
if ndef.after_dig_node then return false end
if SimpleNodes[name] ~= nil then
return SimpleNodes[name]
end
if ndef.groups and ndef.groups.techage_door == 1 then
SimpleNodes[name] = true
return true
end
if name == "ignore" then
SimpleNodes[name] = false
return false
end
if name == "air" then
SimpleNodes[name] = true
return true
end
if ndef.buildable_to == true then
SimpleNodes[name] = true
return true
end
-- don't remove nodes with some intelligence or undiggable nodes
if ndef.drop == "" then
SimpleNodes[name] = false
return false
end
if ndef.diggable == false then
SimpleNodes[name] = false
return false
end
if ndef.after_dig_node then
SimpleNodes[name] = false
return false
end
-- add it to the white list
RegisteredNodesToBeDug[node.name] = true
SimpleNodes[name] = true
return true
end
-- Simple nodes
function techage.register_simple_nodes(node_names, is_valid)
if is_valid == nil then is_valid = true end
for _,name in ipairs(node_names or {}) do
SimpleNodes[name] = is_valid
end
end
techage.dig_states = {
NOT_DIGGABLE = 1,
INV_FULL = 2,
@ -218,7 +396,7 @@ function techage.dropped_node(node, ndef)
return handle_drop(ndef.drop)
end
return ndef.drop or node.name
end
end
-- needed for windmill plants
local function determine_ocean_ids()
@ -264,7 +442,7 @@ function techage.item_image(x, y, itemname, count)
end
label = "label["..(x + offs)..","..(y + 0.45)..";"..tostring(size).."]"
end
return "box["..x..","..y..";0.85,0.9;#808080]"..
"item_image["..x..","..y..";1,1;"..itemname.."]"..
tooltip..
@ -275,59 +453,23 @@ function techage.item_image_small(x, y, itemname, tooltip_prefix)
local name = unpack(string.split(itemname, " "))
local tooltip = ""
local ndef = minetest.registered_nodes[name] or minetest.registered_items[name] or minetest.registered_craftitems[name]
if ndef and ndef.description then
local text = minetest.formspec_escape(ndef.description)
tooltip = "tooltip["..x..","..y..";0.8,0.8;"..tooltip_prefix..": "..text..";#0C3D32;#FFFFFF]"
end
return "box["..x..","..y..";0.65,0.7;#808080]"..
"item_image["..x..","..y..";0.8,0.8;"..name.."]"..
tooltip
end
function techage.mydump(o, indent, nested, level)
local t = type(o)
if not level and t == "userdata" then
-- when userdata (e.g. player) is passed directly, print its metatable:
return "userdata metatable: " .. techage.mydump(getmetatable(o))
end
if t ~= "table" then
return basic_dump(o)
end
-- Contains table -> true/nil of currently nested tables
nested = nested or {}
if nested[o] then
return "<circular reference>"
end
nested[o] = true
indent = " "
level = level or 1
function techage.vector_dump(posses)
local t = {}
local dumped_indexes = {}
for i, v in ipairs(o) do
t[#t + 1] = techage.mydump(v, indent, nested, level + 1)
dumped_indexes[i] = true
for _,pos in ipairs(posses) do
t[#t + 1] = minetest.pos_to_string(pos)
end
for k, v in pairs(o) do
if not dumped_indexes[k] then
if type(k) ~= "string" or not is_valid_identifier(k) then
k = "["..techage.mydump(k, indent, nested, level + 1).."]"
end
v = techage.mydump(v, indent, nested, level + 1)
t[#t + 1] = k.." = "..v
end
end
nested[o] = nil
if indent ~= "" then
local indent_str = string.rep(indent, level)
local end_indent_str = string.rep(indent, level - 1)
return string.format("{%s%s%s}",
indent_str,
table.concat(t, ","..indent_str),
end_indent_str)
end
return "{"..table.concat(t, ", ").."}"
return table.concat(t, " ")
end
-- title bar help (width is the fornmspec width)
@ -339,7 +481,153 @@ end
function techage.wrench_tooltip(x, y)
local tooltip = S("Block has an\nadditional wrench menu")
return "label["..x..","..y..";"..minetest.colorize("#000000", minetest.formspec_escape("[?]")).."]"..
return "image["..x.."," .. y .. ";0.5,0.5;techage_inv_wrench.png]" ..
"tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
end
techage.RegisteredMobsMods = {}
-- Register mobs mods for the move/fly controllers
function techage.register_mobs_mods(mod)
techage.RegisteredMobsMods[mod] = true
end
function techage.beduino_signed_var(val)
val = val or 0
return val >= 32768 and val - 0x10000 or val
end
-------------------------------------------------------------------------------
-- Terminal history buffer
-------------------------------------------------------------------------------
local BUFFER_DEPTH = 10
function techage.historybuffer_add(pos, s)
local mem = techage.get_mem(pos)
mem.hisbuf = mem.hisbuf or {}
if #s > 2 then
table.insert(mem.hisbuf, s)
if #mem.hisbuf > BUFFER_DEPTH then
table.remove(mem.hisbuf, 1)
end
mem.hisbuf_idx = #mem.hisbuf + 1
end
end
function techage.historybuffer_priv(pos)
local mem = techage.get_mem(pos)
mem.hisbuf = mem.hisbuf or {}
mem.hisbuf_idx = mem.hisbuf_idx or 1
mem.hisbuf_idx = math.max(1, mem.hisbuf_idx - 1)
return mem.hisbuf[mem.hisbuf_idx]
end
function techage.historybuffer_next(pos)
local mem = techage.get_mem(pos)
mem.hisbuf = mem.hisbuf or {}
mem.hisbuf_idx = mem.hisbuf_idx or 1
mem.hisbuf_idx = math.min(#mem.hisbuf, mem.hisbuf_idx + 1)
return mem.hisbuf[mem.hisbuf_idx]
end
-------------------------------------------------------------------------------
-- Player TA5 Experience Points
-------------------------------------------------------------------------------
function techage.get_expoints(player)
if player and player.get_meta then
local meta = player:get_meta()
if meta then
return meta:get_int("techage_ex_points")
end
end
end
-- Can only be used from one collider
function techage.add_expoint(player, number)
if player and player.get_meta then
local meta = player:get_meta()
if meta then
if not meta:contains("techage_collider_number") then
meta:set_string("techage_collider_number", number)
end
if meta:get_string("techage_collider_number") == number then
meta:set_int("techage_ex_points", meta:get_int("techage_ex_points") + 1)
return true
else
minetest.chat_send_player(player:get_player_name(), "[techage] More than one collider is not allowed!")
return false
end
end
end
end
-- Delete number with: `//lua minetest.get_player_by_name("<name>"):get_meta():set_string("techage_collider_number", "")`
function techage.on_remove_collider(player)
if player and player.get_meta then
local meta = player:get_meta()
if meta then
meta:set_string("techage_collider_number", "")
end
end
end
function techage.set_expoints(player, ex_points)
if player and player.get_meta then
local meta = player:get_meta()
if meta then
meta:set_int("techage_ex_points", ex_points)
return true
end
end
end
-------------------------------------------------------------------------------
-- Scheduler for a table-based, cyclic call of functions
-------------------------------------------------------------------------------
local TABLE_SIZE = 256
techage.scheduler = {}
local function add_to_table(tbl, i, func)
while i < TABLE_SIZE do
if not tbl[i] then
tbl[i] = func
return i + 1
end
i = i + 1
end
return i
end
function techage.scheduler.init(pos)
local mem = techage.get_mem(pos)
mem.sched_idx = 0
end
-- tFunc : (empty) table of functions
-- call_rate : (2,4,8,16,32,64 or 128)
-- offset : 0-128
-- func : function to be called
function techage.scheduler.register(tFunc, call_rate, offset, func)
local i= 0
while i < TABLE_SIZE do
if (i % call_rate) == offset then
i = add_to_table(tFunc, i, func)
else
i = i + 1
end
end
return tFunc
end
-- tFunc : table of functions
-- default : default function (optional)
-- Returns a function to be called be the callee
function techage.scheduler.get(pos, tFunc, default)
local mem = techage.get_mem(pos)
mem.sched_idx = ((mem.sched_idx or 0) + 1) % TABLE_SIZE
return tFunc[mem.sched_idx] or default or function() end
end

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Liquid lib
]]--
@ -30,35 +30,32 @@ local function help(x, y)
"tooltip["..x..","..y..";0.5,0.5;"..tooltip..";#0C3D32;#FFFFFF]"
end
function techage.liquid.formspec(pos, nvm)
local title = S("Liquid Tank")
function techage.liquid.formspec(pos, nvm, title)
title = title or S("Liquid Tank")
local itemname = "techage:liquid"
if nvm.liquid and nvm.liquid.amount and nvm.liquid.amount > 0 and nvm.liquid.name then
itemname = nvm.liquid.name.." "..nvm.liquid.amount
end
local name = minetest.get_node(pos).name
if name == "techage:ta4_tank" then
local public = dump((M(pos):get_int("public") or 0) == 1)
return "size[5,3]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;4.8,0.5;#c6e8ff]"..
"label[1.5,-0.1;"..minetest.colorize("#000000", title).."]"..
help(4.4, -0.1)..
techage.item_image(2, 1, itemname)..
"checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]"
local meta = M(pos)
local public = dump((meta:get_int("public") or 0) == 1)
local keep_assignment = dump((meta:get_int("keep_assignment") or 0) == 1)
return "size[8,3.5]"..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[0.2,-0.1;"..minetest.colorize("#000000", title).."]"..
help(7.4, -0.1)..
techage.item_image(3.5, 1, itemname)..
"checkbox[0.1,2.5;public;"..S("Allow public access to the tank")..";"..public.."]"..
"checkbox[0.1,3;keep_assignment;"..S("keep assignment")..";"..keep_assignment.."]"
else
return "size[4,2]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;3.8,0.5;#c6e8ff]"..
"label[1,-0.1;"..minetest.colorize("#000000", title).."]"..
help(3.4, -0.1)..
techage.item_image(1.5, 1, itemname)
return "size[8,2]"..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[0.2,-0.1;"..minetest.colorize("#000000", title).."]"..
help(7.4, -0.1)..
techage.item_image(3.5, 1, itemname)
end
end
end
function techage.liquid.is_empty(pos)
local nvm = techage.get_nvm(pos)
@ -78,7 +75,25 @@ techage.liquid.recv_message = {
return "unsupported"
end
end,
}
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 128 then
return 0, techage.get_node_lvm(pos).name
elseif topic == 134 then
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = nvm.liquid.amount or 0
if payload[1] == 1 then
local value = techage.power.percent(LQD(pos).capa, nvm.liquid.amount)
return 0, {math.floor(value + 0.5)}
else
return 0, {nvm.liquid.amount}
end
else
return 2, ""
end
end,
}
-- like: register_liquid("techage:ta3_barrel_oil", "techage:ta3_barrel_empty", 10, "techage:oil")
function techage.register_liquid(full_container, empty_container, container_size, inv_item)
@ -86,12 +101,15 @@ function techage.register_liquid(full_container, empty_container, container_size
ContainerDef[empty_container] = ContainerDef[empty_container] or {}
ContainerDef[empty_container][inv_item] = full_container
IsLiquid[inv_item] = true
if inv_item == "techage:water" and container_size == 1 then
techage.register_water_bucket(empty_container, full_container)
end
end
local function get_liquid_def(full_container)
return LiquidDef[full_container]
end
local function get_container_def(container_name)
return ContainerDef[container_name]
end
@ -112,7 +130,7 @@ local function fill_container(pos, inv, empty_container)
local full_container = get_full_container(empty_container, nvm.liquid.name)
if empty_container and full_container then
local ldef = get_liquid_def(full_container)
if ldef and nvm.liquid.amount - ldef.size >= 0 then
if ldef and nvm.liquid.amount - ldef.size >= 0 then
if inv:room_for_item("dst", {name = full_container}) then
inv:add_item("dst", {name = full_container})
nvm.liquid.amount = nvm.liquid.amount - ldef.size
@ -137,7 +155,7 @@ local function empty_container(pos, inv, full_container)
local tank_size = (ndef_lqd and ndef_lqd.capa) or 0
local ldef = get_liquid_def(full_container)
if ldef and (not nvm.liquid.name or ldef.inv_item == nvm.liquid.name) then
if nvm.liquid.amount + ldef.size <= tank_size then
if nvm.liquid.amount + ldef.size <= tank_size then
if inv:room_for_item("dst", {name = ldef.container}) then
inv:add_item("dst", {name = ldef.container})
nvm.liquid.amount = nvm.liquid.amount + ldef.size
@ -160,22 +178,22 @@ local function fill_on_punch(nvm, empty_container, item_count, puncher)
if empty_container and full_container then
local item = {name = full_container}
local ldef = get_liquid_def(full_container)
if ldef and nvm.liquid.amount - ldef.size >= 0 then
if ldef and nvm.liquid.amount - ldef.size >= 0 then
if item_count > 1 then -- can't be simply replaced?
-- check for extra free space
local inv = puncher:get_inventory()
if inv:room_for_item("main", {name = full_container}) then
-- add full container and return
-- the empty once - 1
inv:add_item("main", {name = full_container})
inv:add_item("main", {name = full_container})
item = {name = empty_container, count = item_count - 1}
else
return -- no free space
end
end
nvm.liquid.amount = nvm.liquid.amount - ldef.size
if nvm.liquid.amount == 0 then
nvm.liquid.name = nil
if nvm.liquid.amount == 0 then
nvm.liquid.name = nil
end
return item -- to be added to the players inv.
end
@ -184,8 +202,8 @@ local function fill_on_punch(nvm, empty_container, item_count, puncher)
local count = math.max(nvm.liquid.amount, 99)
local name = nvm.liquid.name
nvm.liquid.amount = nvm.liquid.amount - count
if nvm.liquid.amount == 0 then
nvm.liquid.name = nil
if nvm.liquid.amount == 0 then
nvm.liquid.name = nil
end
return {name = name, count = count}
end
@ -193,12 +211,12 @@ local function fill_on_punch(nvm, empty_container, item_count, puncher)
end
local function legacy_items(full_container, item_count)
if full_container == "techage:hydrogen" then
if full_container == "techage:isobutane" then
return {container = "", size = item_count, inv_item = full_container}
elseif full_container == "techage:oil_source" then
return {container = "", size = item_count, inv_item = full_container}
end
end
end
-- check if the wielded full container can be emptied into the tank
local function empty_on_punch(pos, nvm, full_container, item_count)
@ -206,10 +224,10 @@ local function empty_on_punch(pos, nvm, full_container, item_count)
nvm.liquid.amount = nvm.liquid.amount or 0
local lqd_def = get_liquid_def(full_container) or legacy_items(full_container, item_count)
local ndef_lqd = LQD(pos)
if lqd_def and ndef_lqd then
if lqd_def and ndef_lqd then
local tank_size = ndef_lqd.capa or 0
if not nvm.liquid.name or lqd_def.inv_item == nvm.liquid.name then
if nvm.liquid.amount + lqd_def.size <= tank_size then
if nvm.liquid.amount + lqd_def.size <= tank_size then
nvm.liquid.amount = nvm.liquid.amount + lqd_def.size
nvm.liquid.name = lqd_def.inv_item
return {name = lqd_def.container}
@ -230,10 +248,10 @@ function techage.liquid.on_punch(pos, node, puncher, pointed_thing)
if mem.blocking_time > techage.SystemTime then
return
end
local wielded_item = puncher:get_wielded_item():get_name()
local item_count = puncher:get_wielded_item():get_count()
local new_item = fill_on_punch(nvm, wielded_item, item_count, puncher)
local new_item = fill_on_punch(nvm, wielded_item, item_count, puncher)
or empty_on_punch(pos, nvm, wielded_item, item_count)
if new_item then
puncher:set_wielded_item(new_item)

View File

@ -89,5 +89,3 @@ techage.manual_DE.aPlanTable = {
"",
"",
}

View File

@ -9,7 +9,7 @@
See LICENSE.txt for more information
mark.lua:
]]--
local marker_region = {}
@ -27,9 +27,9 @@ end
function techage.mark_region(name, pos1, pos2, owner, secs)
if not name or not pos1 or not pos2 then return end
techage.unmark_region(name)
local thickness = 0.2
local sizex, sizey, sizez = (1 + pos2.x - pos1.x) / 2, (1 + pos2.y - pos1.y) / 2, (1 + pos2.z - pos1.z) / 2
local markers = {}
@ -96,4 +96,3 @@ minetest.register_entity(":techage:region_cube", {
techage.unmark_region(self.player_name)
end,
})

View File

@ -9,7 +9,7 @@
See LICENSE.txt for more information
mark.lua:
]]--
local marker_region = {}
@ -44,7 +44,7 @@ function techage.mark_cube(name, pos1, pos2, nametag, color, time)
local size_x = math.abs(pos1.x - pos2.x) + 1
local size_y = math.abs(pos1.y - pos2.y) + 1
local size_z = math.abs(pos1.z - pos2.z) + 1
local marker = minetest.add_entity(
{x = new_x, y = new_y, z = new_z}, "techage:position_cube")
if marker ~= nil then
@ -126,4 +126,3 @@ minetest.register_entity(":techage:position_side", {
techage.unmark_position(self.player_name)
end,
})

130
basis/mark_lib.lua Normal file
View File

@ -0,0 +1,130 @@
--[[
TechAge
=======
Copyright (C) 2020-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Block marker lib for door/move/fly controller
]]--
local MAX_NUM = 128
local marker = {}
local MarkedNodes = {} -- t[player] = {{entity, pos},...}
local MaxNumber = {}
local CurrentPos -- to mark punched entities
local function unmark_position(name, pos)
pos = vector.round(pos)
for idx,item in ipairs(MarkedNodes[name] or {}) do
if vector.equals(pos, item.pos) then
item.entity:remove()
table.remove(MarkedNodes[name], idx)
CurrentPos = pos
return
end
end
end
function marker.unmark_all(name)
for _,item in ipairs(MarkedNodes[name] or {}) do
item.entity:remove()
end
MarkedNodes[name] = nil
end
local function mark_position(name, pos)
pos = vector.round(pos)
if not CurrentPos or not vector.equals(pos, CurrentPos) then -- entity not punched?
if #MarkedNodes[name] < MaxNumber[name] then
local entity = minetest.add_entity(pos, "techage:block_marker")
if entity ~= nil then
entity:get_luaentity().player_name = name
table.insert(MarkedNodes[name], {pos = pos, entity = entity})
end
CurrentPos = nil
return true
end
end
CurrentPos = nil
end
function marker.get_poslist(name)
local idx = 0
local lst = {}
for _,item in ipairs(MarkedNodes[name] or {}) do
table.insert(lst, item.pos)
idx = idx + 1
if idx >= MAX_NUM then break end
end
return lst
end
minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
if puncher and puncher:is_player() then
local name = puncher:get_player_name()
if not MarkedNodes[name] then
return
end
mark_position(name, pointed_thing.under)
end
end)
function marker.start(name, max_num)
MaxNumber[name] = max_num or 99
MarkedNodes[name] = {}
end
function marker.stop(name)
MarkedNodes[name] = nil
MaxNumber[name] = nil
end
minetest.register_on_leaveplayer(function(ObjectRef, timed_out)
if ObjectRef and ObjectRef:is_player() then
local name = ObjectRef:get_player_name()
marker.unmark_all(name)
end
end)
minetest.register_entity(":techage:block_marker", {
initial_properties = {
visual = "cube",
textures = {
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
"techage_cube_mark.png",
},
physical = false,
visual_size = {x=1.1, y=1.1},
collisionbox = {-0.55,-0.55,-0.55, 0.55,0.55,0.55},
glow = 8,
},
on_step = function(self, dtime)
self.ttl = (self.ttl or 2400) - 1
if self.ttl <= 0 then
local pos = self.object:get_pos()
unmark_position(self.player_name, pos)
end
end,
on_punch = function(self, hitter)
local pos = self.object:get_pos()
local name = hitter:get_player_name()
if name == self.player_name then
unmark_position(name, pos)
end
end,
})
return marker

View File

@ -3,7 +3,7 @@
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
@ -13,33 +13,33 @@
]]--
--[[
--[[
Node states:
+-----------------------------------+ +------------+
| | | |
| V V |
| +---------+ |
| | | |
| +---------| STOPPED | |
| | | | |
| button | +---------+ |
| | ^ |
button | V | button |
| +---------+ | | button
| +--------->| |---------+ |
| | power | RUNNING | |
| | +------| |---------+ |
| | | +---------+ | |
| | | ^ | | |
| | | | | | |
| | V | V V |
| +---------+ +----------+ +---------+ |
| | | | | | | |
+---| NOPOWER | | STANDBY/ | | FAULT |----------+
| | | BLOCKED | | |
+---------+ +----------+ +---------+
| | | |
| V V |
| +---------+ |
| | | |
| +---------| STOPPED | |
| | | | |
| button | +---------+ |
| | ^ |
button | V | button |
| +---------+ | | button
| +--------->| |---------+ |
| | power | RUNNING | |
| | +------| |---------+ |
| | | +---------+ | |
| | | ^ | | |
| | | | | | |
| | V | V V |
| +---------+ +----------+ +---------+ |
| | | | | | | |
+---| NOPOWER | | STANDBY/ | | FAULT |----------+
| | | BLOCKED | | |
+---------+ +----------+ +---------+
| cycle time operational needs power
@ -62,24 +62,28 @@ local P = minetest.string_to_pos
local M = minetest.get_meta
local N = techage.get_node_lvm
local MAX_CYCLE_TIME = 20
--
-- TechAge machine states
--
techage.RUNNING = 1 -- in normal operation/turned on
techage.BLOCKED = 2 -- a pushing node is blocked due to a full destination inventory
techage.STANDBY = 3 -- nothing to do (e.g. no input items), or node (world) not loaded
techage.NOPOWER = 4 -- only for power consuming nodes, no operation
techage.FAULT = 5 -- any fault state (e.g. wrong source items), which can be fixed by the player
techage.STOPPED = 6 -- not operational/turned off
techage.RUNNING = 1 -- in normal operation/turned on
techage.BLOCKED = 2 -- a pushing node is blocked due to a full destination inventory
techage.STANDBY = 3 -- nothing to do (e.g. no input items), or node (world) not loaded
techage.NOPOWER = 4 -- only for power consuming nodes, no operation
techage.FAULT = 5 -- any fault state (e.g. wrong source items), which can be fixed by the player
techage.STOPPED = 6 -- not operational/turned off
techage.UNLOADED = 7 -- Map block unloaded
techage.INACTIVE = 8 -- Map block loaded but node is not actively working
techage.StatesImg = {
"techage_inv_button_on.png",
"techage_inv_button_on.png",
"techage_inv_button_warning.png",
"techage_inv_button_standby.png",
"techage_inv_button_nopower.png",
"techage_inv_button_standby.png",
"techage_inv_button_nopower.png",
"techage_inv_button_error.png",
"techage_inv_button_off.png",
"techage_inv_button_off.png",
}
local function error(pos, msg)
@ -133,13 +137,15 @@ local function has_power(pos, nvm)
return true
end
local function swap_node(pos, name)
local function swap_node(pos, new_name, old_name)
local node = techage.get_node_lvm(pos)
if node.name == name then
if node.name == new_name then
return
end
node.name = name
minetest.swap_node(pos, node)
if node.name == old_name then
node.name = new_name
minetest.swap_node(pos, node)
end
end
-- true if node_timer should be executed
@ -174,8 +180,9 @@ function NodeStates:new(attr)
cycle_time = attr.cycle_time, -- for running state
standby_ticks = attr.standby_ticks, -- for standby state
-- optional
countdown_ticks = attr.countdown_ticks or 1,
node_name_passive = attr.node_name_passive,
node_name_active = attr.node_name_active,
node_name_active = attr.node_name_active,
infotext_name = attr.infotext_name,
has_power = attr.has_power or has_power,
can_start = attr.can_start or can_start,
@ -183,6 +190,7 @@ function NodeStates:new(attr)
stop_node = attr.stop_node,
formspec_func = attr.formspec_func,
on_state_change = attr.on_state_change,
quick_start = attr.quick_start,
}
setmetatable(o, self)
self.__index = self
@ -218,7 +226,7 @@ function NodeStates:stop(pos, nvm)
self.stop_node(pos, nvm, state)
end
if self.node_name_passive then
swap_node(pos, self.node_name_passive)
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
@ -253,9 +261,9 @@ function NodeStates:start(pos, nvm)
if self.start_node then
self.start_node(pos, nvm, state)
end
nvm.techage_countdown = 1
nvm.techage_countdown = self.countdown_ticks
if self.node_name_active then
swap_node(pos, self.node_name_active)
swap_node(pos, self.node_name_active, self.node_name_passive)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
@ -272,6 +280,11 @@ function NodeStates:start(pos, nvm)
self.on_state_change(pos, state, RUNNING)
end
start_timer_delayed(pos, self.cycle_time)
if self.quick_start and state == STOPPED then
self.quick_start(pos, 0)
end
self:trigger_state(pos, nvm)
return true
end
return false
@ -282,7 +295,7 @@ function NodeStates:standby(pos, nvm, err_string)
if state == RUNNING or state == BLOCKED then
nvm.techage_state = STANDBY
if self.node_name_passive then
swap_node(pos, self.node_name_passive)
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
@ -299,7 +312,7 @@ function NodeStates:standby(pos, nvm, err_string)
return true
end
return false
end
end
-- special case of standby for pushing nodes
function NodeStates:blocked(pos, nvm, err_string)
@ -307,7 +320,7 @@ function NodeStates:blocked(pos, nvm, err_string)
if state == RUNNING then
nvm.techage_state = BLOCKED
if self.node_name_passive then
swap_node(pos, self.node_name_passive)
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
@ -324,14 +337,14 @@ function NodeStates:blocked(pos, nvm, err_string)
return true
end
return false
end
end
function NodeStates:nopower(pos, nvm, err_string)
local state = nvm.techage_state or RUNNING
if state ~= NOPOWER then
nvm.techage_state = NOPOWER
if self.node_name_passive then
swap_node(pos, self.node_name_passive)
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
@ -348,7 +361,7 @@ function NodeStates:nopower(pos, nvm, err_string)
return true
end
return false
end
end
function NodeStates:fault(pos, nvm, err_string)
local state = nvm.techage_state or STOPPED
@ -356,7 +369,7 @@ function NodeStates:fault(pos, nvm, err_string)
if state == RUNNING or state == STOPPED then
nvm.techage_state = FAULT
if self.node_name_passive then
swap_node(pos, self.node_name_passive)
swap_node(pos, self.node_name_passive, self.node_name_active)
end
if self.infotext_name then
local number = M(pos):get_string("node_number")
@ -373,7 +386,7 @@ function NodeStates:fault(pos, nvm, err_string)
return true
end
return false
end
end
function NodeStates:get_state(nvm)
return nvm.techage_state or techage.STOPPED
@ -425,7 +438,7 @@ function NodeStates:state_button_event(pos, nvm, fields)
if state == STOPPED or state == STANDBY or state == BLOCKED then
if not self:start(pos, nvm) and (state == STANDBY or state == BLOCKED) then
self:stop(pos, nvm)
end
end
elseif state == RUNNING or state == FAULT or state == NOPOWER then
self:stop(pos, nvm)
end
@ -458,7 +471,7 @@ function NodeStates:on_receive_message(pos, topic, payload)
if node.name == "ignore" then -- unloaded node?
return "unloaded"
elseif nvm.techage_state == RUNNING then
local ttl = (nvm.last_active or 0) + 2 * (self.cycle_time or 0)
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
if ttl < minetest.get_gametime() then
return "inactive"
end
@ -472,7 +485,55 @@ function NodeStates:on_receive_message(pos, topic, payload)
return "unsupported"
end
end
function NodeStates:on_beduino_receive_cmnd(pos, topic, payload)
if topic == 1 then
if payload[1] == 0 then
self:stop(pos, techage.get_nvm(pos))
return 0
else
self:start(pos, techage.get_nvm(pos))
return 0
end
else
return 2 -- unknown or invalid topic
end
end
function NodeStates:on_beduino_request_data(pos, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 128 then
return 0, techage.get_node_lvm(pos).name
elseif topic == 129 then
local node = minetest.get_node(pos)
if node.name == "ignore" then -- unloaded node?
return 0, {techage.UNLOADED}
elseif nvm.techage_state == RUNNING then
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
if ttl < minetest.get_gametime() then
return 0, {techage.INACTIVE}
end
end
return 0, {nvm.techage_state or STOPPED}
else
return 2, "" -- topic is unknown or invalid
end
end
function NodeStates.get_beduino_state(pos)
local node = minetest.get_node(pos)
local nvm = techage.get_nvm(pos)
if node.name == "ignore" then -- unloaded node?
return 0, {techage.UNLOADED}
elseif nvm.techage_state == RUNNING then
local ttl = (nvm.last_active or 0) + MAX_CYCLE_TIME
if ttl < minetest.get_gametime() then
return 0, {techage.INACTIVE}
end
end
return 0, {nvm.techage_state or STOPPED}
end
-- restart timer
function NodeStates:on_node_load(pos)
local nvm = techage.get_nvm(pos)

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Data storage system for node related volatile and non-volatile data.
Non-volatile data is stored from time to time and at shutdown.
Volatile data is lost at every shutdown.
@ -41,14 +41,14 @@ local function get_keys(pos)
end
local function pos_from_key(key1, key2)
local x1 = (math.floor(key1 / (4096 * 4096)) - 2048) * 16
local y1 = ((math.floor(key1 / 4096) % 4096) - 2048) * 16
local z1 = ((key1 % 4096) - 2048) * 16
local x2 = math.floor(key2 / (16 * 16))
local y2 = math.floor(key2 / 16) % 16
local z2 = key2 % 16
return {x = x1 + x2, y = y1 + y2, z = z1 + z2}
end
@ -66,12 +66,12 @@ local function debug(key1, item)
end
print("mapblock", string.format("%09X", key1), cnt.." nodes")
end
-------------------------------------------------------------------
-- Storage scheduler
-------------------------------------------------------------------
local CYCLE_TIME = 900 -- store data every 15 min
local CYCLE_TIME = 600 -- store data every 10 min
local JobQueue = {}
local first = 0
local last = -1
@ -97,7 +97,9 @@ minetest.register_globalstep(function(dtime)
SystemTime = SystemTime + dtime
local key = pop()
if key and NvmStore[key] then
--debug(key, NvmStore[key])
-- minetest.log("warning",
-- string.format("[TA Storage] SystemTime = %.3f, #JobQueue = %d, in_use = %s",
-- SystemTime, last - first, NvmStore[key].in_use))
local t = minetest.get_us_time()
if NvmStore[key].in_use then
NvmStore[key].in_use = nil
@ -137,12 +139,12 @@ end
-- Returns non-volatile node data as table
function techage.get_nvm(pos)
local key1, key2 = get_keys(pos)
if not NvmStore[key1] then
NvmStore[key1] = backend.get_mapblock_data(key1)
push(key1)
end
local block = NvmStore[key1]
block.in_use = true
if not block[key2] then
@ -151,6 +153,18 @@ function techage.get_nvm(pos)
return block[key2]
end
-- Returns true/false
function techage.has_nvm(pos)
local key1, key2 = get_keys(pos)
if not NvmStore[key1] then
NvmStore[key1] = backend.get_mapblock_data(key1)
push(key1)
end
return NvmStore[key1][key2] ~= nil
end
function techage.peek_nvm(pos)
local key1, key2 = get_keys(pos)
local block = NvmStore[key1] or {}
@ -161,7 +175,7 @@ end
function techage.del_mem(pos)
local hash = minetest.hash_node_position(pos)
MemStore[hash] = nil
local key1, key2 = get_keys(pos)
NvmStore[key1] = NvmStore[key1] or backend.get_mapblock_data(key1)
NvmStore[key1][key2] = nil

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Storage backend for node related data as node metadata
]]--
@ -35,7 +35,7 @@ if use_marshal then
if not marshal then
error("Please install marshal via 'luarocks install lua-marshal'")
end
serialize = marshal.encode
deserialize = function(s)
@ -65,6 +65,7 @@ function api.store_mapblock_data(key, mapblock_data)
if pos then
item._POS_ = nil
local data = serialize(item)
item._POS_ = pos
local meta = M(pos)
meta:set_string("ta_data", data)
meta:mark_as_private("ta_data")
@ -76,12 +77,12 @@ end
function api.get_node_data(pos)
local tbl = {}
local s = M(pos):get_string("ta_data")
if s ~= "" then
tbl = deserialize(s) or {}
end
tbl._POS_ = table.copy(pos)
return tbl
end

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Storage backend for node related data via sqlite database
]]--
@ -20,6 +20,7 @@ local M = minetest.get_meta
-------------------------------------------------------------------
local MN = minetest.get_current_modname()
local WP = minetest.get_worldpath()
local use_marshal = minetest.settings:get_bool('techage_use_marshal', false)
local MAR_MAGIC = 0x8e
if not techage.IE then
@ -44,7 +45,7 @@ if sqlite3 then sqlite3 = nil end
db:exec[[
CREATE TABLE mapblocks(id INTEGER PRIMARY KEY, key INTEGER, data BLOB);
CREATE UNIQUE INDEX idx ON mapblocks(key);
CREATE UNIQUE INDEX idx ON mapblocks(key);
]]
local set = db:prepare("INSERT or REPLACE INTO mapblocks VALUES(NULL, ?, ?);")
@ -54,8 +55,7 @@ local function set_block(key, data)
set:reset()
set:bind(1, key)
set:bind_blob(2, data)
set:step()
return true
set:step()
end
local function get_block(key)
@ -72,12 +72,16 @@ end
local api = {}
function api.store_mapblock_data(key, mapblock_data)
-- deactivated due to weird server crashes without error logs
--local s = marshal.encode(mapblock_data)
local s = minetest.serialize(mapblock_data)
return set_block(key, s)
end
if use_marshal and mapblock_data then
local data = marshal.encode(mapblock_data)
if data then
set_block(key, data)
end
else
set_block(key, minetest.serialize(mapblock_data))
end
end
function api.get_mapblock_data(key)
local s = get_block(key)
if s then
@ -89,8 +93,8 @@ function api.get_mapblock_data(key)
end
api.store_mapblock_data(key, {})
return {}
end
end
function api.get_node_data(pos)
-- legacy data available?
local s = M(pos):get_string("ta_data")

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Storage backend for node number mapping via sqlite database
]]--
@ -46,7 +46,7 @@ if sqlite3 then sqlite3 = nil end
db:exec[[
CREATE TABLE numbers(id INTEGER PRIMARY KEY, number INTEGER, x INTEGER, y INTEGER, z INTEGER);
CREATE UNIQUE INDEX idx ON numbers(number);
CREATE UNIQUE INDEX idx ON numbers(number);
]]
local set = db:prepare("INSERT or REPLACE INTO numbers VALUES(NULL, ?, ?, ?, ?);")
@ -58,7 +58,7 @@ local function set_block(number, pos)
set:bind(2, pos.x)
set:bind(3, pos.y)
set:bind(4, pos.z)
set:step()
set:step()
return true
end
@ -94,7 +94,7 @@ if Version == 3 then
storage:set_string(number, "")
end
end
elseif Version == 4 then
elseif Version == 4 then
NextNumber = storage:get_int("NextNumber")
else
error("[] Invalid version number for 'number to pos mapping' table!")
@ -108,28 +108,28 @@ local api = {}
function api.get_nodepos(number)
return get_block(number)
end
end
function api.set_nodepos(number, pos)
set_block(number, pos)
end
end
function api.add_nodepos(pos)
local num = tostring(NextNumber)
NextNumber = NextNumber + 1
storage:set_int("NextNumber", NextNumber)
set_block(num, pos)
return num
end
end
function api.del_nodepos(number)
del_block(number)
end
end
-- delete invalid entries
function api.delete_invalid_entries(node_def)
minetest.log("info", "[TechAge] Data maintenance started")
for id, num, x, y, z in db:urows('SELECT * FROM numbers') do
for id, num, x, y, z in db:urows('SELECT * FROM numbers') do
local pos = {x = x, y = y, z = z}
local name = techage.get_node_lvm(pos).name
if not node_def[name] then
@ -137,6 +137,6 @@ function api.delete_invalid_entries(node_def)
end
end
minetest.log("info", "[TechAge] Data maintenance finished")
end
end
return api

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Storage backend for node number mapping via mod storage
]]--
@ -59,23 +59,23 @@ storage:set_int("Version", Version)
-------------------------------------------------------------------
function backend.get_nodepos(number)
return minetest.string_to_pos(storage:get_string(number))
end
end
function backend.set_nodepos(number, pos)
storage:set_string(number, minetest.pos_to_string(pos))
end
end
function backend.add_nodepos(pos)
local num = tostring(NextNumber)
NextNumber = NextNumber + 1
storage:set_int("NextNumber", NextNumber)
storage:set_string(num, minetest.pos_to_string(pos))
return num
end
end
function backend.del_nodepos(number)
storage:set_string(number, "")
end
end
-- delete invalid entries
function backend.delete_invalid_entries(node_def)
@ -88,11 +88,11 @@ function backend.delete_invalid_entries(node_def)
if not node_def[name] then
backend.del_nodepos(number)
else
minetest.get_meta(pos):set_string("node_number", number)
minetest.get_meta(pos):set_string("node_number", number)
end
end
end
minetest.log("info", "[TechAge] Data maintenance finished")
end
end
return backend

103
basis/oggfiles.lua Normal file
View File

@ -0,0 +1,103 @@
techage.OggFileList = {
"autobahn_motor", -- ./mods/autobahn/sounds
"signs_bot_ping", -- ./mods/signs_bot/sounds
"signs_bot_go_away", -- ./mods/signs_bot/sounds
"signs_bot_step", -- ./mods/signs_bot/sounds
"signs_bot_pong", -- ./mods/signs_bot/sounds
"signs_bot_error", -- ./mods/signs_bot/sounds
"normal2", -- ./mods/hyperloop/sounds
"up2", -- ./mods/hyperloop/sounds
"down2", -- ./mods/hyperloop/sounds
"ele_norm", -- ./mods/hyperloop/sounds
"door", -- ./mods/hyperloop/sounds
"hyperloop_crowbar", -- ./mods/hyperloop/sounds
"ele_door", -- ./mods/hyperloop/sounds
"techage_watermill", -- ./mods/techage/sounds
"techage_button", -- ./mods/techage/sounds
"techage_steamengine", -- ./mods/techage/sounds
"techage_generator", -- ./mods/techage/sounds
"techage_gasflare", -- ./mods/techage/sounds
"techage_explore", -- ./mods/techage/sounds
"techage_mill", -- ./mods/techage/sounds
"techage_reactor", -- ./mods/techage/sounds
"techage_valve", -- ./mods/techage/sounds
"techage_oildrill", -- ./mods/techage/sounds
"techage_turbine", -- ./mods/techage/sounds
"techage_booster", -- ./mods/techage/sounds
"techage_quarry", -- ./mods/techage/sounds
"techage_reboiler", -- ./mods/techage/sounds
"jetpack_loop", -- ./mods/jetpack/sounds
"paperflip1", -- ./mods/unified_inventory/sounds
"teleport", -- ./mods/unified_inventory/sounds
"electricity", -- ./mods/unified_inventory/sounds
"owl", -- ./mods/unified_inventory/sounds
"click", -- ./mods/unified_inventory/sounds
"birds", -- ./mods/unified_inventory/sounds
"paperflip2", -- ./mods/unified_inventory/sounds
"dingdong", -- ./mods/unified_inventory/sounds
"trash", -- ./mods/unified_inventory/sounds
"trash_all", -- ./mods/unified_inventory/sounds
"ta4_jetpack", -- ./mods/ta4_jetpack/sounds
"ta4_jetpack_alarm", -- ./mods/ta4_jetpack/sounds
"ta4_jetpack_on", -- ./mods/ta4_jetpack/sounds
"player_damage", -- ./games/minetest_game/mods/player_api/sounds
"env_sounds_water", -- ./games/minetest_game/mods/env_sounds/sounds
"env_sounds_lava", -- ./games/minetest_game/mods/env_sounds/sounds
"doors_door_close", -- ./games/minetest_game/mods/doors/sounds
"doors_steel_door_close", -- ./games/minetest_game/mods/doors/sounds
"doors_door_open", -- ./games/minetest_game/mods/doors/sounds
"doors_fencegate_close", -- ./games/minetest_game/mods/doors/sounds
"doors_glass_door_close", -- ./games/minetest_game/mods/doors/sounds
"doors_fencegate_open", -- ./games/minetest_game/mods/doors/sounds
"doors_glass_door_open", -- ./games/minetest_game/mods/doors/sounds
"doors_steel_door_open", -- ./games/minetest_game/mods/doors/sounds
"fire_flint_and_steel", -- ./games/minetest_game/mods/fire/sounds
"fire_large", -- ./games/minetest_game/mods/fire/sounds
"fire_fire", -- ./games/minetest_game/mods/fire/sounds
"fire_extinguish_flame", -- ./games/minetest_game/mods/fire/sounds
"fire_small", -- ./games/minetest_game/mods/fire/sounds
"tnt_ignite", -- ./games/minetest_game/mods/tnt/sounds
"tnt_gunpowder_burning", -- ./games/minetest_game/mods/tnt/sounds
"tnt_explode", -- ./games/minetest_game/mods/tnt/sounds
"carts_cart_new", -- ./games/minetest_game/mods/carts/sounds
"carts_cart_moving", -- ./games/minetest_game/mods/carts/sounds
"xpanes_steel_bar_door_open", -- ./games/minetest_game/mods/xpanes/sounds
"xpanes_steel_bar_door_close", -- ./games/minetest_game/mods/xpanes/sounds
"default_break_glass", -- ./games/minetest_game/mods/default/sounds
"default_dig_dig_immediate", -- ./games/minetest_game/mods/default/sounds
"default_dig_cracky", -- ./games/minetest_game/mods/default/sounds
"default_dig_choppy", -- ./games/minetest_game/mods/default/sounds
"default_water_footstep", -- ./games/minetest_game/mods/default/sounds
"player_damage", -- ./games/minetest_game/mods/default/sounds
"default_gravel_footstep", -- ./games/minetest_game/mods/default/sounds
"default_dig_metal", -- ./games/minetest_game/mods/default/sounds
"default_gravel_dug", -- ./games/minetest_game/mods/default/sounds
"default_hard_footstep", -- ./games/minetest_game/mods/default/sounds
"default_sand_footstep", -- ./games/minetest_game/mods/default/sounds
"default_grass_footstep", -- ./games/minetest_game/mods/default/sounds
"default_chest_close", -- ./games/minetest_game/mods/default/sounds
"default_cool_lava", -- ./games/minetest_game/mods/default/sounds
"default_place_node_hard", -- ./games/minetest_game/mods/default/sounds
"default_ice_dug", -- ./games/minetest_game/mods/default/sounds
"default_dig_crumbly", -- ./games/minetest_game/mods/default/sounds
"default_tool_breaks", -- ./games/minetest_game/mods/default/sounds
"default_ice_footstep", -- ./games/minetest_game/mods/default/sounds
"default_dig_cracky", -- ./games/minetest_game/mods/default/sounds
"default_chest_open", -- ./games/minetest_game/mods/default/sounds
"default_gravel_dig", -- ./games/minetest_game/mods/default/sounds
"default_dig_oddly_breakable_by_hand", -- ./games/minetest_game/mods/default/sounds
"default_dug_metal", -- ./games/minetest_game/mods/default/sounds
"default_dirt_footstep", -- ./games/minetest_game/mods/default/sounds
"default_dig_choppy", -- ./games/minetest_game/mods/default/sounds
"default_glass_footstep", -- ./games/minetest_game/mods/default/sounds
"default_snow_footstep", -- ./games/minetest_game/mods/default/sounds
"default_place_node", -- ./games/minetest_game/mods/default/sounds
"default_dig_snappy", -- ./games/minetest_game/mods/default/sounds
"default_dug_node", -- ./games/minetest_game/mods/default/sounds
"default_metal_footstep", -- ./games/minetest_game/mods/default/sounds
"default_ice_dig", -- ./games/minetest_game/mods/default/sounds
"default_place_node_metal", -- ./games/minetest_game/mods/default/sounds
"default_wood_footstep", -- ./games/minetest_game/mods/default/sounds
"default_furnace_active", -- ./games/minetest_game/mods/default/sounds
"default_item_smoke", -- ./games/minetest_game/mods/default/sounds
}

88
basis/pack_lib.lua Normal file
View File

@ -0,0 +1,88 @@
--[[
TechAge
=======
Copyright (C) 2019-2024 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Packing functions
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local M = minetest.get_meta
-- string/usercode conversion
local function usercode_to_string(tbl)
if tbl and tbl.inventory then
for list_name,list in pairs(tbl.inventory) do
for i,item in ipairs(list) do
tbl.inventory[list_name][i] = item:to_string()
end
end
end
end
local function string_to_usercode(tbl)
if tbl and tbl.inventory then
for list_name,list in pairs(tbl.inventory) do
for i,item in ipairs(list) do
tbl.inventory[list_name][i] = ItemStack(item)
end
end
end
end
-- pack/unpack node nvm data
local function pack_nvm(pos)
if techage.has_nvm(pos) then
local s = minetest.serialize(techage.get_nvm(pos))
techage.del_mem(pos)
return s
end
end
local function unpack_nvm(pos, s)
if s and s ~= "" then
local tbl = minetest.deserialize(s)
local nvm = techage.get_nvm(pos)
for k,v in pairs(tbl) do
nvm.k = v
end
end
end
-- pack/unpack node metedata
local function pack_meta(pos)
local tbl = M(pos):to_table() or {}
usercode_to_string(tbl)
return minetest.serialize(tbl)
end
local function unpack_meta(pos, s)
if s and s ~= "" then
local tbl = minetest.deserialize(s) or {}
string_to_usercode(tbl)
M(pos):from_table(tbl)
end
end
-------------------------------------------------------------------------------
-- preserve/restore API functions
-------------------------------------------------------------------------------
function techage.preserve_nodedata(pos)
local smeta = pack_meta(pos)
local snvm = pack_nvm(pos)
return minetest.serialize({smeta = smeta, snvm = snvm})
end
function techage.restore_nodedata(pos, s)
local tbl = minetest.deserialize(s) or {}
unpack_nvm(pos, tbl.snvm)
unpack_meta(pos, tbl.smeta)
end

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Recipe lib for formspecs
]]--
@ -22,10 +22,23 @@ local range = techage.in_range
techage.recipes = {}
local GROUP_ITEMS = {
stone = "default:cobble",
wood = "default:wood",
book = "default:book",
sand = "default:sand",
leaves = "default:leaves",
stick = "default:stick",
tree = "default:tree",
vessel = "vessels:glass_bottle",
wool = "wool:white",
}
local RECIPE = {
output = {name = "", num = 0},
waste = {name = "", num = 0},
input = {
input = {
{name = "", num =0},
{name = "", num =0},
{name = "", num =0},
@ -33,6 +46,22 @@ local RECIPE = {
},
}
local function filter_recipes_based_on_points(recipes, owner)
local ex_points = 0
if owner then
local player = minetest.get_player_by_name(owner)
ex_points = techage.get_expoints(player) or 0
end
local tbl = {}
for _,item in ipairs(recipes) do
if ex_points >= (item.ex_points or 0) then
tbl[#tbl + 1] = item
end
end
return tbl
end
-- Formspec
local function input_string(recipe)
@ -45,11 +74,14 @@ local function input_string(recipe)
return table.concat(tbl, "")
end
function techage.recipes.get(nvm, rtype)
function techage.recipes.get(nvm, rtype, owner)
local recipes = Recipes[rtype] or {}
return recipes[nvm.recipe_idx or 1]
if owner then
recipes = filter_recipes_based_on_points(recipes, owner)
end
return recipes[nvm.recipe_idx or 1] or recipes[1]
end
-- Add 4 input/output/waste recipe
-- {
-- output = "<item-name> <units>", -- units = 1..n
@ -63,7 +95,7 @@ function techage.recipes.add(rtype, recipe)
if not Recipes[rtype] then
Recipes[rtype] = {}
end
local name, num, output
local item = {input = {}}
for idx = 1,4 do
@ -71,7 +103,7 @@ function techage.recipes.add(rtype, recipe)
name, num = unpack(string.split(inp, " "))
item.input[idx] = {name = name or "", num = tonumber(num) or 0}
end
if recipe.waste then
if recipe.waste then
name, num = unpack(string.split(recipe.waste, " "))
else
name, num = "", "0"
@ -80,24 +112,24 @@ function techage.recipes.add(rtype, recipe)
name, num = unpack(string.split(recipe.output, " "))
item.output = {name = name or "", num = tonumber(num) or 0}
item.catalyst = recipe.catalyst
item.ex_points = recipe.ex_points or 0
Recipes[rtype][#Recipes[rtype]+1] = item
output = name
if minetest.global_exists("unified_inventory") then
unified_inventory.register_craft({
output = recipe.output,
items = recipe.input,
type = rtype,
})
end
techage.recipes.register_craft({
output = recipe.output,
items = recipe.input,
type = rtype,
})
NormalizedRecipes[output] = {
output = recipe.output,
output = recipe.output,
items = recipe.input,
}
end
function techage.recipes.formspec(x, y, rtype, nvm)
function techage.recipes.formspec(x, y, rtype, nvm, owner)
local recipes = Recipes[rtype] or {}
recipes = filter_recipes_based_on_points(recipes, owner)
nvm.recipe_idx = range(nvm.recipe_idx or 1, 1, #recipes)
local idx = nvm.recipe_idx
local recipe = recipes[idx] or RECIPE
@ -122,13 +154,15 @@ function techage.recipes.on_receive_fields(pos, formname, fields, player)
return
end
local nvm = techage.get_nvm(pos)
nvm.recipe_idx = nvm.recipe_idx or 1
if not nvm.running then
if not nvm.running then
if fields.next == ">>" then
nvm.recipe_idx = nvm.recipe_idx + 1
return true
elseif fields.priv == "<<" then
nvm.recipe_idx = nvm.recipe_idx - 1
return true
end
end
end
@ -136,4 +170,123 @@ end
function techage.recipes.get_recipe(name)
return NormalizedRecipes[name]
end
function techage.recipes.set_recipe(pos, rtype, idx)
local nvm = techage.get_nvm(pos)
if not nvm.running then
local recipes = Recipes[rtype] or {}
idx = tonumber(idx) or 1
nvm.recipe_idx = range(idx, 1, #recipes)
end
end
function techage.recipes.get_default_group_item_name(item_name)
if item_name and item_name:sub(1, 6) == "group:" then
local default_name = GROUP_ITEMS[item_name:sub(7)]
if default_name then
return default_name
end
end
return item_name
end
function techage.recipes.add_group_item(group, default_item_name)
GROUP_ITEMS[group] = default_item_name
end
-------------------------------------------------------------------------------
-- Borrowed from ghaydn
-------------------------------------------------------------------------------
local has_i3 = minetest.get_modpath("i3")
local has_ui = minetest.get_modpath("unified_inventory")
local has_cg = minetest.get_modpath("craftguide")
local function format_i3(input)
local output = {}
for _, entry in ipairs(input) do
local secondput = ""
if type(entry) == "table" then
for _, secondtry in ipairs(entry) do
secondput = secondput..secondtry..","
end
table.insert(output, secondput)
else
table.insert(output, entry)
end
end
return output
end
techage.recipes.register_craft_type = function(name, def)
if has_cg then
local cg_def = {
description = def.description,
icon = def.icon,
}
craftguide.register_craft_type(name, cg_def)
end
if has_i3 then
local i3_def = {
description = def.description,
icon = def.icon,
width = def.width or 3,
height = def.height or 3,
dynamic_display_size = def.dynamic_display_size or nil,
uses_crafting_grid = def.uses_crafting_grid,
}
i3.register_craft_type(name, i3_def)
end
if has_ui then
local ui_def = {
description = def.description,
icon = def.icon,
width = def.width or 3,
height = def.height or 3,
dynamic_display_size = def.dynamic_display_size or nil,
uses_crafting_grid = def.uses_crafting_grid,
}
unified_inventory.register_craft_type(name, ui_def)
end
end
techage.recipes.register_craft = function(def)
if not def.items then
if def.input then
def.items = table.copy(def.input)
elseif def.recipe then
def.items = table.copy(def.recipe)
end
end
if not def.result then
if def.output then def.result = def.output end
end
if has_cg then
local cg_def = {
result = def.result,
type = def.type,
items = def.items,
}
craftguide.register_craft(cg_def)
end
if has_i3 then
local i3_def = {
result = def.result,
type = def.type,
items = format_i3(def.items),
width = def.width or 3,
}
i3.register_craft(i3_def)
end
if has_ui then
local ui_def = {
output = def.result,
type = def.type,
items = def.items,
width = def.width or 3,
height = def.height or 3,
}
unified_inventory.register_craft(ui_def)
end
end

74
basis/shared_inv.lua Normal file
View File

@ -0,0 +1,74 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Library for shared inventories
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local M = minetest.get_meta
local S = techage.S
techage.shared_inv = {}
local hyperloop = techage.hyperloop
local remote_pos = techage.hyperloop.remote_pos
local function copy_inventory_list(from_pos, to_pos, listname)
local inv1 = minetest.get_inventory({type="node", pos=from_pos})
local inv2 = minetest.get_inventory({type="node", pos=to_pos})
inv2:set_list(listname, inv1:get_list(listname))
end
function techage.shared_inv.node_timer(pos, elapsed)
local rmt_pos = remote_pos(pos)
if rmt_pos and techage.is_activeformspec(pos) then
copy_inventory_list(rmt_pos, pos, "main")
return true
end
return false
end
-- Synchronize the client inventory with the server one
function techage.shared_inv.before_inv_access(pos, listname)
if hyperloop.is_client(pos) then
local rmt_pos = remote_pos(pos)
if rmt_pos then
copy_inventory_list(rmt_pos, pos, listname)
return true
end
end
return false
end
-- Synchronize the client inventory with the server one
function techage.shared_inv.after_inv_access(pos, listname)
if hyperloop.is_client(pos) then
local rmt_pos = remote_pos(pos)
if rmt_pos then
copy_inventory_list(pos, rmt_pos, listname)
return true
end
end
return false
end
function techage.shared_inv.on_rightclick(pos, clicker, listname)
if hyperloop.is_client(pos) then
local rmt_pos = remote_pos(pos)
if rmt_pos then
copy_inventory_list(rmt_pos, pos, listname)
techage.set_activeformspec(pos, clicker)
minetest.get_node_timer(pos):start(2)
end
end
end

116
basis/shared_tank.lua Normal file
View File

@ -0,0 +1,116 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Library for shared inventories
]]--
-- for lazy programmers
local M = minetest.get_meta
local NDEF = function(pos) return minetest.registered_nodes[techage.get_node_lvm(pos).name] or {} end
techage.shared_tank = {}
local liquid = networks.liquid
local hyperloop = techage.hyperloop
local remote_pos = techage.hyperloop.remote_pos
local is_paired = techage.hyperloop.is_paired
local menu = techage.menu
local function formspec(pos)
local ndef = NDEF(pos)
local status = M(pos):get_string("conn_status")
if hyperloop.is_client(pos) or hyperloop.is_server(pos) then
local title = ndef.description .. " " .. status
local nvm = techage.get_nvm(remote_pos(pos))
return techage.liquid.formspec(pos, nvm, title)
else
return menu.generate_formspec(pos, ndef, hyperloop.SUBMENU)
end
end
function techage.shared_tank.node_timer(pos)
if techage.is_activeformspec(pos) and is_paired(pos) then
M(pos):set_string("formspec", formspec(pos))
return true
end
return false
end
function techage.shared_tank.on_rightclick(pos, node, clicker)
--if hyperloop.is_client(pos) then
techage.set_activeformspec(pos, clicker)
minetest.get_node_timer(pos):start(2)
--end
M(pos):set_string("formspec", formspec(pos))
end
function techage.shared_tank.can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
pos = remote_pos(pos)
return techage.liquid.is_empty(pos)
end
function techage.shared_tank.peek_liquid(pos, indir)
if is_paired(pos) then
pos = remote_pos(pos)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end
end
function techage.shared_tank.take_liquid(pos, indir, name, amount)
if is_paired(pos) then
pos = remote_pos(pos)
local nvm = techage.get_nvm(pos)
amount, name = liquid.srv_take(nvm, name, amount)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return amount, name
end
return 0, name
end
function techage.shared_tank.put_liquid(pos, indir, name, amount)
if is_paired(pos) then
pos = remote_pos(pos)
-- check if it is not powder
local ndef = minetest.registered_craftitems[name] or {}
if not ndef.groups or ndef.groups.powder ~= 1 then
local nvm = techage.get_nvm(pos)
local ndef = NDEF(pos)
local leftover = liquid.srv_put(nvm, name, amount, ndef.liquid.capa)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return leftover
end
end
return amount
end
function techage.shared_tank.untake_liquid(pos, indir, name, amount)
if is_paired(pos) then
pos = remote_pos(pos)
local nvm = techage.get_nvm(pos)
local ndef = NDEF(pos)
local leftover = liquid.srv_put(nvm, name, amount, ndef.liquid.capa)
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(pos))
end
return leftover
end
return amount
end
techage.shared_tank.formspec = formspec

318
basis/submenu.lua Normal file
View File

@ -0,0 +1,318 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
A formspec control to generate formspec strings for machine settings and monitoring
]]--
local S = techage.S
techage.menu = {}
local function index(list, x)
for idx, v in ipairs(list or {}) do
if tostring(v) == x then return idx end
end
return nil
end
local function allow_put(inv, listname, index, stack, player)
local list = inv:get_list(listname)
stack:set_count(1)
inv:set_stack(listname, index, stack)
return 0
end
local function allow_take(inv, listname, index, stack, player)
local list = inv:get_list(listname)
stack:set_count(0)
inv:set_stack(listname, index, stack)
return 0
end
-- generate the formspec string to be placed into a container frame
local function generate_formspec_substring(pos, meta, form_def, player_name)
local tbl = {}
local player_inv_needed = false
if meta and form_def then
local nvm = techage.get_nvm(pos)
for i,elem in ipairs(form_def) do
local offs = (i - 1) * 0.9 - 0.2
tbl[#tbl+1] = "label[0," .. offs .. ";" .. minetest.formspec_escape(elem.label) .. ":]"
tbl[#tbl+1] = "tooltip[0," .. offs .. ";4,1;" .. elem.tooltip .. "]"
if elem.type == "label" then
-- none
elseif elem.type == "number" then
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_int(elem.name)
end
if nvm.running or techage.is_running(nvm) then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
else
tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]"
end
elseif elem.type == "numbers" then
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_string(elem.name)
end
if nvm.running or techage.is_running(nvm) then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
else
tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]"
end
elseif elem.type == "float" then
local val = elem.default
if meta:contains(elem.name) then
val = tonumber(meta:get_string(elem.name)) or 0
end
if nvm.running or techage.is_running(nvm) then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
else
tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. val .. "]"
end
elseif elem.type == "ascii" then
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_string(elem.name)
end
if nvm.running or techage.is_running(nvm) then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. minetest.formspec_escape(val) .. "]"
else
tbl[#tbl+1] = "field[5," .. (offs+0.2) .. ";5.3,1;" .. elem.name .. ";;" .. minetest.formspec_escape(val) .. "]"
end
elseif elem.type == "const" then
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. elem.value .. "]"
elseif elem.type == "output" then
local val = nvm[elem.name] or meta:get_string(elem.name) or ""
if tonumber(val) then
val = techage.round(val)
end
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
elseif elem.type == "dropdown" then
if nvm.running or techage.is_running(nvm) then
local val = elem.default or ""
if meta:contains(elem.name) then
val = meta:get_string(elem.name) or ""
end
tbl[#tbl+1] = "label[4.75," .. offs .. ";" .. val .. "]"
elseif elem.on_dropdown then -- block provides a specific list of choice elements
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_string(elem.name) or ""
end
local choices = elem.on_dropdown(pos)
local l = choices:split(",")
local idx = index(l, val) or 1
tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. choices .. ";" .. idx .. "]"
else
local val = elem.default
if meta:contains(elem.name) then
val = meta:get_string(elem.name) or ""
end
local idx
if elem.values then
idx = index(elem.values, val) or 1
else
local l = elem.choices:split(",")
idx = index(l, val) or 1
end
tbl[#tbl+1] = "dropdown[4.72," .. (offs) .. ";5.5,1.4;" .. elem.name .. ";" .. elem.choices .. ";" .. idx .. "]"
end
elseif elem.type == "items" then -- inventory
if elem.size then
tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.size .. ",1;]"
else
tbl[#tbl+1] = "list[detached:" .. minetest.formspec_escape(player_name) .. "_techage_wrench_menu;cfg;4.75," .. offs .. ";" .. elem.width .. "," .. elem.height .. ";]"
end
player_inv_needed = true
end
end
if nvm.running or techage.is_running(nvm) then
local offs = #form_def * 0.9 - 0.2
tbl[#tbl+1] = "label[0," .. offs .. ";" .. S("Note: You can't change any values while the block is running!") .. "]"
end
end
return player_inv_needed, table.concat(tbl, "")
end
local function value_check(elem, value, player_name)
if elem.check then
return elem.check(value, player_name)
end
return value ~= nil
end
local function evaluate_data(pos, meta, form_def, fields, player_name)
local res = true
if meta and form_def then
local nvm = techage.get_nvm(pos)
if nvm.running or techage.is_running(nvm) then
return res
end
for idx,elem in ipairs(form_def) do
if elem.type == "number" then
if fields[elem.name] then
if fields[elem.name] == "" then
meta:set_string(elem.name, "")
elseif fields[elem.name]:find("^[%d ]+$") then
local val = tonumber(fields[elem.name])
if value_check(elem, val, player_name) then
meta:set_int(elem.name, val)
--print("set_int", elem.name, val)
else
res = false
end
else
res = false
end
end
elseif elem.type == "numbers" then
if fields[elem.name] then
if fields[elem.name] == "" then
meta:set_string(elem.name, "")
elseif fields[elem.name]:find("^[%d ]+$") and
value_check(elem, fields[elem.name], player_name) then
meta:set_string(elem.name, fields[elem.name])
else
res = false
end
end
elseif elem.type == "float" then
if fields[elem.name] == ""then
meta:set_string(elem.name, "")
elseif fields[elem.name] then
local val = tonumber(fields[elem.name])
if val and value_check(elem, val, player_name) then
meta:set_string(elem.name, val)
else
res = false
end
end
elseif elem.type == "ascii" then
if fields[elem.name] == ""then
meta:set_string(elem.name, "")
elseif fields[elem.name] then
if value_check(elem, fields[elem.name], player_name) then
meta:set_string(elem.name, fields[elem.name])
else
res = false
end
end
elseif elem.type == "dropdown" then
if fields[elem.name] ~= nil then
if elem.values then
local l = elem.choices:split(",")
local idx = index(l, fields[elem.name]) or 1
local text = elem.values[idx]
meta:set_string(elem.name, text)
else
meta:set_string(elem.name, fields[elem.name])
end
end
elseif elem.type == "items" and player_name then
local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu"
local dinv = minetest.get_inventory({type = "detached", name = inv_name})
local ninv = minetest.get_inventory({type = "node", pos = pos})
if dinv and ninv then
for i = 1, ninv:get_size("cfg") do
ninv:set_stack("cfg", i, dinv:get_stack("cfg", i))
end
end
end
end
end
return res
end
function techage.menu.generate_formspec(pos, ndef, form_def, player_name)
local meta = minetest.get_meta(pos)
local number = techage.get_node_number(pos) or "-"
local mem = techage.get_mem(pos)
mem.star = ((mem.star or 0) + 1) % 2
local star = mem.star == 1 and "*" or ""
if player_name then
local inv_name = minetest.formspec_escape(player_name) .. "_techage_wrench_menu"
minetest.create_detached_inventory(inv_name, {
allow_put = allow_put,
allow_take = allow_take})
local dinv = minetest.get_inventory({type = "detached", name = inv_name})
local ninv = minetest.get_inventory({type = "node", pos = pos})
if dinv and ninv then
dinv:set_size('cfg', ninv:get_size("cfg"))
for i = 1, ninv:get_size("cfg") do
dinv:set_stack("cfg", i, ninv:get_stack("cfg", i))
end
end
end
if meta and number and ndef and form_def then
local title = ndef.description .. " (" .. number .. ")"
local player_inv_needed, text = generate_formspec_substring(pos, meta, form_def, player_name)
local buttons
if player_inv_needed then
buttons = "button[0.5,6.2;3,1;refresh;" .. S("Refresh") .. "]" ..
"button_exit[3.5,6.2;3,1;cancel;" .. S("Cancel") .. "]" ..
"button[6.5,6.2;3,1;save;" .. S("Save") .. "]" ..
"list[current_player;main;1,7.2;8,2;]"
else
buttons = "button[0.5,8.4;3,1;refresh;" .. S("Refresh") .. "]" ..
"button_exit[3.5,8.4;3,1;cancel;" .. S("Cancel") .. "]" ..
"button[6.5,8.4;3,1;save;" .. S("Save") .. "]"
end
if #form_def > 8 then
local size = (#form_def * 10) - 60
return "size[10,9]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"box[0,-0.1;9.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" ..
"scrollbaroptions[max=" .. size .. "]" ..
"scrollbar[9.4,0.6;0.4,7.7;vertical;wrenchmenu;]" ..
"scroll_container[0,1;12,9;wrenchmenu;vertical;]" ..
text ..
"scroll_container_end[]" ..
buttons
else
return "size[10,9]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"box[0,-0.1;9.8,0.5;#c6e8ff]" ..
"label[0.2,-0.1;" .. minetest.colorize( "#000000", title) .. "]" ..
"label[9.5,-0.1;" .. minetest.colorize( "#000000", star) .. "]" ..
"container[0,1]" ..
text ..
"container_end[]" ..
buttons
end
end
return ""
end
function techage.menu.eval_input(pos, form_def, fields, player_name)
if fields.save or fields.key_enter_field then
local meta = minetest.get_meta(pos)
evaluate_data(pos, meta, form_def, fields, player_name)
end
return fields.refresh or fields.save or fields.key_enter_field
end
function techage.dropdown_index(sChoices, selected_value)
local l = sChoices:split(",")
return index(l, selected_value) or 1
end

167
basis/teleport.lua Normal file
View File

@ -0,0 +1,167 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
For tupe/pipe blocks with teleport support
]]--
-- for lazy programmers
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local NDEF = function(pos) return minetest.registered_nodes[techage.get_node_lvm(pos).name] or {} end
local M = minetest.get_meta
local S = techage.S
local menu = techage.menu
techage.teleport = {}
local PairingList = {} -- {owner = {node_type = {channel = pos}}}
local function get_pairing_table1(meta)
local owner = meta:get_string("owner")
local node_type = meta:get_string("tele_node_type")
PairingList[owner] = PairingList[owner] or {}
PairingList[owner][node_type] = PairingList[owner][node_type] or {}
return PairingList[owner][node_type]
end
local function get_pairing_table2(oldmetadata)
local owner = oldmetadata.fields.owner
local node_type = oldmetadata.fields.tele_node_type
PairingList[owner] = PairingList[owner] or {}
PairingList[owner][node_type] = PairingList[owner][node_type] or {}
return PairingList[owner][node_type]
end
local function get_free_server_list(pos)
local tbl = {""}
for name, pos in pairs(get_pairing_table1(M(pos))) do
table.insert(tbl, name)
end
return table.concat(tbl, ",")
end
local TELE_MENU = {
{
type = "label",
label = S("Enter a block name or select an existing one"),
tooltip = "",
name = "l1",
},
{
type = "ascii",
name = "conn_name",
label = S("Block name"),
tooltip = S("Connection name for this block"),
default = "",
},
{
type = "dropdown",
choices = "",
on_dropdown = get_free_server_list,
name = "remote_name",
label = S("Remote name"),
tooltip = S("Connection name of the remote block"),
},
{
type = "output",
label = S("Status"),
tooltip = S("Connection status"),
name = "status",
default = "",
},
}
function techage.teleport.formspec(pos)
local ndef = NDEF(pos)
return menu.generate_formspec(pos, ndef, TELE_MENU)
end
local function store_connection(pos, peer_pos)
local meta = M(pos)
local status = S("connected to") .. " " .. P2S(peer_pos)
meta:set_string("tele_status", status)
meta:set_string("tele_peer_pos", P2S(peer_pos))
meta:set_string("formspec", "")
end
function techage.teleport.prepare_pairing(pos, node_type, status)
local meta = M(pos)
if node_type then
meta:set_string("tele_node_type", node_type)
end
status = status or S("not connected")
meta:set_string("tele_status", status)
meta:set_string("tele_peer_pos", "")
meta:set_string("formspec", techage.teleport.formspec(pos))
end
function techage.teleport.stop_pairing(pos, oldmetadata)
-- disconnect peer node
if oldmetadata and oldmetadata.fields then
if oldmetadata.fields.tele_peer_pos then
local peer_pos = S2P(oldmetadata.fields.tele_peer_pos)
local meta = M(peer_pos)
if meta:get_string("conn_name") ~= "" then -- Server
local tbl = get_pairing_table1(meta)
tbl[meta:get_string("conn_name")] = peer_pos
techage.teleport.prepare_pairing(peer_pos, nil, S("server not connected"))
else
techage.teleport.prepare_pairing(peer_pos)
end
elseif oldmetadata.fields.conn_name then
local tbl = get_pairing_table2(oldmetadata)
tbl[oldmetadata.fields.conn_name] = nil
end
end
end
function techage.teleport.is_connected(pos)
return M(pos):get_string("tele_peer_pos") ~= ""
end
function techage.teleport.get_remote_pos(pos)
local s = M(pos):get_string("tele_peer_pos")
if s ~= "" then
return S2P(s)
end
end
function techage.teleport.after_formspec(pos, player, fields, max_dist, ex_points)
if techage.get_expoints(player) >= ex_points then
if techage.menu.eval_input(pos, TELE_MENU, fields) then
if not techage.teleport.is_connected(pos) then
local meta = M(pos)
if fields.remote_name ~= "" then -- Client
local tbl = get_pairing_table1(meta)
local peer_pos = tbl[fields.remote_name]
if peer_pos then
if vector.distance(pos, peer_pos) <= max_dist then
tbl[fields.remote_name] = nil
store_connection(pos, peer_pos)
store_connection(peer_pos, pos)
M(pos):set_string("status", S("Connected"))
else
M(pos):set_string("status", S("Distance > @1 blocks", max_dist))
meta:set_string("formspec", techage.teleport.formspec(pos))
end
end
elseif fields.conn_name ~= "" then -- Server
local tbl = get_pairing_table1(meta)
tbl[fields.conn_name] = pos
techage.teleport.prepare_pairing(pos, nil, S("server not connected"))
end
end
end
else
M(pos):set_string("status", S("Ex-points missing (@1 < @2)", techage.get_expoints(player), ex_points))
M(pos):set_string("formspec", techage.teleport.formspec(pos))
end
end

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Tube wall entry
]]--
@ -27,7 +27,7 @@ minetest.register_node("techage:tube_wall_entry", {
"basic_materials_concrete_block.png^techage_tube_hole.png",
"basic_materials_concrete_block.png^techage_tube_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Tube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
@ -35,11 +35,11 @@ minetest.register_node("techage:tube_wall_entry", {
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
on_rotate = screwdriver.disallow, -- important!
groups = {crumbly = 2, cracky = 2, snappy = 2},

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Tubes based on tubelib2
]]--
@ -27,13 +27,13 @@ techage.KnownNodes = {
local Tube = tubelib2.Tube:new({
-- North, East, South, West, Down, Up
dirs_to_check = {1,2,3,4,5,6},
max_tube_length = 200,
max_tube_length = 200,
show_infotext = false,
primary_node_names = {
"techage:tubeS", "techage:tubeA",
"techage:tubeS", "techage:tubeA",
"techage:ta4_tubeS", "techage:ta4_tubeA",
"techage:tube_wall_entry",
},
},
after_place_tube = function(pos, param2, tube_type, num_tubes, tbl)
local name = minetest.get_node(pos).name
if name == "techage:tubeS" or name == "techage:tubeA" then
@ -58,7 +58,7 @@ minetest.register_node("techage:tubeS", {
"techage_tube_hole.png",
"techage_tube_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Tube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
@ -66,11 +66,11 @@ minetest.register_node("techage:tubeS", {
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
@ -106,11 +106,11 @@ minetest.register_node("techage:tubeA", {
"techage_tube_knee2.png",
"techage_tube_hole2.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
Tubes in TA4 design based on tubelib2
]]--
@ -25,7 +25,7 @@ minetest.register_node("techage:ta4_tubeS", {
"techage_tube_hole.png",
"techage_tube_hole.png",
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not Tube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
@ -33,11 +33,11 @@ minetest.register_node("techage:ta4_tubeS", {
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {
@ -73,11 +73,11 @@ minetest.register_node("techage:ta4_tubeA", {
"techage_tubeta4_knee2.png",
"techage_tubeta4_hole2.png",
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Tube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir",
drawtype = "nodebox",
node_box = {

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
Wind turbine helper function
]]--
@ -16,6 +16,12 @@ local S = techage.S
local P = minetest.string_to_pos
local M = minetest.get_meta
local OCEAN = "ocean"
if minetest.global_exists("asuna") then
OCEAN = "below"
end
local function chat_message(player_name, msg)
if player_name then
minetest.chat_send_player(player_name, S("[TA4 Wind Turbine]").." "..msg)
@ -39,7 +45,7 @@ function techage.valid_place_for_windturbine(pos, player_name, num_turbines)
local data = minetest.get_biome_data({x=pos.x, y=-2, z=pos.z})
if data then
local name = minetest.get_biome_name(data.biome)
if not string.find(name, "ocean") then
if not string.find(name, OCEAN) then
return chat_message(player_name, S("This is a").." "..name.." "..S("biome and no ocean!"))
end
end
@ -49,15 +55,15 @@ function techage.valid_place_for_windturbine(pos, player_name, num_turbines)
num = #minetest.find_nodes_in_area(pos1, pos2, {"air", "ignore"})
if num < (41 * 41 * 21 * 0.9) then
techage.mark_region(player_name, pos1, pos2, "")
return chat_message(player_name,
return chat_message(player_name,
S("Here is not enough wind\n(A free air space of 41x41x21 m is necessary)!"))
end
-- Check for water surface (occean)
pos1 = {x=pos.x-20, y=1, z=pos.z-20}
pos2 = {x=pos.x+20, y=1, z=pos.z+20}
num = #minetest.find_nodes_in_area(pos1, pos2,
num = #minetest.find_nodes_in_area(pos1, pos2,
{"default:water_source", "default:water_flowing", "ignore"})
if num < (41*41 * 0.8) then
techage.mark_region(player_name, pos1, pos2, "")
return chat_message(player_name, S("Here is not enough water (41x41 m)!"))
@ -71,7 +77,7 @@ function techage.valid_place_for_windturbine(pos, player_name, num_turbines)
techage.mark_region(player_name, pos1, pos2, "")
return chat_message(player_name, S("The next wind turbines is too close!"))
end
if num_turbines == 0 then
chat_message(player_name, minetest.pos_to_string(pos).." "..
S("is a suitable place for a wind turbine!"))

60
beduino/kv_store.lua Normal file
View File

@ -0,0 +1,60 @@
--[[
TechAge
=======
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
K/V Store for the Beduino controller
]]--
local COSTS = 400
local function ta_kv_init(cpu_pos, address, regA, regB, regC)
local nvm = techage.get_nvm(cpu_pos)
nvm.kv_store = {}
return 1, COSTS
end
local function ta_kv_add(cpu_pos, address, regA, regB, regC)
local nvm = techage.get_nvm(cpu_pos)
local text = vm16.read_ascii(cpu_pos, regA, 32)
nvm.kv_store[text] = regB
return 1, COSTS
end
local function ta_kv_get(cpu_pos, address, regA, regB, regC)
local nvm = techage.get_nvm(cpu_pos)
local text = vm16.read_ascii(cpu_pos, regA, 32)
return nvm.kv_store[text] or 0, COSTS
end
local kvstore_c = [[
// Initialize the key/value store
func ta_kv_init() {
return system(0x140, 0);
}
// Add a key/value pair to the store
func ta_kv_add(key_str, value) {
return system(0x141, key_str, value);
}
// Returns the value for the given key string
func ta_kv_get(key_str) {
return system(0x142, key_str);
}
]]
minetest.register_on_mods_loaded(function()
if minetest.global_exists("beduino") and minetest.global_exists("vm16") then
beduino.lib.register_SystemHandler(0x140, ta_kv_init)
beduino.lib.register_SystemHandler(0x141, ta_kv_add)
beduino.lib.register_SystemHandler(0x142, ta_kv_get)
vm16.register_ro_file("beduino", "lib/ta_kvstore.c", kvstore_c)
end
end)

View File

@ -3,13 +3,13 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Chest Cart
]]--
-- for lazy programmers
@ -59,7 +59,7 @@ end
minetest.register_node("techage:chest_cart", {
description = S("TA Chest Cart"),
tiles = {
-- up, down, right, left, back, front
-- up, down, right, left, back, front
"techage_chest_cart_top.png",
"techage_chest_cart_bottom.png",
"techage_chest_cart_side.png",
@ -83,13 +83,13 @@ minetest.register_node("techage:chest_cart", {
groups = {cracky = 2, crumbly = 2, choppy = 2},
node_placement_prediction = "",
diggable = false,
on_place = minecart.on_nodecart_place,
on_punch = minecart.on_nodecart_punch,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
on_rightclick = on_rightclick,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
inv:set_size('main', 4)
@ -99,14 +99,14 @@ minetest.register_node("techage:chest_cart", {
M(pos):set_string("formspec", formspec())
end
end,
set_cargo = function(pos, data)
local inv = M(pos):get_inventory()
for idx, stack in ipairs(data) do
inv:set_stack("main", idx, stack)
end
end,
get_cargo = function(pos)
local inv = M(pos):get_inventory()
local data = {}
@ -159,7 +159,16 @@ techage.register_node({"techage:chest_cart"}, {
return "unsupported"
end
end,
})
on_beduino_request_data = function(pos, src, topic, payload)
if topic == 131 then -- Chest State
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return 0, {techage.get_inv_state_num(inv, "main")}
else
return 2, ""
end
end,
})
Tube:set_valid_sides("techage:chest_cart", {"L", "R", "F", "B"})

View File

@ -9,7 +9,7 @@
See LICENSE.txt for more information
TA3 Tank Cart
]]--
-- for lazy programmers
@ -20,8 +20,8 @@ local S2P = minetest.string_to_pos
local Pipe = techage.LiquidPipe
local MP = minetest.get_modpath("minecart")
local liquid = networks.liquid
local CAPACITY = 100
local liquid = networks.liquid
local CAPACITY = 200
local function on_rightclick(pos, node, clicker)
if clicker and clicker:is_player() then
@ -41,7 +41,7 @@ local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
return true
end
end
return false
end
@ -58,7 +58,7 @@ local function take_liquid(pos, indir, name, amount)
end
return amount, name
end
local function put_liquid(pos, indir, name, amount)
-- check if it is not powder
local ndef = minetest.registered_craftitems[name] or {}
@ -85,7 +85,7 @@ end
minetest.register_node("techage:tank_cart", {
description = S("TA Tank Cart"),
tiles = {
-- up, down, right, left, back, front
-- up, down, right, left, back, front
"techage_tank_cart_top.png",
"techage_tank_cart_bottom.png",
"techage_tank_cart_side.png",
@ -110,7 +110,7 @@ minetest.register_node("techage:tank_cart", {
groups = {cracky = 2, crumbly = 2, choppy = 2},
node_placement_prediction = "",
diggable = false,
on_place = minecart.on_nodecart_place,
on_punch = minecart.on_nodecart_punch,
@ -118,29 +118,32 @@ minetest.register_node("techage:tank_cart", {
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
M(pos):set_string("formspec", techage.liquid.formspec(pos, nvm))
-- Delete the network between pump and cart
Pipe:after_dig_node(pos)
Pipe:after_place_node(pos)
end,
set_cargo = function(pos, data)
local nvm = techage.get_nvm(pos)
nvm.liquid = data
end,
get_cargo = function(pos)
local nvm = techage.get_nvm(pos)
local data = nvm.liquid
nvm.liquid = {}
return data
end,
has_cargo = function(pos)
return not techage.liquid.is_empty(pos)
end,
on_timer = node_timer,
on_rightclick = on_rightclick,
})
techage.register_node({"techage:tank_cart"}, techage.liquid.recv_message)
techage.register_node({"techage:tank_cart"}, techage.liquid.recv_message)
liquid.register_nodes({"techage:tank_cart"},
Pipe, "tank", {"U"}, {

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Doser
]]--
@ -54,14 +54,14 @@ local function get_liquids(pos)
Liquids[hash] = tbl
return Liquids[hash]
end
local function del_liquids(pos)
local hash = minetest.hash_node_position(pos)
Liquids[hash] = nil
end
-- if liquids are missing, update the cached liquid table
local function reload_liquids(pos)
local function reload_liquids(pos)
local hash = minetest.hash_node_position(pos)
-- determine the available input liquids
local tbl = {}
@ -73,11 +73,11 @@ local function reload_liquids(pos)
end
Liquids[hash] = tbl
return Liquids[hash]
end
end
local function reactor_cmnd(pos, cmnd, payload)
return techage.transfer(
pos,
pos,
6, -- outdir
cmnd, -- topic
payload, -- payload
@ -136,7 +136,7 @@ local function untake(pos, taken)
for _,item in pairs(taken) do
liquid.untake(pos, Pipe, item.outdir, item.name, item.num)
end
end
end
local function dosing(pos, nvm, elapsed)
-- trigger reactor (power)
@ -177,11 +177,37 @@ local function dosing(pos, nvm, elapsed)
end
end
end
-- check leftover
local leftover
local mem = techage.get_mem(pos)
if mem.waste_leftover then
leftover = reactor_cmnd(pos, "waste", {
name = mem.waste_leftover.name,
amount = mem.waste_leftover.num}) or mem.waste_leftover.num
if leftover > 0 then
mem.waste_leftover.num = leftover
State:blocked(pos, nvm)
return
end
mem.waste_leftover = nil
end
if mem.output_leftover then
leftover = reactor_cmnd(pos, "output", {
name = mem.output_leftover.name,
amount = mem.output_leftover.num}) or mem.output_leftover.num
if leftover > 0 then
mem.output_leftover.num = leftover
State:blocked(pos, nvm)
return
end
mem.output_leftover = nil
end
-- inputs
local taken = {}
local mem = techage.get_mem(pos)
mem.dbg_cycles = (mem.dbg_cycles or 0) - 1
for _,item in pairs(recipe.input) do
if item.name ~= "" then
local outdir = liquids[item.name] or reload_liquids(pos)[item.name]
@ -203,13 +229,13 @@ local function dosing(pos, nvm, elapsed)
end
end
-- waste
local leftover
if recipe.waste.name ~= "" then
leftover = reactor_cmnd(pos, "waste", {
name = recipe.waste.name,
amount = recipe.waste.num})
if not leftover or (tonumber(leftover) or 1) > 0 then
untake(pos, taken)
name = recipe.waste.name,
amount = recipe.waste.num}) or recipe.waste.num
if leftover > 0 then
mem.waste_leftover = {name = recipe.waste.name, num = leftover}
mem.output_leftover = {name = recipe.output.name, num = recipe.output.num}
State:blocked(pos, nvm)
reactor_cmnd(pos, "stop")
return
@ -217,22 +243,22 @@ local function dosing(pos, nvm, elapsed)
end
-- output
leftover = reactor_cmnd(pos, "output", {
name = recipe.output.name,
amount = recipe.output.num})
if not leftover or (tonumber(leftover) or 1) > 0 then
untake(pos, taken)
name = recipe.output.name,
amount = recipe.output.num}) or recipe.output.num
if leftover > 0 then
mem.output_leftover = {name = recipe.output.name, num = leftover}
State:blocked(pos, nvm)
reactor_cmnd(pos, "stop")
return
end
State:keep_running(pos, nvm, COUNTDOWN_TICKS)
end
end
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
dosing(pos, nvm, elapsed)
return State:is_active(nvm)
end
end
local function on_rightclick(pos)
local nvm = techage.get_nvm(pos)
@ -243,10 +269,14 @@ local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
if not nvm.running then
recipes.on_receive_fields(pos, formname, fields, player)
if not nvm.running then
if recipes.on_receive_fields(pos, formname, fields, player) then
local mem = techage.get_mem(pos)
mem.waste_leftover = nil
mem.output_leftover = nil
end
end
local mem = techage.get_mem(pos)
mem.dbg_cycles = 5
@ -301,7 +331,7 @@ minetest.register_node("techage:ta4_doser_on", {
"techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_hole_pipe.png",
"techage_filling_ta4.png^techage_frame_ta4.png",
{
image = "techage_filling8_ta4.png^techage_frame8_ta4.png^techage_appl_pump_up8.png",
name = "techage_filling8_ta4.png^techage_frame8_ta4.png^techage_appl_pump_up8.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -319,7 +349,7 @@ minetest.register_node("techage:ta4_doser_on", {
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_timer = node_timer,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
diggable = false,
@ -332,18 +362,27 @@ liquid.register_nodes({"techage:ta4_doser", "techage:ta4_doser_on"}, Pipe, "pump
techage.register_node({"techage:ta4_doser", "techage:ta4_doser_on"}, {
on_recv_message = function(pos, src, topic, payload)
return State:on_receive_message(pos, topic, payload)
if topic == "recipe" then
techage.recipes.set_recipe(pos, "ta4_doser", payload)
return true
else
return State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
return State:on_beduino_request_data(pos, topic, payload)
end,
})
if minetest.global_exists("unified_inventory") then
unified_inventory.register_craft_type("ta4_doser", {
description = S("TA4 Reactor"),
icon = 'techage_reactor_filler_plan.png',
width = 2,
height = 2,
})
end
techage.recipes.register_craft_type("ta4_doser", {
description = S("TA4 Reactor"),
icon = 'techage_reactor_filler_plan.png',
width = 2,
height = 2,
})
minetest.register_craft({
output = "techage:ta4_doser",

View File

@ -8,7 +8,7 @@
AGPL v3
See LICENSE.txt for more information
TA4 Liquid Filter
]]--
@ -17,10 +17,9 @@
-- If necessary, this can be adjusted later.
local M = minetest.get_meta
local networks = techage.networks
local S = techage.S
local Pipe = techage.LiquidPipe
local liquid = techage.liquid
local liquid = networks.liquid
-- Checks if the filter structure is ok and returns the amount of gravel
local function checkStructure(pos)
@ -100,9 +99,6 @@ minetest.register_node("techage:ta4_liquid_filter_filler", {
after_place_node = function(pos)
Pipe:after_place_node(pos)
end,
tubelib2_on_update2 = function(pos, dir, tlib2, node)
liquid.update_network(pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
@ -115,9 +111,10 @@ minetest.register_node("techage:ta4_liquid_filter_filler", {
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
liquid = {
liquid.register_nodes({"techage:ta4_liquid_filter_filler"},
Pipe, "tank", {"U"}, {
capa = 1,
peek = function(...) return nil end,
put = function(pos, indir, name, amount)
@ -146,15 +143,9 @@ minetest.register_node("techage:ta4_liquid_filter_filler", {
untake = function(pos, outdir, name, amount, player_name)
return amount
end,
},
}
)
networks = {
pipe2 = {
sides = {U = 1}, -- Pipe connection sides
ntype = "tank",
},
},
})
minetest.register_node("techage:ta4_liquid_filter_sink", {
description = S("TA4 Liquid Filter Sink"),
@ -181,9 +172,6 @@ minetest.register_node("techage:ta4_liquid_filter_sink", {
after_place_node = function(pos)
Pipe:after_place_node(pos)
end,
tubelib2_on_update2 = function(pos, dir, tlib2, node)
liquid.update_network(pos)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
end,
@ -195,16 +183,12 @@ minetest.register_node("techage:ta4_liquid_filter_sink", {
groups = {cracky=2},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {
sides = {R = 1}, -- Pipe connection sides
ntype = "pump",
},
},
})
Pipe:add_secondary_node_names({"techage:ta4_liquid_filter_filler", "techage:ta4_liquid_filter_sink"})
liquid.register_nodes({"techage:ta4_liquid_filter_sink"},
Pipe, "pump", {"R"}, {}
)
minetest.register_craft({
output = 'techage:ta4_liquid_filter_filler',
@ -222,4 +206,4 @@ minetest.register_craft({
{'basic_materials:concrete_block', 'techage:ta3_pipeS', 'techage:ta3_pipeS'},
{'basic_materials:concrete_block', 'basic_materials:concrete_block', 'basic_materials:concrete_block'},
}
})
})

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
TA4 Reactor
]]--
@ -48,16 +48,13 @@ minetest.register_node("techage:ta4_reactor_fillerpipe", {
Pipe:after_place_node(pos1)
end
end,
-- tubelib2_on_update2 = function(pos, dir, tlib2, node)
-- liquid.update_network(pos, dir, tlib2, node)
-- end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
end,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
sunlight_propagates = true,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},
@ -67,7 +64,7 @@ minetest.register_node("techage:ta4_reactor_fillerpipe", {
local function stand_cmnd(pos, cmnd, payload)
return techage.transfer(
{x = pos.x, y = pos.y-1, z = pos.z},
{x = pos.x, y = pos.y-1, z = pos.z},
5, -- outdir
cmnd, -- topic
payload, -- payload
@ -86,11 +83,11 @@ techage.register_node({"techage:ta4_reactor_fillerpipe"}, {
on_transfer = function(pos, in_dir, topic, payload)
if topic == "check" then
local pos2,node = Pipe:get_node(pos, 5)
if not node or node.name ~= "techage:ta4_reactor" then
if not node or node.name ~= "techage:ta4_reactor" then
return false
end
pos2,node = Pipe:get_node(pos2, 5)
if not node or node.name ~= "techage:ta4_reactor_stand" then
if not node or node.name ~= "techage:ta4_reactor_stand" then
return false
end
return true
@ -98,7 +95,7 @@ techage.register_node({"techage:ta4_reactor_fillerpipe"}, {
return base_waste(pos, payload or {})
elseif topic == "catalyst" then
local pos2,node = Pipe:get_node(pos, 5)
if not node or node.name ~= "techage:ta4_reactor" then
if not node or node.name ~= "techage:ta4_reactor" then
return
end
local inv = M(pos2):get_inventory()
@ -161,7 +158,7 @@ minetest.register_node("techage:ta4_reactor", {
end,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
paramtype = "light",
use_texture_alpha = techage.CLIP,
paramtype2 = "facedir",
@ -171,6 +168,28 @@ minetest.register_node("techage:ta4_reactor", {
sounds = default.node_sound_metal_defaults(),
})
techage.register_node({"techage:ta4_reactor"}, {
on_inv_request = function(pos, in_dir, access_type)
local meta = minetest.get_meta(pos)
return meta:get_inventory(), "main"
end,
on_pull_item = function(pos, in_dir, num, item_name)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.get_items(pos, inv, "main", num)
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return techage.put_items(inv, "main", stack)
end,
})
minetest.register_craft({
output = 'techage:ta4_reactor',
recipe = {
@ -194,7 +213,7 @@ minetest.register_lbm({
name = "techage:update_reactor",
nodenames = {
"techage:ta4_reactor",
"techage:ta4_reactor",
},
run_at_every_load = true,

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
TA4 Reactor Stand and Base
]]--
@ -26,7 +26,7 @@ local function play_sound(pos)
local mem = techage.get_mem(pos)
if not mem.handle or mem.handle == -1 then
mem.handle = minetest.sound_play("techage_reactor", {
pos = pos,
pos = pos,
gain = 0.5,
max_hear_distance = 10,
loop = true})
@ -58,8 +58,8 @@ local function on_nopower(pos)
nvm.running = false
end
local function is_running(pos, nvm)
return nvm.running
local function is_running(pos, nvm)
return nvm.running
end
minetest.register_node("techage:ta4_reactor_stand", {
@ -76,14 +76,14 @@ minetest.register_node("techage:ta4_reactor_stand", {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
fixed = {
{ -8/16, 2/16, -8/16, 8/16, 4/16, 8/16 },
{ -8/16, -8/16, -8/16, -6/16, 8/16, -6/16 },
{ 6/16, -8/16, -8/16, 8/16, 8/16, -6/16 },
{ -8/16, -8/16, 6/16, -6/16, 8/16, 8/16 },
{ 6/16, -8/16, 6/16, 8/16, 8/16, 8/16 },
{-1/8, -4/8, -1/8, 1/8, 4/8, 1/8},
{-4/8, -1/8, -1/8, 4/8, 1/8, 1/8},
{-4/8, -1/8, -3/8, -3/8, 1/8, 3/8},
@ -94,7 +94,7 @@ minetest.register_node("techage:ta4_reactor_stand", {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, 1/2, 1/2},
},
after_place_node = function(pos, placer)
local nvm = techage.get_nvm(pos)
M(pos):set_string("infotext", S("off"))
@ -102,13 +102,6 @@ minetest.register_node("techage:ta4_reactor_stand", {
Pipe:after_place_node(pos)
Cable:after_place_node(pos)
end,
-- tubelib2_on_update2 = function(pos, dir, tlib2, node)
-- if tlib2.tube_type == "ele1" then
-- power.update_network(pos, dir, tlib2, node)
-- else
-- liquid.update_network(pos, dir, tlib2, node)
-- end
-- end,
on_timer = function(pos, elapsed)
local nvm = techage.get_nvm(pos)
local consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED)
@ -124,7 +117,7 @@ minetest.register_node("techage:ta4_reactor_stand", {
Cable:after_dig_node(pos)
techage.del_mem(pos)
end,
paramtype = "light",
use_texture_alpha = techage.CLIP,
paramtype2 = "facedir",
@ -162,7 +155,7 @@ techage.register_node({"techage:ta4_reactor_stand"}, {
local nvm = techage.get_nvm(pos)
if nvm.has_power then
play_sound(pos)
end
end
end,
})
@ -177,18 +170,15 @@ minetest.register_node("techage:ta4_reactor_base", {
"techage_concrete.png",
"techage_concrete.png",
},
after_place_node = function(pos, placer)
M(pos):set_int("outdir", networks.side_to_outdir(pos, "R"))
Pipe:after_place_node(pos)
end,
-- tubelib2_on_update2 = function(pos, dir, tlib2, node)
-- liquid.update_network(pos, dir, tlib2, node)
-- end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
Pipe:after_dig_node(pos)
end,
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
groups = {cracky=2},

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
TA3 Coal Power Station Boiler Base
]]--
@ -39,7 +39,7 @@ minetest.register_node("techage:coalboiler_base", {
after_place_node = after_place_node,
after_dig_node = after_dig_node,
paramtype = "light",
paramtype2 = "facedir",
on_rotate = screwdriver.disallow,
@ -49,7 +49,7 @@ minetest.register_node("techage:coalboiler_base", {
})
Pipe:add_secondary_node_names({"techage:coalboiler_base"})
-- for logical communication
techage.register_node({"techage:coalboiler_base"}, {
on_transfer = function(pos, in_dir, topic, payload)
@ -65,4 +65,3 @@ minetest.register_craft({
{"default:stone", "default:stone", "default:stone"},
},
})

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
TA3 Coal Power Station Boiler Top
]]--
@ -62,14 +62,14 @@ minetest.register_node("techage:coalboiler_top", {
type = "fixed",
fixed = {-13/32, -48/32, -13/32, 13/32, 16/32, 13/32},
},
can_dig = boiler.can_dig,
on_timer = node_timer,
on_rightclick = boiler.on_rightclick,
after_place_node = after_place_node,
after_dig_node = after_dig_node,
on_punch = boiler.on_punch,
paramtype = "light",
paramtype2 = "facedir",
groups = {cracky=1},
@ -108,4 +108,3 @@ minetest.register_craft({
{"default:stone", "", "default:stone"},
},
})

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
TA3 Cooler
]]--
@ -19,7 +19,7 @@ local S = techage.S
local Pipe = techage.SteamPipe
local function transfer(pos, in_dir, topic, payload)
return techage.transfer(pos, in_dir, topic, payload, Pipe,
return techage.transfer(pos, in_dir, topic, payload, Pipe,
{"techage:coalboiler_base"})
end
@ -37,7 +37,7 @@ minetest.register_node("techage:cooler", {
tiles = {
-- up, down, right, left, back, front
{
image = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
name = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -47,7 +47,7 @@ minetest.register_node("techage:cooler", {
},
},
{
image = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
name = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -61,10 +61,10 @@ minetest.register_node("techage:cooler", {
"techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png",
},
after_place_node = after_place_node,
after_dig_node = after_dig_node,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
@ -78,7 +78,7 @@ minetest.register_node("techage:cooler_on", {
tiles = {
-- up, down, right, left, back, front
{
image = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
name = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -88,7 +88,7 @@ minetest.register_node("techage:cooler_on", {
},
},
{
image = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
name = "techage_filling4_ta3.png^techage_appl_cooler4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -102,10 +102,10 @@ minetest.register_node("techage:cooler_on", {
"techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png",
},
after_place_node = after_place_node,
after_dig_node = after_dig_node,
paramtype2 = "facedir",
drop = "techage:cooler",
groups = {cracky=2, crumbly=2, choppy=2, not_in_creative_inventory=1},
@ -131,4 +131,3 @@ minetest.register_craft({
{"basic_materials:steel_bar", "default:wood", "basic_materials:steel_bar"},
},
})

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Coal Power Station Firebox
]]--
@ -25,7 +25,7 @@ local BURN_CYCLE_FACTOR = 0.5
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
local power = techage.transfer(
{x=pos.x, y=pos.y+2, z=pos.z},
{x=pos.x, y=pos.y+2, z=pos.z},
nil, -- outdir
"trigger", -- topic
nil, -- payload
@ -34,7 +34,7 @@ local function node_timer(pos, elapsed)
)
nvm.burn_cycles = (nvm.burn_cycles or 0) - math.max((power or 0.02), 0.02)
if nvm.burn_cycles <= 0 then
local taken = firebox.get_fuel(pos)
local taken = firebox.get_fuel(pos)
if taken then
nvm.burn_cycles = (firebox.Burntime[taken:get_name()] or 1) / CYCLE_TIME * BURN_CYCLE_FACTOR
nvm.burn_cycles_total = nvm.burn_cycles
@ -83,10 +83,10 @@ minetest.register_node("techage:coalfirebox", {
allow_metadata_inventory_put = firebox.allow_metadata_inventory_put,
allow_metadata_inventory_take = firebox.allow_metadata_inventory_take,
on_rightclick = firebox.on_rightclick,
after_place_node = function(pos, placer)
if firebox.is_free_position(pos, placer:get_player_name()) then
techage.add_node(pos, "techage:coalfirebox")
techage.add_node(pos, "techage:coalfirebox", true)
local nvm = techage.get_nvm(pos)
nvm.running = false
nvm.burn_cycles = 0
@ -149,7 +149,7 @@ minetest.register_node("techage:coalfirehole_on", {
"techage_coal_boiler.png^[colorize:black:80",
"techage_coal_boiler.png^[colorize:black:80",
{
image = "techage_coal_boiler4.png^[colorize:black:80^techage_appl_firehole4.png",
name = "techage_coal_boiler4.png^[colorize:black:80^techage_appl_firehole4.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -207,6 +207,18 @@ techage.register_node({"techage:coalfirebox"}, {
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 128 then
return 0, techage.get_node_lvm(pos).name
elseif topic == 129 then
return 0, {nvm.running and techage.RUNNING or techage.STOPPED}
elseif topic == 132 then
return 0, {techage.fuel.get_fuel_amount(nvm)}
else
return 2, ""
end
end,
})
minetest.register_craft({

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Power Station Generator
]]--
@ -30,7 +30,7 @@ local function formspec(self, pos, nvm)
end
local function transfer_turbine(pos, topic, payload)
return techage.transfer(pos, "L", topic, payload, nil,
return techage.transfer(pos, "L", topic, payload, nil,
{"techage:turbine", "techage:turbine_on"})
end
@ -145,7 +145,7 @@ minetest.register_node("techage:generator", {
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_generator.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_generator.png^[transformFX]",
},
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_timer = node_timer,
@ -170,7 +170,7 @@ minetest.register_node("techage:generator_on", {
"techage_filling_ta3.png^techage_appl_hole_electric.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_open.png^techage_frame_ta3.png",
{
image = "techage_filling4_ta3.png^techage_appl_generator4.png^techage_frame4_ta3.png",
name = "techage_filling4_ta3.png^techage_appl_generator4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -180,7 +180,7 @@ minetest.register_node("techage:generator_on", {
},
},
{
image = "techage_filling4_ta3.png^techage_appl_generator4.png^[transformFX]^techage_frame4_ta3.png",
name = "techage_filling4_ta3.png^techage_appl_generator4.png^[transformFX]^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -190,7 +190,7 @@ minetest.register_node("techage:generator_on", {
},
},
},
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
on_timer = node_timer,
@ -231,6 +231,17 @@ techage.register_node({"techage:generator", "techage:generator_on"}, {
return State:on_receive_message(pos, topic, payload)
end
end,
on_beduino_receive_cmnd = function(pos, src, topic, payload)
return State:on_beduino_receive_cmnd(pos, topic, payload)
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 135 then -- Delivered Power
return 0, {math.floor((nvm.provided or 0) + 0.5)}
else
return State:on_beduino_request_data(pos, topic, payload)
end
end,
})
-- used by power terminal
@ -247,7 +258,7 @@ control.register_nodes({"techage:generator", "techage:generator_on"}, {
running = techage.is_running(nvm) or false,
available = PWR_PERF,
provided = nvm.provided or 0,
termpoint = meta:get_string("termpoint"),
termpoint = meta:get_string("termpoint"),
}
end
return false

View File

@ -3,11 +3,11 @@
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
Copyright (C) 2019-2022 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA3 Coal Power Station Firebox
]]--
@ -28,7 +28,7 @@ local BURN_CYCLE_FACTOR = 0.5
local function node_timer(pos, elapsed)
local nvm = techage.get_nvm(pos)
local power = techage.transfer(
{x=pos.x, y=pos.y+2, z=pos.z},
{x=pos.x, y=pos.y+2, z=pos.z},
nil, -- outdir
"trigger", -- topic
nil, -- payload
@ -85,10 +85,10 @@ minetest.register_node("techage:oilfirebox", {
can_dig = fuel.can_dig,
on_rightclick = fuel.on_rightclick,
on_receive_fields = fuel.on_receive_fields,
after_place_node = function(pos, placer)
if firebox.is_free_position(pos, placer:get_player_name()) then
techage.add_node(pos, "techage:oilfirebox")
techage.add_node(pos, "techage:oilfirebox", true)
local nvm = techage.get_nvm(pos)
nvm.running = false
nvm.burn_cycles = 0
@ -103,7 +103,7 @@ minetest.register_node("techage:oilfirebox", {
return true
end
end,
on_destruct = function(pos)
firebox.set_firehole(pos, nil)
end,
@ -132,6 +132,18 @@ techage.register_node({"techage:oilfirebox"}, {
return "unsupported"
end
end,
on_beduino_request_data = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == 128 then
return 0, techage.get_node_lvm(pos).name
elseif topic == 129 then
return 0, {nvm.running and techage.RUNNING or techage.STOPPED}
elseif topic == 132 then
return 0, {fuel.get_fuel_amount(nvm)}
else
return 2, ""
end
end,
})
minetest.register_craft({
@ -142,5 +154,3 @@ minetest.register_craft({
{'', '', ''},
},
})

View File

@ -7,7 +7,7 @@
AGPL v3
See LICENSE.txt for more information
TA3 Power Station Turbine
]]--
@ -19,12 +19,12 @@ local S = techage.S
local Pipe = techage.SteamPipe
local function transfer_cooler(pos, topic, payload)
return techage.transfer(pos, 6, topic, payload, Pipe,
return techage.transfer(pos, 6, topic, payload, Pipe,
{"techage:cooler", "techage:cooler_on"})
end
local function transfer_generator(pos, topic, payload)
return techage.transfer(pos, "R", topic, payload, nil,
return techage.transfer(pos, "R", topic, payload, nil,
{"techage:generator", "techage:generator_on"})
end
@ -41,7 +41,7 @@ local function play_sound(pos)
local mem = techage.get_mem(pos)
if not mem.handle or mem.handle == -1 then
mem.handle = minetest.sound_play("techage_turbine", {
pos = pos,
pos = pos,
gain = 1,
max_hear_distance = 15,
loop = true})
@ -69,7 +69,7 @@ local function after_dig_node(pos, oldnode)
techage.del_mem(pos)
end
local function tubelib2_on_update2(pos, outdir, tlib2, node)
local function tubelib2_on_update2(pos, outdir, tlib2, node)
swap_node(pos, "techage:turbine")
stop_sound(pos)
end
@ -82,14 +82,14 @@ minetest.register_node("techage:turbine", {
"techage_filling_ta3.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_open.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
"techage_filling_ta3.png^techage_appl_turbine.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_appl_turbine.png^techage_frame_ta3.png^[transformFX",
"techage_filling_ta3.png^techage_appl_turbine.png^techage_frame_ta3.png",
},
after_place_node = after_place_node,
after_dig_node = after_dig_node,
tubelib2_on_update2 = tubelib2_on_update2,
paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, choppy=2},
on_rotate = screwdriver.disallow,
@ -105,7 +105,7 @@ minetest.register_node("techage:turbine_on", {
"techage_filling_ta3.png^techage_appl_open.png^techage_frame_ta3.png",
"techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png",
{
image = "techage_filling4_ta3.png^techage_appl_turbine4.png^techage_frame4_ta3.png",
name = "techage_filling4_ta3.png^techage_appl_turbine4.png^techage_frame4_ta3.png^[transformFX",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -115,7 +115,7 @@ minetest.register_node("techage:turbine_on", {
},
},
{
image = "techage_filling4_ta3.png^techage_appl_turbine4.png^techage_frame4_ta3.png",
name = "techage_filling4_ta3.png^techage_appl_turbine4.png^techage_frame4_ta3.png",
backface_culling = false,
animation = {
type = "vertical_frames",
@ -125,9 +125,9 @@ minetest.register_node("techage:turbine_on", {
},
},
},
tubelib2_on_update2 = tubelib2_on_update2,
paramtype2 = "facedir",
groups = {not_in_creative_inventory=1},
diggable = false,
@ -168,7 +168,7 @@ techage.register_node({"techage:turbine", "techage:turbine_on"}, {
on_node_load = function(pos, node)
if node.name == "techage:turbine_on" then
play_sound(pos)
end
end
end,
})
@ -180,4 +180,3 @@ minetest.register_craft({
{"default:wood", "techage:iron_ingot", "basic_materials:steel_bar"},
},
})

89
collider/cooler.lua Normal file
View File

@ -0,0 +1,89 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Cooler as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local Pipe = techage.LiquidPipe
minetest.register_node("techage:ta4_collider_cooler", {
description = S("TA4 Collider Cooler"),
tiles = {
-- up, down, right, left, back, front
{
name = "techage_appl_cooler4.png^techage_frame4_ta4_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
{
name = "techage_appl_cooler4.png^techage_frame4_ta4_top.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 0.4,
},
},
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_hole_pipe.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_hole_pipe.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_cooler.png",
"techage_filling_ta4.png^techage_frame_ta4.png^techage_cooler.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {},
},
after_place_node = function(pos, placer, itemstack)
Pipe:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end,
})
Pipe:add_secondary_node_names({"techage:ta4_collider_cooler"})
Pipe:set_valid_sides("techage:ta4_collider_cooler", {"R", "L"})
techage.register_node({"techage:ta4_collider_cooler"}, {
on_transfer = function(pos, in_dir, topic, payload)
if topic == "cooler" then
return true
else
return false
end
end,
})
minetest.register_craft({
output = "techage:ta4_collider_cooler",
recipe = {
{'', 'dye:blue', ''},
{'', 'techage:cooler', ''},
{'', 'techage:aluminum', ''},
},
})

448
collider/detector.lua Normal file
View File

@ -0,0 +1,448 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Detector as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local getpos = techage.assemble.get_pos
local CYCLE_TIME = 2
local TNO_MAGNETS = 22
local IMPROBABILITY = 40 -- every 40 min
-- one point per 40 min: check every 20 s => factor = 40 * 3 = 120
IMPROBABILITY = (minetest.settings:get("techage_expoint_rate_in_min") or 40) * 3
local TIME_SLOTS = 10
local Schedule = {[0] =
-- Route: 0 = forward, 1 = right, 2 = backward, 3 = left
-- Gas left/right
{name = "techage:ta4_collider_pipe_inlet", yoffs = 1, route = {3,3,3,2}, check = techage.gas_inlet_check},
{name = "techage:ta4_collider_pipe_inlet", yoffs = 1, route = {1,1,1,2}, check = techage.gas_inlet_check},
-- Power left/right
{name = "techage:ta4_collider_cable_inlet", yoffs = 2, route = {3,3,3}, check = techage.power_inlet_check},
{name = "techage:ta4_collider_cable_inlet", yoffs = 2, route = {1,1,1}, check = techage.power_inlet_check},
-- Cooler
{name = "techage:ta4_collider_pipe_inlet", yoffs = 0, route = {0}, check = techage.cooler_check},
{name = "techage:ta4_collider_pipe_inlet", yoffs = 2, route = {0}, check = techage.cooler_check},
-- Air outlet
{name = "techage:ta4_collider_pipe_outlet", yoffs = 2, route = {}, check = techage.air_outlet_check},
-- All nodes
{name = "shell", yoffs = 0, route = {}, check = nil},
}
local function play_sound(pos)
minetest.sound_play("techage_hum", {
pos = pos,
gain = 0.5,
max_hear_distance = 10,
})
end
local function terminal_message(pos, msg)
local term_num = M(pos):contains("term_num") and M(pos):get_string("term_num")
local own_num = M(pos):get_string("node_number")
if term_num and own_num then
techage.send_single(own_num, term_num, "text", msg)
end
end
local function experience_points(pos)
if math.random(IMPROBABILITY) == 1 then
local owner = M(pos):get_string("owner")
local own_num = M(pos):get_string("node_number")
local player = minetest.get_player_by_name(owner)
if player then
if techage.add_expoint(player, own_num) then
terminal_message(pos, "Experience point reached!")
end
end
end
end
local function check_shell(pos, param2)
local pos1 = getpos(pos, param2, {3,3,3,2}, 0)
local pos2 = getpos(pos, param2, {1,1,1,0}, 2)
local _, tbl = minetest.find_nodes_in_area(pos1, pos2, {"techage:ta4_detector_magnet", "techage:ta4_colliderblock", "default:obsidian_glass"})
if tbl["techage:ta4_detector_magnet"] < 16 then
return false, "Magnet missing"
elseif tbl["techage:ta4_colliderblock"] < 31 then
return false, "Steel block missing"
elseif tbl["default:obsidian_glass"] < 1 then
return false, "Obsidian glass missing"
end
return true
end
local function check_state(pos)
-- Cyclically check all connections
local param2 = minetest.get_node(pos).param2
local nvm = techage.get_nvm(pos)
nvm.ticks = (nvm.ticks or 0) + 1
local idx = nvm.ticks % TIME_SLOTS
local item = Schedule[idx]
if idx == 1 then
nvm.result = true
end
if item then
if item.name == "shell" then
local res, err = check_shell(pos, param2)
if not res then
nvm.result = false
nvm.runnning = false
terminal_message(pos, (err or "unknown") .. "!!!")
return nvm.result
end
else
local pos2 = getpos(pos, param2, item.route, item.yoffs)
local nvm2 = techage.get_nvm(pos2)
local meta2 = M(pos2)
local node2 = minetest.get_node(pos2)
if item.name == node2.name then
local res, err = item.check(pos2, node2, meta2, nvm2)
--print("check_state", idx, res, err)
if not res then
nvm.result = false
nvm.runnning = false
terminal_message(pos, (err or "unknown") .. "!!!")
return nvm.result
end
else
nvm.result = false
nvm.runnning = false
terminal_message(pos, "Detector defect!!!")
end
end
elseif idx == #Schedule + 1 then
return nvm.result
end
end
local function add_laser(pos)
local param2 = minetest.get_node(pos).param2
local pos1 = getpos(pos, param2, {3,3}, 1)
local pos2 = getpos(pos, param2, {1,1,1}, 1)
techage.del_laser(pos)
techage.add_laser(pos, pos1, pos2)
end
local function create_task(pos, task)
local mem = techage.get_mem(pos)
if not mem.co then
mem.co = coroutine.create(task)
end
local _, err = coroutine.resume(mem.co, pos)
if err then
mem.co = nil
--print(err)
return
end
minetest.after(0.4, create_task, pos, task)
end
-- Call on_cyclic_check of all magents so that the magnets don't need a FLB.
local function magnets_on_cyclic_check(pos, nvm)
local ndef = minetest.registered_nodes["techage:ta4_magnet"]
for idx,pos2 in ipairs(nvm.magnet_positions or {}) do
local res = ndef.on_cyclic_check(pos2)
if res == -2 then
terminal_message(pos, "Magnet #" .. idx .. " defect!!!")
return false
elseif res == -1 then
terminal_message(pos, "Vacuum defect!!!")
techage.air_outlet_reset({x=pos.x, y=pos.y + 2, z=pos.z})
return false
end
end
return true
end
-- Turn off all magnets so that they don't consume power
local function magnets_turn_off(pos, nvm)
local ndef = minetest.registered_nodes["techage:ta4_magnet"]
for idx,pos2 in ipairs(nvm.magnet_positions or {}) do
ndef.on_turn_off(pos2)
end
end
local function cable_inlets_turn_on_off(pos, on)
local turn_on_off = function(pos, param2, item)
local pos2 = getpos(pos, param2, item.route, item.yoffs)
local node2 = minetest.get_node(pos2)
if item.name == node2.name then
local nvm = techage.get_nvm(pos2)
techage.power_inlet_turn_on_off(pos2, nvm, on)
end
end
local param2 = minetest.get_node(pos).param2
turn_on_off(pos, param2, Schedule[2])
turn_on_off(pos, param2, Schedule[3])
end
minetest.register_node("techage:ta4_detector_core", {
description = S("TA4 Collider Detector Core"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^techage_collider_detector_core.png",
"default_steel_block.png^techage_collider_detector_core.png",
"default_steel_block.png^techage_collider_detector_core.png",
"default_steel_block.png^techage_collider_detector_core.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack)
local nvm = techage.get_nvm(pos)
local meta = M(pos)
local own_num = techage.add_node(pos, "techage:ta4_detector_core")
meta:set_string("node_number", own_num)
meta:set_string("owner", placer:get_player_name())
M({x=pos.x, y=pos.y - 1, z=pos.z}):set_string("infotext", S("TA4 Collider Detector") .. " " .. own_num)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
on_timer = function(pos, elapsed)
local nvm = techage.get_nvm(pos)
if nvm.running then
if not magnets_on_cyclic_check(pos, nvm) then
techage.del_laser(pos)
terminal_message(pos, "Detector stopped.")
magnets_turn_off(pos, nvm)
cable_inlets_turn_on_off(pos, false)
nvm.running = false
nvm.magnet_positions = nil
else
local res = check_state(pos)
if res == true then
experience_points(pos)
add_laser(pos)
if nvm.ticks <= TIME_SLOTS then -- only once
terminal_message(pos, "Detector running.")
end
elseif res == false then
techage.del_laser(pos)
magnets_turn_off(pos, nvm)
cable_inlets_turn_on_off(pos, false)
nvm.running = false
nvm.magnet_positions = nil
terminal_message(pos, "Detector stopped.")
end
if nvm.running then
play_sound(pos)
end
end
end
return true
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
techage.on_remove_collider(digger)
techage.remove_node(pos, oldnode, oldmetadata)
techage.del_mem(pos)
end,
})
local function check_expr(own_num, term_num, text, expr)
techage.send_single(own_num, term_num, "text", text .. "..." .. (expr and "ok" or "error!!!"))
return expr
end
local function start_task(pos)
local term_num = M(pos):contains("term_num") and M(pos):get_string("term_num")
local param2 = minetest.get_node(pos).param2
local pos2 = getpos(pos, param2, {3,3,3}, 1)
local own_num = M(pos):get_string("node_number")
local nvm = techage.get_nvm(pos)
nvm.magnet_positions = {}
if term_num and param2 and pos2 then
techage.send_single(own_num, term_num, "text", "#### Start ####")
coroutine.yield()
local resp = techage.tube_inlet_command(pos2, "enumerate", 1)
if not check_expr(own_num, term_num, "- Check number of magnets", resp == TNO_MAGNETS) then
nvm.locked = false
return
end
coroutine.yield()
techage.send_single(own_num, term_num, "text", "- Check position of magnets...")
resp = techage.tube_inlet_command(pos2, "distance")
if resp ~= true then
techage.send_single(own_num, term_num, "append", "#" .. resp .. " defect!!!")
nvm.locked = false
return
end
techage.send_single(own_num, term_num, "append", "ok")
coroutine.yield()
techage.send_single(own_num, term_num, "text", "- Start magnets...")
local t = {}
for num = 1, TNO_MAGNETS do
local resp = techage.tube_inlet_command(pos2, "pos", num)
if not resp or type(resp) ~= "table" then
techage.send_single(own_num, term_num, "append", "#" .. num .. " defect!!!")
nvm.magnet_positions = nil
nvm.locked = false
return
else
t[#t + 1] = resp
end
coroutine.yield()
end
nvm.magnet_positions = t
techage.send_single(own_num, term_num, "append", "ok")
cable_inlets_turn_on_off(pos, true)
coroutine.yield()
techage.send_single(own_num, term_num, "text", "- Check magnets...")
-- The check will be performed by the timer, so wait 5 sec.
for i = 1,14 do
coroutine.yield()
end
if nvm.magnet_positions then
techage.send_single(own_num, term_num, "append", "ok")
else
nvm.locked = false
return
end
coroutine.yield()
techage.send_single(own_num, term_num, "text", "- Check detector...")
for _,item in ipairs(Schedule)do
if item.name == "shell" then
local res, err = check_shell(pos, param2)
if not res then
techage.send_single(own_num, term_num, "append", err .. "!!!")
nvm.magnet_positions = nil
nvm.locked = false
cable_inlets_turn_on_off(pos, false)
return
end
else
local pos2 = getpos(pos, param2, item.route, item.yoffs)
local nvm2 = techage.get_nvm(pos2)
local meta2 = M(pos2)
local node2 = minetest.get_node(pos2)
if item.name == node2.name then
local res, err = item.check(pos2, node2, meta2, nvm2)
if not res then
techage.send_single(own_num, term_num, "append", err .. "!!!")
nvm.magnet_positions = nil
nvm.locked = false
cable_inlets_turn_on_off(pos, false)
return
end
else
techage.send_single(own_num, term_num, "append", "defect!!!")
nvm.magnet_positions = nil
nvm.locked = false
cable_inlets_turn_on_off(pos, false)
return
end
coroutine.yield()
end
end
techage.send_single(own_num, term_num, "append", "ok")
coroutine.yield()
techage.send_single(own_num, term_num, "text", "Collider starting...")
nvm.ticks = 0
nvm.running = true
end
end
local function test_magnet(pos, payload)
local term_num = M(pos):contains("term_num") and M(pos):get_string("term_num")
local param2 = minetest.get_node(pos).param2
local pos2 = getpos(pos, param2, {3,3,3}, 1)
local own_num = M(pos):get_string("node_number")
local magnet_num = tonumber(payload)
local res, err = techage.tube_inlet_command(pos2, "test", magnet_num)
if res then
techage.send_single(own_num, term_num, "text", "magnet #" .. magnet_num .. ": ok")
else
techage.send_single(own_num, term_num, "text", "magnet #" .. magnet_num .. ": " .. (err or "unknown error") .. "!!!")
end
end
techage.register_node({"techage:ta4_detector_core"}, {
on_recv_message = function(pos, src, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "connect" then
M(pos):set_string("term_num", src)
return true
elseif topic == "start" then
-- Worker block
nvm.locked = true
create_task(pos, start_task)
return true
elseif topic == "stop" then
nvm.running = false
techage.del_laser(pos)
nvm.locked = false
magnets_turn_off(pos, nvm)
cable_inlets_turn_on_off(pos, false)
nvm.magnet_positions = nil
return "Detector stopped."
elseif topic == "status" then
if nvm.running == true then
return "running"
elseif nvm.result == false then
return "fault"
else
return "stopped"
end
elseif topic == "test"then
if payload and tonumber(payload) then
test_magnet(pos, payload)
return true
else
return "Invalid magnet number"
end
elseif topic == "points" then
local owner = M(pos):get_string("owner")
local player = minetest.get_player_by_name(owner)
if player then
local points = techage.get_expoints(player)
return "Ex. Points = " .. points
end
else
return "unsupported"
end
end,
on_node_load = function(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})
minetest.register_craft({
output = "techage:ta4_detector_core",
recipe = {
{'techage:aluminum', 'basic_materials:heating_element', 'default:steel_ingot'},
{'default:diamond', 'techage:ta4_wlanchip', 'techage:electric_cableS'},
{'default:steel_ingot', '', 'techage:aluminum'},
},
})

375
collider/inlets.lua Normal file
View File

@ -0,0 +1,375 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Tube/Pipe Inputs/Outputs as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local PWR_NEEDED = 15
local CYCLE_TIME = 2
local GAS_CAPA = 20
local AIR_CAPA = 1000
local VTube = techage.VTube
local Pipe = techage.LiquidPipe
local Cable = techage.ElectricCable
local power = networks.power
local liquid = networks.liquid
--------------------------------------------------------------------------------
-- Tube Input
--------------------------------------------------------------------------------
minetest.register_node("techage:ta4_collider_tube_inlet", {
description = S("TA4 Collider Tube Input"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^techage_collider_tube_open.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-4/8, -4/8, -4/8, -1/8, 4/8, 4/8},
{ 1/8, -4/8, -4/8, 4/8, 4/8, 4/8},
{-4/8, 1/8, -4/8, 4/8, 4/8, 4/8},
{-4/8, -4/8, -4/8, 4/8, -1/8, 4/8},
},
},
selection_box = {
type = "fixed",
fixed = {-4/8, -4/8, -4/8, 4/8, 4/8, 4/8},
},
paramtype2 = "facedir",
paramtype = "light",
use_texture_alpha = techage.CLIP,
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack)
VTube:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode)
VTube:after_dig_node(pos)
techage.del_mem(pos)
end,
})
VTube:add_secondary_node_names({"techage:ta4_collider_tube_inlet"})
VTube:set_valid_sides("techage:ta4_collider_tube_inlet", {"F"})
-- Called from the detector via tube ring
techage.register_node({"techage:ta4_collider_tube_inlet"}, {
on_transfer = function(pos, in_dir, topic, payload)
if topic == "distance" then
return pos
elseif topic == "enumerate" and payload then
return payload - 1
elseif topic == "check" then
local nvm = techage.get_nvm(pos)
nvm.check_received = true
return true
end
end,
})
-- Used by the detector to check the tube connection
function techage.tube_inlet_command(pos, command, payload)
if command == "distance" then
local pos2 = techage.transfer(pos, "F", command, payload, VTube, {"techage:ta4_magnet"})
if type(pos2) == "table" then
local dist = math.abs(pos.x - pos2.x) + math.abs(pos.z - pos2.z)
if pos.y == pos2.y and dist == VTube.max_tube_length + 1 then
return true
end
return 0
else
return pos2
end
end
return techage.transfer(pos, "F", command, payload, VTube, {"techage:ta4_magnet"})
end
minetest.register_craft({
output = "techage:ta4_collider_tube_inlet",
recipe = {
{'', '', ''},
{'techage:ta4_vtubeS', 'techage:ta4_colliderblock', ''},
{'', '', ''},
},
})
--------------------------------------------------------------------------------
-- Pipe Input (gas)
--------------------------------------------------------------------------------
minetest.register_node("techage:ta4_collider_pipe_inlet", {
description = S("TA4 Collider Pipe Input"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^techage_appl_hole_pipe.png",
},
drawtype = "nodebox",
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {},
},
after_place_node = function(pos, placer, itemstack)
local nvm = techage.get_nvm(pos)
Pipe:after_place_node(pos)
nvm.liquid = {}
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end,
})
liquid.register_nodes({"techage:ta4_collider_pipe_inlet"}, Pipe, "tank", {"F"}, {
capa = GAS_CAPA,
peek = function(pos, indir)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end,
put = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_put(nvm, name, amount, GAS_CAPA)
end,
take = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_take(nvm, name, amount)
end,
untake = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
liquid.srv_put(nvm, name, amount, GAS_CAPA)
end,
})
techage.register_node({"techage:ta4_collider_pipe_inlet"}, {
on_transfer = function(pos, in_dir, topic, payload)
-- called from heatexchanger
if topic == "detector" then
local nvm = techage.get_nvm(pos)
nvm.detector_received = true
return true
end
end,
})
-- Used by the detector to check for gas pressure
function techage.gas_inlet_check(pos, node, meta, nvm)
nvm.liquid = nvm.liquid or {}
if nvm.liquid.amount == GAS_CAPA and nvm.liquid.name == "techage:isobutane" then
return true
end
return false, "no gas"
end
-- Used by the detector to check for cooler connection
function techage.cooler_check(pos, node, meta, nvm)
if nvm.detector_received then
nvm.detector_received = nil
return true
end
return false, "Cooler defect"
end
minetest.register_craft({
output = "techage:ta4_collider_pipe_inlet",
recipe = {
{'', '', ''},
{'techage:ta3_pipeS', 'techage:ta4_colliderblock', ''},
{'', '', ''},
},
})
--------------------------------------------------------------------------------
-- Pipe Output (air)
--------------------------------------------------------------------------------
local function init_air(nvm)
nvm.liquid = {
amount = AIR_CAPA,
name = "air",
}
return nvm.liquid
end
minetest.register_node("techage:ta4_collider_pipe_outlet", {
description = S("TA4 Collider Pipe Output"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png^techage_appl_hole_pipe.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
},
drawtype = "nodebox",
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {},
},
after_place_node = function(pos, placer, itemstack)
local nvm = techage.get_nvm(pos)
init_air(nvm)
Pipe:after_place_node(pos)
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
techage.del_mem(pos)
end,
})
liquid.register_nodes({"techage:ta4_collider_pipe_outlet"}, Pipe, "tank", {"U"}, {
capa = AIR_CAPA,
peek = function(pos, indir)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end,
put = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_put(nvm, name, amount, AIR_CAPA)
end,
take = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_take(nvm, name, amount)
end,
untake = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
liquid.srv_put(nvm, name, amount, AIR_CAPA)
end,
})
-- Used by the detector to check the vacuum
function techage.air_outlet_check(pos, node, meta, nvm)
nvm.liquid = nvm.liquid or {}
if nvm.liquid.amount == 0 then
return true
end
return false, "no vacuum"
end
function techage.air_outlet_reset(pos)
local nvm = techage.get_nvm(pos)
init_air(nvm)
end
minetest.register_craft({
output = "techage:ta4_collider_pipe_outlet",
recipe = {
{'', 'techage:ta3_pipeS', ''},
{'', 'techage:ta4_colliderblock', ''},
{'', '', ''},
},
})
--------------------------------------------------------------------------------
-- Cable Input (power)
--------------------------------------------------------------------------------
minetest.register_node("techage:ta4_collider_cable_inlet", {
description = S("TA4 Collider Cable Input"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^techage_appl_hole_electric.png",
},
drawtype = "nodebox",
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
networks = {
pipe2 = {},
},
after_place_node = function(pos, placer, itemstack)
Cable:after_place_node(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
on_timer = function(pos, elapsed)
local nvm = techage.get_nvm(pos)
if nvm.running then
nvm.consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED)
else
nvm.consumed = 0
end
return true
end,
after_dig_node = function(pos, oldnode)
Cable:after_dig_node(pos)
techage.del_mem(pos)
end,
})
-- Used by the detector to check for power
function techage.power_inlet_check(pos, node, meta, nvm)
if nvm.consumed == PWR_NEEDED then
return true
end
return false, "no power"
end
-- Used by the detector to turn on/off the node
function techage.power_inlet_turn_on_off(pos, nvm, on)
nvm.running = on
end
power.register_nodes({"techage:ta4_collider_cable_inlet"}, Cable, "con", {"F"})
techage.register_node({"techage:ta4_collider_cable_inlet"}, {
on_node_load = function(pos)
minetest.get_node_timer(pos):start(CYCLE_TIME)
end,
})
minetest.register_craft({
output = "techage:ta4_collider_cable_inlet",
recipe = {
{'', '', ''},
{'techage:electric_cableS', 'techage:ta4_colliderblock', ''},
{'', '', ''},
},
})

333
collider/magnet.lua Normal file
View File

@ -0,0 +1,333 @@
--[[
TechAge
=======
Copyright (C) 2019-2023 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Magnet as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local S2P = minetest.string_to_pos
local P2S = minetest.pos_to_string
local PWR_NEEDED = 5
local CYCLE_TIME = 2
local CAPACITY = 10
local Cable = techage.ElectricCable
local Pipe = techage.LiquidPipe
local VTube = techage.VTube
local power = networks.power
local liquid = networks.liquid
local function is_junction(pos, side)
local node = techage.get_node_lvm(techage.get_pos(pos, side))
return node and techage.string_compare(node.name, "techage:ta3_junction")
end
-- Turn the magnet to the right direction
local function handle_legacy_magnet(pos)
if M(pos):get_string("version") ~= "V2" then
if is_junction(pos, "B") and not is_junction(pos, "F") then
local node = techage.get_node_lvm(pos)
node.param2 = (node.param2 + 2) % 4
minetest.swap_node(pos, node)
end
end
M(pos):set_string("version", "V2")
end
minetest.register_node("techage:ta4_colliderblock", {
description = S("TA4 Collider Steel Block"),
tiles = {
"default_steel_block.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:ta4_detector_magnet", {
description = S("TA4 Collider Detector Magnet"),
tiles = {
-- up, down, right, left, back, front
"techage_collider_magnet.png^techage_collider_magnet_appl.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png",
"techage_collider_magnet.png",
"techage_collider_magnet.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:ta4_magnet", {
description = S("TA4 Collider Magnet"),
inventory_image = minetest.inventorycube(
"techage_collider_magnet.png^techage_appl_hole_electric.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png^techage_appl_hole_pipe.png^techage_collider_magnet_sign.png",
"techage_collider_magnet.png^techage_collider_magnet_tube.png"),
tiles = {
-- up, down, right, left, back, front
"techage_collider_magnet.png^techage_appl_hole_electric.png",
"techage_collider_magnet.png",
"techage_collider_magnet.png^techage_collider_magnet_tube.png",
"techage_collider_magnet.png^techage_collider_magnet_tube.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png^techage_collider_magnet_sign.png",
"techage_collider_magnet.png^techage_collider_magnet_appl.png^techage_appl_hole_pipe.png^techage_collider_magnet_sign.png",
},
drawtype = "nodebox",
use_texture_alpha = techage.CLIP,
node_box = {
type = "fixed",
fixed = {
{-11/16, -11/16, -11/16, 11/16, 11/16, -2/16},
{-11/16, -11/16, 2/16, 11/16, 11/16, 11/16},
{-11/16, 2/16, -11/16, 11/16, 11/16, 11/16},
{-11/16, -11/16, -11/16, 11/16, -2/16, 11/16},
},
},
selection_box = {
type = "fixed",
fixed = {-4/8, -4/8, -4/8, 4/8, 4/8, 4/8},
},
collision_box = {
type = "fixed",
fixed = {-11/16, -11/16, -11/16, 11/16, 11/16, 11/16},
},
wield_scale = {x = 0.8, y = 0.8, z = 0.8},
paramtype2 = "facedir",
paramtype = "light",
use_texture_alpha = techage.CLIP,
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack)
if pos.y > techage.collider_min_depth then
minetest.remove_node(pos)
minetest.add_item(pos, ItemStack("techage:ta4_magnet"))
return
end
local nvm = techage.get_nvm(pos)
nvm.liquid = {}
Pipe:after_place_node(pos)
Cable:after_place_node(pos)
VTube:after_place_node(pos)
M(pos):set_string("infotext", S("TA4 Collider Magnet") .. " #0")
M(pos):set_string("version", "V2")
end,
-- To be called by the detector
on_cyclic_check = function(pos)
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.consumed = power.consume_power(pos, Cable, 6, PWR_NEEDED)
if nvm.tube_damage then
nvm.tube_damage = nil
nvm.running = nil
return -1
elseif nvm.liquid.amount == CAPACITY and
nvm.liquid.name == "techage:isobutane" and
nvm.consumed == PWR_NEEDED then
nvm.running = true
return 0
end
nvm.running = nil
return -2
end,
on_turn_off = function(pos)
local nvm = techage.get_nvm(pos)
nvm.running = nil
end,
tubelib2_on_update2 = function(pos, outdir, tlib2, node)
if tlib2.tube_type == "vtube" then
local nvm = techage.get_nvm(pos)
nvm.tube_damage = true
elseif tlib2.tube_type == "pipe2" then
local nvm = techage.get_nvm(pos)
nvm.liquid = nvm.liquid or {}
nvm.liquid.amount = 0
end
end,
after_dig_node = function(pos, oldnode)
Pipe:after_dig_node(pos)
Cable:after_dig_node(pos)
VTube:after_dig_node(pos)
techage.del_mem(pos)
end,
})
power.register_nodes({"techage:ta4_magnet"}, Cable, "con", {"U"})
liquid.register_nodes({"techage:ta4_magnet"}, Pipe, "tank", {"F"}, {
capa = CAPACITY,
peek = function(pos, indir)
local nvm = techage.get_nvm(pos)
return liquid.srv_peek(nvm)
end,
put = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_put(nvm, name, amount, CAPACITY)
end,
take = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
return liquid.srv_take(nvm, name, amount)
end,
untake = function(pos, indir, name, amount)
local nvm = techage.get_nvm(pos)
liquid.srv_put(nvm, name, amount, CAPACITY)
end,
})
VTube:add_secondary_node_names({"techage:ta4_magnet"})
VTube:set_valid_sides("techage:ta4_magnet", {"R", "L"})
local function send_to_next(pos, in_dir, topic, payload)
return techage.transfer(pos, in_dir, topic, payload, VTube,
{"techage:ta4_magnet", "techage:ta4_collider_tube_inlet"})
end
--[[
Commands
--------
distance : Check distance between all magnets.
Returns pos of next magnet or the number of the defect magnet.
enumerate : Give each magnet a unique number (1...n)
pos : Read the position
test : Test all magnet attributs.
Returns true or false, err
]]--
techage.register_node({"techage:ta4_magnet"}, {
on_transfer = function(pos, in_dir, topic, payload)
local nvm = techage.get_nvm(pos)
if topic == "distance" then
local pos2 = send_to_next(pos, in_dir, topic, payload)
if type(pos2) == "table" then
local dist = math.abs(pos.x - pos2.x) + math.abs(pos.z - pos2.z)
if pos.y == pos2.y and dist == VTube.max_tube_length + 1 then
return pos
end
return nvm.number or 0
else
return pos2
end
elseif topic == "enumerate" and payload then
handle_legacy_magnet(pos)
payload = tonumber(payload) or 1
nvm.number = payload
M(pos):set_string("infotext", S("TA4 Collider Magnet") .. " #" .. payload)
return send_to_next(pos, in_dir, topic, payload + 1)
elseif topic == "pos" then
if payload and tonumber(payload) == nvm.number then
nvm.tube_damage = nil
return pos
else
return send_to_next(pos, in_dir, topic, payload)
end
elseif topic == "test" then
if payload and tonumber(payload) == nvm.number then
if not nvm.liquid or not nvm.liquid.amount or nvm.liquid.amount < CAPACITY then
return false, "no gas"
elseif nvm.liquid.name ~= "techage:isobutane" then
return false, "wrong gas"
elseif nvm.consumed ~= PWR_NEEDED then
return false, "no power"
elseif nvm.tube_damage then
nvm.tube_damage = nil
return false, "no vacuum"
end
return true
else
return send_to_next(pos, in_dir, topic, payload)
end
end
end,
})
minetest.register_node("techage:ta4_magnet_base", {
description = S("TA4 Collider Magnet Base"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-6/16, -8/16, -6/16, 6/16, 5/16, 6/16},
},
},
paramtype2 = "facedir",
groups = {cracky = 1},
is_ground_content = false,
paramtype = "light",
use_texture_alpha = techage.CLIP,
sounds = default.node_sound_metal_defaults(),
})
minetest.register_craft({
output = "techage:ta4_colliderblock",
recipe = {
{'techage:aluminum', '', 'default:steel_ingot'},
{'', '', ''},
{'default:steel_ingot', '', 'techage:aluminum'},
},
})
minetest.register_craft({
output = "techage:ta4_detector_magnet 2",
recipe = {
{'default:steel_ingot', '', 'techage:aluminum'},
{'dye:red', 'basic_materials:gold_wire', 'dye:brown'},
{'techage:aluminum', '', 'default:steel_ingot'},
},
})
minetest.register_craft({
output = "techage:ta4_magnet",
recipe = {
{'techage:ta3_pipeS', '', 'techage:electric_cableS'},
{'techage:ta4_round_ceramic', 'techage:ta4_detector_magnet', 'techage:ta4_round_ceramic'},
{'', '', ''},
},
})
minetest.register_craft({
output = "techage:ta4_magnet_base 4",
recipe = {
{'techage:aluminum', 'default:steel_ingot', ''},
{'techage:aluminum', 'default:steel_ingot', ''},
{'techage:aluminum', 'default:steel_ingot', ''},
},
})
minetest.register_lbm({
label = "Repair Magnets",
name = "techage:magnets",
nodenames = {"techage:ta4_magnet", "techage:ta4_collider_pipe_inlet"},
run_at_every_load = false,
action = function(pos, node)
local nvm = techage.get_nvm(pos)
if nvm.liquid and nvm.liquid.name == "techage:hydrogen" then
nvm.liquid.name = "techage:isobutane"
end
end,
})

130
collider/vacuumtube.lua Normal file
View File

@ -0,0 +1,130 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Vacuum Tube as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local VTube = tubelib2.Tube:new({
dirs_to_check = {1,2,3,4},
max_tube_length = 5,
tube_type = "vtube",
show_infotext = false,
primary_node_names = {"techage:ta4_vtubeS", "techage:ta4_vtubeA"},
secondary_node_names = {"techage:ta4_magnet"},
after_place_tube = function(pos, param2, tube_type, num_tubes)
minetest.swap_node(pos, {name = "techage:ta4_vtube"..tube_type, param2 = param2})
end,
})
techage.VTube = VTube
minetest.register_node("techage:ta4_vtubeS", {
description = S("TA4 Vacuum Tube"),
drawtype = "nodebox",
tiles = {
-- up, down, right, left, back, front
"techage_collider_tube.png^[transformR90",
"techage_collider_tube.png^[transformR90",
"techage_collider_tube.png",
"techage_collider_tube.png",
'techage_collider_tube_open.png',
'techage_collider_tube_open.png',
},
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, -6/16, 8/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, 6/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, 8/16, -6/16, 8/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
after_place_node = function(pos, placer, itemstack, pointed_thing)
if not VTube:after_place_tube(pos, placer, pointed_thing) then
minetest.remove_node(pos)
return true
end
return false
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
VTube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {cracky = 2},
sounds = default.node_sound_metal_defaults(),
})
minetest.register_node("techage:ta4_vtubeA", {
description = S("TA4 Vacuum Tube"),
drawtype = "nodebox",
tiles = {
-- up, down, right, left, back, front
"techage_collider_tube.png^[transformR90",
'techage_collider_tube.png^techage_collider_tube_open.png',
"techage_collider_tube.png",
"techage_collider_tube.png",
"techage_collider_tube.png^[transformR90",
'techage_collider_tube.png^techage_collider_tube_open.png',
},
node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, -6/16, 8/16, 8/16},
{ 6/16, -8/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, 6/16, -8/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, 6/16, 8/16, 8/16, 8/16},
{-8/16, -8/16, -8/16, 8/16, -6/16, -6/16},
},
},
selection_box = {
type = "fixed",
fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16},
},
after_dig_node = function(pos, oldnode, oldmetadata, digger)
VTube:after_dig_tube(pos, oldnode, oldmetadata)
end,
paramtype2 = "facedir", -- important!
on_rotate = screwdriver.disallow, -- important!
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {cracky = 1, not_in_creative_inventory=1},
drop = "techage:ta4_vtubeS",
sounds = default.node_sound_metal_defaults(),
})
minetest.register_craft({
output = "techage:ta4_vtubeS 4",
recipe = {
{'', 'default:steel_ingot', ''},
{'techage:aluminum', 'dye:blue', 'techage:aluminum'},
{'', 'default:steel_ingot', ''},
},
})

208
collider/worker.lua Normal file
View File

@ -0,0 +1,208 @@
--[[
TechAge
=======
Copyright (C) 2019-2021 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
TA4 Detector Worlker as part of the Collider
]]--
-- for lazy programmers
local M = minetest.get_meta
local S = techage.S
local AssemblyPlan = {
-- y-offs, path, facedir-offs, name
-- 0 = forward, 1 = right, 2 = backward, 3 = left
-- level 1
-- left/right
{ 1, {3,3,3,2}, 0, "techage:ta4_colliderblock"},
{ 1, {3,3,3}, 0, "techage:ta4_colliderblock"},
{ 1, {3,3,3,0}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,1,2}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,1}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,1,0}, 0, "techage:ta4_colliderblock"},
-- front
{ 1, {3,3,2}, 0, "techage:ta4_colliderblock"},
{ 1, {3,2}, 0, "techage:ta4_colliderblock"},
{ 1, {2}, 0, "techage:ta4_colliderblock"},
{ 1, {1,2}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,2}, 0, "techage:ta4_colliderblock"},
-- back
{ 1, {3,3,0}, 0, "techage:ta4_colliderblock"},
{ 1, {3,0}, 0, "techage:ta4_colliderblock"},
{ 1, {0}, 2, "techage:ta4_collider_pipe_inlet"},
{ 1, {1,0}, 0, "techage:ta4_colliderblock"},
{ 1, {1,1,0}, 0, "techage:ta4_colliderblock"},
-- middle
{ 1, {3,3}, 0, "techage:ta4_detector_magnet"},
{ 1, {3}, 0, "techage:ta4_detector_magnet"},
{ 1, {1}, 0, "techage:ta4_detector_magnet"},
{ 1, {1,1}, 0, "techage:ta4_detector_magnet"},
-- level 2
-- left/right
{ 2, {3,3,3,2}, 1, "techage:ta4_collider_pipe_inlet"},
{ 2, {3,3,3}, 1, "techage:ta4_collider_tube_inlet"},
{ 2, {3,3,3,0}, 0, "techage:ta4_colliderblock"},
{ 2, {1,1,1,2}, 3, "techage:ta4_collider_pipe_inlet"},
{ 2, {1,1,1}, 3, "techage:ta4_collider_tube_inlet"},
{ 2, {1,1,1,0}, 0, "techage:ta4_colliderblock"},
-- front
{ 2, {3,3,2}, 0, "techage:ta4_detector_magnet"},
{ 2, {3,2}, 0, "techage:ta4_detector_magnet"},
{ 2, {2}, 0, "default:obsidian_glass"},
{ 2, {1,2}, 0, "techage:ta4_detector_magnet"},
{ 2, {1,1,2}, 0, "techage:ta4_detector_magnet"},
-- back
{ 2, {3,3,0}, 0, "techage:ta4_detector_magnet"},
{ 2, {3,0}, 0, "techage:ta4_detector_magnet"},
{ 2, {0}, 0, "techage:ta4_colliderblock"},
{ 2, {1,0}, 0, "techage:ta4_detector_magnet"},
{ 2, {1,1,0}, 0, "techage:ta4_detector_magnet"},
-- level 3
-- left/right
{ 3, {3,3,3,2}, 0, "techage:ta4_colliderblock"},
{ 3, {3,3,3}, 1, "techage:ta4_collider_cable_inlet"},
{ 3, {3,3,3,0}, 0, "techage:ta4_colliderblock"},
{ 3, {1,1,1,2}, 0, "techage:ta4_colliderblock"},
{ 3, {1,1,1}, 3, "techage:ta4_collider_cable_inlet"},
{ 3, {1,1,1,0}, 0, "techage:ta4_colliderblock"},
-- front
{ 3, {3,3,2}, 0, "techage:ta4_colliderblock"},
{ 3, {3,2}, 0, "techage:ta4_colliderblock"},
{ 3, {2}, 0, "techage:ta4_colliderblock"},
{ 3, {1,2}, 0, "techage:ta4_colliderblock"},
{ 3, {1,1,2}, 0, "techage:ta4_colliderblock"},
-- back
{ 3, {3,3,0}, 0, "techage:ta4_colliderblock"},
{ 3, {3,0}, 0, "techage:ta4_colliderblock"},
{ 3, {0}, 2, "techage:ta4_collider_pipe_inlet"},
{ 3, {1,0}, 0, "techage:ta4_colliderblock"},
{ 3, {1,1,0}, 0, "techage:ta4_colliderblock"},
-- middle
{ 3, {3,3}, 0, "techage:ta4_detector_magnet"},
{ 3, {3}, 0, "techage:ta4_detector_magnet"},
{ 3, {}, 0, "techage:ta4_collider_pipe_outlet"},
{ 3, {1}, 0, "techage:ta4_detector_magnet"},
{ 3, {1,1}, 0, "techage:ta4_detector_magnet"},
-- Core block
{ 1, {}, 0, "techage:ta4_detector_core"},
}
local t = {}
for name, cnt in pairs(techage.assemble.count_items(AssemblyPlan)) do
t[#t + 1] = " - " .. cnt .. " " .. name
end
local LABEL = table.concat(t, "\n")
local function build(pos, player_name)
minetest.chat_send_player(player_name, S("[TA4] Detector is being built!"))
local inv = M(pos):get_inventory()
techage.assemble.build_inv(pos, inv, AssemblyPlan, player_name)
end
local function remove(pos, player_name)
minetest.chat_send_player(player_name, S("[TA4] Detector is being removed!"))
local inv = M(pos):get_inventory()
techage.assemble.remove_inv(pos, inv, AssemblyPlan, player_name)
end
local function formspec()
return "size[8,8.2]"..
"list[context;src;5,0;3,3;]"..
"label[0.2,-0.2;" .. S("Item list") .. ":\n" .. LABEL .. "]" ..
"button_exit[0,3.5;4,1;build;" .. S("Build detector") .. "]" ..
"button_exit[4,3.5;4,1;remove;" .. S("Remove detector") .. "]" ..
"list[current_player;main;0,4.5;8,4;]"..
"listring[context;src]"..
"listring[current_player;main]"
end
minetest.register_node("techage:ta4_collider_detector_worker", {
description = S("TA4 Collider Detector Worker"),
tiles = {
-- up, down, right, left, back, front
"default_steel_block.png^techage_collider_detector_appl.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_banner.png",
"default_steel_block.png^techage_collider_detector_appl.png^techage_collider_detector_banner.png",
},
paramtype2 = "facedir",
groups = {cracky = 1},
on_rotate = screwdriver.disallow,
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = function(pos, placer, itemstack)
if pos.y > (techage.collider_min_depth - 2) then
minetest.remove_node(pos)
minetest.add_item(pos, ItemStack("techage:ta4_collider_detector_worker"))
return
end
local inv = M(pos):get_inventory()
inv:set_size("src", 9)
M(pos):set_string("formspec", formspec())
end,
on_receive_fields = function(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
if fields.build then
if not nvm.assemble_locked then
build(pos, player:get_player_name())
end
elseif fields.remove then
if not nvm.assemble_locked then
local nvm = techage.get_nvm({x=pos.x, y=pos.y + 1, z=pos.z})
if not nvm.locked then
remove(pos, player:get_player_name())
end
end
end
end,
after_dig_node = function(pos, oldnode)
techage.del_mem(pos)
end,
can_dig = function(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local nvm = techage.get_nvm(pos)
if nvm.assemble_locked or nvm.assemble_build then
minetest.after(30, function(pos)
local nvm = techage.get_nvm(pos)
nvm.assemble_locked = false
end, pos)
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("src")
end,
})
minetest.register_craft({
output = "techage:ta4_collider_detector_worker",
recipe = {
{'techage:aluminum', 'default:chest', 'default:steel_ingot'},
{'', 'basic_materials:gear_steel', ''},
{'default:steel_ingot', 'default:mese_crystal', 'techage:aluminum'},
},
})

View File

@ -30,7 +30,7 @@ local TOTAL_MAX = INV_SIZE * FUEL_STACK_MAX
local function count_coal(metadata)
local total = 0
for _,stack in pairs(metadata.inventory.fuel) do
for _,stack in pairs(metadata.inventory.fuel or {}) do
total = total + stack:get_count()
end
return total

View File

@ -3,111 +3,59 @@
]]--
local S = techage.S
local M = minetest.get_meta
local MP = minetest.get_modpath("techage")
local tItems = techage.Items -- k/v table with item definitions
local tPlans = techage.ConstructionPlans -- k/v table with plan definitions
local settings = {
symbol_item = "techage:construction_board",
}
doclib.create_manual("techage", "DE", settings)
doclib.create_manual("techage", "EN", settings)
doclib.create_manual("techage", "pt-BR", settings)
local function tooltip(item)
if type(item) == "table" then
local img, name = item[1], item[2]
if img == "" then -- larger image for the plan?
return "", name
end
local ndef = minetest.registered_nodes[name]
if ndef and ndef.description then
return img, minetest.formspec_escape(ndef.description)
end
return img
end
return item
end
local content
content = dofile(MP.."/doc/manual_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta1_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta2_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta3_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta4_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_ta5_DE.lua")
doclib.add_to_manual("techage", "DE", content)
content = dofile(MP.."/doc/manual_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta1_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta2_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta3_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta4_EN.lua")
doclib.add_to_manual("techage", "EN", content)
content = dofile(MP.."/doc/manual_ta5_EN.lua")
doclib.add_to_manual("techage", "EN", content)
-- formspec images
local function plan(images)
local tbl = {}
if images == "none" then return "label[1,3;"..S("No plan available") .."]" end
for y=1,#images do
for x=1,#images[1] do
local item = images[y][x] or false
if item ~= false then
local img, tooltip = tooltip(item)
local x_offs, y_offs = (x-1) * 0.9, (y-1) * 0.9 + 0.8
if img == "top_view" then
tbl[#tbl+1] = "label["..x_offs..","..y_offs..";"..S("Top view").."]"
elseif img == "side_view" then
tbl[#tbl+1] = "label["..x_offs..","..y_offs..";"..S("Side view").."]"
elseif img == "" then
img = tooltip -- use tooltip for bigger image
tbl[#tbl+1] = "image["..x_offs..","..y_offs..";2.2,2.2;"..img.."]"
elseif string.find(img, ":") then
tbl[#tbl+1] = "item_image["..x_offs..","..y_offs..";1,1;"..img.."]"
else
tbl[#tbl+1] = "image["..x_offs..","..y_offs..";1,1;"..img.."]"
end
if tooltip then
tbl[#tbl+1] = "tooltip["..x_offs..","..y_offs..";1,1;"..tooltip..";#0C3D32;#FFFFFF]"
end
end
end
end
return table.concat(tbl)
end
local function formspec_help(meta, manual)
local bttn
local idx = meta:get_int("index")
local box = "box[9.5,0.9;1,1.1;#BBBBBB]"
local aTitel = manual.aTitel
local aText = manual.aText
local aItemName = manual.aItemName -- item identifier as key
local aPlanTable = manual.aPlanTable -- plan identifier as key
if aPlanTable[idx] ~= "" then
bttn = "button[9.6,1;1,1;plan;"..S("Plan").."]"
elseif aItemName[idx] ~= "" then
local item = tItems[aItemName[idx]] or ""
if string.find(item, ":") then
bttn = box.."item_image[9.6,1;1,1;"..item.."]"
else
bttn = "image[9.3,1;2,2;"..item.."]"
end
else
bttn = box
end
return "size[11,10]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"item_image[9.6,0;1,1;techage:construction_board]"..
"tablecolumns[tree,width=1;text,width=10,align=inline]"..
"tableoptions[opendepth=1]"..
"table[0.1,0;9,5;page;"..table.concat(aTitel, ",")..";"..idx.."]"..
bttn..
"style_type[textarea;textcolor=#FFFFFF]"..
"textarea[0.3,5.7;11,5.3;;"..(aText[idx] or "")..";]"..
"box[0,5.75;10.775,4.45;#000000]"
end
local function formspec_plan(meta, manual)
local idx = meta:get_int("index")
local images = tPlans[manual.aPlanTable[idx]] or "none"
local titel = string.sub(manual.aTitel[idx], 3) or "unknown"
return "size[11,10]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"label[0,0;"..titel..":]"..
"button[10,0;1,0.8;back;<<]"..
plan(images)
end
content = dofile(MP.."/doc/manual_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta1_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta2_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta3_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta4_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
content = dofile(MP.."/doc/manual_ta5_pt-BR.lua")
doclib.add_to_manual("techage", "pt-BR", content)
local board_box = {
type = "wallmounted",
--wall_top = {-8/16, 15/32, -6/16, 8/16, 8/16, 6/16},
--wall_bottom = {-8/16, 15/32, -6/16, 8/16, 8/16, 6/16},
wall_side = {-16/32, -11/32, -16/32, -15/32, 6/16, 8/16},
}
@ -118,33 +66,20 @@ minetest.register_node("techage:construction_board", {
drawtype = "nodebox",
node_box = board_box,
selection_box = board_box,
after_place_node = function(pos, placer, itemstack)
local meta = minetest.get_meta(pos)
meta:set_int("index", 1)
meta:set_string("formspec", formspec_help(meta, techage.manual_DE))
M(pos):set_string("infotext", "TA Konstruktionsplan (DE)")
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "DE"))
end,
on_receive_fields = function(pos, formname, fields, player)
local player_name = player:get_player_name()
if minetest.is_protected(pos, player_name) then
return
end
local meta = minetest.get_meta(pos)
if fields.plan then
meta:set_string("formspec", formspec_plan(meta, techage.manual_DE))
elseif fields.back then
meta:set_string("formspec", formspec_help(meta, techage.manual_DE))
elseif fields.page then
local evt = minetest.explode_table_event(fields.page)
if evt.type == "CHG" then
local idx = tonumber(evt.row)
meta:set_int("index", idx)
meta:set_string("formspec", formspec_help(meta, techage.manual_DE))
end
end
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "DE", fields))
end,
paramtype2 = "wallmounted",
paramtype = "light",
use_texture_alpha = techage.CLIP,
@ -170,33 +105,20 @@ minetest.register_node("techage:construction_board_EN", {
drawtype = "nodebox",
node_box = board_box,
selection_box = board_box,
after_place_node = function(pos, placer, itemstack)
local meta = minetest.get_meta(pos)
meta:set_int("index", 1)
meta:set_string("formspec", formspec_help(meta, techage.manual_EN))
M(pos):set_string("infotext", "TA Construction Board (EN)")
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "EN"))
end,
on_receive_fields = function(pos, formname, fields, player)
local player_name = player:get_player_name()
if minetest.is_protected(pos, player_name) then
return
end
local meta = minetest.get_meta(pos)
if fields.plan then
meta:set_string("formspec", formspec_plan(meta, techage.manual_EN))
elseif fields.back then
meta:set_string("formspec", formspec_help(meta, techage.manual_EN))
elseif fields.page then
local evt = minetest.explode_table_event(fields.page)
if evt.type == "CHG" then
local idx = tonumber(evt.row)
meta:set_int("index", idx)
meta:set_string("formspec", formspec_help(meta, techage.manual_EN))
end
end
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "EN", fields))
end,
paramtype2 = "wallmounted",
paramtype = "light",
use_texture_alpha = techage.CLIP,
@ -215,6 +137,45 @@ minetest.register_craft({
},
})
minetest.register_node("techage:construction_board_pt_BR", {
description = "TA Placa de construção (pt-BR)",
inventory_image = 'techage_constr_plan_inv.png',
tiles = {"techage_constr_plan.png"},
drawtype = "nodebox",
node_box = board_box,
selection_box = board_box,
after_place_node = function(pos, placer, itemstack)
M(pos):set_string("infotext", "TA Placa de construção (pt-BR)")
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "pt-BR"))
end,
on_receive_fields = function(pos, formname, fields, player)
local player_name = player:get_player_name()
if minetest.is_protected(pos, player_name) then
return
end
M(pos):set_string("formspec", doclib.formspec(pos, "techage", "pt-BR", fields))
end,
paramtype2 = "wallmounted",
paramtype = "light",
use_texture_alpha = techage.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
sounds = default.node_sound_wood_defaults(),
})
minetest.register_craft({
output = "techage:construction_board_pt_BR",
recipe = {
{"default:stick", "default:stick", "default:paper"},
{"default:paper", "default:paper", "default:paper"},
{"default:paper", "default:paper", "default:paper"},
},
})
minetest.register_craft({
type = "shapeless",
output = "techage:construction_board_EN",
@ -224,5 +185,35 @@ minetest.register_craft({
minetest.register_craft({
type = "shapeless",
output = "techage:construction_board",
recipe = {"techage:construction_board_pt_BR"},
})
minetest.register_craft({
type = "shapeless",
output = "techage:construction_board_pt_BR",
recipe = {"techage:construction_board_EN"},
})
--
-- Legacy API functions
--
function techage.add_to_manual(language, titles, texts, items, plans)
local content = {titles = titles, texts = texts, images = items or {}, plans = plans or {}}
doclib.add_to_manual("techage", language, content)
end
function techage.add_manual_items(table_with_items)
for name, image in pairs(table_with_items) do
doclib.add_manual_image("techage", "EN", name, image)
doclib.add_manual_image("techage", "DE", name, image)
doclib.add_manual_image("techage", "pt-BR", name, image)
end
end
function techage.add_manual_plans(table_with_plans)
for name, plan in pairs(table_with_plans) do
doclib.add_manual_plan("techage", "EN", name, plan)
doclib.add_manual_plan("techage", "DE", name, plan)
doclib.add_manual_plan("techage", "pt-BR", name, plan)
end
end

View File

@ -7,12 +7,12 @@
AGPL v3
See LICENSE.txt for more information
TA Items Table
]]--
techage.Items = {
local items = {
techage_ta1 = "techage_ta1.png",
iron = "techage:iron_ingot",
charcoal = "techage:charcoal",
@ -29,6 +29,10 @@ techage.Items = {
wlanchip = "techage:ta4_wlanchip",
tube = "techage:tubeS",
concentrator = "techage:concentrator27",
ta1_sluice = "techage:ta1_sluice_closed",
ta1_sluice_handle = "techage:ta1_sluice_handle_closed",
ta1_board1 = "techage:ta1_board1_apple",
ta1_board2 = "techage:ta1_board2_apple",
----------------
techage_ta2 = "techage_ta2.png",
ta2_firebox = "techage:firebox",
@ -50,8 +54,8 @@ techage.Items = {
ta2_forceload = "techage:forceload",
ta2_driveaxle = "techage:axle",
ta2_generator = "techage:ta2_generator_off",
ta2_winch = "techage:ta2_winch",
ta2_weight_chest = "techage:ta2_weight_chest",
ta2_winch = "techage:ta2_winch",
ta2_weight_chest = "techage:ta2_weight_chest",
---------------------
techage_ta3 = "techage_ta3.png",
techage_ta31 = "techage_ta3b.png",
@ -81,6 +85,7 @@ techage.Items = {
ta3_powerswitchbox = "techage:powerswitch_box",
ta3_powerterminal = "techage:ta3_power_terminal",
ta3_trowel = "techage:trowel",
ta3_screwdriver = "techage:screwdriver",
ta3_tinygenerator = "techage:tiny_generator",
ta3_akkublock = "techage:ta3_akku",
ta3_furnace = "techage:ta3_furnace_pas",
@ -105,35 +110,40 @@ techage.Items = {
ta3_logic = "techage:ta3_logic",
ta3_nodedetector = "techage:ta3_nodedetector_off",
ta3_playerdetector = "techage:ta3_playerdetector_off",
ta3_lightdetector = "techage:ta3_lightdetector_off",
ta3_repeater = "techage:ta3_repeater",
ta3_sequencer = "techage:ta3_sequencer",
ta3_timer = "techage:ta3_timer",
ta3_terminal = "techage:terminal2",
ta3_signallamp = "techage:signal_lamp_off",
ta3_colorlamp = "techage:color_lamp_off",
ta3_doorblock = "techage:doorblock20",
ta3_soundblock = "techage:ta3_soundblock",
ta3_programmer = "techage:programmer",
ta3_doorcontroller = "techage:ta3_doorcontroller",
ta3_drill_pipe_wrench = "techage:ta3_drill_pipe_wrench",
ta3_pipe = "techage:ta3_pipeS",
ta3_pipe = "techage:ta3_pipeS",
ta3_pipe_wall_entry = "techage:ta3_pipe_wall_entry",
ta3_mesecons_converter = "techage:ta3_mesecons_converter",
ta3_valve = "techage:ta3_valve_closed",
ta3_motor = "techage:ta3_motor_off",
ta3_injector = "techage:ta3_injector_pas",
ta3_command_converter = "techage:ta3_command_converter_off",
ta3_flipflop = "techage:ta3_flipflop_off",
----------------------------
techage_ta4 = "techage_ta4.png",
techage_ta4c = "techage_ta4c.png",
ta4_windturbine = "techage:ta4_wind_turbine",
ta4_pillar = "techage:pillar",
ta4_blinklamp = "techage:rotor_signal_lamp_off",
ta4_nacelle = "techage:ta4_wind_turbine_nacelle",
ta4_minicell = "techage:ta4_solar_minicell",
ta4_pipe = "techage:ta4_pipeS",
ta4_tube = "techage:ta4_tubeS",
ta4_junctionpipe = "techage:ta4_junctionpipe25",
ta4_pipeinlet = "techage:ta4_pipe_inlet",
ta4_pipe = "techage:ta4_pipeS",
ta4_tube = "techage:ta4_tubeS",
ta4_junctionpipe = "techage:ta4_junctionpipe25",
ta4_pipeinlet = "techage:ta4_pipe_inlet",
ta4_turbine = "techage:ta4_turbine",
ta4_generator = "techage:ta4_generator",
ta4_heatexchanger = "techage:heatexchanger3",
ta4_heatexchanger = "techage:heatexchanger3",
ta4_powercable = "techage:ta4_power_cableS",
ta4_powerbox = "techage:ta4_power_box",
ta4_solarmodule = "techage:ta4_solar_module",
@ -187,12 +197,37 @@ techage.Items = {
ta4_electricmeter = "techage:ta4_electricmeter",
ta4_transformer = "techage:ta4_transformer",
power_reduction = "techage_power_reduction.png",
--ta4_ "",
ta4_button_2x = "techage:ta4_button_2x",
ta4_button_4x = "techage:ta4_button_4x",
ta4_sequencer = "techage:ta4_sequencer",
ta4_movecontroller = "techage:ta4_movecontroller",
ta4_turncontroller = "techage:ta4_turncontroller",
ta4_signallamp_2x = "techage:ta4_signallamp_2x",
ta4_signallamp_4x = "techage:ta4_signallamp_4x",
ta4_terminal = "techage:terminal3",
ta4_autocrafter = "techage:ta4_autocrafter_pas",
ta4_recipeblock = "techage:ta4_recipeblock",
ta4_chargedetector = "techage:ta4_chargedetector_off",
ta4_gaze_sensor = "techage:ta4_gaze_sensor_off",
ta4_nodedetector = "techage:ta4_nodedetector_off",
----------------------------
techage_ta5 = "techage:ta5_fr_nucleus",
ta5_flycontroller = "techage:ta5_flycontroller",
ta5_aichip = "techage:ta5_aichip",
ta5_aichip2 = "techage:ta5_aichip2",
ta5_tele_pipe = "techage:ta5_tele_pipe",
ta5_tele_tube = "techage:ta5_tele_tube",
ta5_chest = "techage:ta5_hl_chest",
ta5_tank = "techage:ta5_hl_tank",
ta5_magnet = "techage:ta5_magnet1",
ta5_pump = "techage:ta5_pump",
ta5_fr_shell = "techage:ta5_fr_shell",
ta5_fr_nucleus = "techage:ta5_fr_nucleus",
ta5_fr_controller = "techage:ta5_fr_controller_pas",
}
function techage.add_manual_items(table_with_items)
for name, tbl in pairs(table_with_items) do
techage.Items[name] = tbl
end
end
for name, image in pairs(items) do
doclib.add_manual_image("techage", "DE", name, image)
doclib.add_manual_image("techage", "EN", name, image)
doclib.add_manual_image("techage", "pt-BR", name, image)
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +0,0 @@
--[[
TechAge
=======
Copyright (C) 2019-2020 Joachim Stolberg
AGPL v3
See LICENSE.txt for more information
API to add further chapters to the manuals
]]--
function techage.add_to_manual(language, titles, texts, items, plans)
local tbl
if language == "DE" then
tbl = techage.manual_DE
elseif language == "EN" then
tbl = techage.manual_EN
else
minetest.log("error", "[techage] Invalid manual language provided for 'techage.add_to_manual'!")
return
end
for _, item in ipairs(titles) do
tbl.aTitel[#tbl.aTitel + 1] = item
end
for _, item in ipairs(texts) do
tbl.aText[#tbl.aText + 1] = item
end
for _, item in ipairs(items) do
tbl.aItemName[#tbl.aItemName + 1] = item
end
for _, item in ipairs(plans) do
tbl.aPlanTable[#tbl.aPlanTable + 1] = item
end
end

152
doc/manual_pt-BR.lua Normal file
View File

@ -0,0 +1,152 @@
return {
titles = {
"1,Mod Tech Age",
"2,TA1: Idade do Ferro",
"2,TA2: Idade do Vapor",
"2,TA3: Idade do Petróleo",
"2,TA4: Tempos atuais (Presente)",
"2,TA5: Futuro",
"1,Dicas",
"1,Mudanças a partir da versão 1.0",
"2,Dicas sobre a troca",
"1,Minérios e Minerais",
"2,Meridium",
"2,Usmium",
"2,Baborium",
"2,Petróleo",
"2,Bauxita",
"2,Basalto",
"2,History",
},
texts = {
"O Tech Age é um mod de tecnologia com 5 estágios de desenvolvimento:\n"..
"\n",
"Utilize ferramentas e instrumentos auxiliares como queimadores de carvão\\, peneiras de cascalho\\, martelos e funis para extrair e processar minérios e metais necessários.\n"..
"\n",
"Construa uma máquina a vapor com eixos de transmissão e use-a para operar suas primeiras máquinas de processamento de minérios.\n"..
"\n",
"Encontre e extraia óleo\\, construa ferrovias para transporte de óleo. Uma usina fornece a eletricidade necessária para suas máquinas. A luz elétrica ilumina suas instalações industriais.\n"..
"\n",
"Fontes de energia renovável\\, como vento\\, sol e biocombustíveis\\, ajudam você a sair da era do petróleo. Com tecnologias modernas e máquinas inteligentes\\, você parte para o futuro.\n"..
"\n",
"Máquinas para superar espaço e tempo\\, novas fontes de energia e outras conquistas moldam sua vida.\n"..
"\n"..
"Nota: Clicando no sinal de adição\\, você acessa os subcapítulos deste manual.\n"..
"\n"..
"\n"..
"\n",
"Esta documentação está disponível tanto \"dentro do jogo\" (plano de construção de blocos) quanto no GitHub como arquivos MD.\n"..
"\n"..
" - Link: https://github.com/joe7575/techage/wiki\nOs planos de construção (diagramas) para a construção das máquinas e as imagens estão disponíveis apenas no jogo.\n"..
"\n"..
"Com o Tech Age\\, você precisa começar do zero. Você só pode criar blocos TA2 com os itens do TA1\\, para o TA3 você precisa dos resultados do TA2\\, e assim por diante.\n"..
"\n"..
"No TA2\\, as máquinas só funcionam com eixos de transmissão.\n"..
"\n"..
"A partir do TA3\\, as máquinas funcionam com eletricidade e têm uma interface de comunicação para controle remoto.\n"..
"\n"..
"O TA4 adiciona mais fontes de energia\\, mas também desafios logísticos mais altos (linhas de energia\\, transporte de itens).\n"..
"\n",
"A partir da V1.0 (17/07/2021)\\, as seguintes alterações foram feitas:\n"..
"\n"..
" - O algoritmo para calcular a distribuição de energia foi alterado. Isso torna os sistemas de armazenamento de energia mais importantes. Eles compensam as flutuações\\, o que é importante em redes maiores com vários geradores.\n"..
" - Por esse motivo\\, o TA2 recebeu seu próprio sistema de armazenamento de energia.\n"..
" - Os blocos de bateria do TA3 também servem como armazenamento de energia. Sua funcionalidade foi adaptada de acordo.\n"..
" - O sistema de armazenamento do TA4 foi revisado. O permutador de calor recebeu um novo número porque a funcionalidade foi movida do bloco inferior para o bloco central. Se eles estiverem sendo controlados remotamente\\, o número do nó deve ser adaptado. Os geradores não têm mais um menu próprio\\, mas são ligados/desligados apenas através do permutador de calor. O permutador de calor e o gerador agora devem estar conectados à mesma rede!\n"..
" - Vários sistemas de energia podem agora ser acoplados via blocos transformadores TA4.\n"..
" - Um novo bloco medidor de eletricidade TA4 para sub-redes também foi adicionado.\n"..
" - Pelo menos um bloco de bateria ou um sistema de armazenamento em cada rede.\n"..
"\n",
"Muitos outros blocos receberam alterações menores. Portanto\\, é possível que máquinas ou sistemas não reiniciem imediatamente após a troca. Em caso de falhas\\, as seguintes dicas ajudarão:\n"..
"\n"..
" - Desligue e ligue as máquinas novamente.\n"..
" - Remova um bloco de cabo de energia e coloque-o de volta no lugar.\n"..
" - Remova completamente o bloco e coloque-o de volta no lugar.\n"..
"\n",
"Techage adiciona novos itens ao jogo:\n"..
"\n"..
" - Meridium - uma liga para a produção de ferramentas luminosas no TA1\n"..
" - Usmium - um minério que é extraído no TA2 e necessário para o TA3\n"..
" - Baborium - um metal necessário para receitas no TA3\n"..
" - Petróleo - necessário no TA3\n"..
" - Bauxita - um minério de alumínio necessário no TA4 para produzir alumínio\n"..
" - Basalto - surge quando água e lava se encontram\n"..
"\n",
"O Meridium é uma liga de aço e cristais de mesecons. Lingotes de Meridium podem ser feitos com a caldeira a carvão a partir de aço e cristais de mesecons. O Meridium brilha no escuro. Ferramentas feitas de Meridium também emitem luz e são\\, portanto\\, muito úteis na mineração subterrânea.\n"..
"\n"..
"\n"..
"\n",
"O Usmium ocorre apenas como pepitas e só pode ser obtido lavando cascalho com o sistema de lavagem de cascalho TA2/TA3.\n"..
"\n"..
"\n"..
"\n",
"O Baborium só pode ser obtido através da mineração subterrânea. Essa substância só pode ser encontrada a uma profundidade de -250 a -340 metros.\n"..
"\n"..
"O Baborium só pode ser derretido na Fornalha Industrial TA3.\n"..
"\n"..
"\n"..
"\n",
"O Petróleo só pode ser encontrado com a ajuda do Explorer e extraído com a ajuda de máquinas apropriadas do TA3. Veja TA3.\n"..
"\n"..
"\n"..
"\n",
"A Bauxita é extraída apenas na mineração subterrânea. A Bauxita só é encontrada na pedra a uma altura entre -50 e -500 metros.\n"..
"É necessária para a produção de alumínio\\, que é principalmente usada no TA4.\n"..
"\n"..
"\n"..
"\n",
"O Basalto só é criado quando lava e água se encontram.\n"..
"A melhor coisa a fazer é montar um sistema onde uma fonte de lava e uma fonte de água se encontram.\n"..
"O Basalto é formado onde ambos os líquidos se encontram.\n"..
"Você pode construir um gerador automático de basalto com o Sign Bot.\n"..
"\n"..
"\n"..
"\n",
" - 28.09.2019: Solar system added\n"..
" - 05.10.2019: Data on the solar system and description of the inverter and the power terminal changed\n"..
" - 18.11.2019: Chapter for ores\\, reactor\\, aluminum\\, silo\\, bauxite\\, furnace heating\\, gravel washing system added\n"..
" - 22.02.2020: corrections and chapters on the update\n"..
" - 29.02.2020: ICTA controller added and further corrections\n"..
" - 14.03.2020 Lua controller added and further corrections\n"..
" - 22.03.2020 More TA4 blocks added\n"..
"\n",
},
images = {
"",
"",
"",
"",
"",
"techage_ta4",
"",
"",
"",
"",
"meridium",
"usmium",
"baborium",
"oil",
"bauxite",
"basalt",
"",
},
plans = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

172
doc/manual_ta1_DE.lua Normal file
View File

@ -0,0 +1,172 @@
return {
titles = {
"1,TA1: Eisenzeitalter",
"2,Köhler / Coal Pile",
"2,Kohlebrenner / Coal Burner",
"2,Wassermühle",
"3,TA1 Mühle",
"3,TA1 Schleusenschieber / TA1 Sluice Gate",
"3,TA1 Schleusengriff / TA1 Sluice Handle",
"3,TA1 Apfelholzbrett / TA1 Apple Wood Board",
"3,TA1 Apfel Mühlbachbrett / TA1 Apple Millrace Board",
"2,Erze und Werkzeuge",
"3,Hammer",
"3,Kiessieb / Gravel Sieve",
"3,Trichter / Hopper",
"3,Kies sieben mit dem Trichter",
"3,Meridium",
},
texts = {
"In TA1 geht es darum\\, mit einfachen Werkzeugen und Gerätschaften ausreichend Erze zu schürfen und Holzkohle herzustellen\\, so dass damit TA2 Maschinen hergestellt und betrieben werden können.\n"..
"\n"..
"Natürlich muss es für ein Eisenzeitalter auch Eisen geben und nicht nur Stahl (steel)\\, wie in \"Minetest Game\". Daher wurden einige Rezepte geändert\\, so dass zuerst Eisen hergestellt werden muss und erst später dann Stahl.\n"..
"\n"..
"Auch ist die Haltbarkeit der Werkzeuge an die Zeitalter angelehnt und entspricht damit nicht dem Minetest Originalspiel.\n"..
"Die Haltbarkeit/Härte bspw. für eine Axt ist:\n"..
"\n"..
" - Bronze: 20\n"..
" - Stahl: 30\n"..
"\n"..
"\n"..
"\n",
"Den Köhler brauchst du\\, um Holzkohle herzustellen. Holzkohle wird für den Brenner\\, aber auch bspw. in TA2 für die Dampfmaschine benötigt.\n"..
"\n"..
"Für den Köhler brauchst du:\n"..
"\n"..
" - einen Anzünderblock ('techage:lighter')\n"..
" - 26 Hölzblöcke (wood)\\, die zu einem Würfen aufgeschichtet werden. Die Holzsorte spielt keine Rolle.\n"..
" - Erde (dirt) um den Holzhaufen abzudecken.\n"..
" - Feuerstein und Eisen (technischer Name: 'fire:flint_and_steel') um den Anzünderblock anzuzünden.\n"..
"\n"..
"Bauanleitung (siehe auch Plan):\n"..
"\n"..
" - Baue eine 5x5 große Fläche aus Erde (dirt)\n"..
" - Platziere in die Mitte einen Anzünder (lighter)\n"..
" - Platziere rund um den Anzünder 7 Holz (wood)\\, aber lasse ein Loch zum Anzünder frei\n"..
" - Baue weitere 2 Schichten Holz darüber\\, so dass ein 3x3x3 großer Holzwürfel entsteht\n"..
" - Überdecke alles mit einer Schicht Erde zu einem 5x5x5 großen Würfel\\, aber lasse das Loch zum Anzünder frei\n"..
" - Entzünde den Anzünder und verschließe das Loch sofort mit jeweils einem Block Holz und Erde\n"..
" - Wenn du alles richtig gemacht hast\\, fängt der Köhler nach wenigen Sekunden an zu rauchen\n"..
" - Öffne den Köhler erst\\, wenn der Rauch verschwunden ist (ca. 20 min)\n"..
"\n"..
"Dann kannst du die 9 Holzkohleblöcke entnehmen und den Köhler erneut füllen.\n"..
"\n"..
"\n"..
"\n",
"Den Kohlebrenner benötigst du bspw. um Eisen und andere Erze im Schmelztiegel zu schmelzen. Es gibt verschiedene Rezepte\\, welche verschiedene Temperaturen benötigen. Je höher der Turm\\, um so heißer ist die Flamme. Eine Höhe von 11 Blöcken über der Bodenplatte ist für alle Rezepte ausreichend\\, ein Brenner mit dieser Höhe verbraucht aber auch mehr Holzkohle.\n"..
"\n"..
"Bauanleitung (siehe auch Plan):\n"..
"\n"..
" - Baue einen Turm aus Stein (cobble) mit einer 3x3 Grundfläche (7-11 Blöcke hoch)\n"..
" - Lasse unten ein Loch an einer Seite offen\n"..
" - Lege einen Anzünder (lighter) hinein\n"..
" - Fülle den Turm bis zum Rand mit Holzkohle\\, in dem du die Holzkohle von oben in das Loch fallen lässt\n"..
" - Entzünde den Anzünder durch das Loch\n"..
" - Platziere den Schmelztiegel oben auf dem Turm direkt in die Flamme\\, einen Block über dem Turmrand\n"..
" - Um den Brenner anzuhalten\\, schließe das Loch vorübergehend bspw. mit einem Erdblock.\n"..
"\n"..
"Der Schmelztiegel hat ein eigenes Menü mit Rezepten und ein Inventar\\, wo du die Erze hinein legst.\n"..
"\n"..
"\n"..
"\n",
"Mit der Wassermühle können Weizen und andere Getreide zu Mehl gemahlen und dann im Ofen zu Brot gebacken werden. Die Mühle wird mit\n"..
"Wasserkraft angetrieben. Dazu muss ein Mühlbach über einen Kanal zum Mühlrad geführt werden.\n"..
"Über eine Schleuse kann der Wasserfluss und damit das Mühlrad gesteuert werden.\n"..
"Die Schleuse besteht aus Schleusenschieber und Schleusengriff.\n"..
"\n"..
"Die Abbildung rechts (auf \"Plan\" klicken) zeigt den Aufbau der Wassermühle.\n"..
"\n"..
"\n"..
"\n",
"Mit der Wassermühle können Weizen und andere Getreide zu Mehl gemahlen und dann im Ofen zu Brot gebacken werden.\n"..
"Die Mühle muss mit einer TA1 Achse mit dem Mühlrad verbunden werden. Die Kraft des Mühlrades reicht nur für eine Mühle.\n"..
"\n"..
"Die Mühle kann mit Hilfe eines Minecart Hoppers automatisiert werden\\, so dass das Mehl bspw. direkt von der Mühle in einen Ofen befördert wird\\, um daraus Brot zu backen.\n"..
"\n"..
"\n"..
"\n",
"Der Schleusenschieber muss auf gleicher Höhe wie die Wasseroberfläche direkt an einen Teich oder in einen Bach gesetzt werden.\n"..
"Wird die Schleuse geöffnet\\, so fließt Wasser durch den Schieber. Dieses Wasser muss dann zum Mühlrad geleitet werden und treibt dort die Mühle an.\n"..
"\n"..
"\n"..
"\n",
"Der TA1 Schleusengriff muss auf den Schleusenschieber gesetzt werden. Mit Hilfe des Schleusengriffs (Rechtsklick) kann der Schieber geöffnet werden.\n"..
"\n"..
"\n"..
"\n",
"Block in verschiedenen Holzsorten zum Bauen des Mühlbachkanals. Es kann aber auch jedes andere Material verwendet werden.\n"..
"\n"..
"\n"..
"\n",
"Block in verschiedenen Holzsorten zum Bauen des Mühlbachkanals. Dieser Block eignet sich speziell in Verbindung mit den Pfosten des Holzzauns um eine Stütze für den Kanal zu bauen.\n"..
"\n"..
"\n"..
"\n",
"TA1 hat seine eigenen Werkzeuge wie Hammer und Kiessieb\\, aber auch der Minecart Hopper kann genutzt werden.\n"..
"\n"..
"\n"..
"\n",
"Mit dem TA1 Hammer können Steine (stone) und Kopfsteinpflaster-Steine (cobble) zu Kies (gravel) zertrümmert werden. Der Hammer ist in verschiedenen Ausführungen und damit verschiedenen Eigenschaften verfügbar: Bronze\\, Stahl\\, Mese und Diamant.\n"..
"\n"..
"\n"..
"\n",
"Mit dem Kiessieb können Erze aus dem Kies gesiebt werden. Dazu mit dem Kies (gravel) auf das Sieb klicken. Der gesiebte Kies und die Erze fallen unten heraus.\n"..
"\n"..
"Um hier nicht stundenlang am Sieb zu stehen\\, kann das Sieben mit dem Trichter (hopper) automatisiert werden.\n"..
"\n"..
"\n"..
"\n",
"Der Hopper aus der Mod \"Minecart\" dient in erster Linie zum Be- und Entladen von Minecarts. Er saugt Gegenstände (items) von oben ein und gibt diese nach rechts weiter. Beim Platzieren des Trichters muss daher auf die Ausgaberichtung geachtet werden.\n"..
"\n"..
"Der Trichter kann aber auch Items aus Kisten (chest) ziehen\\, sofern die Kiste neben oder auf dem Trichter steht. \n"..
"\n"..
"Der Trichter kann auch Items in Kisten legen\\, sofern die Kiste neben dem Trichter steht.\n"..
"\n"..
"\n"..
"\n",
"Mit Hilfe von zwei Kisten\\, zwei Trichtern und einem Kiessieb kann der Siebevorgang automatisiert werden. Der Plan rechts zeigt den Aufbau.\n"..
"\n"..
"Bei den Kisten darauf achten\\, dass es die \"chest_locked\" ist\\, sonst klaut dir jemand die wertvollen Erze aus der Kiste unten.\n"..
"\n"..
"\n"..
"\n",
"TA1 hat seine eigene Metalllegierung Meridium. Meridium Ingots können mit dem Kohlebrenner aus Stahl und Mesesplittern hergestellt werden. Meridium leuchtet im Dunkeln. Auch Werkzeuge aus Meridium leuchten und sind daher im Untertagebau sehr hilfreich.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta1",
"",
"",
"",
"",
"ta1_sluice",
"ta1_sluice_handle",
"ta1_board1",
"ta1_board2",
"ta1_gravelsieve",
"hammer",
"ta1_gravelsieve",
"ta1_hopper",
"",
"meridium",
},
plans = {
"",
"coalpile",
"coalburner",
"watermill1",
"watermill2",
"",
"",
"",
"",
"",
"",
"",
"",
"hoppersieve",
"",
}
}

170
doc/manual_ta1_EN.lua Normal file
View File

@ -0,0 +1,170 @@
return {
titles = {
"1,TA1: Iron Age",
"2,Charcoal Pile (charcoal burner)",
"2,Melting Furnace",
"2,Watermill",
"3,TA1 mill",
"3,TA1 sluice gate",
"3,TA1 sluice handle",
"3,TA1 Apple Wood Board",
"3,TA1 Apple Millrace Board",
"2,Ores and Tools",
"3,Hammer",
"3,Gravel Sieve",
"3,Hopper",
"3,Gravel seven with the hopper",
"3,Meridium",
},
texts = {
"TA1 is about mining sufficient ores and producing charcoal with simple tools and equipment\\, so that TA2 machines can be manufactured and operated.\n"..
"\n"..
"Of course\\, for an iron age there must also be iron and not just steel\\, as in \"Minetest Game\". As a result\\, some recipes have been changed so that iron has to be produced first and then steel later.\n"..
"\n"..
"The durability of the tools is based on the ages and therefore does not correspond to the original Minetest game.\n"..
"The durability / hardness for an axe\\, for example:\n"..
"\n"..
" - Bronze: 20\n"..
" - Steel: 30\n"..
"\n"..
"\n"..
"\n",
"You need the Charcoal Pile to make charcoal. Charcoal is required for the melting furnace\\, but also\\, for example\\, in TA2 for the steam engine.\n"..
"\n"..
"For the charcoal burner you need:\n"..
"\n"..
" - a lighter block ('techage:lighter')\n"..
" - 26 wooden blocks that are stacked into a pile of wood. The type of wood is irrelevant\n"..
" - Dirt to cover the pile of wood\n"..
" - Flint and Iron (technical name: 'fire:flint_and_steel') to light the lighter block\n"..
"\n"..
"Building instructions (see also plan):\n"..
"\n"..
" - Build a 5x5 area of dirt\n"..
" - Place 7 wood around the lighter but leave a hole to the lighter\n"..
" - Build another 2 layers of wood on top\\, making a 3x3x3 wooden cube\n"..
" - Cover everything with a layer of dirt into a 5x5x5 cube\\, but keep the hole to the lighter open\n"..
" - Light the lighter and immediately close the hole with a block of wood and dirt\n"..
" - If you have done everything correctly\\, the coal burner will start smoking after a few seconds\n"..
" - Only open the charcoal burner when the smoke has disappeared (approx. 20 min)\n"..
"\n"..
"Then you can remove the 9 charcoal blocks and refill the Charcoal Pile.\n"..
"\n"..
"\n"..
"\n",
"You need the melting furnace\\, for example\\, to melt iron and other ores in the melting pot. There are different recipes that require different temperatures. The higher the melting tower\\, the hotter the flame. A height of 11 blocks above the base plate is for all recipes\\, but a burner with this height also requires more charcoal.\n"..
"\n"..
"Building instructions (see also plan):\n"..
"\n"..
" - Build a stone tower (cobble) with a 3x3 base (7-11 blocks high)\n"..
" - Leave a hole open on one side at the bottom\n"..
" - Put a lighter in it\n"..
" - Fill the tower to the brim with charcoal by dropping the charcoal into the hole from above\n"..
" - Light the lighter through the hole\n"..
" - Place the melting pot on top of the tower directly into the flame\\, one block above the tower edge\n"..
" - To stop the burner\\, temporarily close the hole with an dirt block\\, for example.\n"..
"\n"..
"The melting pot has its own menu of recipes and an inventory where you have to put the ores in.\n"..
"\n"..
"\n"..
"\n",
"The watermill can be used to grind wheat and other grains into flour and then bake them in the furnace to make bread. \n"..
"The mill is powered by water power. To do this\\, a millrace must be led to the mill wheel via a canal.\n"..
"The water flow and thus the mill wheel can be controlled via a sluice. The sluice consists of the sluice lock and sluice handle.\n"..
"\n"..
"The picture on the right (click on \"Plan\") shows the structure of the watermill. \n"..
"\n"..
"\n"..
"\n",
"The watermill can be used to grind wheat and other grains into flour and then bake them in the oven to make bread. The mill must be connected to the mill wheel with a TA1 axle. The power of the mill wheel is only enough for one mill.\n"..
"\n"..
"The mill can be automated with the help of a Minecart Hopper\\, so that the flour\\, for example\\, is transported directly from the mill into an furnace in order to bake bread from it.\n"..
"\n"..
"\n"..
"\n",
"The sluice gate valve must be placed directly next to a pond or in a stream at the same height as the water surface.\n"..
"When the gate is opened\\, water flows through the slide. This water then has to be fed to the mill wheel\\, where it drives the mill.\n"..
"\n"..
"\n"..
"\n",
"The TA1 sluice handle must be placed on the sluice gate. The gate can be opened with the aid of the sluice handle (right click).\n"..
"\n"..
"\n"..
"\n",
"Block in different types of wood for building the millrace canal. However\\, any other material can also be used.\n"..
"\n"..
"\n"..
"\n",
"Block in different types of wood for building the millrace canal. This block is especially suitable in connection\n"..
"with posts of the wooden fence to build a support of the canal.\n"..
"\n"..
"\n"..
"\n",
"TA1 has its own tools such as hammer and gravel sieve\\, but the Minecart Hopper can also be used.\n"..
"\n"..
"\n"..
"\n",
"The TA1 hammer can be used to knock/dig stone in a mine\\, but also to smash cobble to gravel. The hammer is available in different versions and therefore different properties: bronze\\, steel\\, brass and diamond.\n"..
"\n"..
"\n"..
"\n",
"Ores can be sifted from the gravel with the gravel sieve. To do this\\, click on the sieve with the gravel. The sifted gravel and ores fall out below.\n"..
"\n"..
"In order not to stand at the sieve for hours\\, sieving can be automated with the hopper.\n"..
"\n"..
"\n"..
"\n",
"The hopper from the \"Minecart\" mod is primarily used for loading and unloading Minecarts. He sucks in items from above and passes them on to the right. Therefore\\, when placing the hopper\\, pay attention to the direction of dispensing.\n"..
"\n"..
"The hopper can also pull items from boxes (chest)\\, provided the box is next to or on the hopper.\n"..
"\n"..
"The hopper can also put items in boxes if the box is next to the hopper.\n"..
"\n"..
"\n"..
"\n",
"With the help of two boxes\\, two hoppers and a gravel sieve\\, the sieving process can be automated. The plan on the right shows the structure.\n"..
"\n"..
"Make sure that the boxes are \"chest_locked\"\\, otherwise someone will steal the valuable ores from the box below.\n"..
"\n"..
"\n"..
"\n",
"TA1 has its own metal alloy meridium. Meridium ingots can be made with the coal burner from steel and mesecons crystals. Meridium glows in the dark. Tools made of Meridium also light up and are therefore very helpful in underground mining.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta1",
"",
"",
"",
"",
"ta1_sluice",
"ta1_sluice_handle",
"ta1_board1",
"ta1_board2",
"ta1_gravelsieve",
"hammer",
"ta1_gravelsieve",
"ta1_hopper",
"",
"meridium",
},
plans = {
"",
"coalpile",
"coalburner",
"watermill1",
"watermill2",
"",
"",
"",
"",
"",
"",
"",
"",
"hoppersieve",
"",
}
}

153
doc/manual_ta1_pt-BR.lua Normal file
View File

@ -0,0 +1,153 @@
return {
titles = {
"1,TA1: Idade do Ferro",
"2,Pilha de Carvão (queimador de carvão)",
"2,Forno de Fundição",
"2,Moinho d'Água",
"3,Moinho d'Água TA1",
"3,Comporta TA1",
"3,Alavanca de Comporta TA1",
"3,Placa de Madeira de Maçã TA1",
"3,Placa de Curso d'Água de Maçã TA1",
"1,Minérios e Ferramentas",
"2,Martelo",
"2,Peneira de Cascalho(Sieve)",
"2,Funil (Minecart Hopper)",
"2,Peneirando sete cascalhos com Funil",
},
texts = {
"TA1 trata da extração de minérios suficientes e da produção de carvão com ferramentas e equipamentos simples\\, para que as máquinas TA2 possam ser fabricadas e operadas.\n"..
"\n"..
"É claro que\\, para uma Idade do Ferro\\, deve haver ferro e não apenas aço\\, como em \"Minetest Game\". Como resultado\\, algumas receitas foram alteradas para que o ferro precise ser produzido primeiro e\\, posteriormente\\, o aço.\n"..
"\n"..
"A durabilidade das ferramentas é baseada nas eras e\\, portanto\\, não corresponde ao jogo original do Minetest.\n"..
"A durabilidade/dureza de um machado\\, por exemplo:\n"..
"\n"..
" - Bronze: 20\n"..
" - Aço: 30\n"..
"\n"..
"\n"..
"\n",
"Você precisa da Pilha de Carvão para fazer carvão. O carvão é necessário para a fundição\\, mas também\\, por exemplo\\, em TA2 para a máquina a vapor.\n"..
"\n"..
"Para o queimador de carvão\\, você precisa de:\n"..
"\n"..
" - Um bloco de acendedor ('techage:lighter')\n"..
" - 26 blocos de madeira empilhados para formar um monte de madeira. O tipo de madeira é irrelevante.\n"..
" - Terra para cobrir o monte de madeira\n"..
" - Pedra lascada e Ferro (nome técnico: 'fire:flint_and_steel') para acender o bloco de acendedor\n"..
"\n"..
"Instruções de construção (veja também o plano):\n"..
"\n"..
" - Construa uma área de 5x5 de terra\n"..
" - Coloque 7 blocos de madeira ao redor do acendedor\\, mas deixe um buraco para o acendedor\n"..
" - Construa mais 2 camadas de madeira em cima\\, formando um cubo de madeira 3x3x3\n"..
" - Cubra tudo com uma camada de terra formando um cubo de 5x5x5\\, mas mantenha o buraco para o acendedor aberto\n"..
" - Acenda utilizando o isqueiro e feche imediatamente o buraco com um bloco de madeira e terra\n"..
" - Se você fez tudo corretamente\\, o queimador de carvão começará a soltar fumaça após alguns segundos\n"..
" - Só abra o queimador de carvão quando a fumaça tiver desaparecido (aproximadamente 20 minutos)\n"..
" - Então você pode remover os 9 blocos de carvão e reabastecer a Pilha de Carvão.\n"..
"\n"..
"\n"..
"\n",
"Você precisa do forno de fundição\\, por exemplo\\, para fundir ferro e outros minérios no Vaso de fundição(cadinho). Existem receitas diferentes que requerem diferentes temperaturas. Quanto mais alto a torre de fusão\\, mais quente é a chama. Uma altura de 11 blocos acima da placa base é para todas as receitas\\, mas um queimador com essa altura também requer mais carvão.\n"..
"\n"..
"Instruções de construção (veja também o plano):\n"..
"\n"..
" - Construa uma torre de pedregulho (cobble) com uma base de 3x3 (7-11 blocos de altura)\n"..
" - Deixe um buraco aberto de um lado na parte inferior\n"..
" - Coloque um acendedor nele\n"..
" - Encha a torre até a borda com carvão despejando o carvão no buraco de cima para baixo\n"..
" - Acenda o acendedor através do buraco\n"..
" - Coloque o Vaso de fundição(cadinho) no topo da torre diretamente na chama\\, um bloco acima da borda da torre\n"..
" - Para parar o queimador\\, feche temporariamente o buraco com um bloco de terra\\, por exemplo.\n"..
" - O Vaso de fundição(cadinho) tem seu próprio menu de receitas e um inventário onde você precisa colocar os minérios.\n"..
"\n"..
"\n"..
"\n",
"O moinho d'água pode ser usado para moer trigo e outros grãos para fazer farinha e depois assá-los no forno para fazer pão.\n"..
"O moinho é alimentado por energia hidráulica. Para isso\\, um curso de água deve ser conduzido até a roda do moinho através de um canal.\n"..
"O fluxo de água e\\, portanto\\, a roda do moinho\\, podem ser controlados por meio de uma comporta. A comporta é composta pelo bloqueio de comporta e pela alavanca de comporta.\n"..
"\n"..
"A imagem à direita (clique em \"Plano\") mostra a estrutura do moinho d'água.\n"..
"\n"..
"\n"..
"\n",
"O moinho d'água pode ser usado para moer trigo e outros grãos para fazer farinha e depois assá-los no forno para fazer pão. O moinho deve ser conectado à roda do moinho com um eixo TA1. A potência da roda do moinho é apenas suficiente para um moinho.\n"..
"\n"..
"O moinho pode ser automatizado com a ajuda de um Funil(Minecart Hopper)\\, para que a farinha\\, por exemplo\\, seja transportada diretamente do moinho para um forno para assar pão.\n"..
"\n"..
"\n"..
"\n",
"A válvula de comporta deve ser colocada diretamente ao lado de um lago ou em um riacho na mesma altura que a superfície da água.\n"..
"Quando a comporta é aberta\\, a água flui através do canal. Essa água deve ser conduzida até a roda do moinho\\, onde movimenta o moinho.\n"..
"\n"..
"\n"..
"\n",
"A alavanca de comporta TA1 deve ser colocada na comporta. A comporta pode ser aberta com a ajuda da alavanca de comporta (clique com o botão direito).\n"..
"\n"..
"\n"..
"\n",
"Podem ser usados bloco de diferentes tipos de madeira para construir o canal do curso d'água. No entanto\\, qualquer outro material também pode ser usado.\n"..
"\n"..
"\n"..
"\n",
"Podem ser utilizados blocos em diferentes tipos de madeira para construir o canal do curso d'água. Este bloco é especialmente adequado em conexão com postes da cerca de madeira para construir um suporte do canal.\n"..
"\n"..
"\n"..
"\n",
"O TA1 possui suas próprias ferramentas\\, como martelo e peneira de cascalho\\, mas o Funil(Minecart Hopper) também pode ser utilizado.\n"..
"\n",
"O martelo TA1 pode ser utilizado para bater/escavar pedra em uma mina\\, mas também para quebrar pedregulho(cobble) em cascalho(gravel). O martelo está disponível em diferentes versões\\, cada uma com propriedades distintas: bronze\\, aço\\, latão e diamante.\n"..
"\n",
"Minérios podem ser peneirados do cascalho com a peneira de cascalho. Para fazer isso\\, clique na peneira com o cascalho. O cascalho peneirado e os minérios caem abaixo.\n"..
"\n"..
"Para não ficar horas na peneira\\, é possível automatizar o processo com o Funil(Minecart Hopper).\n"..
"\n",
"O funil do mod \"Minecart Hopper\" é utilizado principalmente para carregar e descarregar carrinhos de mineração. Ele suga itens de cima e os passa para a direita. Portanto\\, ao posicionar o funil\\, preste atenção na direção de dispensa.\n"..
"\n"..
"O funil também pode puxar itens de baús\\, desde que a caixa esteja ao lado ou em cima do funil.\n"..
"\n"..
"O funil também pode colocar itens em baús se a caixa estiver ao lado do funil.\n"..
"\n",
"Com a ajuda de dois baús\\, dois funis e uma peneira de cascalho\\, o processo de peneiração pode ser automatizado. O plano à direita mostra a estrutura.\n"..
"\n"..
"Certifique-se de que os baús são protegidos\\, caso contrário\\, alguém pode roubar os minérios valiosos do baú abaixo.\n"..
"\n"..
"Meridium\n"..
"O TA1 possui sua própria liga metálica\\, o Meridium. Lingotes de meridium podem ser feitos com a caldeira a carvão\\, utilizando aço e cristais de mesecons. O meridium brilha no escuro. Ferramentas feitas de meridium também emitem luz\\, sendo\\, portanto\\, muito úteis na mineração subterrânea.\n"..
"\n",
},
images = {
"techage_ta1",
"",
"",
"",
"",
"ta1_sluice",
"ta1_sluice_handle",
"ta1_board1",
"ta1_board2",
"",
"",
"",
"",
"",
},
plans = {
"",
"coalpile",
"coalburner",
"watermill1",
"watermill2",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

308
doc/manual_ta2_DE.lua Normal file
View File

@ -0,0 +1,308 @@
return {
titles = {
"1,TA2: Dampfzeitalter",
"2,Dampfmaschine",
"3,TA2 Feuerbox / Firebox",
"3,TA2 Boiler",
"3,TA2 Zylinder /Cylinder",
"3,TA2 Schwungrad / Flywheel",
"3,TA2 Dampfleitungen / Steam Pipe",
"3,TA2 Antriebsachsen / TA2 Drive Axle",
"3,TA2 Stromgenerator / TA2 Power Generator",
"2,TA2 Energiespeicher",
"3,TA2 Seilwinde / TA2 Winch",
"3,TA2 Gewichtekiste / TA2 Weight Chest",
"3,TA2 Kupplung / TA2 Clutch",
"2,Items schieben und sortieren",
"3,Röhren / TechAge Tube",
"3,Röhren Konzentrator / Tube Concentrator",
"3,TA2 Schieber / Pusher",
"3,TA2 Verteiler / Distributor",
"2,Kieswaschanlage",
"3,TA2 Kiesspüler / Gravel Rinser",
"2,Stein brechen\\, mahlen und sieben",
"3,TA2 Steinbrecher / Quarry",
"3,TA2 Mühle / Grinder",
"3,TA2 Kiessieb / Gravel Sieve",
"2,Items produzieren",
"3,TA2 Autocrafter",
"3,TA2 Elektronikfabrik / Electronic Fab",
"2,Sonstige Blöcke",
"3,TA2 Flüssigkeitensammler / Liquid Sampler",
"3,TA2 Gesicherte Kiste / Protected Chest",
"3,Techage Forceload Block",
},
texts = {
"In TA2 geht es darum\\, erste Maschinen zur Verarbeitung von Erzen zu bauen und zu betreiben. Einige Maschinen müssen dazu über Antriebsachsen angetrieben werden. Dazu musst du eine Dampfmaschine bauen und diese mit Kohle oder Holzkohle anheizen.\n"..
"\n"..
"In TA2 steht auch ein Kiesspüler zur Verfügung\\, mit dem seltene Erze wie Usmium Nuggets ausgewaschen werden können. Diese Nuggets wirst du später für weitere Rezepte brauchen.\n"..
"\n"..
"\n"..
"\n",
"Die Dampfmaschine besteht aus mehreren Blöcken und muss wie im Plan rechts abgebildet\\, zusammen gebaut werden. Dazu werden die Blöcke TA2 Feuerbox\\, TA2 Boiler oben\\, TA2 Boiler unten\\, TA2 Zylinder\\, TA2 Schwungrad und Dampfleitungen benötigt.\n"..
"\n"..
"Zusätzlich werden Antriebsachsen sowie Getriebeblöcke für Richtungswechsel benötigt. Das Schwungrad muss über die Antriebsachsen mit allen Maschinen verbunden werden\\, die angetrieben werden müssen.\n"..
"\n"..
"Bei allen Blöcken beim Setzen immer auch die Ausrichtung achten:\n"..
"\n"..
" - Zylinder links\\, Schwungrad rechts daneben\n"..
" - Dampfleitungen anschließen\\, wo ein entsprechendes Loch ist\n"..
" - Antriebsachse beim Schwungrad nur rechts\n"..
" - bei allen Maschinen kann die Antriebsachse an allen Seiten angeschlossen werden\\, welche nicht durch andere Funktionen belegt wird\\, wie bspw. die IN und OUT Löcher bei Mühle und Sieb.\n"..
"\n"..
"Der Boiler muss mit Wasser gefüllt werden. Dazu bis zu 10 Eimer Wasser in den Boiler füllen.\n"..
"Die Feuerbox muss mit Kohle oder Holzkohle gefüllt werden.\n"..
"Wenn das Wasser heiß ist (Temperaturanzeige ganz oben)\\, kann die Dampfmaschine am Schwungrad gestartet werden.\n"..
"\n"..
"Die Dampfmaschine leistet 25 ku und kann damit mehrere Maschinen gleichzeitig antreiben.\n"..
"\n"..
"\n"..
"\n",
"Teil der Dampfmaschine. \n"..
"\n"..
"Die Feuerbox muss mit Kohle oder Holzkohle gefüllt werden. Die Brenndauer ist abhängig von der Leistung\\, die von der Dampfmaschine angefordert wird. Unter Volllast brennt Kohle 32 s und Holzkohle 96 s.\n"..
"\n"..
"\n"..
"\n",
"Teil der Dampfmaschine. Muss mit Wasser gefüllt werden. Dies erfolgt durch Klicken mit einem Wassereimer auf den Boiler. Wenn kein Wasser mehr vorhanden ist oder die Temperatur zu weit absinkt\\, schaltet sich die Dampfmaschine ab. Bei der Dampfmaschine geht bei jedem Kolbenhub etwas Wasser als Dampf verloren\\, daher muss regelmäßig Wasser nachgefüllt werden.\n"..
"\n"..
"\n"..
"\n",
"Teil der Dampfmaschine.\n"..
"\n"..
"\n"..
"\n",
"Antriebsteil der Dampfmaschine. Das Schwungrad muss über Antriebsachsen mit den Maschinen verbunden werden. \n"..
"\n"..
"\n"..
"\n",
"Teil der Dampfmaschine. Der Boiler muss mit dem Zylinder über die Dampfleitungen (steam pipes) verbunden werden. Die Dampfleitung besitzt keine Abzweigungen\\, die maximale Länge beträgt 12 m (Blöcke).\n"..
"\n"..
"\n"..
"\n",
"Die Antriebsachsen dienen zur Kraftübertragung von der Dampfmaschine zu anderen Maschinen. Die maximale Länge einer Antriebsachse beträgt 10 Blöcke. Über Getriebeblöcke können auch größere Strecken überbrückt\\, sowie Abzweigungen und Richtungswechsel realisiert werden.\n"..
"\n"..
"\n"..
"\n",
"Um Lampen oder andere Stromverbraucher an einer Dampfmaschine betreiben zu können\\, wird der TA2 Stromgenerator benötigt. Der TA2 Stromgenerator muss auf einer Seite mit Antriebsachsen verbunden werden und liefert dann auf der anderen Seite elektrischen Strom.\n"..
"\n"..
"Wird der Stromgenerator nicht mit ausreichend Kraft versorgt\\, geht er in einen Fehlerzustand und muss über einen Rechtsklick wieder aktiviert werden.\n"..
"\n"..
"Das Stromgenerator nimmt primär max. 25 ku an Achsenkraft auf und gibt sekundär max. 24 ku als Strom wieder ab. Er verbraucht also ein ku für die Umwandlung.\n"..
"\n"..
"\n"..
"\n",
"Bei größeren Anlagen mit mehreren Dampfmaschinen oder vielen angetriebenen Maschinen empfiehlt sich ein Energiespeicher. Der Energiespeicher bei TA2 arbeitet mit Lageenergie. Dazu wird Balast (Steine\\, Kies) in einer Kiste mit Hilfe einer Seilwinde in die Höhe gezogen. Ist überschüssige Energie im Achsen-Netzwerk vorhanden\\, so wird die Kiste nach oben gezogen. Wird kurzfristig mehr Energie benötigt\\, als die Dampfmaschine liefern kann\\, so gibt der Energiespeicher die gespeicherte Energie wieder ab\\, und die Balast-Kiste bewegt sich wieder nach unten.\n"..
"\n"..
"Der Energiespeicher besteht aus mehreren Blöcken und muss wie im Plan rechts abgebildet\\, zusammen gebaut werden.\n"..
"\n"..
"Um die maximale Speicherkapazität zu erreichen\\, muss die Kiste mit Gewichten komplett gefüllt\\, und der Mast inklusive der zwei Getriebeblöcke 12 Blöcke hoch sein. Kleinere Aufbauten sind aber auch möglich.\n"..
"\n"..
"\n"..
"\n",
"Die Seilwinde muss mit einem Getriebeblock verbunden werden und kann so überschüssige Energie aufnehmen und damit eine Gewichtekiste nach oben ziehen. Achte beim Aufbau der Seilwinde darauf\\, dass der Pfeil auf der Blockoberseite zum Getriebeblock zeigt. Die maximale Seillänge beträgt 10 Blöcke.\n"..
"\n"..
"\n"..
"\n",
"Diese Kiste muss mit bis zu 10 Blöcken Abstand unter die Seilwinde gesetzt und mit Pflastersteinen Kies oder Sand gefüllt werden. Ist das Mindestgewicht von einem Stack (99+ Items) erreicht und überschüssige Energie vorhanden\\, wird die Kiste automatisch über eine Seil mit der Seilwinde verbunden und in die Höhe gezogen.\n"..
"\n"..
"\n"..
"\n",
"Mit der Kupplung können Achsen und Maschinen vom Energiespeicher getrennt werden. Damit kommen die Achsen nach der Kupplung zum Stillstand und Maschinenanlagen können umgebaut werden. Achte beim Aufbau der Kupplung darauf\\, dass der Pfeil auf der Blockoberseite zum Energiespeicher zeigt. \n"..
"\n"..
"\n"..
"\n",
"Um Gegenstände (Items) von einer Verarbeitungsstation zur nächsten weiter zu transportieren\\, werden Schieber und Röhren verwendet. Siehe Plan.\n"..
"\n"..
"\n"..
"\n",
"Zwei Maschinen können mit Hilfe eines Schiebers und einer Röhre (tube) verbunden werden. Röhren besitzen keine Abzweigungen. Die maximale Länge beträgt 200 m (Blöcke).\n"..
"\n"..
"Röhren können alternativ mit Hilfe der Shift-Taste platziert werden. Dies erlaubt bspw. Röhren parallel zu verlegen\\, ohne dass diese sich unbeabsichtigt verbinden.\n"..
"\n"..
"Die Transportkapazität einer Röhre ist unbegrenzt und nur durch die Schieber begrenzt.\n"..
"\n"..
"\n"..
"\n",
"Über den Konzentrator können mehrere Röhren zu einer Röhre zusammengeführt werden. Die Richtung\\, in der alle Items weitergegeben werden\\, ist mit einem Pfeil markiert.\n"..
"\n"..
"\n"..
"\n",
"Ein Schieber ist in der Lage\\, Items aus Kisten oder Maschinen zu ziehen und in andere Kisten oder Maschinen zu schieben. Oder anders gesagt: Zwischen zwei Blöcken mit Inventar muss ein und genau ein Schieber sein. Mehrere Schieber in Reihe sind nicht möglich.\n"..
"In die Gegenrichtung ist ein Schieber für Items aber durchlässig\\, so dass eine Kiste über eine Röhre gefüllt und ebenso geleert werden kann. \n"..
"\n"..
"Ein Schieber geht in den Zustand \"standby\"\\, wenn der keine Items zum Schieben hat. Ist der Ausgang blockiert oder das Inventory des Empfängers voll\\, so geht der Schieber in den Zustand \"blocked\". Aus beiden Zuständen kommt der Schieber nach einigen Sekunden selbsttätig wieder raus\\, sofern sich die Situation geändert hat.\n"..
"\n"..
"Der Verarbeitungsleistung eines TA2 Schiebers beträgt 2 Items alle 2 s.\n"..
"\n"..
"\n"..
"\n",
"Der Verteiler ist in der Lage\\, die Items aus seinem Inventar sortiert in bis zu vier Richtungen weiter zu transportieren. Dazu muss der Verteiler entsprechend konfiguriert werden. \n"..
"\n"..
"Der Verteiler besitzt dazu ein Menü mit 4 Filter mit unterschiedlichen Farben\\, entsprechend den 4 Ausgängen. Soll ein Ausgang genutzt werden\\, so muss der entsprechende Filter über die \"on\" Checkbox aktiviert werden. Alle Items\\, die für diesen Filter konfiguriert sind\\, werden über den zugeordneten Ausgang ausgegeben. Wird ein Filter aktiviert\\, ohne das Items konfiguriert werden\\, so sprechen wir hier von einem \"nicht-konfigurierten\"\\, offenen Ausgang.\n"..
"\n"..
"*Achtung: Der Verteiler ist an seinen Ausgängen gleichzeitig ein Schieber. Daher niemals die Gegenstände mit einem Schieber aus dem Verteiler ziehen!*\n"..
"\n"..
"Für einen nicht-konfigurierten Ausgang gibt es zwei Betriebsarten:\n"..
"\n"..
"1) Alle Items ausgeben\\, die an keine anderen Ausgängen ausgegeben werden können\\, auch wenn diese blockiert sind.\n"..
"\n"..
"2) Nur die Items ausgeben\\, die für keinen anderen Filter konfiguriert wurden.\n"..
"\n"..
"Im ersten Fall werden immer alle Items weitergeleitet und der Verteiler läuft nicht voll. Im zweiten Fall werden Items zurückgehalten und der Verteiler kann voll laufen und in der Folge blockieren.\n"..
"\n"..
"Einstellbar ist die Betriebsart über die \"blockiere\" Checkbox.\n"..
"\n"..
"Der Verarbeitungsleistung eines TA2 Verteilers beträgt 4 Items alle 2 s\\, wobei der Verteiler dabei versucht\\, die 4 Items auf die offenen Ausgänge zu verteilen.\n"..
"\n"..
"Wird dasselbe Item in einem Filter mehrfach hinterlegt\\, so beeinflusst dies das langfristige Verteilungsverhältnis entsprechend.\n"..
"\n"..
"Bitte beachte\\, dass die Verteilung ein probabilistischer Vorgang ist\\, d.h. die Verhältnisse werden nicht exakt\\, sondern nur langfristig eingehalten.\n"..
"\n"..
"In den Filtern beträgt die maximale Stackgröße 12\\; insgesamt können höchstens 36 Items konfiguriert werden.\n"..
"\n"..
"\n"..
"\n",
"Die Kieswaschanlage ist eine komplexere Maschine mit dem Ziel\\, Usmium Nuggets aus gesiebtem Kies auszuwaschen. Für den Aufbau wird ein TA2 Kiesspüler mit Achsenantrieb\\, ein Trichter\\, eine Kiste\\, sowie fließendes Wasser benötigt. \n"..
"\n"..
"Aufbau von links nach rechts (siehe auch Plan):\n"..
"\n"..
" - Ein Erdblock\\, darauf die Wasserquelle\\, umgeben auf 3 Seiten von bspw. Glasblöcken\n"..
" - daneben den Kiesspüler\\, ggf. mit Röhrenanschlüssen für den Kies An- und Abtransport\n"..
" - dann den Trichter mit Kiste\n"..
"\n"..
"Das Ganze umgeben von weiteren Glasblöcken\\, so dass das Wasser über den Kiesspüler und den Trichter fließt und ausgespülten Nuggets vom Trichter wieder eingesammelt werden können.\n"..
"\n"..
"\n"..
"\n",
"Der Kiesspüler ist in der Lage\\, aus bereits gesiebtem Kies die Erze Usmium und Kupfer auszuspülen\\, sofern dieser von Wasser überspült wird.\n"..
"\n"..
"Ob der Kiesspüler korrekt arbeitet\\, kann mit Hilfe von Stöcken (sticks) getestet werden\\, wenn diese in das Inventar des Kiesspülers getan werden. Diese müssen einzeln ausgespült und vom Trichter eingefangen werden.\n"..
"\n"..
"Die Verarbeitungsleistung ist ein Kies Item alle 2 s. Der Kiesspüler benötigt 3 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Das Brechen\\, Mahlen und Siebe von Gestein dient zur Gewinnung von Erzen. Gesiebtes Kies kann aber auch anderweitig genutzt werden. Steinbrecher\\, Mühle und Sieb müssen angetrieben und damit in der Nähe einer Dampfmaschine aufgebaut werden.\n"..
"\n"..
"\n"..
"\n",
"Der Steinbrecher dient zum Abbau von Steinen und anderen Materialien aus dem Untergrund. Der Steinbrecher gräbt ein 5x5 Blöcke großes Loch. Die Tiefe ist einstellbar.\n"..
"Die Verarbeitungsleistung ist ein Block alle 4 s. Der Steinbrecher benötigt 10 ku Energie. Die maximale Tiefe beträgt 20 Meter. Für größere Tiefen siehe TA3/TA4.\n"..
"\n"..
"\n"..
"\n",
"Die Mühle ist in der Lage\\, verschiedenes Gestein\\, aber auch Holz und andere Items zu mahlen.\n"..
"Die Verarbeitungsleistung ist ein Item alle 4 s. Die Mühle benötigt 4 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Das Kiessieb ist in der Lage\\, Kies zu sieben um Erze zu gewinnen. Als Ergebnis erhält man teilweise \"gesiebtes Kies\"\\, was nicht wieder gesiebt werden kann.\n"..
"Die Verarbeitungsleistung ist ein Item alle 4 s. Das Kiessieb benötigt 3 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Mit TA2 Maschinen können nicht nur Erze gewonnen\\, sondern auch Gegenstände hergestellt werden.\n"..
"\n",
"Der Autocrafter dient zur automatischen Herstellung von Waren. Alles was der Spieler über das \"Crafting Grid\" herstellen kann\\, kann auch durch den Autocrafter erledigt werden. Dazu müssen im Menü des Autocrafters das Rezept eingegeben und die notwendigen Zutaten hinzugefügt werden.\n"..
"\n"..
"Zutaten und hergestellte Waren können über Röhren und Schieber in und aus dem Block transportiert werden.\n"..
"\n"..
"Die Verarbeitungsleistung ist ein Item alle 4 s. Der Autocrafter benötigt 4 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Die Elektronikfabrik ist eine Spezialmaschine und nur für die Herstellung der Vakuumröhren nutzbar. Vakuumröhren werden für TA3 Maschinen und Blöcke benötigt.\n"..
"\n"..
"Die Verarbeitungsleistung ist eine Vakuumröhre alle 6 s. Die Elektronikfabrik benötigt 8 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"",
"Für manche Rezepte wird Wasser benötigt. Damit auch diese Rezepte automatisiert mit dem Autocrafter bearbeitet werden können\\, muss Wasser in Eimern bereitgestellt werden. Hierzu dient der Flüssigkeitensammler. Er benötigt leere Eimer und muss ins Wasser gestellt werden.\n"..
"\n"..
"Die Verarbeitungsleistung ist ein Wassereimer alle 8 s. Der Flüssigkeitensammler benötigt 3 ku Energie.\n"..
"\n"..
"\n"..
"\n",
"Die gesicherte Kiste kann nur von den Spielern genutzt werden\\, die an diesem Ort auch bauen können\\, also Protection Rechte besitzen. Es spielt dabei keine Rolle\\, wer die Kiste setzt. \n"..
"\n"..
"\n"..
"\n",
"Minetest teilt die Karte in sogenannte Map-Blocks ein. Das sind Würfel mit 16x16x16 Blöcke Kantenlänge. So ein Map-Block wird vom Server immer komplett geladen\\, aber es werden nur die Blöcke um einen Spieler herum geladen (ca. 2-3 Blöcke in alle Richtungen). In Sichtrichtung des Spielers sind es auch mehr Map-Blöcke. Nur dieser Teil der Welt ist aktiv und nur hier wachsen Pflanzen und Bäume bzw. laufen die Maschinen.\n"..
"\n"..
"Mit einem Forceload-Block kannst du erzwingen\\, dass der Map-Block\\, in dem der Forceload Block steht\\, immer geladen bleibt\\, solange du auf dem Server bist. Wenn alle deine Farmen und Maschinen mit Forceload Blöcken abgedeckt sind\\, ist immer alles am Laufen.\n"..
"\n"..
"Die Map-Blöcke mit ihren Koordinaten sind vordefiniert\\, also bspw. (0\\,0\\,0) bis (15\\,15\\,15)\\, oder (16\\,16\\,16) bis (31\\,31\\,31).\n"..
"Man kann einen Forceload-Block innerhalb eines Map-Blockes verschieben wie man will\\, die Position des Map-Blocks bleibt dabei unverändert. \n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta2",
"",
"ta2_firebox",
"ta2_boiler",
"ta2_cylinder",
"ta2_flywheel",
"ta2_steampipe",
"ta2_driveaxle",
"ta2_generator",
"",
"ta2_winch",
"ta2_weight_chest",
"techage:ta2_clutch_off",
"",
"tube",
"concentrator",
"ta2_pusher",
"ta2_distributor",
"",
"ta2_rinser",
"ta2_grinder",
"ta2_quarry",
"ta2_grinder",
"ta2_gravelsieve",
"",
"ta2_autocrafter",
"ta2_electronicfab",
"",
"ta2_liquidsampler",
"ta2_chest",
"ta2_forceload",
},
plans = {
"",
"steamengine",
"",
"",
"",
"",
"",
"",
"",
"ta2_storage",
"",
"",
"",
"itemtransport",
"",
"",
"",
"",
"gravelrinser",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

308
doc/manual_ta2_EN.lua Normal file
View File

@ -0,0 +1,308 @@
return {
titles = {
"1,TA2: Steam Age",
"2,Steam Engine",
"3,TA2 Firebox",
"3,TA2 Boiler",
"3,TA2 Cylinder",
"3,TA2 Flywheel",
"3,TA2 Steam Pipes",
"3,TA2 Drive Axle / TA2 Gearbox",
"3,TA2 Power Generator",
"2,TA2 energy storage",
"3,TA2 Winch",
"3,TA2 Weight Chest",
"3,TA2 Clutch",
"2,Push and sort items",
"3,TechAge Tube",
"3,Tube Concentrator",
"3,TA2 Pusher",
"3,TA2 Distributor",
"2,Gravel washer",
"3,TA2 Gravel Rinser",
"2,Dig stone\\, grind and sieve",
"3,TA2 Quarry",
"3,TA2 Grinder",
"3,TA2 Gravel Sieve",
"2,Produce Items",
"3,TA2 Autocrafter",
"3,TA2 Electronic Fab",
"2,Other blocks",
"3,TA2 Liquid Sampler",
"3,TA2 Protected Chest",
"3,Techage Forceload Block",
},
texts = {
"TA2 is about building and operating the first machines for processing ores. Some machines have to be driven via drive axles. To do this\\, you need to build a steam engine and heat it with coal or charcoal.\n"..
"\n"..
"In TA2 there is also a gravel rinser that can be used to wash out rare ores such as Usmium nuggets. You will need these nuggets later for further recipes.\n"..
"\n"..
"\n"..
"\n",
"The steam engine consists of several blocks and must be assembled as shown in the plan on the right. The blocks TA2 fire box\\, TA2 boiler top\\, TA2 boiler bottom\\, TA2 cylinder\\, TA2 flywheel and steam pipes are required.\n"..
"\n"..
"In addition\\, drive axles and gear blocks are required for changing direction. The flywheel must be connected to all machines that have to be driven via the drive axles.\n"..
"\n"..
"Always pay attention to the alignment of all blocks when placing:\n"..
"\n"..
" - Cylinder on the left\\, flywheel on the right\n"..
" - Connect steam pipes where there is a corresponding hole\n"..
" - Drive axle on flywheel only on the right\n"..
" - In all machines\\, the drive axles can be connected on all sides\\, which is not occupied by other functions\\, such as the IN and OUT holes in the grinder and sieve.\n"..
"\n"..
"The boiler must be filled with water. Fill up to 10 buckets of water in the boiler.\n"..
"The fire box must be filled with coal or charcoal.\n"..
"When the water is hot (temperature display at the top)\\, the steam engine can be started on the flywheel.\n"..
"\n"..
"The steam engine has a capacity of 25 ku\\, so it can drive several machines at the same time.\n"..
"\n"..
"\n"..
"\n",
"Part of the steam engine.\n"..
"\n"..
"The fire box must be filled with coal or charcoal. The burning time depends on the power demanded by the steam engine. Coal burns for 32 s and charcoal for 96 s under full load.\n"..
"\n"..
"\n"..
"\n",
"Part of the steam engine. Must be filled with water. This is done by clicking on the boiler with a water bucket. When there is no more water or the temperature drops too low\\, the steam engine switches off. With the steam engine\\, some water is lost as steam with each piston stroke\\, so water has to be refilled regularly.\n"..
"\n"..
"\n"..
"\n",
"Part of the steam engine.\n"..
"\n"..
"\n"..
"\n",
"Drive part of the steam engine. The flywheel must be connected to the machines via drive axles.\n"..
"\n"..
"\n"..
"\n",
"Part of the steam engine. The boiler must be connected to the cylinder via the steam pipes. The steam pipe has no branches\\, the maximum length is 12 m (blocks).\n"..
"\n"..
"\n"..
"\n",
"The drive axles are used to transmit power from the steam engine to other machines. The maximum length of a drive axis is 10 blocks. With TA2 Gearboxes\\, larger distances can be bridged\\, and branches and changes of direction can be realized.\n"..
"\n"..
"\n"..
"\n",
"The TA2 Power Generator is required to operate lamps or other power consumers on a steam engine. The TA2 Power Generator has to be connected to drive axles on one side and then supplies electricity on the other side.\n"..
"\n"..
"If the Power Generator is not supplied with sufficient power\\, it goes into an error state and must be reactivated with a right-click.\n"..
"\n"..
"The Power Generator takes max. 25 ku of axle power and provides on the other side max. 24 ku as electricity. So he consumes one ku for the conversion.\n"..
"\n"..
"\n"..
"\n",
"For larger systems with several steam engines or many driven machines\\, an energy storage system is recommended. The energy storage at TA2 works with position energy. For this purpose\\, ballast (stones\\, gravel\\, sand) is pulled up in a chest with the help of a cable winch. If there is excess energy in the axis network\\, the chest is pulled upwards. If more energy is required in the short term than the steam engine can supply\\, the energy store releases the stored energy again and the weight chest moves down again. \n"..
"The energy storage consists of several blocks and must be assembled as shown in the plan on the right. \n"..
"In order to achieve the maximum storage capacity\\, the chest must be completely filled with weights and the mast including the two gear boxes must be 12 blocks high. Smaller structures are also possible.\n"..
"\n"..
"\n"..
"\n",
"The cable winch must be connected to a gear box and can absorb excess energy and thus pull a weight chest upwards. \n"..
"When assembling the cable winch\\, make sure that the arrow on the top of the block points to the gearbox.\n"..
"The maximum rope length is 10 blocks. \n"..
"\n"..
"\n"..
"\n",
"This chest must be placed under the winch with a distance of up to 10 blocks and filled with cobblestone\\, gravel or sand. If the minimum weight of a stack (99+ items) is reached and there is excess energy\\, the box is automatically connected to the winch via a rope and pulled up. \n"..
"\n"..
"\n"..
"\n",
"With the clutch\\, axles and machines can be separated from the energy storage. This means that the axles after the clutch come to a standstill and machine systems can be rebuilt. When assembling the clutch\\, make sure that the arrow on the top of the block points to the energy storage system.\n"..
"\n"..
"\n"..
"\n",
"In order to transport objects from one processing station to the next\\, pushers and tubes are used. See plan.\n"..
"\n"..
"\n"..
"\n",
"Two machines can be connected with the help of a pusher and a tube. Tubes have no branches. The maximum length is 200 m (blocks).\n"..
"\n"..
"Alternatively\\, tubes can be placed using the Shift key. This allows\\, for example\\, tubes to be laid in parallel without them accidentally connecting.\n"..
"\n"..
"The transport capacity of a tube is unlimited and only limited by the pusher.\n"..
"\n"..
"\n"..
"\n",
"Several tubes can be combined into one tube via the concentrator. The direction in which all items are passed on is marked with an arrow. \n"..
"\n"..
"\n"..
"\n",
"A pusher is able to pull items out of boxes or machines and push them into other boxes or machines. In other words\\, there must be one and exactly one pusher between two blocks with inventory. Multiple pushers in a row are not possible.\n"..
"In the opposite direction\\, however\\, a pusher is permeable for items\\, so that a box can be filled via a tube and also taught.\n"..
"\n"..
"A pusher goes into the \"standby\" state if it has no items to push. If the output is blocked or the recipient's inventory is full\\, the pusher goes into the \"blocked\" state. The pusher automatically comes out of both states after a few seconds if the situation has changed.\n"..
"\n"..
"The processing power of a TA2 pusher is 2 items every 2 s.\n"..
"\n"..
"\n"..
"\n",
"The distributor is able to transport the items from his inventory sorted in up to four directions. To do this\\, the distributor must be configured accordingly.\n"..
"\n"..
"The distributor has a menu with 4 filters with different colors\\, corresponding to the 4 outputs. If an output is to be used\\, the corresponding filter must be activated via the \"on\" checkbox. All items that are configured for this filter are output via the assigned output. If a filter is activated without items being configured\\, we are talking about an \"unconfigured\"\\, open output.\n"..
"\n"..
"*Attention: The distributor is also a pusher at its output sides. Therefore\\, never pull items out of the distributor with a pusher!*\n"..
"\n"..
"There are two operating modes for a non-configured output:\n"..
"\n"..
"1) Output all items that cannot be output to any other exit\\, even if they are blocked.\n"..
"\n"..
"2) Only output the items that have not been configured for any other filter.\n"..
"\n"..
"In the first case\\, all items are always forwarded and the distributor does not run full. In the second case\\, items are held back and the distributor can run full and then block.\n"..
"\n"..
"The operating mode can be set using the \"blocking mode\" checkbox.\n"..
"\n"..
"The processing power of a TA2 distributor is 4 items every 2 s\\, whereby the distributor tries to distribute the 4 items to the open outputs.\n"..
"\n"..
"If the same item is configured multiple times in one filter\\, the long term distribution ratio will be influenced accordingly.\n"..
"\n"..
"Please note that the distribution is a probabilistic process. This means that the distribution rations won't be matched exactly\\, but only in the long term.\n"..
"\n"..
"The maximum stack size in the filters is 12\\; in total\\, not more than 36 items can be configured.\n"..
"\n"..
"\n"..
"\n",
"The gravel washer is a more complex machine with the goal of washing Usmium nuggets out of sieved gravel. A TA2 rinser with axis drive\\, a hopper\\, a chest and running water are required for the installation.\n"..
"\n"..
"Structure from left to right (see also plan):\n"..
"\n"..
" - A dirt block\\, on top of it the water source\\, surrounded on 3 sides by e.g. glass blocks\n"..
" - next to it the gravel rinser\\, if necessary with tube connections for the gravel delivery and removal\n"..
" - then the hopper with chest\n"..
"\n"..
"The whole thing is surrounded by further glass blocks\\, so that the water flows over the gravel rinser and the hopper and rinsed-out nuggets can be collected again by the hopper.\n"..
"\n"..
"\n"..
"\n",
"The gravel washer is able to rinse out the Usmium and copper ores from gravel that has already been sieved\\, provided that this is flushed with water.\n"..
"\n"..
"Whether the Gravel Rinser works correctly can be tested with sticks if these are placed in the inventory of the Gravel Rinser. These must be rinsed out individually and caught by the hopper.\n"..
"\n"..
"The processing power is one gravel item every 2 s. The gravel washer needs 3 ku of energy.\n"..
"\n"..
"\n"..
"\n",
"Crushing\\, grinding and sieving of cobblestone is used to extract ores. Sieved gravel can also be used for other purposes. Quarry\\, grinder and sieve must be driven and thus installed near a steam engine.\n"..
"\n"..
"\n"..
"\n",
"The quarry is used to remove stones and other materials from the underground. The quarry digs a 5x5 block hole. The depth is adjustable.\n"..
"The processing power is one block every 4 s. The quarry needs 10 ku of energy. The maximum depth is 20 meters. For greater depths see TA3 / TA4.\n"..
"\n"..
"\n"..
"\n",
"The grinder is able to grind various rocks\\, but also wood and other items.\n"..
"The processing power is one item every 4 s. The grinder needs 4 ku of energy.\n"..
"\n"..
"\n"..
"\n",
"The gravel sieve is able to sieve gravel to extract ores. The result is partially \"sieved gravel\"\\, which cannot be sieved again.\n"..
"The processing power is one item every 4 s. The gravel sieve requires 3 ku of energy.\n"..
"\n"..
"\n"..
"\n",
"TA2 machines can not only extract ores\\, but also produce objects.\n"..
"\n",
"The autocrafter is used for the automatic production of goods. Everything that the player can produce via the \"Crafting Grid\" can also be done by the autocrafter. To do this\\, the recipe must be entered in the menu of the autocrafter and the necessary ingredients added.\n"..
"\n"..
"Ingredients and manufactured goods can be transported in and out of the block via tubes and pushers.\n"..
"\n"..
"The processing power is one item every 4 s. The autocrafter requires 4 ku of energy.\n"..
"\n"..
"\n"..
"\n",
"The electronic fab is a special machine and can only be used for the production of vacuum tubes. Vacuum tubes are required for TA3 machines and blocks.\n"..
"\n"..
"The processing power is one vacuum tube every 6 s. The electronic fab requires 8 ku of energy.\n"..
"\n"..
"\n"..
"\n",
"",
"Some recipes require water. So that these recipes can also be processed automatically with the autocrafter\\, water must be provided in buckets. The liquid sampler is used for this. He needs empty buckets and has to be put in the water.\n"..
"\n"..
"The processing capacity is one water bucket every 8 s. The liquid sampler requires 3 ku of energy.\n"..
"\n"..
"\n"..
"\n",
"The protected chest can only be used by players who can build at this location\\, i.e. who have protection rights. It does not matter who sets the chest.\n"..
"\n"..
"\n"..
"\n",
"Minetest divides the map into so-called map blocks. These are cubes with an edge length of 16x16x16 blocks. Such a map block is always loaded completely by the server\\, but only the blocks around a player are loaded (approx. 2-3 blocks in all directions). In the player's direction of view\\, there are also more map blocks. Only this part of the world is active and only here do plants and trees grow or the machines run.\n"..
"\n"..
"With a forceload block you can force the map block in which the forceload block is located to remain loaded as long as you are on the server. When all your farms and machines are covered with Forceload blocks\\, everything is always running.\n"..
"\n"..
"The map blocks with their coordinates are predefined\\, e.g. (0\\,0\\,0) to (15\\,15\\,15)\\, or (16\\,16\\,16) to (31\\,31\\,31).\n"..
"You can move a forceload block within a map block as you like\\, the position of the map block remains unchanged.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta2",
"",
"ta2_firebox",
"ta2_boiler",
"ta2_cylinder",
"ta2_flywheel",
"ta2_steampipe",
"ta2_driveaxle",
"ta2_generator",
"",
"ta2_winch",
"ta2_weight_chest",
"techage:ta2_clutch_off",
"",
"tube",
"concentrator",
"ta2_pusher",
"ta2_distributor",
"",
"ta2_rinser",
"ta2_grinder",
"ta2_quarry",
"ta2_grinder",
"ta2_gravelsieve",
"",
"ta2_autocrafter",
"ta2_electronicfab",
"",
"ta2_liquidsampler",
"ta2_chest",
"ta2_forceload",
},
plans = {
"",
"steamengine",
"",
"",
"",
"",
"",
"",
"",
"ta2_storage",
"",
"",
"",
"itemtransport",
"",
"",
"",
"",
"gravelrinser",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

306
doc/manual_ta2_pt-BR.lua Normal file
View File

@ -0,0 +1,306 @@
return {
titles = {
"1,TA2: Era a Vapor",
"2,Máquina a Vapor",
"3,Caixa de Fogo(Firebox) TA2",
"3,TA2 Caldeira(Boiler)",
"3,TA2 Cilindro(Cylinder)",
"3,TA2 Volante(Flywheel)",
"3,TA2 Tubos de Vapor(Steam pipes)",
"3,TA2 Eixo de Transmissão(Drive axle) TA2 / Caixa de Engrenagem(Gearbox)",
"3,TA2 Gerador de Energia",
"2,TA2 Armazenamento de Energia",
"3,TA2 Guincho",
"3,TA2 Baú de Pesos",
"3,TA2 Embreagem",
"2,Empurrar e classificar itens",
"3,Tubo TechAge",
"3,Tubo Concentrador",
"3,TA2 Pusher",
"3,TA2 Distributor(Distribuidor)",
"2,Gravel washer(Lavador de cascalho)",
"3,TA2 Gravel Rinser(Enxaguatório de cascalho)",
"2,Escavar pedra\\, moer e peneirar",
"3,TA2 Quarry(Pedreira)",
"3,TA2 Grinder(Moedor)",
"3,TA2 Gravel Sieve(Peneira de cascalho)",
"2,Produzindo Itens",
"3,TA2 Autocrafter",
"3,TA2 Electronic Fab",
"2,Outros Blocos",
"3,TA2 Liquid Sampler",
"3,TA2 Protected Chest",
"3,Techage Forceload Block",
},
texts = {
"TA2 trata-se de construir e operar as primeiras máquinas para processamento de minérios. Algumas máquinas precisam ser acionadas por eixos de transmissão. Para fazer isso\\, você precisa construir uma máquina a vapor e aquecê-la com carvão ou carvão vegetal.\n"..
"\n"..
"No TA2\\, há também um lavador de cascalho que pode ser usado para lavar minérios raros\\, como pepitas de Usmium. Você precisará dessas pepitas posteriormente para receitas adicionais.\n"..
"\n"..
"\n"..
"\n",
"A máquina a vapor é composta por vários blocos e deve ser montada conforme mostrado no plano à direita. São necessários os blocos da Caixa de Fogo(Firebox) TA2\\, parte superior da Caldeira(Boiler) TA2\\, parte inferior da Caldeira(Boiler) TA2\\, Cilindro(Cylinder) TA2\\, Volante(Flywheel) TA2 e Tubos de Vapor(steam piper) TA2.\n"..
"\n"..
"Além disso\\, são necessários Eixos de Transmissão(drive axles) e blocos de Engrenagem(gear) para mudança de direção. O Volante deve ser conectado a todas as máquinas que precisam ser acionadas pelos Eixos de Transmissão.\n"..
"\n"..
"Sempre preste atenção ao alinhamento de todos os blocos ao colocá-los:\n"..
"\n"..
" - Cilindro à esquerda\\, volante à direita\n"..
" - Conectar os tubos de vapor onde há um furo correspondente\n"..
" - Eixo de transmissão no volante apenas à direita\n"..
" - Em todas as máquinas\\, os eixos de transmissão podem ser conectados em todos os lados que não estejam ocupados por outras funções\\, como os furos de ENTRADA(IN) e SAÍDA(OUTPUT) no Moedor(grinder) e na Peneira(sieve).\n"..
"\n"..
"A Caldeira deve ser preenchida com água. Preencha até 10 baldes de água na caldeira.\n"..
"A Caixa de fogo deve ser preenchida com carvão ou carvão vegetal.\n"..
"Quando a água estiver quente (indicador de temperatura no topo)\\, a máquina a vapor pode ser iniciada no Volante.\n"..
"\n"..
"A máquina a vapor tem uma capacidade de 25ku\\, podendo acionar várias máquinas ao mesmo tempo.\n"..
"\n"..
"\n"..
"\n",
"Parte da máquina a vapor.\n"..
"\n"..
"A Caixa de fogo deve ser preenchida com carvão ou carvão vegetal. O tempo de queima depende da potência exigida pela máquina a vapor. O carvão queima por 32s e o carvão vegetal por 96s em carga máxima.\n"..
"\n"..
"\n"..
"\n",
"Parte da máquina a vapor. Deve ser preenchida com água. Isso é feito clicando na caldeira com um balde de água. Quando não há mais água ou a temperatura cai muito\\, a máquina a vapor desliga. Com a máquina a vapor\\, parte da água é perdida como vapor a cada curso do pistão\\, então a água deve ser reabastecida regularmente.\n"..
"\n"..
"\n"..
"\n",
"Parte da máquina a vapor.\n"..
"\n"..
"\n"..
"\n",
"Parte motora da máquina a vapor. O Volante deve ser conectado às máquinas por meio de eixos de transmissão.\n"..
"\n"..
"\n"..
"\n",
"Parte da máquina a vapor. A caldeira deve ser conectada ao cilindro por meio dos Tubos de vapor. O tubo de vapor não tem ramificações\\, o comprimento máximo é 12 m (blocos).\n"..
"\n"..
"\n"..
"\n",
"Os Eixos de transmissão são usados para transmitir energia da máquina a vapor para outras máquinas. O comprimento máximo de um eixo de transmissão é 10 blocos. Com as Caixas de Engrenagem TA2\\, é possível vencer distâncias maiores\\, e também realizar ramificações e mudanças de direção.\n"..
"\n"..
"\n"..
"\n",
"O Gerador de Energia TA2 é necessário para operar lâmpadas ou outros consumidores de energia em uma Máquina a vapor. O Gerador de Energia TA2 deve ser conectado aos eixos de transmissão de um lado e\\, em seguida\\, fornece eletricidade do outro lado.\n"..
"\n"..
"Se o Gerador de Energia não receber energia suficiente\\, ele entra em estado de erro e deve ser reativado com um clique direito.\n"..
"\n"..
"O Gerador de Energia consome no máximo 25ku de potência do eixo e fornece no máximo 24ku como eletricidade do outro lado. Portanto\\, ele consome um ku para a conversão.\n"..
"\n"..
"\n"..
"\n",
"Para sistemas maiores com várias máquinas a vapor ou muitas máquinas acionadas\\, é recomendado um sistema de armazenamento de energia. O armazenamento de energia no TA2 funciona com energia potencial. Para isso\\, o peso (pedras\\, cascalho\\, areia) é puxado para cima em um baú com a ajuda de um guincho. Se houver excesso de energia na rede de eixos\\, o baú é puxado para cima. Se mais energia for necessária a curto prazo do que a máquina a vapor pode fornecer\\, o armazenamento de energia libera a energia armazenada novamente e o baú de pesos desce novamente.\n"..
"O armazenamento de energia é composto por vários blocos e deve ser montado conforme mostrado no plano à direita. \n"..
"Para alcançar a capacidade máxima de armazenamento\\, o baú deve ser completamente preenchido com pesos e o mastro\\, incluindo as duas caixas de engrenagens\\, deve ter 12 blocos de altura. Estruturas menores também são possíveis.\n"..
"\n"..
"\n"..
"\n",
"O guincho deve ser conectado a uma caixa de engrenagens e pode absorver energia excessiva e assim puxar um baú de pesos para cima. \n"..
"Ao montar o guincho\\, certifique-se de que a seta no topo do bloco aponte para a caixa de engrenagens.\n"..
"O comprimento máximo da corda é 10 blocos. \n"..
"\n"..
"\n"..
"\n",
"Este baú deve ser colocado sob o guincho com uma distância de até 10 blocos e preenchido com pedras\\, cascalho ou areia. Se o peso mínimo de uma pilha (99+ itens)\n"..
"\n",
"Com a embreagem\\, eixos e máquinas podem ser separados do armazenamento de energia. Isso significa que os eixos após a embreagem param e sistemas de máquinas podem ser reconstruídos. Ao montar a embreagem\\, certifique-se de que a seta na parte superior do bloco aponta para o sistema de armazenamento de energia.\n"..
"\n"..
"\n"..
"\n",
"Para transportar objetos de uma estação de processamento para a próxima\\, são usados pushers e tubos. Veja o plano.\n"..
"\n"..
"\n"..
"\n",
"Duas máquinas podem ser conectadas com a ajuda de um pusher e um tubo. Tubos não têm ramificações. O comprimento máximo é 200m (blocos).\n"..
"\n"..
"Alternativamente\\, os tubos podem ser colocados usando a tecla Shift. Isso permite\\, por exemplo\\, que tubos sejam colocados em paralelo sem que eles se conectem acidentalmente.\n"..
"\n"..
"A capacidade de transporte de um tubo é ilimitada e é limitada apenas pelo pusher.\n"..
"\n"..
"\n"..
"\n",
"Vários tubos podem ser combinados em um único tubo via concentrador. A direção na qual todos os itens são passados é marcada com uma seta. \n"..
"\n"..
"\n"..
"\n",
"Um pusher(empurrador) é capaz de puxar itens de caixas ou máquinas e empurrá-los para outras caixas ou máquinas. Em outras palavras\\, deve haver um e apenas um pusher entre dois blocos com inventário. Múltiplos pushers em sequência não são possíveis.\n"..
"No entanto\\, na direção oposta\\, um pusher é permeável a itens\\, de modo que uma caixa pode ser preenchida via tubo e também ensinada.\n"..
"\n"..
"Um pusher entra no estado \"standby\" se não tiver itens para empurrar. Se a saída estiver bloqueada ou o inventário do destinatário estiver cheio\\, o pusher entra no estado \"bloqueado\". O pusher automaticamente sai de ambos os estados após alguns segundos se a situação mudar.\n"..
"\n"..
"A capacidade de processamento de um pusher TA2 é de 2 itens a cada 2 s.\n"..
"\n"..
"\n"..
"\n",
"O distribuidor é capaz de transportar os itens de seu inventário ordenados em até quatro direções. Para fazer isso\\, o distribuidor deve ser configurado conforme necessário.\n"..
"\n"..
"O distribuidor possui um menu com 4 filtros com cores diferentes\\, correspondendo às 4 saídas. Se uma saída for usada\\, o filtro correspondente deve ser ativado via caixa de seleção \"ligado\". Todos os itens configurados para este filtro são enviados através da saída designada. Se um filtro for ativado sem que itens sejam configurados\\, estamos falando de uma saída \"não configurada\"\\, aberta.\n"..
"\n"..
"*Atenção: O distribuidor também é um pusher em suas saídas. Portanto\\, nunca puxe itens do distribuidor com um pusher!*\n"..
"\n"..
"Existem dois modos de operação para uma saída não configurada:\n"..
"\n"..
"1) Enviar todos os itens que não podem ser enviados para nenhuma outra saída\\, mesmo que estejam bloqueados.\n"..
"\n"..
"2) Enviar apenas os itens que não foram configurados para nenhum outro filtro.\n"..
"\n"..
"No primeiro caso\\, todos os itens são sempre encaminhados e o distribuidor não fica cheio. No segundo caso\\, os itens são retidos e o distribuidor pode ficar cheio e\\, em seguida\\, bloquear.\n"..
"\n"..
"O modo de operação pode ser definido usando a caixa de seleção \"modo de bloqueio\".\n"..
"\n"..
"A capacidade de processamento de um distribuidor TA2 é de 4 itens a cada 2s\\, onde o distribuidor tenta distribuir os 4 itens para as saídas abertas.\n"..
"\n"..
"Se o mesmo item for configurado várias vezes em um filtro\\, a proporção de distribuição a longo prazo será influenciada de acordo.\n"..
"\n"..
"Observe que a distribuição é um processo probabilístico. Isso significa que as proporções de distribuição não serão correspondidas exatamente\\, mas apenas a longo prazo.\n"..
"\n"..
"O tamanho máximo de pilha nos filtros é 12\\; no total\\, não mais que 36 itens podem ser configurados.\n"..
"\n"..
"\n"..
"\n",
"O lavador de cascalho é uma máquina mais complexa com o objetivo de lavar pepitas de Usmium a partir de cascalho peneirado. Um enxaguatório TA2 com eixo de acionamento\\, um funil\\, um baú e água corrente são necessários para a instalação.\n"..
"\n"..
"Estrutura da esquerda para a direita (veja também o plano):\n"..
"\n"..
" - Um bloco de terra\\, sobre ele a fonte de água\\, cercada em 3 lados\\, por exemplo\\, por blocos de vidro\n"..
" - Ao lado\\, o enxaguatório de cascalho\\, se necessário com conexões de tubulação para a entrega e remoção de cascalho\n"..
" - Em seguida\\, o funil com baú\n"..
"\n"..
"O conjunto é cercado por mais blocos de vidro\\, para que a água flua sobre o enxaguatório de cascalho e o funil\\, e as pepitas lavadas possam ser coletadas novamente pelo funil.\n"..
"\n"..
"\n"..
"\n",
"O lavador de cascalho é capaz de enxaguar os minérios de Usmium e cobre do cascalho que já foi peneirado\\, desde que seja lavado com água.\n"..
"\n"..
"Se o Enxaguatório de Cascalho funciona corretamente\\, pode ser testado com pedaços de madeira\\, se estes forem colocados no inventário do Enxaguatório de Cascalho. Eles devem ser enxaguados individualmente e recolhidos pelo funil.\n"..
"\n"..
"A capacidade de processamento é de um item de cascalho a cada 2s. O lavador de cascalho precisa de 3 ku de energia.\n"..
"\n"..
"\n"..
"\n",
"Esmagar\\, moer e peneirar pedregulhos é usado para extrair minérios. O cascalho peneirado também pode ser usado para outros fins. A pedreira\\, moedor e peneira devem ser acionados e\\, portanto\\, instalados perto de uma máquina a vapor.\n"..
"\n"..
"\n"..
"\n",
"A pedreira é usada para remover pedras e outros materiais do subsolo. A pedreira escava um buraco de 5x5 blocos. A profundidade é ajustável.\n"..
"A capacidade de processamento é de um bloco a cada 4s. A pedreira precisa de 10 ku de energia. A profundidade máxima é de 20 metros. Para maiores profundidades\\, consulte TA3 / TA4.\n"..
"\n"..
"\n"..
"\n",
"O moedor é capaz de moer várias rochas\\, mas também madeira e outros itens.\n"..
"A capacidade de processamento é de um item a cada 4s. O moedor precisa de 4 ku de energia.\n"..
"\n"..
"\n"..
"\n",
"A peneira de cascalho é capaz de peneirar cascalho para extrair minérios. O resultado é parcialmente \"sieved gravel\"\\, que não pode ser peneirado novamente.\n"..
"A capacidade de processamento é de um item a cada 4s. A peneira de cascalho requer 3 ku de energia.\n"..
"\n"..
"\n"..
"\n",
"As máquinas TA2 podem não apenas extrair minérios\\, mas também produzir objetos.\n"..
"\n",
"O autocrafter é usado para a produção automática de bens. Tudo o que o jogador pode produzir via \"Crafting Grid\" também pode ser feito pelo autocrafter. Para isso\\, a receita deve ser inserida no menu do autocrafter e os ingredientes necessários adicionados.\n"..
"\n"..
"Ingredientes e produtos fabricados podem ser transportados para dentro e para fora do bloco por meio de tubos e pushers.\n"..
"\n"..
"A capacidade de processamento é de um item a cada 4s. O autocrafter requer 4 ku de energia.\n"..
"\n"..
"\n"..
"\n",
"O electronic fab é uma máquina especial e só pode ser usada para a produção de tubos de vácuo. Tubos de vácuo são necessários para máquinas e blocos TA3.\n"..
"\n"..
"A capacidade de processamento é de um tubo de vácuo a cada 6s. O electronic fab requer 8 ku de energia.\n"..
"\n"..
"\n"..
"\n",
"",
"Algumas receitas requerem água. Para que essas receitas também possam ser processadas automaticamente com o autocrafter\\, água deve ser fornecida em baldes. Isso é feito usando o liquid sampler. Ele precisa de baldes vazios e deve ser colocado na água.\n"..
"\n"..
"A capacidade de processamento é de um balde de água a cada 8s. O liquid sampler requer 3 ku de energia.\n"..
"\n"..
"\n"..
"\n",
"O protected chest só pode ser usado por jogadores que têm permissão de construção neste local\\, ou seja\\, que têm direitos de proteção. Não importa quem coloca o baú.\n"..
"\n"..
"\n"..
"\n",
"O Minetest divide o mapa em chamados map blocks. Estes são cubos com uma aresta de 16x16x16 blocos. Um map block é sempre completamente carregado pelo servidor\\, mas apenas os blocos ao redor de um jogador são carregados (aproximadamente 2-3 blocos em todas as direções). Na direção de visão do jogador\\, também existem mais map blocks. Apenas esta parte do mundo é ativa e apenas aqui as plantas e árvores crescem ou as máquinas funcionam.\n"..
"\n"..
"Com um bloco forceload\\, você pode forçar o map block em que o bloco forceload está localizado a permanecer carregado enquanto você estiver no servidor. Quando todos os seus campos e máquinas estão cobertos com blocos Forceload\\, tudo está sempre em execução.\n"..
"\n"..
"Os map blocks com suas coordenadas são predefinidos\\, por exemplo\\, (0\\,0\\,0) a (15\\,15\\,15)\\, ou (16\\,16\\,16) a (31\\,31\\,31).\n"..
"Você pode mover um bloco forceload dentro de um map block como quiser\\, a posição do map block permanece inalterada.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta2",
"",
"ta2_firebox",
"ta2_boiler",
"ta2_cylinder",
"ta2_flywheel",
"ta2_steampipe",
"ta2_driveaxle",
"ta2_generator",
"",
"ta2_winch",
"",
"techage:ta2_clutch_off",
"",
"tube",
"concentrador",
"ta2_pusher",
"ta2_distributor",
"",
"ta2_rinser",
"ta2_grinder",
"ta2_quarry",
"ta2_grinder",
"ta2_gravelsieve",
"",
"ta2_autocrafter",
"ta2_electronicfab",
"",
"ta2_liquidsampler",
"ta2_chest",
"ta2_forceload",
},
plans = {
"",
"steamengine",
"",
"",
"",
"",
"",
"",
"",
"ta2_storage",
"",
"",
"",
"itemtransport",
"",
"",
"",
"",
"gravelrinser",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

934
doc/manual_ta3_DE.lua Normal file
View File

@ -0,0 +1,934 @@
return {
titles = {
"1,TA3: Ölzeitalter",
"2,Kohlekraftwerk / Ölkraftwerk",
"3,TA3 Kraftwerks-Feuerbox / Power Station Firebox",
"3,TA3 Kraftwerks-Ölbrenner / TA3 Power Station Oil Burner",
"3,TA3 Boiler unten/oben",
"3,TA3 Turbine",
"3,TA3 Generator",
"3,TA3 Kühler / Cooler",
"2,Elektrischer Strom",
"3,Bedeutung von Speichersystemen",
"3,TA Stromkabel / Electric Cable",
"3,TA Verteilerdose / Electric Junction Box",
"3,TA Stromleitung / Power Line",
"3,TA Strommast / Power Pole",
"3,TA Strommastkopf / Power Pole Top",
"3,TA Strommastkopf 2 / Power Pole Top 2",
"3,TA Stromschalter / Power Switch",
"3,TA Stromschalter klein / Power Switch Small",
"3,TA Stromschalterbox / Power Switch Box",
"3,TA3 Kleiner Stromgenerator / Tiny Power Generator",
"3,TA3 Akku Block / TA3 Accu Box",
"3,TA3 Strom Terminal / Power Terminal",
"3,TA3 Elektromotor / TA3 Electric Motor",
"2,TA3 Industrieofen",
"3,TA3 Ofen-Ölbrenner / Furnace Oil Burner",
"3,TA3 Ofenoberteil / Furnace Top",
"3,TA3 Gebläse / Booster",
"2,Flüssigkeiten",
"3,TA3 Tank / TA3 Tank",
"3,TA3 Pumpe / TA3 Pump",
"3,TA Einfülltrichter / TA Liquid Filler",
"3,TA4 Röhre / Pipe",
"3,TA3 Rohr/Wanddurchbruch / TA3 Pipe Wall Entry Blöcke",
"3,TA Ventil / TA Valve",
"2,Öl-Förderung",
"3,TA3 Ölexplorer / Oil Explorer",
"3,TA3 Ölbohrkiste / Oil Drill Box",
"3,TA3 Ölpumpe / Oil Pumpjack",
"3,TA3 Bohrgestänge / Drill Pipe",
"3,Öltank / Oil Tank",
"2,Öl-Transport",
"3,Öl-Transport mit dem Tankwagen",
"3,Öl-Transport mit Fässern über Minecarts",
"3,Tankwagen / Tank Cart",
"3,Kistenwagen / Chest Cart",
"2,Öl-Verarbeitung",
"3,Destillationsturm / distiller tower",
"4,Aufkocher / reboiler)",
"2,Logik-/Schalt-Blöcke",
"3,TA3 Taster/Schalter / Button/Switch",
"3,TA3 Kommando Konverter / Command Converter",
"3,TA3 Flipflop / Flip-Flop",
"3,TA3 Logikblock / Logic Block",
"3,TA3 Wiederholer / Repeater",
"3,TA3 Sequenzer / Sequencer",
"3,TA3 Timer",
"3,TA3 Terminal",
"3,TechAge Farblampe / Color Lamp",
"3,Tür/Tor Blöcke / Door/Gate Blocks",
"3,TA3 Tür Controller / Door Controller",
"3,TA3 Tür Controller II / Door Controller II",
"3,TA3 Sound Block",
"3,TA3 Mesecons Umsetzer / TA3 Mesecons Converter",
"2,Detektoren",
"3,TA3 Detektor / Detector",
"3,TA3 Wagen Detektor / Cart Detector",
"3,TA3 Block Detektor / Node Detector",
"3,TA3 Spieler Detektor / Player Detector",
"3,TA3 Lichtdetektor",
"2,TA3 Maschinen",
"3,TA3 Schieber / Pusher",
"3,TA3 Verteiler / Distributor",
"3,TA3 Autocrafter",
"3,TA3 Elektronikfabrik / Electronic Fab",
"3,TA3 Steinbrecher / Quarry",
"3,TA3 Kiessieb / Gravel Sieve",
"3,TA3 Kieswaschanlage / Gravel Rinser",
"3,TA3 Mühle / Grinder",
"3,TA3 Injektor / Injector",
"2,Werkzeuge",
"3,Techage Info Tool",
"3,TechAge Programmer",
"3,TechAge Kelle / Trowel",
"3,TA3 Bohrgestängezange / TA3 Drill Pipe Wrench",
"3,Techage Schraubendreher / Screwdriver",
"3,TechAge Montagewerkzeug / Assembly Tool",
},
texts = {
"Bei TA3 gilt es\\, die Dampf-betriebenen Maschinen durch leistungsfähigere und mit elektrischem Strom betriebene Maschinen abzulösen.\n"..
"\n"..
"Dazu musst du Kohlekraftwerke und Generatoren bauen. Bald wirst du sehen\\, dass dein Strombedarf nur mit Öl-betriebenen Kraftwerken zu decken ist. Also machst du dich auf die Suche nach Erdöl. Bohrtürme und Ölpumpen helfen die\\, an das Öl zu kommen. Schienenwege dienen dir zum Öltransport bis in die Kraftwerke.\n"..
"\n"..
"Das Industrielle Zeitalter ist auf seinem Höhepunkt.\n"..
"\n"..
"\n"..
"\n",
"Das Kohlekraftwerk besteht aus mehreren Blöcken und muss wie im Plan rechts abgebildet\\, zusammen gebaut werden. Dazu werden die Blöcke TA3 Kraftwerks-Feuerbox\\, TA3 Boiler oben\\, TA3 Boiler unten\\, TA3 Turbine\\, TA3 Generator und TA3 Kühler benötigt.\n"..
"\n"..
"Der Boiler muss mit Wasser gefüllt werden. Dazu bis zu 10 Eimer Wasser in den Boiler füllen.\n"..
"Die Feuerbox muss mit Kohle oder Holzkohle gefüllt werden.\n"..
"Wenn das Wasser heiß ist\\, kann der Generator gestartet werden.\n"..
"\n"..
"Das Kraftwerk kann alternativ auch mit einem Ölbrenner ausgestattet und dann mit Öl betrieben werden.\n"..
"Das Öl kann über eine Pumpe und Ölleitung nachgefüllt werden.\n"..
"\n"..
"Das Kraftwerk liefert eine Leistung von 80 ku.\n"..
"\n"..
"\n"..
"\n",
"Teil des Kraftwerks. \n"..
"Die Feuerbox muss mit Kohle oder Holzkohle gefüllt werden. Die Brenndauer ist abhängig von der Leistung\\, die vom Kraftwerk angefordert wird. Unter Volllast brennt Kohle 20 s und Holzkohle 60 s. Unter Teillast entsprechend länger (50% Last = doppelte Zeit).\n"..
"\n"..
"\n"..
"\n",
"Teil des Kraftwerks. \n"..
"\n"..
"Der Ölbrenner kann mit Erdöl\\, Schweröl\\, Naphtha oder Benzin gefüllt werden. Die Brenndauer ist abhängig von der Leistung\\, die vom Kraftwerk angefordert wird. Unter Volllast brennt Erdöl 15 s\\, Schweröl 20 s\\, Naphtha 22 s und Benzin 25 s. \n"..
"\n"..
"Unter Teillast entsprechend länger (50% Last = doppelte Zeit).\n"..
"\n"..
"Der Ölbrenner kann nur 50 Einheiten Kraftstoff aufnehmen. Ein zusätzlicher Öltank und eine Ölpumpe sind daher ratsam.\n"..
"\n"..
"\n"..
"\n",
"Teil des Kraftwerk. Muss mit Wasser gefüllt werden. Wem kein Wasser mehr vorhanden ist oder die Temperatur zu weit absinkt\\, schaltet sich das Kraftwerk ab. Der Wasserverbrauch des TA3-Kessels ist durch den geschlossenen Dampfkreislauf viel geringer als bei der Dampfmachine.\n"..
"Bei der Dampfmaschine geht bei jedem Kolbenhub etwas Wasser als Dampf verloren.\n"..
"\n"..
"\n"..
"\n",
"Die Turbine ist Teil des Kraftwerk. Sie muss neben den Generator gesetzt und über Dampfleitungen mit dem Boiler und dem Kühler\\, wie im Plan abgebildet\\, verbunden werden.\n"..
"\n"..
"\n"..
"\n",
"Der Generator dient zur Stromerzeugung. Er muss über Stromkabel und Verteilerdosen mit den Maschinen verbunden werden.\n"..
"\n"..
"\n"..
"\n",
"Dient zur Abkühlung des heißen Dampfs aus der Turbine. Muss über Dampfleitungen mit dem Boiler und der Turbine\\, wie im Plan abgebildet\\, verbunden werden.\n"..
"\n"..
"\n"..
"\n",
"In TA3 (und TA4) werden die Maschinen mit Strom angetrieben. Dazu müssen die Maschinen\\, Speichersysteme und Generatoren mit Stromkabel verbunden werden.\n"..
"TA3 besitzt 2 Arten von Stromkabel:\n"..
"\n"..
" - Isolierte Kabel (TA Stromkabel) für die lokale Verkabelung im Boden oder in Gebäuden. Diese Kabel lassen sich in der Wand oder im Boden verstecken (können mit der Kelle \"verputzt\" werden).\n"..
" - Überlandleitungen (TA Stromleitung) für Freiluftverkabelung über große Strecken. Diese Kabel sind geschützt\\, können also von anderen Spielern nicht entfernt werden.\n"..
"\n"..
"Mehrere Verbraucher\\, Speichersysteme und Generatoren können in einem Stromnetzwerk zusammen betrieben werden. Mit Hilfe der Verteilerdosen können so Netzwerke aufgebaut werden.\n"..
"Wird zu wenig Strom bereitgestellt\\, gehen die Verbraucher aus.\n"..
"In diesem Zusammenhang ist auch wichtig\\, dass die Funktionsweise von Forceload Blöcken verstanden wurde\\, denn bspw. Generatoren liefern nur Strom\\, wenn der entsprechende Map-Block geladen ist. Dies kann mit einen Forceload Block erzwungen werden.\n"..
"\n"..
"In TA4 kommt noch ein Kabel für die Solaranlage hinzu.\n"..
"\n"..
"\n"..
"\n",
"Speichersysteme im Stromnetz erfüllen zwei Aufgaben:\n"..
"\n"..
" - Um Bedarfsspitzen abzufangen: Alle Generatoren liefern immer gerade soviel Leistung\\, wie benötigt wird. Werden aber Verbraucher ein/ausgeschaltet oder kommt es aus anderen Gründen zu Bedarfsschwankungen\\, so können Verbraucher kurzzeitig ausfallen. Um dies zu verhindern\\, sollte immer mindestens ein Akkublock in jedem Netzwerk vorhanden sein. Dieser dient als Puffer und gleicht diese Schwankungen im Sekundenbereich aus.\n"..
" - Um regenerative Energie zu speichern: Solar und Wind stehen nicht 24 Stunden am Tag zur Verfügung. Damit die Stromversorgung nicht ausfällt\\, wenn kein Strom produziert wird\\, müssen ein oder mehrere Speichersysteme im Netzwerk verbaut werden. Alternativ können die Lücken auch mit Öl/Kohle-Strom überbrückt werden.\n"..
"\n"..
"Ein Speichersystem gibt seine Kapazität in kud an\\, also ku pro day (Tag). Bspw. ein Speichersystem mit 100 kud liefert 100 ku einen Spieltag lang\\, oder auch 10 ku für 10 Spieltage.\n"..
"\n"..
"Alle TA3/TA4 Energiequellen besitzen eine einstellbare Ladecharakteristik. Standardmäßig ist diese auf \"80% - 100%\" eingestellt. Dies bedeutet\\, dass die Leistung ab 80% Füllung des Speichersystems immer weiter reduziert wird\\, bis sie bei 100 % komplett abschaltet. Sofern Strom im Netzwerk benötigt wird\\, werden die 100 % nie erreicht\\, da die Leistung des Generators irgendwann auf den Strombedarf im Netzwerk abgesunken ist und damit das Speichersystem nicht mehr geladen\\, sondern nur noch die Verbraucher bedient werden.\n"..
"\n"..
"Dies hat mehrere Vorteile:\n"..
"\n"..
" - Die Ladecharakteristik ist einstellbar. Damit kann man bspw. Öl/Kohle Energiequellen bei 60% und die regenerativen Energiequellen erst bei 80% zurückfahren. Damit wird nur Öl/Kohle verbrannt\\, wenn nicht ausreichend regenerativen Energiequellen zur Verfügung stehen.\n"..
" - Mehrere Energiequellen können parallel betrieben werden und werden dabei nahezu gleichmäßig belastet\\, denn alle Energiequellen arbeiten bspw. bis 80% Ladekapazität des Speichersystems mit ihrer vollen Leistung und fahren dann gleichzeitig ihre Leistung zurück.\n"..
" - Alle Speichersysteme in einem Netzwerk bilden einen großen Puffer. An jedem Speichersystem aber auch am Strom Terminal kann immer die Ladekapazität und der Füllungsgrad des gesamten Speichersystems in Prozent abgelesen werden.\n"..
"\n"..
"\n"..
"\n",
"Für die lokale Verkabelung im Boden oder in Gebäuden.\n"..
"Abzweigungen können mit Hilfe von Verteilerdosen realisiert werden. Die maximale Kabellänge zwischen Maschinen oder Verteilerdosen beträgt 1000 m. Es können maximale 1000 Knoten in einem Strom-Netzwerk verbunden werden. Als Knoten zählen alle Blöcke mit Stromanschluss\\, also auch Verteilerdosen.\n"..
"\n"..
"Da die Stromkabel nicht automatisch geschützt sind\\, wird für längere Strecken die Überlandleitungen (TA Stromleitung) empfohlen.\n"..
"\n"..
"Stromkabel können mit der Kelle verputzt also in der Wand oder im Boden versteckt werden. Als Material zum Verputzen können alle Stein-\\, Clay- und sonstige Blöcke ohne \"Intelligenz\" genutzt werden. Erde (dirt) geht nicht\\, da Erde zu Gras oder ähnlichem konvertiert werden kann\\, was die Leitung zerstören würde.\n"..
"\n"..
"Zum Verputzen muss mit der Kelle auf das Kabel geklickt werden. Das Material\\, mit dem das Kabel verputzt werden soll\\, muss sich im Spieler-Inventar ganz links befinden.\n"..
"Die Kabel können wieder sichtbar gemacht werden\\, indem man mit der Kelle wieder auf den Block klickt.\n"..
"\n"..
"Außer Kabel können auch die TA Verteilerdose und die TA Stromschalterbox verputzt werden.\n"..
"\n"..
"\n"..
"\n",
"Mit der Verteilerdose kann Strom in bis zu 6 Richtungen verteilt werden. Verteilerdosen können auch mit der Kelle verputzt (versteckt) und wieder sichtbar gemacht werden.\n"..
"\n"..
"\n"..
"\n",
"Mit der TA Stromleitung und den Strommasten können halbwegs realistische Überlandleitungen realisiert werden. Die Strommasten-Köpfe dienen gleichzeitig zum Schutz der Stromleitung (Protection). Dazu muss alle 16 m oder weniger ein Masten gesetzt werden. Der Schutz gilt aber nur die die Stromleitung und die Masten\\, alle anderen Blöcke in diesem Bereich sind dadurch nicht geschützt.\n"..
"\n"..
"\n"..
"\n",
"Dient zum Bauen von Strommasten. Ist durch den Strommast-Kopf vor Zerstörung geschützt und kann nur vom Besitzer wieder abgebaut werden.\n"..
"\n"..
"\n"..
"\n",
"Hat bis zu vier Arme und erlaubt damit\\, Strom in bis zu 6 Richtungen weiter zu verteilen. \n"..
"Der Strommastkopf schützt Stromleitungen und Masten in einem Radius von 8 m.\n"..
"\n"..
"\n"..
"\n",
"Dieser Strommastkopf hat zwei feste Arme und wird für die Überlandleitungen genutzt. Er kann aber auch Strom nach unten und oben weiterleiten.\n"..
"Der Strommastkopf schützt Stromleitungen und Masten in einem Radius von 8 m.\n"..
"\n"..
"\n"..
"\n",
"Mit dem Schalter kann der Strom ein- und ausgeschaltet werden. Der Schalter muss dazu auf eine Stromschalterbox gesetzt werden. Die Stromschalterbox muss dazu auf beiden Seiten mit dem Stromkabel verbunden sein.\n"..
"\n"..
"\n"..
"\n",
"Mit dem Schalter kann der Strom ein- und ausgeschaltet werden. Der Schalter muss dazu auf eine Stromschalterbox gesetzt werden. Die Stromschalterbox muss dazu auf beiden Seiten mit dem Stromkabel verbunden sein.\n"..
"\n"..
"\n"..
"\n",
"siehe TA Stromschalter.\n"..
"\n"..
"\n"..
"\n",
"Der kleine Stromgenerator wird mit Benzin betrieben und kann für kleine Verbraucher mit bis zu 12 ku genutzt werden. Unter Volllast brennt Benzin 150 s. Unter Teillast entsprechend länger (50% Last = doppelte Zeit).\n"..
"\n"..
"Der Stromgenerator kann nur 50 Einheiten Benzin aufnehmen. Ein zusätzlicher Tank und eine Pumpe sind daher ratsam.\n"..
"\n"..
"\n"..
"\n",
"Der Akku Block dient zur Speicherung von überschüssiger Energie und gibt bei Stromausfall automatisch Strom ab (soweit vorhanden).\n"..
"Mehrere Akku Blocks zusammen bilden ein TA3 Energiespeichersystem. Jeder Akku Block hat eine Anzeige für den Ladezustand und für die gespeicherte Ladung\\, wobei hier immer die Werte für das gesamte Netzwerk angezeigt werden. Die gespeicherte Ladung wird in \"kud\" also \"ku-days\" angezeigt (analog zu kWh) 5 kud entspricht damit bspw. 5 ku für einen Spieltag (20 min) oder 1 ku für 5 Spieltage.\n"..
"\n"..
"Ein Akku Block hat 3.33 kud.\n"..
"\n"..
"\n"..
"\n",
"Das Strom-Terminal muss mit dem Stromnetz verbunden werden. Es zeigt Daten aus dem Stromnetz an.\n"..
"\n"..
"In der oberen Hälfte werden die wichtigsten Größen ausgegeben:\n"..
"\n"..
" - aktuelle/maximale Generatorleistung\n"..
" - aktueller Stromaufnahme aller Verbraucher\n"..
" - aktueller Ladestrom in/aus dem Speichersystems\n"..
" - aktuellen Ladezustand des Speichersystems in Prozent\n"..
"\n"..
"In der unteren Hälfte wird die Anzahl der Netzwerkblöcke ausgegeben.\n"..
"\n"..
"Über den Reiter \"console\" können weitere Daten zu den Generatoren und Speichersystemen abgefragt werden.\n"..
"\n"..
"\n"..
"\n",
"Um TA2 Maschinen über das Stromnetz betreiben zu können\\, wird der TA3 Elektromotor benötigt. Dieser wandelt Strom in Achsenkraft um.\n"..
"Wird der Elektromotor nicht mit ausreichend Strom versorgt\\, geht er in einen Fehlerzustand und muss über einen Rechtsklick wieder aktiviert werden.\n"..
"\n"..
"Das Elektromotor nimmt primär max. 40 ku an Strom auf und gibt sekundär max. 39 ku als Achsenkraft wieder ab. Er verbraucht also ein ku für die Umwandlung.\n"..
"\n"..
"\n"..
"\n",
"Der TA3 Industrieofen dient als Ergänzung zu normalen Ofen (furnace). Damit können alle Waren mit \"Koch\" Rezepten\\, auch im Industrieofen hergestellt werden. Es gibt aber auch spezielle Rezepte\\, die nur im Industrieofen hergestellt werden können.\n"..
"Der Industrieofen hat sein eigenes Menü zur Rezeptauswahl. Abhängig von den Waren im Industrieofen Inventar links kann rechts das Ausgangsprodukt gewählt werden.\n"..
"\n"..
"Der Industrieofen benötigt Strom (für das Gebläse) sowie Schweröl/Benzin für den Brenner. Der Industrieofen muss wie im Plan rechts abgebildet\\, zusammen gebaut werden.\n"..
"\n"..
"Siehe auch TA4 Ofenheizung.\n"..
"\n"..
"\n"..
"\n",
"Ist Teil des TA3 Industrieofen.\n"..
"\n"..
"Der Ölbrenner kann mit Erdöl\\, Schweröl\\, Naphtha oder Benzin betrieben werden. Die Brennzeit beträgt für Erdöl 65 s\\, Schweröl 80 s\\, Naphtha 90 s und Benzin 100 s.\n"..
"\n"..
"Der Ölbrenner kann nur 50 Einheiten Kraftstoff aufnehmen. Ein zusätzlicher Tank und eine Pumpe sind daher ratsam.\n"..
"\n"..
"\n"..
"\n",
"Ist Teil des TA3 Industrieofen. Siehe TA3 Industrieofen.\n"..
"\n"..
"\n"..
"\n",
"Ist Teil des TA3 Industrieofen. Siehe TA3 Industrieofen.\n"..
"\n"..
"\n"..
"\n",
"Flüssigkeiten wie Wasser oder Öl können nur die spezielle Leitungen gepumpt und in Tanks gespeichert werden. Wie auch bei Wasser gibt es aber Behälter (Kanister\\, Fässer)\\, in denen die Flüssig gelagert und transportiert werden kann.\n"..
"\n"..
"Über die gelben Leitungen und Verbindungsstücke ist es auch möglich\\, mehrere Tanks zu verbinden. Allerdings müssen die Tanks den selben Inhalt haben und zwischen Tank\\, Pumpe und Verteiler muss immer mindestens eine gelbe Leitung sein.\n"..
"\n"..
"Bspw. zwei Tanks direkt mit einem Verteilerstück zu verbinden\\, geht nicht.\n"..
"\n"..
"Um Flüssigkeiten von Behältern nach Tanks umzufüllen\\, dient der Einfülltrichter. Im Plan ist dargestellt\\, wie Kanistern oder Fässer mit Flüssigkeiten über Schieber in einen Einfülltrichter geschoben werden. Im Einfülltrichter wird der Behälter geleert und die Flüssigkeit nach unten in den Tank geleitet. \n"..
"\n"..
"Der Einfülltrichter kann auch unter einen Tank gesetzt werden\\, um den Tank zu leeren.\n"..
"\n"..
"\n"..
"\n",
"In einem Tank können Flüssigkeiten gespeichert werden. Ein Tank kann über eine Pumpe gefüllt bzw. geleert werden. Dazu muss die Pumpe über einer Leitung (gelbe Röhre) mit dem Tank verbunden sein.\n"..
"\n"..
"Ein Tank kann auch von Hand gefüllt oder geleert werden\\, indem mit einem vollen oder leeren Flüssigkeitsbehälter (Fass\\, Kanister) auf den Tank geklickt wird. Dabei ist zu beachten\\, dass Fässer nur komplett gefüllt oder entleert werden können. Sind bspw. weniger als 10 Einheiten im Tank\\, muss dieser Rest mit Kanistern entnommen oder leergepumpt werden.\n"..
"\n"..
"In einen TA3 Tank passen 1000 Einheiten oder 100 Fässer einer Flüssigkeit.\n"..
"\n"..
"\n"..
"\n",
"Mit der Pumpe können Flüssigkeiten von Tanks oder Behältern zu anderen Tanks oder Behältern gepumpt werden. Bei der Pumpe muss die Pumprichtung (Pfeil) beachtet werden. Über die gelben Leitungen und Verbindungsstücke ist es auch möglich\\, mehrere Tanks auf jeder Seite der Pumpe anzuordnen. Allerdings müssen die Tanks den selben Inhalt haben.\n"..
"\n"..
"Die TA3 Pumpe pumpt 4 Einheiten Flüssigkeit alle zwei Sekunden.\n"..
"\n"..
"Hinweis 1: Die Pumpe darf nicht direkt neben den Tank platziert werden. Es muss immer mindestens ein Stück gelbe Leitung dazwischen sein.\n"..
"\n"..
"Hinweis 2: Nach dem Starten markiert die Pumpe 10 x die Blöcke\\, von und zu denen gepumpt wird.\n"..
"\n"..
"\n"..
"\n",
"Um Flüssigkeiten zwischen Behältern und Tanks umzufüllen\\, dient der Einfülltrichter.\n"..
"\n"..
" - wird der Einfülltrichter unter einen Tank gesetzt und werden leere Fässer mit einem Schieber oder von Hand in den Einfülltrichter gegeben\\, wird der Tankinhalt in die Fässer umgefüllt und die Fässer können ausgangsseitig wieder entnommen werden\n"..
" - wird der Einfülltrichter auf einen Tank gesetzt und werden volle Fässer mit einem Schieber oder von Hand in den Einfülltrichter gegeben\\, werden diese in den Tank umgefüllt und die Fässer können ausgangsseitig wieder entnommen werden\n"..
"\n"..
"Dabei ist zu beachten\\, dass Fässer nur komplett gefüllt oder entleert werden können. Sind bspw. weniger als 10 Einheiten im Tank\\, muss dieser Rest mit Kanistern entnommen oder leergepumpt werden.\n"..
"\n"..
"\n"..
"\n",
"Die gelben Röhren dienen zur Weiterleitung von Gas und Flüssigkeiten. \n"..
"Die maximale Leitungslänge beträgt 100 m.\n"..
"\n"..
"\n"..
"\n",
"Die Blöcke dienen als Wanddurchbrüche für Röhren\\, so dass keine Löcher offen bleiben.\n"..
"\n"..
"\n"..
"\n",
"Für die gelben Röhren gibt es ein Ventil\\, welches über Mausklicks geöffnet und geschlossen werden kann.\n"..
"Das Ventil kann auch über on/off Kommandos angesteuert werden.\n"..
"\n"..
"\n"..
"\n",
"Um deine Generatoren und Öfen mit Öl betreiben zu können\\, muss du zuerst nach Öl suchen und einen Bohrturm errichten und danach das Öl fördern.\n"..
"Dazu dienen dir TA3 Ölexplorer\\, TA3 Ölbohrkiste und TA3 Ölpumpe.\n"..
"\n"..
"\n"..
"\n",
"Mit dem Ölexplorer kannst du nach Öl suchen. Dazu den Block auf den Boden setzen und mit Rechtsklick die Suche starten. Der Ölexplorer kann oberirdisch und unterirdisch in allen Tiefen eingesetzt werden.\n"..
"Über die Chat-Ausgabe wird dir angezeigt\\, in welcher Tiefe nach Öl gesucht wurde und wie viel Öl (oil) gefunden wurde.\n"..
"Du kannst mehrfach auf den Block klicken\\, um auch in tieferen Bereichen nach Öl zu suchen. Ölfelder haben eine Größe von 4000 bis zu 20000 Items.\n"..
"\n"..
"Falls die Suche erfolglos war\\, musst du den Block ca. 16 m weiter setzen.\n"..
"Der Ölexplorer sucht immer innerhalb des ganzen Map-Blocks und darunter nach Öl\\, in dem er gesetzt wurde. Eine erneute Suche im gleichen Map-Block (16x16 Feld) macht daher keinen Sinn.\n"..
"\n"..
"Falls Öl gefunden wurde\\, wird die Stelle für den Bohrturm angezeigt. Du musst den Bohrturm innerhalb des angezeigten Bereiches errichten\\, die Stelle am besten gleich mit einem Schild markieren und den ganzen Bereich gegen fremde Spieler schützen.\n"..
"\n"..
"Gib die Suche nach Öl nicht zu schnell auf. Es kann wenn du Pech hast\\, sehr lange dauern\\, bis du eine Ölquelle gefunden hast.\n"..
"Es macht auch keinen Sinn\\, einen Bereich den ein anderer Spieler bereits abgesucht hat\\, nochmals abzusuchen. Die Chance\\, irgendwo Öl zu finden\\, ist für alle Spieler gleich.\n"..
"\n"..
"Der Ölexplorer kann immer wieder zur Suche nach Öl eingesetzt werden.\n"..
"\n"..
"\n"..
"\n",
"Die Ölbohrkiste muss an die Stelle gesetzt werden\\, die vom Ölexplorer angezeigt wurde. An anderen Stellen nach Öl zu bohren ist zwecklos.\n"..
"Wird auf den Button der Ölbohrkiste geklickt\\, wird über der Kiste ein Bohrturm errichtet. Dies dauert einige Sekunden.\n"..
"Die Ölbohrkiste hat 4 Seiten\\, bei IN muss das Bohrgestänge über Schieber angeliefert und bei OUT muss das Bohrmaterial abtransportiert werden. Über eine der anderen zwei Seiten muss die Ölbohrkiste mit Strom versorgt werden.\n"..
"\n"..
"Die Ölbohrkiste bohrt bis zum Ölfeld (1 Meter in 16 s) und benötigt dazu 16 ku Strom.\n"..
"Wurde das Ölfeld erreicht\\, kann der Bohrturm abgebaut und die Kiste entfernt werden.\n"..
"\n"..
"\n"..
"\n",
"An die Stelle der Ölbohrkiste muss nun die Ölpumpe platziert werden. Auch die Ölpumpe benötigt Strom (16 ku) und liefert alle 8 s ein Einheit Erdöl. Das Erdöl muss in einem Tank gesammelt werden. Dazu muss die Ölpumpe über eine Leitung (gelbe Röhre) mit dem Tank verbunden werden.\n"..
"Ist alles Öl abgepumpt\\, kann auch die Ölpumpe wieder entfernt werden.\n"..
"\n"..
"\n"..
"\n",
"Das Bohrgestänge wird für die Bohrung benötigt. Es werden so viele Bohrgestänge Items benötigt wie als Tiefe für das Ölfeld angegeben wurde. Das Bohrgestänge ist nach der Bohrung nutzlos\\, kann aber auch nicht abgebaut werden und verbleibt im Boden. Es gibt aber ein Werkzeug\\, um die Bohrgestänge Blöcke wieder entfernen zu können (-> Werkzeuge -> TA3 Bohrgestängezange).\n"..
"\n"..
"\n"..
"\n",
"Der Öltank ist die große Ausführung des TA3 Tanks (siehe Flüssigkeiten -> TA3 Tank).\n"..
"\n"..
"Der große Tank kann 4000 Einheiten Öl\\, aber auch jede andere Art von Flüssigkeit aufnehmen.\n"..
"\n"..
"\n"..
"\n",
"",
"Um Öl von der Ölquelle zur Ölverarbeitungsanlage zu befördern\\, können Tankwagen (tank carts) genutzt werden. Ein Tankwagen kann direkt über Pumpen gefüllt bzw. geleert werden. In beiden Fällen muss die gelbe Röhre von oben mit dem Tankwagen verbunden werden.\n"..
"\n"..
"Dazu sind folgende Schritte notwendig:\n"..
"\n"..
" - Den Tankwagen vor den Prellbock setzen. Der Prellbock darf noch nicht mit einer Zeit programmiert sein\\, so dass der Tankwagen nicht automatisch losfährt\n"..
" - Den Tankwagen über gelbe Röhren mit der Pumpe verbinden\n"..
" - Pumpe einschalten\n"..
" - Prellbock mit einer Zeit (10 - 20 s) programmieren\n"..
"\n"..
"Diese Reihenfolge muss auf beiden Seiten /Füllen/Leeren) eingehalten werden.\n"..
"\n"..
"\n"..
"\n",
"In die Minecarts können Kanister und Fässer geladen werden. Das Öl muss dazu zuvor in Fässer umgeladen werden. Die Ölfässer können direkt mit einem Schieber und Röhren in das Minecart geschoben werden (siehe Plan). Die leeren Fässer\\, welche per Minecart von der Entladestation zurück kommen\\, können über einen Hopper entladen werden\\, der unter der Schiene an der Haltestelle platziert wird.\n"..
"\n"..
"Es ist mit dem Hopper nicht möglich\\, an *einer* Haltestelle sowohl die leeren Fässer zu entladen\\, als auch die vollen Fässer zu beladen. Der Hopper lädt die vollen Fässer sofort wieder aus. Daher ist es ratsam\\, jeweils 2 Stationen auf der Be- und Entladeseite einzurichten und den Minecart dann über eine Aufzeichnungsfahrt entsprechend zu programmieren.\n"..
"\n"..
"Der Plan zeigt\\, wie das Öl in einen Tank gepumpt und über einen Einfülltrichter in Fässer umgefüllt und in Minecarts geladen werden kann.\n"..
"\n"..
"Damit die Minecarts automatisch wieder starten\\, müssen die Prellböcke mit Stationsname und Wartezeit konfiguriert werden. Für das Entladen reichen 5 s. Da aber die Schieber immer für mehrere Sekunden in den Standby fallen\\, wenn kein Minecart da ist\\, muss für das Beladen eine Zeit von 15 oder mehr Sekunden eingegeben werden.\n"..
"\n"..
"\n"..
"\n",
"Der Tankwagen dient zum Transport von Flüssigkeiten. Es kann wie Tanks mit Pumpen gefüllt bzw. geleert werden. In beiden Fällen muss die gelbe Röhre von oben mit dem Tankwagen verbunden werden.\n"..
"\n"..
"In den Tankwagen passen 200 Einheiten.\n"..
"\n"..
"\n"..
"\n",
"Der Kistenwagen dient zum Transport von Items. Es kann wie Kisten über Schieber gefüllt bzw. geleert werden.\n"..
"\n"..
"In den Kistenwagen passen 4 Stacks.\n"..
"\n"..
"\n"..
"\n",
"Öl ist ein Stoffgemisch und besteht aus sehr vielen Komponenten. Über einen Destillationsturm kann das Öl in seine Hauptbestandteile wie Bitumen\\, Schweröl\\, Naphtha\\, Benzin und Gas zerlegt werden.\n"..
"Die weitere Verarbeitung zu Endprodukten erfolgt im Chemischen Reaktor.\n"..
"\n"..
"\n"..
"\n",
"Der Destillationsturm muss wie im Plan rechts oben aufgebaut werden. \n"..
"Über den Basisblock wird das Bitumen abgelassen. Der Ausgang ist auf der Rückseite des Basisblocks (Pfeilrichtung beachten).\n"..
"Auf diesen Basisblock kommen die \"Destillationsturm\" Blöcke mit den Nummern: 1\\, 2\\, 3\\, 2\\, 3\\, 2\\, 3\\, 4\n"..
"An den Öffnungen von unten nach oben werden Schweröl\\, Naphtha und Benzin abgeleitet. Ganz oben wird das Propangas abgefangen.\n"..
"Es müssen alle Öffnungen am Turm mit Tanks verbunden werden.\n"..
"Der Aufkocher (reboiler) muss mit dem Block \"Destillationsturm 1\" verbunden werden.\n"..
"\n"..
"Der Aufkocher benötigt Strom (nicht im Plan zu sehen)!\n"..
"\n"..
"\n"..
"\n",
"Der Aufkocher erhitzt das Erdöl auf ca. 400°C. Dabei verdampft es weitgehend und wird in den Destillationsturm zur Abkühlung geleitet.\n"..
"\n"..
"Der Aufkocher benötigt 14 Einheiten Strom und produziert alle 16 s jeweils eine Einheit Bitumen\\, Schweröl\\, Naphtha\\, Benzin und Propangas.\n"..
"Dazu muss der Aufkocher über einen Pumpe mit Erdöl versorgt werden.\n"..
"\n"..
"\n"..
"\n",
"Neben den Röhren für Warentransport\\, sowie den Gas- und Stromleitungen gibt es auch noch eine drahtlose Kommunikationsebene\\, über die Blöcke untereinander Daten austauschen können. Dafür müssen keine Leitungen gezogen werden\\, sondern die Verbindung zwischen Sender und Empfänger erfolgt nur über die Blocknummer. \n"..
"\n"..
"*Info:* Eine *Blocknummer* ist eine eindeutige Zahl\\, die von Techage beim Setzen von vielen Techage Blöcken generiert wird. Die Blocknummer dient zur Adressierung bei der Kommunikation zwischen Techage Controllern und Maschinen. Alle Blöcke\\, die an dieser Kommunikation teilnehmen können\\, zeigen die Blocknummer als Info-Text an\\, wenn man mit dem Mauscursor den Block fixiert.\n"..
"\n"..
"Welche Kommandos ein Block unterstützt\\, kann mit dem TechAge Info Werkzeug (Schraubenschlüssel) ausgelesen und angezeigt werden.\n"..
"Die einfachsten Kommandos\\, die von fast allen Blöcken unterstützt werden\\, sind:\n"..
"\n"..
" - 'on' - Block/Maschine/Lampe einschalten\n"..
" - 'off' - Block/Maschine/Lampe ausschalten\n"..
"\n"..
"Mir Hilfe des TA3 Terminal können diese Kommandos sehr einfach ausprobiert werden. Angenommen\\, eine Signallampe hat die Nummer 123.\n"..
"Dann kann mit:\n"..
"\n"..
" cmd 123 on\n"..
"\n"..
"die Lampe ein\\, und mit:\n"..
"\n"..
" cmd 123 off\n"..
"\n"..
"die Lampe wieder ausgeschaltet werden. Diese Kommandos müssen so in das Eingabefeld des TA3 Terminals eingegeben werden.\n"..
"\n"..
"Kommandos wie 'on' und 'off' werden zum Empfänger gesendet\\, ohne dass eine Antwort zurück kommt. Diese Kommandos können daher bspw. mit einem Taster/Schalter auch gleichzeitig an mehrere Empfänger gesendet werden\\, wenn dort im Eingabefeld mehrere Nummern eingegeben werden.\n"..
"\n"..
"Ein Kommandos wie 'state' fordert den Status eines Blockes an. Der Block sendet in Folge seinen Status zurück. Diese Art von bestätigten Kommandos kann gleichzeitig nur an einen Empfänger gesendet werden.\n"..
"Auch dieses Kommandos kann mit dem TA3 Terminal bspw. an einem Schieber ausprobiert werden:\n"..
"\n"..
" cmd 123 state\n"..
"\n"..
"Mögliche Antworten des Schiebers sind:\n"..
"\n"..
" - 'running' --> bin am arbeiten\n"..
" - 'stopped' --> ausgeschaltet\n"..
" - 'standby' --> nichts zu tun\\, da Quell-Inventar leer\n"..
" - 'blocked' --> kann nichts tun\\, da Ziel-Inventar voll\n"..
"\n"..
"Dieser Status und weitere Informationen werden auch ausgegeben\\, wenn mit dem Schraubenschlüssel auf den Block geklickt wird.\n"..
"\n"..
"\n"..
"\n",
"Der Taster/Schalter sendet 'on'/'off' Kommandos zu den Blöcken\\, die über die Nummern konfiguriert wurden.\n"..
"Der Taster/Schalter kann als Taster (button) oder Schalter (switch) konfiguriert werden. Wird er als Taster konfiguriert\\, so kann die Zeit zwischen den 'on' und 'off' Kommandos eingestellt werden. Mit der Betriebsart \"on button\" wird nur ein 'on' und kein 'off' Kommandos gesendet.\n"..
"\n"..
"Über die Checkbox \"public\" kann eingestellt werden\\, ob den Taster von jedem (gesetzt)\\, oder nur vom Besitzer selbst (nicht gesetzt) genutzt werden darf.\n"..
"\n"..
"Hinweis: Mit dem Programmer können Blocknummern sehr einfach eingesammelt und konfiguriert werden.\n"..
"\n"..
"\n"..
"\n",
"Mit dem TA3 Kommando Konverter können 'on' / 'off' Kommandos in andere Kommandos umgewandelt werden\\, sowie die Weiterleitung verhindert oder verzögert werden. Die Nummer des Zielblockes bzw. die Nummern der Zielblöcke\\, die Kommandos die gesendet werden sollen\\, sowie die Verzögerungszeiten in Sekunden müssen eingegeben werden. Wird kein Kommando eingegeben\\, wird nichts gesendet.\n"..
"\n"..
"Die Nummern können auch mit Hilfe des Techage Programmers programmiert werden.\n"..
"\n"..
"\n"..
"\n",
"Das TA3 Flipflop wechselt seinen Zustand mit jedem empfangenen 'on' Kommando. Empfangene 'off' Kommandos werden ignoriert. Damit werden abhängig vom Zustandswechsel abwechselnd 'on' / 'off' Kommandos gesendet. Die Nummer des Zielblockes bzw. die Nummern der Zielblöcke müssen eingegeben werden. Die Nummern können auch mit Hilfe des Techage Programmers programmiert werden.\n"..
"\n"..
"Damit lassen sich bspw. Lampen mit Hilfe von Tastern ein- und wieder ausschalten.\n"..
"\n"..
"\n"..
"\n",
"Den TA3 Logikblock kann man so programmieren\\, dass ein oder mehrere Eingangskommandos zu einem Ausgangskommando verknüpft und gesendet werden. Dieser Block kann daher diverse Logik-Elemente wie AND\\, OR\\, NOT\\, XOR usw. ersetzen.\n"..
"Eingangkommandos für den Logikblock sind 'on'/'off' Kommandos.\n"..
"Eingangskommandos werden über die Nummer referenziert\\, also bspw. '1234' für das Kommando vom Sender mit der Nummer 1234.\n"..
"Das gleiche gilt für Ausgangskommandos.\n"..
"\n"..
"Eine Regel ist wie folgt aufgebaut:\n"..
"\n"..
" <output> = on/off if <input-expression> is true\n"..
"\n"..
"'<output>' ist die Nummer des Blocks\\, zu dem das Kommando gesendet werden soll.\n"..
"'<input-expression>' ist ein boolescher Ausdruck\\, bei dem Eingabenummern ausgewertet werden. \n"..
"\n"..
"*Beispiele für den Input Ausdruck*\n"..
"\n"..
"Signal negieren (NOT):\n"..
"\n"..
" 1234 == off\n"..
"\n"..
"Logisches UND (AND):\n"..
"\n"..
" 1234 == on and 2345 == on\n"..
"\n"..
"Logisches ODER (OR):\n"..
"\n"..
" 1234 == on or 2345 == on\n"..
"\n"..
"Folgende Operatoren sind zulässig: 'and' 'or' 'on' 'off' 'me' '==' '~=' '(' ')'\n"..
"\n"..
"Ist der Ausdruck wahr (true)\\, wird ein Kommando an den Block mit der '<output>' Nummer gesendet.\n"..
"\n"..
"Es können bis zu vier Regeln definiert werden\\, wobei immer alle Regeln geprüft werden\\, wenn ein Kommando empfangen wird.\n"..
"\n"..
"Die interne Durchlaufzeit aller Kommandos beträgt 100 ms.\n"..
"\n"..
"Über das Schlüsselwort 'me' kann die eigene Knotennummer referenziert werden. Damit ist es möglich\\, dass sich der Block selbst ein Kommando sendet (Flip-Flop Funktion).\n"..
"\n"..
"Die Sperrzeit definiert eine Pause nach einem Kommando\\, in der der Logikblock kein weiteres Kommando von extern annimmt. Empfangene Kommandos in der Sperrzeit werden damit verworfen. Die Sperrzeit kann in Sekunden definiert werden.\n"..
"\n"..
"\n"..
"\n",
"Der Wiederholer (repeater) sendet das empfangene Signal an alle konfigurierten Nummern weiter.\n"..
"Dies kann bspw. Sinn machen\\, wenn man viele Blöcke gleichzeitig angesteuert werden sollen. Den Wiederholer kann man dazu mit dem Programmer konfigurieren\\, was nicht bei allen Blöcken möglich ist.\n"..
"\n"..
"\n"..
"\n",
"Der Sequenzer kann eine Reihe von 'on'/'off' Kommandos senden\\, wobei der Abstand zwischen den Kommandos in Sekunden angegeben werden muss. Damit kann man bspw. eine Lampe blinken lassen.\n"..
"Es können bis zu 8 Kommandos konfiguriert werden\\, jedes mit Zielblocknummer und Anstand zum nächsten Kommando.\n"..
"Der Sequenzer wiederholt die Kommandos endlos\\, wenn \"Run endless\" gesetzt wird.\n"..
"Wird also Kommando nichts ausgewählt\\, wird nur die angegeben Zeit in Sekunden gewartet.\n"..
"\n"..
"\n"..
"\n",
"Der Timer kann Kommandos Spielzeit-gesteuert senden. Für jede Kommandozeile kann die Uhrzeit\\, die Zielnummer(n) und das Kommando selbst angegeben werden. Damit lassen sich bspw. Lampen abends ein- und morgens wieder ausschalten.\n"..
"\n"..
"\n"..
"\n",
"Das Terminal dient in erster Linie zum Austesten der Kommandoschnittstelle anderer Blöcke (siehe \"Logik-/Schalt-Blöcke\").\n"..
"Man kann aber auch Kommandos auf Tasten legen und so das Terminal produktiv nutzen.\n"..
"\n"..
" set <button-num> <button-text> <command>\n"..
"\n"..
"Mit 'set 1 ON cmd 123 on' kann bspw. die Usertaste 1 mit dem Kommando 'cnd 123 on' programmiert werden. Wird die Taste gedrückt\\, wird das Kommando gesendet und die Antwort auf dem Bildschirm ausgegeben.\n"..
"\n"..
"Das Terminal besitzt folgende\\, lokalen Kommandos:\n"..
"\n"..
" - 'clear' lösche Bildschirm\n"..
" - 'help' gib eine Hilfeseite aus\n"..
" - 'pub' schalte in den öffentlichen Modus um\n"..
" - 'priv' schalte in den privaten Modus um\n"..
"\n"..
"Im privaten Modus (private) kann das Terminal nur von Spielern verwendet werden\\, die an diesem Ort bauen können\\, also Protection Rechte besitzen. Im öffentlichen Modus (public) können alle Spieler die vorkonfigurierten Tasten verwenden.\n"..
"\n"..
"\n"..
"\n",
"Die Farblampe kann mit 'on'/'off' Kommando ein- bzw. ausgeschaltet werden. Diese Lampe braucht keinen Strom und\n"..
"kann mit der Spritzpistole aus der Mod \"Unified Dyes\" und über Lua/Beduino Kommandos eingefärbt werden.\n"..
"\n"..
"Mit dem Chat-Kommando '/ta_color' wird die Farbpalette mit den Werten für die Lua/Beduino Kommandos angezeigt und mit '/ta_send color <num>' kann die Farbe geändert werden.\n"..
"\n"..
"\n"..
"\n",
"Mit diese Blöcken kann man Türe und Tore realisieren\\, die über Kommandos geöffnet (Blöcke verschwinden) und wieder geschlossen werden können. Pro Tor oder Tür wird dazu ein Tür Controller benötigt. \n"..
"\n"..
"Das Aussehen der Blöcke kann über das Block-Menü eingestellt werden.\n"..
"Damit lassen sich Geheimtüren realisieren\\, die sich nur bei bestimmten Spielern öffnen (mit Hilfe des Spieler-Detektors). \n"..
"\n"..
"\n"..
"\n",
"Der Tür Controller dient zur Ansteuerung der TA3 Tür/Tor Blöcke. Beim Tür Controller müssen die Nummern der Tür/Tor Blöcke eingegeben werden. Wird ein 'on'/'off' Kommando Kommando an den Tür Controller gesendet\\, öffnet/schließt dieser die Tür bzw. das Tor.\n"..
"\n"..
"\n"..
"\n",
"Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen\\, muss der \"Aufzeichnen\" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden\\, die Teil der Tür / des Tores sein sollen. Danach muss der \"Fertig\" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert.\n"..
"\n"..
" Über die Tasten \"Entfernen\" bzw. \"Setzen\" kann die Funktion des Controllers von Hand getestet werden.\n"..
"\n"..
"Wird ein 'on' / 'off' Kommando an den Tür Controller II gesendet\\, entfernt bzw. setzt er die Blöcke ebenfalls.\n"..
"\n"..
"Mit '$send_cmnd(node_number\\, \"exchange\"\\, 2)' können einzelne Böcke gesetzt\\, entfernt\\, bzw. durch andere Blöcke aus dem Inventar ersetzt werden. \n"..
"\n"..
"Mit '$send_cmnd(node_number\\, \"set\"\\, 2)' kann ein Block aus dem Inventory explizit gesetzt werden\\, sofern der Inventory Slot nicht leer ist.\n"..
"\n"..
"Mit '$send_cmnd(node_number\\, \"dig\"\\, 2)' kann ein Block wieder entfernt werden\\, sofern der Inventory Slot leer ist. \n"..
"\n"..
"Mit '$send_cmnd(node_number\\, \"get\"\\, 2)' wird der Name des gesetzten Blocks zurückgeliefert. \n"..
"\n"..
"Die Slot-Nummer des Inventars (1 .. 16) muss in allen drei Fällen als payload übergeben werden.\n"..
"\n"..
"Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.\n"..
"\n"..
"\n"..
"\n",
"Mir dem Sound Block können veschiedene Sounds/Laute abgespielt werden. Es sind alle Sounds der Mods Techage\\, Signs Bot\\, Hyperloop\\, Unified Inventory\\, TA4 Jetpack und Minetest Game verfügbar.\n"..
"\n"..
"Die Sounds können über das Menü und über ein Kommando ausgewählt und abgespielt werden.\n"..
"\n"..
" - Kommando 'on' zum Abspielen eines Sounds\n"..
" - Kommando 'sound <idx>' zur Auswahl eines Sounds über den Index\n"..
" - Kommando 'gain <volume>' zum Einstellen der Lautstärke über den '<volume>' Wert (1 bis 5).\n"..
"\n"..
"\n"..
"\n",
"Der Mesecons Umsetzer dient zur Umwandlung von Techage on/off Kommandos in Mesecons Signale und umgekehrt.\n"..
"Dazu müssen eine oder mehrere Knotennummern eingegeben und der Konverter mit Mesecons Blöcken \n"..
"über Mesecons Leitungen verbunden werden. Den Mesecons Umsetzer kann man auch mit dem Programmer konfigurieren.\n"..
"Der Mesecons Umsetzer akzeptiert bis zu 5 Kommandos pro Sekunde\\, bei höherer Belastung schaltet er sich ab.\n"..
"\n"..
"*Dieser Block existiert aber nur\\, wenn die Mod mesecons aktiv ist!*\n"..
"\n"..
"\n"..
"\n",
"Detektoren scannen ihre Umgebung ab und senden ein 'on'-Kommando\\, wenn das Gesuchte erkannt wurde.\n"..
"\n"..
"\n"..
"\n",
"Der Detektor ist eine spezieller Röhrenblock\\, der erkennt\\, wenn Items über die Röhre weitergegeben werden. Es muss dazu auf beiden Seiten mit der Röhre verbunden sein. Werden Items mit einem Schieber in den Detektor geschoben\\, gibt er diese automatisch weiter.\n"..
"Er sendet ein 'on'\\, wenn ein Item erkannt wird\\, gefolgt von einem 'off' eine Sekunde später.\n"..
"Danach werden weitere Kommando für 8 Sekunden blockiert.\n"..
"Die Wartezeit\\, sowie die Items\\, die ein Kommando auslösen sollen\\, können über das Gabelschlüssel-Menü konfiguriert werden.\n"..
"\n"..
"\n"..
"\n",
"Der Wagen Detektor sendet ein 'on'-Kommando\\, wenn er einen Wagen/Cart (Minecart) direkt vor sich erkannt hat. Zusätzlich kann der Detektor auch den Wagen wieder starten\\, wenn ein 'on'-Kommando empfangen wird.\n"..
"\n"..
"Der Detektor kann auch mit seiner eigenen Nummer programmiert werden. In diesem Falle schiebt er alle Wagen an\\, die in seiner Nähe (ein Block in alle Richtungen) zum Halten kommen.\n"..
"\n"..
"\n"..
"\n",
"Der Block Detektor sendet ein 'on'-Kommando\\, wenn er erkennt\\, dass Blöcke vor ihm erscheinen oder verschwinden\\, muss jedoch entsprechend konfiguriert werden. Nach dem Zurückschalten des Detektors in den Standardzustand (grauer Block) wird ein 'off'-Kommando gesendet. Gültige Blöcke sind alle Arten von Blöcken und Pflanzen\\, aber keine Tiere oder Spieler. Die Sensorreichweite beträgt 3 Blöcke/Meter in Pfeilrichtung.\n"..
"\n"..
"\n"..
"\n",
"Der Spieler Detektor sendet ein 'on'-Kommando\\, wenn er einen Spieler in einem Umkreis von 4 m um den Block herum erkennt. Verlässt der Spieler wieder den Bereich\\, wird ein 'off'-Kommando gesendet.\n"..
"Soll die Suche auf bestimmte Spieler eingegrenzt werden\\, so können diese Spielernamen auch eingegeben werden.\n"..
"\n"..
"\n"..
"\n",
"Der Lichtdetektor sendet einen 'on'-Kommando\\, wenn der Lichtpegel des darüber liegenden Blocks einen bestimmten Pegel überschreitet\\, der über das Rechtsklickmenü eingestellt werden kann.\n"..
"Mit einen TA4 Lua Controller kann die genaue Lichtstärke mit $get_cmd(num\\, 'light_level') ermitteln werden.\n"..
"\n"..
"\n"..
"\n",
"Bei TA3 existieren die gleichen Maschinen wie bei TA2\\, nur sind diese hier leistungsfähiger und benötigen Strom statt Achsenantrieb.\n"..
"Im folgenden sind daher nur die unterschiedlichen\\, technischen Daten angegeben.\n"..
"\n"..
"\n"..
"\n",
"Die Funktion entspricht der von TA2.\n"..
"Die Verarbeitungsleistung beträgt 6 Items alle 2 s.\n"..
"\n"..
"\n"..
"\n",
"Die Funktion des TA3 Verteilers entspricht der von TA2.\n"..
"Die Verarbeitungsleistung beträgt 12 Items alle 4 s.\n"..
"\n"..
"\n"..
"\n",
"Die Funktion entspricht der von TA2.\n"..
"Die Verarbeitungsleistung beträgt 2 Items alle 4 s. Der Autocrafter benötigt hierfür 6 ku Strom.\n"..
"\n"..
"\n"..
"\n",
"Die Funktion entspricht der von TA2\\, nur werden hier TA4 WLAN Chips produziert.\n"..
"Die Verarbeitungsleistung beträgt ein Chip alle 6 s. Der Block benötigt hierfür 12 ku Strom.\n"..
"\n"..
"\n"..
"\n",
"Die Funktion entspricht der von TA2.\n"..
"Die maximale Tiefe beträgt 40 Meter. Der Steinbrecher benötigt 12 ku Strom.\n"..
"\n"..
"\n"..
"\n",
"Die Funktion entspricht der von TA2.\n"..
"Die Verarbeitungsleistung beträgt 2 Items alle 4 s. Der Block benötigt 4 ku Strom.\n"..
"\n"..
"\n"..
"\n",
"Die Funktion entspricht der von TA2.\n"..
"Auch die Wahrscheinlichkeit ist wie bei TA2. Der Block benötigt auch 3 ku Strom.\n"..
"Aber im Gegensatz zu TA2 kann beim TA3 Block bspw. der Status abgefragt werden (Controller)\n"..
"\n"..
"\n"..
"\n",
"Die Funktion entspricht der von TA2.\n"..
"Die Verarbeitungsleistung beträgt 2 Items alle 4 s. Der Block benötigt 6 ku Strom.\n"..
"\n"..
"\n"..
"\n",
"Der Injektor ist ein TA3 Schieber mit speziellen Eigenschaften. Er besitzt ein Menü zur Konfiguration. Hier können bis zu 8 Items konfiguriert werden. Er entnimmt nur diese Items einer Kiste um sie an Maschinen mit Rezepturen weiterzugeben (Autocrafter\\, Industrieofen und Elektronikfabrik).\n"..
"\n"..
"Beim Weitergeben wird in der Zielmaschine pro Item nur eine Position im Inventar genutzt. Sind bspw. nur die ersten drei Einträge im Injektor konfiguriert\\, so werden auch nur die ersten drei Speicherplätze im Inventar der Maschine belegt. Damit wir ein Überlauf im Inventar der Maschine verhindert.\n"..
"\n"..
"Der Injektor kann auch auf \"Ziehe-Modus\" umgeschaltet werden. Dann zieht er nur Items von den Positionen aus der Kiste\\, die in der Konfiguration des Injektors definiert sind. Hier müssen also Item-Typ und Position überein stimmen. Damit können geziehlt Speicherplätze im Inventar einer Kiste geleert werden.\n"..
"\n"..
"Die Verarbeitungsleistung beträgt bis zu 8 mal ein Item alle 4 Sekunden.\n"..
"\n"..
"\n"..
"\n",
"",
"Das Techage Info Tool (Schraubenschlüssel) hat verschiedene Funktionen. Er zeigt die Uhrzeit\\, die Position\\, die Temperatur und das Biome an\\, wenn auf einen unbekannten Block geklickt wird.\n"..
"Wird auf einen TechAge Block mit Kommandoschnittstelle geklickt\\, werden alle verfügbaren Daten abgerufen (siehe auch \"Logik-/Schalt-Blöcke\").\n"..
"\n"..
"Mit Shift+Rechtsklick kann bei einigen Blöcken ein erweitertes Menü geöffnet werden. Hier lassen sich je nach Block weitere Daten abrufen oder spezielle Einstellungen vornehmen. Bei einem Generator kann bspw. die Ladekurve/abschaltung programmiert werden. \n"..
"\n"..
"\n"..
"\n",
"Mit dem Programmer können Blocknummern mit einem Rechtsklick von mehreren Blöcken eingesammelt und mit einem Linksklick in einen Block wie Taster/Schalter geschrieben werden.\n"..
"Wird in die Luft geklickt\\, wird der interne Speicher gelöscht.\n"..
"\n"..
"\n"..
"\n",
"Die Kelle dient zum Verputzen von Stromkabel. Siehe dazu \"TA Stromkabel\".\n"..
"\n"..
"\n"..
"\n",
"Mit diesem Werkzeug lassen sich die Bohrgestängezange Blöcke wieder entfernen\\, wenn dort bspw. ein Tunnel durch soll.\n"..
"\n"..
"\n"..
"\n",
"Der Techage Schraubendreher dient als Ersatz für den normalen Schraubendreher. Es besitzt folgende Funktionen:\n"..
"\n"..
" - Linksklick: Den Block nach links drehen\n"..
" - Rechtsklick: Die sichtbare Seite des Blockes nach oben drehen\n"..
" - Shift+Linksklick: Ausrichtung des angeklickten Blockes speichern\n"..
" - Shift+Rechtsklick: Die gespeicherte Ausrichtung auf den angeklickten Block anwenden\n"..
"\n"..
"\n"..
"\n",
"Das TechAge Montagewerkzeug dient zum Entfernen und wieder Setzen von Techage Blöcken\\, ohne dass diese Blöcke ihre Blocknummer verlieren\\, bzw. beim Setzen eine neue Nummer zugeteilt bekommen. Dies ist bspw. bei Steinbrechern hilfreich\\, da diese oft umgesetzt werden müssen.\n"..
"\n"..
" - Linke Taste: Entfernen eines Blocks\n"..
" - Rechte Taste: Setzen eines Blocks\n"..
"\n"..
"Der Block\\, der zuvor mit dem Montagewerkzeug entfernt wurde und wieder gesetzt werden soll\\, muss sich im Spieler-Inventar ganz links befinden.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta3",
"",
"ta3_firebox",
"ta3_oilbox",
"ta3_boiler",
"ta3_turbine",
"ta3_generator",
"ta3_cooler",
"ta3_powerswitch",
"power_reduction",
"ta3_powercable",
"ta3_powerjunction",
"ta3_powerline",
"ta3_powerpole",
"ta3_powerpole4",
"ta3_powerpole2",
"ta3_powerswitch",
"ta3_powerswitchsmall",
"ta3_powerswitchbox",
"ta3_tinygenerator",
"ta3_akkublock",
"ta3_powerterminal",
"ta3_motor",
"",
"ta3_furnacefirebox",
"ta3_furnace",
"ta3_booster",
"",
"ta3_tank",
"ta3_pump",
"ta3_filler",
"ta3_pipe",
"ta3_pipe_wall_entry",
"ta3_valve",
"techage_ta3",
"ta3_oilexplorer",
"ta3_drillbox",
"ta3_pumpjack",
"ta3_drillbit",
"oiltank",
"",
"tank_cart",
"",
"tank_cart",
"chest_cart",
"techage_ta31",
"",
"reboiler",
"ta3_logic",
"ta3_button",
"ta3_command_converter",
"ta3_flipflop",
"ta3_logic",
"ta3_repeater",
"ta3_sequencer",
"ta3_timer",
"ta3_terminal",
"ta3_colorlamp",
"ta3_doorblock",
"ta3_doorcontroller",
"ta3_doorcontroller",
"ta3_soundblock",
"ta3_mesecons_converter",
"ta3_nodedetector",
"ta3_detector",
"ta3_cartdetector",
"ta3_nodedetector",
"ta3_playerdetector",
"ta3_lightdetector",
"ta3_grinder",
"ta3_pusher",
"ta3_distributor",
"ta3_autocrafter",
"ta3_electronicfab",
"ta3_quarry",
"ta3_gravelsieve",
"ta3_gravelrinser",
"ta3_grinder",
"ta3_injector",
"",
"ta3_end_wrench",
"ta3_programmer",
"ta3_trowel",
"ta3_drill_pipe_wrench",
"ta3_screwdriver",
"techage:assembly_tool",
},
plans = {
"",
"coalpowerstation",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"ta3_furnace",
"",
"",
"",
"ta3_tank",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"ta3_loading",
"",
"",
"",
"ta3_distiller",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

931
doc/manual_ta3_EN.lua Normal file
View File

@ -0,0 +1,931 @@
return {
titles = {
"1,TA3: Oil Age",
"2,Coal-fired Power Station / Oil-fired Power Station",
"3,TA3 power station firebox",
"3,TA3 Power Station Oil Burner",
"3,TA3 boiler base / top",
"3,TA3 turbine",
"3,TA3 generator",
"3,TA3 cooler",
"2,Electrical current",
"3,Importance of storage systems",
"3,TA Electric Cable",
"3,TA Electric Junction Box",
"3,TA Power Line",
"3,TA Power Pole",
"3,TA Power Pole Top",
"3,TA Power Pole Top 2",
"3,TA Power Switch",
"3,TA Power Switch Small",
"3,TA Power Switch Box",
"3,TA3 Small Power Generator",
"3,TA3 Accu Block",
"3,TA3 Power Terminal",
"3,TA3 Electric Motor",
"2,TA3 Industrial Furnace",
"3,TA3 Furnace Oil Burner",
"3,TA3 Furnace Top",
"3,TA3 Booster",
"2,Liquids",
"3,TA3 Tank",
"3,TA3 Pump",
"3,TA Liquid Filler",
"3,TA4 Pipe",
"3,TA3 Pipe Wall Entry Blocks",
"3,TA Valve",
"2,Oil Production",
"3,TA3 Oil Explorer",
"3,TA3 Oil Drill Box",
"3,TA3 Oil Pumpjack",
"3,TA3 Drill Pipe",
"3,Oil tank",
"2,Oil Transportation",
"3,Oil transportation by Tank Carts",
"3,Oil transportation with barrels over Minecarts",
"3,Tank Cart",
"3,Chest Cart",
"2,Oil Processing",
"3,Distillation Tower",
"4,Reboiler",
"2,Logic / Switching Blocks",
"3,TA3 Button / Switch",
"3,TA3 Command Converter",
"3,TA3 Flip-Flop",
"3,TA3 Logic Block",
"3,TA3 Repeater",
"3,TA3 Sequencer",
"3,TA3 Timer",
"3,TA3 Terminal",
"3,TechAge Color Lamp",
"3,Door/Gate Blocks",
"3,TA3 Door Controller",
"3,TA3 Door Controller II",
"3,TA3 Sound Block",
"3,TA3 Mesecons Converter",
"2,Detectors",
"3,TA3 Detector",
"3,TA3 Cart Detector",
"3,TA3 Node Detector",
"3,TA3 Player Detector",
"3,TA3 Light Detector",
"2,TA3 Machines",
"3,TA3 Pusher",
"3,TA3 Distributor",
"3,TA3 Autocrafter",
"3,TA3 Electronic Fab",
"3,TA3 Quarry",
"3,TA3 Gravel Sieve",
"3,TA3 Gravel Rinser",
"3,TA3 Grinder",
"3,TA3 Injector",
"2,Tools",
"3,Techage Info Tool",
"3,TechAge Programmer",
"3,TechAge Trowel / Trowel",
"3,TA3 drill pipe wrench",
"3,Techage Screwdriver",
"3,TechAge Assembly Tool",
},
texts = {
"At TA3 it is important to replace the steam-powered machines with more powerful and electric-powered machines.\n"..
"\n"..
"To do this\\, you have to build coal-fired power plants and generators. You will soon see that your electricity needs can only be met with oil-powered power plants. So you go looking for oil. Drilling derricks and oil pumps help them get the oil. Railways are used to transport oil to the power plants.\n"..
"\n"..
"The industrial age is at its peak.\n"..
"\n"..
"\n"..
"\n",
"The coal-fired power plant consists of several blocks and must be assembled as shown in the plan on the right. The blocks TA3 power station fire box\\, TA3 boiler top\\, TA3 boiler base\\, TA3 turbine\\, TA3 generator and TA3 cooler are required.\n"..
"\n"..
"The boiler must be filled with water. Fill up to 10 buckets of water in the boiler.\n"..
"The fire box must be filled with coal or charcoal.\n"..
"When the water is hot\\, the generator can then be started.\n"..
"\n"..
"Alternatively\\, the power plant can be equipped with an oil burner and then operated with oil.\n"..
"The oil can be refilled using a pump and oil pipe.\n"..
"\n"..
"The power plant delivers an output of 80 ku.\n"..
"\n"..
"\n"..
"\n",
"Part of the power plant.\n"..
"The fire box must be filled with coal or charcoal. The burning time depends on the power that is requested by the power plant. Coal burns for 20 s and charcoal for 60 s under full load. Correspondingly longer under partial load (50% load = double time).\n"..
"\n"..
"\n"..
"\n",
"Part of the power plant.\n"..
"\n"..
"The oil burner can be filled with crude oil\\, fuel oil\\, naphtha or gasoline. The burning time depends on the power that is requested by the power plant. Under full load\\, crude oil burns 15 s\\, fuel oil 20 s\\, naphtha 22 s and gasoline 25 s.\n"..
"\n"..
"Correspondingly longer under partial load (50% load = double time).\n"..
"\n"..
"The oil burner can only hold 50 units of fuel. An additional oil tank and an oil pump are therefore advisable.\n"..
"\n"..
"\n"..
"\n",
"Part of the power plant. Must be filled with water. If there is no more water or the temperature drops too low\\, the power plant switches off.\n"..
"\n"..
"The water consumption of the TA3 boiler is much lower than that of the steam engine due to the closed steam circuit.\n"..
"With the steam engine\\, some water is lost as steam with each piston stroke.\n"..
"\n"..
"\n"..
"\n",
"The turbine is part of the power plant. It must be placed next to the generator and connected to the boiler and cooler via steam pipes as shown in the plan.\n"..
"\n"..
"\n"..
"\n",
"The generator is used to generate electricity. It must be connected to the machines via power cables and junction boxes.\n"..
"\n"..
"\n"..
"\n",
"Used to cool the hot steam from the turbine. Must be connected to the boiler and turbine via steam pipes as shown in the plan.\n"..
"\n"..
"\n"..
"\n",
"In TA3 (and TA4) the machines are powered by electricity. To do this\\, machines\\, storage systems\\, and generators must be connected with power cables.\n"..
"TA3 has 2 types of power cables:\n"..
"\n"..
" - Insulated cables (TA power cables) for local wiring in the floor or in buildings. These cables can be hidden in the wall or in the floor (can be \"plastered\" with the trowel).\n"..
" - Overland lines (TA power line) for outdoor cabling over long distances. These cables are protected and cannot be removed by other players.\n"..
"\n"..
"Several consumers\\, storage systems\\, and generators can be operated together in a power network. Networks can be set up with the help of the junction boxes.\n"..
"If too little electricity is provided\\, consumers run out.\n"..
"In this context\\, it is also important that the functionality of Forceload blocks is understood\\, because generators\\, for example\\, only supply electricity when the corresponding map block is loaded. This can be enforced with a forceload block.\n"..
"\n"..
"In TA4 there is also a cable for the solar system.\n"..
"\n"..
"\n"..
"\n",
"Storage systems in the power grid fulfill two tasks:\n"..
"\n"..
" - To cope with peaks in demand: All generators always deliver just as much power as is needed. However\\, if consumers are switched on/off or there are fluctuations in demand for other reasons\\, consumers can fail for a short time. To prevent this\\, there should always be at least one battery block in every network. This serves as a buffer and compensates for these fluctuations in the seconds range.\n"..
" - To store regenerative energy: Solar and wind are not available 24 hours a day. So that the power supply does not fail when no electricity is produced\\, one or more storage systems must be installed in the network. Alternatively\\, the gaps can also be bridged with oil/coal electricity.\n"..
"\n"..
"A storage system indicates its capacity in kud\\, i.e. ku per day. For example\\, a storage system with 100 kud delivers 100 ku for one game day\\, or 10 ku for 10 game days.\n"..
"\n"..
"All TA3/TA4 energy sources have adjustable charging characteristics. By default this is set to \"80% - 100%\". This means that when the storage system is 80% full\\, the output is reduced further and further until it switches off completely at 100%. If electricity is required in the network\\, 100% will never be reached\\, since the power of the generator has at some point dropped to the electricity demand in the network and the storage system is no longer charged\\, but only the consumers are served.\n"..
"\n"..
"This has several advantages:\n"..
"\n"..
" - The charging characteristics are adjustable. This means\\, for example\\, that oil/coal energy sources can be reduced at 60% and regenerative energy sources only at 80%. This means that oil/coal is only burned if there are not enough renewable energy sources available.\n"..
" - Several energy sources can be operated in parallel and are loaded almost evenly\\, because all energy sources work\\, for example\\, up to 80% of the storage system's charging capacity at their full capacity and then reduce their capacity at the same time.\n"..
" - All storage systems in a network form a large buffer. The charging capacity and the filling level of the entire storage system can always be read in percent on every storage system\\, but also on the electricity terminal.\n"..
"\n"..
" \n"..
"\n",
"For local wiring in the floor or in buildings.\n"..
"Branches can be realized using junction boxes. The maximum cable length between machines or junction boxes is 1000 m. A maximum of 1000 nodes can be connected in a power network. All blocks with power connection\\, including junction boxes\\, count as nodes.\n"..
"\n"..
"Since the power cables are not automatically protected\\, the land lines (TA power line) are recommended for longer distances.\n"..
"\n"..
"Power cables can be plastered with the trowel so they can be hidden in the wall or in the floor. All stone\\, clay and other blocks without \"intelligence\" can be used as plastering material. Dirt does not work because dirt can be converted to grass or the like\\, which would destroy the line.\n"..
"\n"..
"For plastering\\, the cable must be clicked on with the trowel. The material with which the cable is to be plastered must be on the far left in the player inventory.\n"..
"The cables can be made visible again by clicking on the block with the trowel.\n"..
"\n"..
"In addition to cables\\, the TA junction box and the TA power switch box can also be plastered.\n"..
"\n"..
"\n"..
"\n",
"With the junction box\\, electricity can be distributed in up to 6 directions. Junction boxes can also be plastered (hidden) with a trowel and made visible again.\n"..
"\n"..
"\n"..
"\n",
"With the TA power line and the electricity poles\\, reasonably realistic overhead lines can be realized. The power pole heads also serve to protect the power line (protection). A pole must be set every 16 m or less. The protection only applies to the power line and the poles\\, however\\, all other blocks in this area are not protected.\n"..
"\n"..
"\n"..
"\n",
"Used to build electricity poles. Is protected from destruction by the electricity pole head and can only be removed by the owner.\n"..
"\n"..
"\n"..
"\n",
"Has up to four arms and thus allows electricity to be distributed in up to 6 directions.\n"..
"The electricity pole head protects power lines and poles within a radius of 8 m.\n"..
"\n"..
"\n"..
"\n",
"This electricity pole head has two fixed arms and is used for the overhead lines. However\\, it can also transmit current downwards and upwards.\n"..
"The electricity pole head protects power lines and poles within a radius of 8 m.\n"..
"\n"..
"\n"..
"\n",
"The switch can be used to switch the power on and off. To do this\\, the switch must be placed on a power switch box. The power switch box must be connected to the power cable on both sides.\n"..
"\n"..
"\n"..
"\n",
"The switch can be used to switch the power on and off. To do this\\, the switch must be placed on a power switch box. The power switch box must be connected to the power cable on both sides.\n"..
"\n"..
"\n"..
"\n",
"see TA power switch.\n"..
"\n"..
"\n"..
"\n",
"The small power generator runs on gasoline and can be used for small consumers with up to 12 ku. Gasoline burns for 150 s under full load. Correspondingly longer under partial load (50% load = double time).\n"..
"\n"..
"The power generator can only hold 50 units of gasoline. An additional tank and a pump are therefore advisable.\n"..
"\n"..
"\n"..
"\n",
"The accu block (rechargeable battery) is used to store excess energy and automatically delivers power in the event of a power failure (if available).\n"..
"Several accu blocks together form a TA3 energy storage system. Each accu block has a display for the charging state and for the stored load.\n"..
"The values for the entire network are always displayed here. The stored load is displayed in \"kud\" or \"ku-days\" (analogous to kWh) 5 kud thus corresponds\\, for example\\, to 5 ku for a game day (20 min) or 1 ku for 5 game days.\n"..
"\n"..
"A accu block has 3.33 kud\n"..
"\n"..
"\n"..
"\n",
"The power terminal must be connected to the power grid. It shows data from the power grid.\n"..
"\n"..
"The most important figures are displayed in the upper half:\n"..
"\n"..
" - current/maximum generator power\n"..
" - current power consumption of all consumers\n"..
" - current charging current in/from the storage system\n"..
" - Current state of charge of the storage system in percent\n"..
"\n"..
"The number of network blocks is output in the lower half.\n"..
"\n"..
"Additional data on the generators and storage systems can be queried via the \"console\" tab.\n"..
"\n"..
"\n"..
"\n",
"The TA3 Electric Motor is required in order to be able to operate TA2 machines via the power grid. The TA3 Electric Motor converts electricity into axle power.\n"..
"If the electric motor is not supplied with sufficient power\\, it goes into an fault state and must be reactivated with a right-click.\n"..
"\n"..
"The electric motor takes max. 40 ku of electricity and provides on the other side max. 39 ku as axle power. So he consumes one ku for the conversion.\n"..
"\n"..
"\n"..
"\n",
"The TA3 industrial furnace serves as a supplement to normal furnaces. This means that all goods can be produced with \"cooking\" recipes\\, even in an industrial furnace. But there are also special recipes that can only be made in an industrial furnace.\n"..
"The industrial furnace has its own menu for recipe selection. Depending on the goods in the industrial furnace inventory on the left\\, the output product can be selected on the right.\n"..
"\n"..
"The industrial furnace requires electricity (for the booster) and fuel oil / gasoline for the burner. The industrial furnace must be assembled as shown in the plan on the right.\n"..
"\n"..
"See also TA4 heater.\n"..
"\n"..
"\n"..
"\n",
"Is part of the TA3 industrial furnace.\n"..
"\n"..
"The oil burner can be operated with crude oil\\, fuel oil\\, naphtha or gasoline. The burning time is 64 s for crude oil\\, 80 s for fuel oil\\, 90 s for naphtha and 100 s for gasoline.\n"..
"\n"..
"The oil burner can only hold 50 units of fuel. An additional tank and a pump are therefore advisable.\n"..
"\n"..
"\n"..
"\n",
"Is part of the TA3 industrial furnace. See TA3 industrial furnace.\n"..
"\n"..
"\n"..
"\n",
"Is part of the TA3 industrial furnace. See TA3 industrial furnace.\n"..
"\n"..
"\n"..
"\n",
"Liquids such as water or oil can only be pumped through the special pipes and stored in tanks. As with water\\, there are containers (canisters\\, barrels) in which the liquid can be stored and transported.\n"..
"\n"..
"It is also possible to connect several tanks using the yellow pipes and connectors. However\\, the tanks must have the same content and there must always be at least one yellow pipe between the tank\\, pump and distributor pipe.\n"..
"\n"..
"E.g. It is not possible to connect two tanks directly to a distributor pipe.\n"..
"\n"..
"The liquid filler is used to transfer liquids from containers to tanks. The plan shows how canisters or barrels with liquids are pushed into a liquid filler via pushers. The container is emptied in the liquid filler and the liquid is led down into the tank.\n"..
"\n"..
"The liquid filler can also be placed under a tank to empty the tank.\n"..
"\n"..
"\n"..
"\n",
"Liquids can be stored in a tank. A tank can be filled or emptied using a pump. To do this\\, the pump must be connected to the tank via a pipe (yellow pipes).\n"..
"\n"..
"A tank can also be filled or emptied manually by clicking on the tank with a full or empty liquid container (barrel\\, canister). It should be noted that barrels can only be completely filled or emptied. If\\, for example\\, there are less than 10 units in the tank\\, this remainder must be removed with canisters or pumped empty.\n"..
"\n"..
"A TA3 tank can hold 1000 units or 100 barrels of liquid.\n"..
"\n"..
"\n"..
"\n",
"The pump can be used to pump liquids from tanks or containers to other tanks or containers. The pump direction (arrow) must be observed for the pump. The yellow lines and connectors also make it possible to arrange several tanks on each side of the pump. However\\, the tanks must have the same content.\n"..
"\n"..
"The TA3 pump pumps 4 units of liquid every two seconds.\n"..
"\n"..
"Note 1: The pump must not be placed directly next to the tank. There must always be at least a piece of yellow pipe between them.\n"..
"\n"..
"\n"..
"\n",
"The liquid filler is used to transfer liquids between containers and tanks.\n"..
"\n"..
" - If the liquid filler is placed under a tank and empty barrels are put into the liquid filler with a pusher or by hand\\, the contents of the tank are transferred to the barrels and the barrels can be removed from the outlet\n"..
" - If the liquid filler is placed on a tank and if full containers are put into the liquid filler with a pusher or by hand\\, the content is transferred to the tank and the empty containers can be removed on the exit side\n"..
"\n"..
"It should be noted that barrels can only be completely filled or emptied. If\\, for example\\, there are less than 10 units in the tank\\, this remainder must be removed with canisters or pumped empty.\n"..
"\n"..
"\n"..
"\n",
"The yellow pipes are used for the transmission of gas and liquids.\n"..
"The maximum pipe length is 100 m.\n"..
"\n"..
"\n"..
"\n",
"The blocks serve as wall openings for tubes\\, so that no holes remain open.\n"..
"\n"..
"\n"..
"\n",
"There is a valve for the yellow pipes\\, which can be opened and closed with a click of the mouse.\n"..
"The valve can also be controlled via on/off commands.\n"..
"\n"..
"\n"..
"\n",
"In order to run your generators and stoves with oil\\, you must first look for oil and build a derrick and then extract the oil.\n"..
"TA3 oil explorer\\, TA3 oil drilling box and TA3 pump jack are used for this.\n"..
"\n"..
"\n"..
"\n",
"You can search for oil with the oil explorer. To do this\\, place the block on the floor and right-click to start the search. The oil explorer can be used above ground and underground at all depths.\n"..
"The chat output shows you the depth to which oil was searched and how much oil (petroleum) was found.\n"..
"You can click the block multiple times to search for oil in deeper areas. Oil fields range in size from 4\\,000 to 20\\,000 items.\n"..
"\n"..
"If the search was unsuccessful\\, you have to move the block approx. 16 m further.\n"..
"The oil explorer always searches for oil in the whole map block and below\\, in which it was set. A new search in the same map block (16x16 field) therefore makes no sense.\n"..
"\n"..
"If oil is found\\, the location for the derrick is displayed. You have to erect the derrick within the area shown\\, it is best to mark the spot with a sign and protect the entire area against foreign players.\n"..
"\n"..
"Don't give up looking for oil too quickly. If you're unlucky\\, it can take a long time to find an oil well.\n"..
"It also makes no sense to search an area that another player has already searched. The chance of finding oil anywhere is the same for all players.\n"..
"\n"..
"The oil explorer can always be used to search for oil.\n"..
"\n"..
"\n"..
"\n",
"The oil drill box must be placed in the position indicated by the oil explorer. Drilling for oil elsewhere is pointless.\n"..
"If the button on the oil drilling box is clicked\\, the derrick is erected above the box. This takes a few seconds.\n"..
"The oil drilling box has 4 sides\\, at IN the drill pipe has to be delivered via pusher and at OUT the drilling material has to be removed. The oil drilling box must be supplied with power via one of the other two sides.\n"..
"\n"..
"The oil drilling box drills to the oil field (1 meter in 16 s) and requires 16 ku of electricity.\n"..
"Once the oil field has been reached\\, the derrick can be dismantled and the box removed.\n"..
"\n"..
"\n"..
"\n",
"The oil pump (pump-jack) must now be placed in the place of the oil drilling box. The oil pump also requires electricity (16 ku) and supplies one unit of oil every 8 s. The oil must be collected in a tank. To do this\\, the oil pump must be connected to the tank via yellow pipes.\n"..
"Once all the oil has been pumped out\\, the oil pump can also be removed.\n"..
"\n"..
"\n"..
"\n",
"The drill pipe is required for drilling. As many drill pipe items are required as the depth specified for the oil field. The drill pipe is useless after drilling\\, but it also cannot be dismantled and remains in the ground. However\\, there is a tool to remove the drill pipe blocks (-> Tools -> TA3 drill pipe pliers).\n"..
"\n"..
"\n"..
"\n",
"The oil tank is the large version of the TA3 tank (see liquids -> TA3 tank).\n"..
"\n"..
"The large tank can hold 4000 units of oil\\, but also any other type of liquid.\n"..
"\n"..
"\n"..
"\n",
"",
"Tank carts can be used to transport oil from the oil well to the oil processing plant. A tank cart can be filled or emptied directly using pumps. In both cases\\, the yellow pipes must be connected to the tank cart from above.\n"..
"\n"..
"The following steps are necessary:\n"..
"\n"..
" - Place the tank cart in front of the rail bumper block. The bumper block must not yet be programmed with a time so that the tank cart does not start automatically\n"..
" - Connect the tank cart to the pump using yellow pipes\n"..
" - Switch on the pump\n"..
" - Program the bumper with a time (10 - 20 s)\n"..
"\n"..
"This sequence must be observed on both sides (fill / empty).\n"..
"\n"..
"\n"..
"\n",
"Canisters and barrels can be loaded into the Minecarts. To do this\\, the oil must first be transferred to barrels. The oil barrels can be pushed directly into the Minecart with a pusher and tubes (see map). The empty barrels\\, which come back from the unloading station by Minecart\\, can be unloaded using a hopper\\, which is placed under the rail at the stop.\n"..
"\n"..
"It is not possible with the hopper to both *unload the empty barrels and load the full barrels at a stop*. The hopper immediately unloads the full barrels. It is therefore advisable to set up 2 stations on the loading and unloading side and then program the Minecart accordingly using a recording run.\n"..
"\n"..
"The plan shows how the oil can be pumped into a tank and filled into barrels via a liquid filler and loaded into Minecarts.\n"..
"\n"..
"For the Minecarts to start again automatically\\, the bumper blocks must be configured with the station name and waiting time. 5 s are sufficient for unloading. However\\, since the pushers always go into standby for several seconds when there is no Minecart\\, a time of 15 or more seconds must be entered for loading.\n"..
"\n"..
"\n"..
"\n",
"The tank truck is used to transport liquids. Like tanks\\, it can be filled with pumps or emptied. In both cases\\, the yellow tube must be connected to the tank truck from above.\n"..
"\n"..
"200 units fit in the tank truck.\n"..
"\n"..
"\n"..
"\n",
"The chest cart is used to transport items. Like chests\\, it can be filled or emptied using a pusher.\n"..
"\n"..
"4 stacks fit in the chest cart.\n"..
"\n"..
"\n"..
"\n",
"Oil is a mixture of substances and consists of many components. The oil can be broken down into its main components such as bitumen\\, fuel oil\\, naphtha\\, gasoline and propane gas via a distillation tower.\n"..
"Further processing to end products takes place in the chemical reactor.\n"..
"\n"..
"\n"..
"\n",
"The distillation tower must be set up as in the plan at the top right.\n"..
"The bitumen is drained off via the base block. The exit is on the back of the base block (note the direction of the arrow).\n"..
"The \"distillation tower\" blocks with the numbers: 1\\, 2\\, 3\\, 2\\, 3\\, 2\\, 3\\, 4 are placed on this basic block\n"..
"Fuel oil\\, naphtha and gasoline are drained from the openings from bottom to top. The propane gas is caught at the top.\n"..
"All openings on the tower must be connected to tanks.\n"..
"The reboiler must be connected to the \"distillation tower 1\" block.\n"..
"\n"..
"The reboiler needs electricity (not shown in the plan)!\n"..
"\n"..
"\n"..
"\n",
"The reboiler heats the oil to approx. 400 ° C. It largely evaporates and is fed into the distillation tower for cooling.\n"..
"\n"..
"The reboiler requires 14 units of electricity and produces one unit of bitumen\\, fuel oil\\, naphtha\\, gasoline and propane every 16 s.\n"..
"To do this\\, the reboiler must be supplied with oil via a pump.\n"..
"\n"..
"\n"..
"\n",
"In addition to the tubes for goods transport\\, as well as the gas and power pipes\\, there is also a wireless communication level through which blocks can exchange data with each other. No lines have to be drawn for this\\, the connection between transmitter and receiver is only made via the block number. \n"..
"\n"..
"*Info:* A block number is a unique number that is generated by Techage when many Techage blocks are placed. The block number is used for addressing during communication between Techage controllers and machines. All blocks that can participate in this communication show the block number as info text if you fix the block with the mouse cursor.\n"..
"\n"..
"Which commands a block supports can be read out and displayed with the TechAge Info Tool (wrench).\n"..
"The simplest commands supported by almost all blocks are:\n"..
"\n"..
" - 'on' - to turn on block / machine / lamp\n"..
" - 'off' - to turn off the block / machine / lamp\n"..
"\n"..
"With the help of the TA3 Terminal\\, these commands can be tried out very easily. Suppose a signal lamp is number 123.\n"..
"Then with:\n"..
"\n"..
" cmd 123 on\n"..
"\n"..
"the lamp can be turned on and with:\n"..
"\n"..
" cmd 123 off\n"..
"\n"..
"the lamp can be turned off again. These commands must be entered in the input field of the TA3 terminal.\n"..
"\n"..
"Commands such as 'on' and'off' are sent to the recipient without a response coming back. These commands can therefore be sent to several receivers at the same time\\, for example with a push button / switch\\, if several numbers are entered in the input field.\n"..
"\n"..
"A command like 'state' requests the status of a block. The block then sends its status back. This type of confirmed command can only be sent to one recipient at a time.\n"..
"This command can also be tested with the TA3 terminal on a pusher\\, for example:\n"..
"\n"..
" cmd 123 state\n"..
"\n"..
"Possible responses from the pusher are:\n"..
"\n"..
" - 'running' -> I'm working\n"..
" - 'stopped' -> switched off\n"..
" - 'standby' -> nothing to do because source inventory is empty\n"..
" - 'blocked' -> can't do anything because target inventory is full\n"..
"\n"..
"This status and other information is also output when the wrench is clicked on the block.\n"..
"\n"..
"\n"..
"\n",
"The button/switch sends 'on' / 'off' commands to the blocks that have been configured via the numbers.\n"..
"The button/switch can be configured as a button or a switch. If it is configured as a button\\, the time between the 'on' and 'off' commands can be set. With the operating mode \"on button\" only an 'on' and no 'off' command is sent.\n"..
"\n"..
"The checkbox \"public\" can be used to set whether the button can be used by everyone (set) or only by the owner himself (not set).\n"..
"\n"..
"Note: With the programmer\\, block numbers can be easily collected and configured.\n"..
"\n"..
"\n"..
"\n",
"With the TA3 command converter\\, 'on' / 'off' commands can be converted into other commands\\, and forwarding can be prevented or delayed.\n"..
"The number of the target block or the numbers of the target blocks\\, the commands to be sent and the delay times in seconds must be entered. If no command is entered\\, nothing is sent.\n"..
"\n"..
"The numbers can also be programmed using the Techage programmer.\n"..
"\n"..
"\n"..
"\n",
"The TA3 flip-flop changes its state with each received 'on' command. Received 'off' commands are ignored. Depending on the status change\\, 'on' / 'off' commands are sent alternately. The number of the target block or the numbers of the target blocks must be entered. The numbers can also be programmed using the Techage programmer.\n"..
"\n"..
"For example\\, lamps can be switched on and off with the help of buttons.\n"..
"\n"..
"\n"..
"\n",
"The TA3 logic block can be programmed in such a way that one or more input commands are linked to one output command and sent. This block can therefore replace various logic elements such as AND\\, OR\\, NOT\\, XOR etc. \n"..
"Input commands for the logic block are 'on' /'off' commands.\n"..
"Input commands are referenced via the number\\, e.g. '1234' for the command from the sender with the number 1234. \n"..
"The same applies to output commands.\n"..
"\n"..
"A rule is structured as follows: \n"..
"\n"..
" <output> = on/off if <input-expression> is true\n"..
"\n"..
"'<output>' is the block number to which the command should be sent.\n"..
"'<input-expression>' is a boolean expression where input numbers are evaluated.\n"..
"\n"..
"*Examples for the input expression*\n"..
"\n"..
"Negate signal (NOT):\n"..
"\n"..
" 1234 == off\n"..
"\n"..
"Logical AND:\n"..
"\n"..
" 1234 == on and 2345 == on\n"..
"\n"..
"Logical OR:\n"..
"\n"..
" 1234 == on or 2345 == on\n"..
"\n"..
"The following operators are allowed: 'and' 'or' 'on' 'off' 'me' '==' '~=' '(' ')'\n"..
"\n"..
"If the expression is true\\, a command is sent to the block with the '<output>' number. \n"..
"Up to four rules can be defined\\, whereby all rules are always checked when a command is received. \n"..
"The internal processing time for all commands is 100 ms. \n"..
"\n"..
"Your own node number can be referenced using the keyword 'me'. This makes it possible for the block to send itself a command (flip-flop function). \n"..
"\n"..
"The blocking time defines a pause after a command\\, during which the logic block does not accept any further external commands. Commands received during the blocking period are thus discarded. The blocking time can be defined in seconds. \n"..
"\n"..
"\n"..
"\n",
"The repeater sends the received signal to all configured numbers.\n"..
"This can make sense\\, for example\\, if you want to control many blocks at the same time. The repeater can be configured with the programmer\\, which is not possible with all blocks.\n"..
"\n"..
"\n"..
"\n",
"The sequencer can send a series of 'on' / 'off' commands\\, whereby the interval between the commands must be specified in seconds. You can use it to make a lamp blink\\, for example.\n"..
"Up to 8 commands can be configured\\, each with target block number and pending the next command.\n"..
"The sequencer repeats the commands endlessly when \"Run endless\" is set.\n"..
"If nothing is selected\\, only the specified time in seconds is waited for.\n"..
"\n"..
"\n"..
"\n",
"The timer can send commands time-controlled. The time\\, the target number(s) and the command itself can be specified for each command line. This means that lamps can be switched on in the evening and switched off again in the morning.\n"..
"\n"..
"\n"..
"\n",
"The terminal is primarily used to test the command interface of other blocks (see \"Logic / switching blocks\").\n"..
"You can also assign commands to keys and use the terminal productively.\n"..
"\n"..
" set <button-num> <button-text> <command>\n"..
"\n"..
"With 'set 1 ON cmd 123 on'\\, for example\\, user key 1 can be programmed with the command 'cmd 123 on'. If the key is pressed\\, the command is sent and the response is output on the screen.\n"..
"\n"..
"The terminal has the following local commands:\n"..
"\n"..
" - 'clear' clear screen\n"..
" - 'help' output a help page\n"..
" - 'pub' switch to public mode\n"..
" - 'priv' switch to private mode\n"..
"\n"..
"In private mode\\, the terminal can only be used by players who can build at this location\\, i.e. who have protection rights.\n"..
"\n"..
"In public mode\\, all players can use the preconfigured keys.\n"..
"\n"..
"\n"..
"\n",
"The signal lamp can be switched on or off with the 'on' / 'off' command. This lamp does not need electricity and can be colored with the airbrush tool from the mod Unified Dyes\" and via Lua/Beduino commands.\n"..
"\n"..
"With the chat command '/ta_color' the color palette with the values for the Lua/Beduino commands is displayed and with '/ta_send color <num>' the color can be changed.\n"..
"\n"..
"\n"..
"\n",
"With these blocks you can realize doors and gates that can be opened via commands (blocks disappear) and closed again. One door controller is required for each gate or door.\n"..
"\n"..
"The appearance of the blocks can be adjusted via the block menu.\n"..
"This makes it possible to realize secret doors that only open for certain players (with the help of the player detector).\n"..
"\n"..
"\n"..
"\n",
"The door controller is used to control the TA3 door/gate blocks. With the door controller\\, the numbers of the door/gate blocks must be entered. If an 'on' / 'off' command is sent to the door controller\\, this opens/closes the door or gate.\n"..
"\n"..
"\n"..
"\n",
"The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II\\, the \"Record\" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the \"Done\" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the \"Remove\" or \"Set\" buttons. If an 'on' /'off' command is sent to the Door Controller II\\, it removes or sets the blocks as well.\n"..
"\n"..
"With '$send_cmnd(node_number\\, \"exchange\"\\, 2)' individual blocks can be set\\, removed or replaced by other blocks from the inventory. \n"..
"\n"..
"With '$send_cmnd(node_number\\, \"set\"\\, 2)' a block from the inventory can be set explicitly\\, as long as the inventory slot is not empty.\n"..
"\n"..
"A block can be removed again with '$send_cmnd(node_number\\, \"dig\"\\, 2)' if the inventory slot is empty. \n"..
"\n"..
"The name of the set block is returned with '$send_cmnd(node_number\\, \"get\"\\, 2)'.\n"..
"\n"..
"The slot number of the inventory (1 .. 16) must be passed as payload in all three cases.\n"..
"\n"..
"This can also be used to simulate extendable stairs and the like. \n"..
"\n"..
"\n"..
"\n",
"Different sounds can be played with the sound block. All sounds of the Mods Techage\\, Signs Bot\\, Hyperloop\\, Unified Inventory\\, TA4 Jetpack and Minetest Game are available.\n"..
"\n"..
"The sounds can be selected and played via the menu and via command.\n"..
"\n"..
" - Command 'on' to play a sound\n"..
" - Command 'sound <idx>' to select a sound via the index\n"..
" - Command 'gain <volume>' to adjust the volume via the '<volume>' value (1 to 5).\n"..
"\n"..
"\n"..
"\n",
"The Mesecons converter is used to convert Techage on/off commands into Mesecons signals and vice versa.\n"..
"To do this\\, one or more node numbers must be entered and the converter with Mesecons blocks\n"..
"has to be connected via Mesecons cables. The Mesecons converter can also be configured with the programmer.\n"..
"The Mesecons converter accepts up to 5 commands per second\\; it switches itself off at higher loads.\n"..
"\n"..
"*This node only exists if the mod mesecons is active!*\n"..
"\n"..
"\n"..
"\n",
"Detectors scan their surroundings and send an 'on' command when the search is recognized.\n"..
"\n"..
"\n"..
"\n",
"The detector is a special tube block that detects when items are passed on through the tube. To do this\\, it must be connected to tubes on both sides. If items are pushed into the detector with a pusher\\, they are automatically passed on.\n"..
"It sends an 'on' when an item is recognized\\, followed by an 'off' a second later.\n"..
"Then further commands are blocked for 8 seconds.\n"..
"The waiting time and the items that should trigger a command can be configured using the open-ended wrench menu. \n"..
"\n"..
"\n"..
"\n",
"The cart detector sends an 'on' command if it has recognized a cart (Minecart) directly in front of it. In addition\\, the detector can also restart the cart when an 'on' command is received.\n"..
"\n"..
"The detector can also be programmed with its own number. In this case\\, he pushes all the wagons that stop near him (one block in all directions).\n"..
"\n"..
"\n"..
"\n",
"The node detector sends an 'on' command if it detects that nodes (blocks) appear or disappear in front of it\\, but must be configured accordingly. After switching the detector back to the standard state (gray block)\\, an 'off' command is sent. Valid blocks are all types of blocks and plants\\, but not animals or players. The sensor range is 3 blocks / meter in the direction of the arrow.\n"..
"\n"..
"\n"..
"\n",
"The player detector sends an 'on' command if it detects a player within 4 m of the block. If the player leaves the area again\\, an 'off' command is sent.\n"..
"If the search should be limited to specific players\\, these player names can also be entered.\n"..
"\n"..
"\n"..
"\n",
"The light detector sends an 'on' command if the light level of the block above exceeds a certain level\\, which can be set through the right-click menu.\n"..
"If you have a TA4 Lua Controller\\, you can get the exact light level with $get_cmd(num\\, 'light_level')\n"..
"\n"..
"\n"..
"\n",
"TA3 has the same machines as TA2\\, only these are more powerful and require electricity instead of axis drive.\n"..
"Therefore\\, only the different technical data are given below.\n"..
"\n"..
"\n"..
"\n",
"The function corresponds to that of TA2.\n"..
"The processing power is 6 items every 2 s.\n"..
"\n"..
"\n"..
"\n",
"The function of the TA3 distributor corresponds to that of TA2.\n"..
"The processing power is 12 items every 4 s.\n"..
"\n"..
"\n"..
"\n",
"The function corresponds to that of TA2.\n"..
"The processing power is 2 items every 4 s. The autocrafter requires 6 ku of electricity.\n"..
"\n"..
"\n"..
"\n",
"The function corresponds to that of TA2\\, only TA4 WLAN chips are produced here.\n"..
"The processing power is one chip every 6 s. The block requires 12 ku of electricity for this.\n"..
"\n"..
"\n"..
"\n",
"The function corresponds to that of TA2.\n"..
"The maximum depth is 40 meters. The quarry requires 12 ku of electricity.\n"..
"\n"..
"\n"..
"\n",
"The function corresponds to that of TA2.\n"..
"The processing power is 2 items every 4 s. The block requires 4 ku of electricity.\n"..
"\n"..
"\n"..
"\n",
"The function corresponds to that of TA2.\n"..
"The probability is also the same as for TA2. The block also requires 3 ku of electricity.\n"..
"But in contrast to TA2\\, the status of the TA3 block can be read (controller)\n"..
"\n"..
"\n"..
"\n",
"The function corresponds to that of TA2.\n"..
"The processing power is 2 items every 4 s. The block requires 6 ku of electricity.\n"..
"\n"..
"\n"..
"\n",
"The injector is a TA3 pusher with special properties. It has a menu for configuration. Up to 8 items can be configured here. He only takes these items from a chest to pass them on to machines with recipes (autocrafter\\, industrial furnace and electronic fab).\n"..
"\n"..
"When passing on\\, only one position in the inventory is used in the target machine. If\\, for example\\, only the first three entries are configured in the injector\\, only the first three storage locations in the machine's inventory are used. So that an overflow in the machine inventory is prevented.\n"..
"\n"..
"The injector can also be switched to \"pull mode\". Then he only pulls items out of the chest from the positions that are defined in the configuration of the injector. In this case\\, item type and position must match. This allows to empty specific inventory entries of a chest. \n"..
"\n"..
"The processing power is up to 8 times one item every 4 seconds.\n"..
"\n"..
"\n"..
"\n",
"",
"The Techage Info Tool (open-ended wrench) has several functions. It shows the time\\, position\\, temperature and biome when an unknown block is clicked on.\n"..
"If you click on a TechAge block with command interface\\, all available data will be shown (see also \"Logic / switching blocks\").\n"..
"\n"..
"With Shift + right click an extended menu can be opened for some blocks. Depending on the block\\, further data can be called up or special settings can be made here. In the case of a generator\\, for example\\, the charging curve/switch-off can be programmed. \n"..
"\n"..
"\n"..
"\n",
"With the programmer\\, block numbers can be collected from several blocks with a right click and written into a block like a button / switch with a left click.\n"..
"If you click in the air\\, the internal memory is deleted.\n"..
"\n"..
"\n"..
"\n",
"The trowel is used for plastering power cables. See also \"TA power cable\".\n"..
"\n"..
"\n"..
"\n",
"This tool can be used to remove the drill pipe blocks if\\, for example\\, a tunnel is to pass through there.\n"..
"\n"..
"\n"..
"\n",
"The Techage Screwdriver serves as a replacement for the normal screwdriver. It has the following functions:\n"..
"\n"..
" - Left click: turn the block to the left\n"..
" - Right click: turn the visible side of the block upwards\n"..
" - Shift + left click: save the alignment of the clicked block\n"..
" - Shift + right click: apply the saved alignment to the clicked block\n"..
"\n"..
" \n"..
"\n",
"The TechAge Assembly Tool is used to remove and reposition Techage blocks without these blocks losing their block number or being assigned a new number when setting. This is helpful\\, for example\\, for quarries\\, as they often have to be moved.\n"..
"\n"..
" - Left button: Remove a block\n"..
" - Right button: Set a block\n"..
"\n"..
"The block that was previously removed with the assembly tool and is to be placed again must be on the far left of the player inventory.\n"..
"\n"..
"\n"..
"\n",
},
images = {
"techage_ta3",
"",
"ta3_firebox",
"ta3_oilbox",
"ta3_boiler",
"ta3_turbine",
"ta3_generator",
"ta3_cooler",
"ta3_powerswitch",
"power_reduction",
"ta3_powercable",
"ta3_powerjunction",
"ta3_powerline",
"ta3_powerpole",
"ta3_powerpole4",
"ta3_powerpole2",
"ta3_powerswitch",
"ta3_powerswitchsmall",
"ta3_powerswitchbox",
"ta3_tinygenerator",
"ta3_akkublock",
"ta3_powerterminal",
"ta3_motor",
"",
"ta3_furnacefirebox",
"ta3_furnace",
"ta3_booster",
"",
"ta3_tank",
"ta3_pump",
"ta3_filler",
"ta3_pipe",
"ta3_pipe_wall_entry",
"ta3_valve",
"techage_ta3",
"ta3_oilexplorer",
"ta3_drillbox",
"ta3_pumpjack",
"ta3_drillbit",
"oiltank",
"",
"",
"",
"",
"",
"techage_ta31",
"",
"reboiler",
"ta3_logic",
"ta3_button",
"ta3_command_converter",
"ta3_flipflop",
"ta3_logic",
"ta3_repeater",
"ta3_sequencer",
"ta3_timer",
"ta3_terminal",
"ta3_colorlamp",
"ta3_doorblock",
"ta3_doorcontroller",
"ta3_doorcontroller",
"ta3_soundblock",
"ta3_mesecons_converter",
"ta3_nodedetector",
"ta3_detector",
"ta3_cartdetector",
"ta3_nodedetector",
"ta3_playerdetector",
"ta3_lightdetector",
"ta3_grinder",
"ta3_pusher",
"ta3_distributor",
"ta3_autocrafter",
"ta3_electronicfab",
"ta3_quarry",
"ta3_gravelsieve",
"ta3_gravelrinser",
"ta3_grinder",
"ta3_injector",
"",
"ta3_end_wrench",
"ta3_programmer",
"ta3_trowel",
"ta3_drill_pipe_wrench",
"ta3_screwdriver",
"techage:assembly_tool",
},
plans = {
"",
"coalpowerstation",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"ta3_furnace",
"",
"",
"",
"ta3_tank",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"ta3_loading",
"",
"",
"",
"ta3_distiller",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
}
}

Some files were not shown because too many files have changed in this diff Show More