From b86fd8cfa9dadcc359b95cdc1135488beae0f467 Mon Sep 17 00:00:00 2001 From: Ombridride Date: Sat, 29 Nov 2014 15:40:55 +0100 Subject: [PATCH] merge server with github --- mods/bobblocks/blocks.lua | 844 ++++++++++++++++++ mods/bobblocks/depends.txt | 2 + mods/bobblocks/health.lua | 95 ++ mods/bobblocks/health.lua~ | 95 ++ mods/bobblocks/init.lua | 8 + mods/bobblocks/init.lua~ | 11 + mods/bobblocks/readme.txt | 53 ++ .../bobblocks/sounds/bobblocks_glassblock.ogg | Bin 0 -> 15029 bytes mods/bobblocks/sounds/bobblocks_health.ogg | Bin 0 -> 8811 bytes mods/bobblocks/sounds/bobblocks_trap_fall.ogg | Bin 0 -> 12025 bytes .../sounds/bobblocks_trap_fall_major.ogg | Bin 0 -> 23782 bytes .../textures/bobblocks_blueblock.png | Bin 0 -> 3193 bytes mods/bobblocks/textures/bobblocks_btm.png | Bin 0 -> 3193 bytes .../textures/bobblocks_btm_sides.png | Bin 0 -> 3193 bytes .../textures/bobblocks_greenblock.png | Bin 0 -> 3193 bytes .../textures/bobblocks_greyblock.png | Bin 0 -> 3193 bytes .../textures/bobblocks_health_off.png | Bin 0 -> 3193 bytes .../textures/bobblocks_health_on.png | Bin 0 -> 3193 bytes .../textures/bobblocks_health_one_sides.png | Bin 0 -> 3193 bytes .../textures/bobblocks_indigoblock.png | Bin 0 -> 3193 bytes .../textures/bobblocks_invbluepole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_invgreenpole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_invgreypole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_invindigopole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_invorangepole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_invredpole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_invvioletpole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_invwhitepole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_invyellowpole.png | Bin 0 -> 3211 bytes .../textures/bobblocks_majorspike.png | Bin 0 -> 3190 bytes .../textures/bobblocks_minorspike.png | Bin 0 -> 3190 bytes .../textures/bobblocks_orangeblock.png | Bin 0 -> 3193 bytes .../bobblocks/textures/bobblocks_redblock.png | Bin 0 -> 3193 bytes .../textures/bobblocks_redblock_off.png | Bin 0 -> 3193 bytes .../bobblocks/textures/bobblocks_trap_set.png | Bin 0 -> 3211 bytes .../textures/bobblocks_violetblock.png | Bin 0 -> 3193 bytes .../textures/bobblocks_whiteblock.png | Bin 0 -> 3193 bytes .../textures/bobblocks_yellowblock.png | Bin 0 -> 3193 bytes mods/bobblocks/trap.lua | 183 ++++ mods/maptools/init.lua | 15 +- mods/mesecons/mesecons/actionqueue.lua | 20 +- mods/mesecons/mesecons/init.lua | 48 +- mods/mesecons/mesecons/internal.lua | 554 ++++++------ mods/mesecons/mesecons/legacy.lua | 55 +- mods/mesecons/mesecons/presets.lua | 8 +- mods/mesecons/mesecons/services.lua | 47 +- mods/mesecons/mesecons/settings.lua | 22 +- .../textures/jeija_mesecon_crossing_off.png | Bin 341 -> 0 bytes .../textures/jeija_mesecon_crossing_on.png | Bin 340 -> 0 bytes .../textures/jeija_mesecon_curved_off.png | Bin 307 -> 0 bytes .../textures/jeija_mesecon_curved_on.png | Bin 307 -> 0 bytes .../textures/jeija_mesecon_inverter_off.png | Bin 743 -> 0 bytes .../textures/jeija_mesecon_inverter_on.png | Bin 725 -> 0 bytes .../mesecons/textures/jeija_mesecon_on.png | Bin 196 -> 0 bytes .../mesecons/textures/jeija_mesecon_plug.png | Bin 713 -> 0 bytes .../textures/jeija_mesecon_socket_off.png | Bin 751 -> 0 bytes .../textures/jeija_mesecon_socket_on.png | Bin 737 -> 0 bytes .../textures/jeija_mesecon_t_junction_off.png | Bin 330 -> 0 bytes .../textures/jeija_mesecon_t_junction_on.png | Bin 319 -> 0 bytes ..._mesecon_off.png => mesecons_wire_inv.png} | Bin ...res_full_off.png => mesecons_wire_off.png} | Bin ...wires_full_on.png => mesecons_wire_on.png} | Bin .../mesecons/textures/wires_bump_off.png | Bin 347 -> 0 bytes .../mesecons/textures/wires_bump_on.png | Bin 386 -> 0 bytes mods/mesecons/mesecons/textures/wires_inv.png | Bin 167 -> 0 bytes mods/mesecons/mesecons/textures/wires_off.png | Bin 454 -> 0 bytes mods/mesecons/mesecons/textures/wires_on.png | Bin 492 -> 0 bytes .../mesecons/textures/wires_vertical_off.png | Bin 373 -> 0 bytes .../mesecons/textures/wires_vertical_on.png | Bin 396 -> 0 bytes mods/mesecons/mesecons/util.lua | 104 ++- mods/mesecons/mesecons/wires.lua | 470 +++++----- mods/mesecons/mesecons_blinkyplant/init.lua | 133 +-- mods/mesecons/mesecons_button/init.lua | 4 +- mods/mesecons/mesecons_compatibility/init.lua | 24 + mods/mesecons/mesecons_delayer/init.lua | 4 +- mods/mesecons/mesecons_detector/init.lua | 16 +- mods/mesecons/mesecons_extrawires/corner.lua | 2 +- .../mesecons/mesecons_extrawires/mesewire.lua | 7 +- .../mesecons_extrawires/tjunction.lua | 2 +- .../mesecons/mesecons_extrawires/vertical.lua | 152 ++-- mods/mesecons/mesecons_gates/init.lua | 8 +- mods/mesecons/mesecons_hydroturbine/init.lua | 4 +- mods/mesecons/mesecons_insulated/init.lua | 8 +- mods/mesecons/mesecons_lightstone/init.lua | 14 +- mods/mesecons/mesecons_luacontroller/init.lua | 30 +- .../mesecons_microcontroller/init.lua | 82 +- mods/mesecons/mesecons_movestones/init.lua | 47 +- mods/mesecons/mesecons_mvps/init.lua | 61 +- mods/mesecons/mesecons_noteblock/init.lua | 1 - mods/mesecons/mesecons_pistons/init.lua | 58 +- .../mesecons/mesecons_pressureplates/init.lua | 89 +- mods/mesecons/mesecons_random/init.lua | 2 +- mods/mesecons/mesecons_receiver/init.lua | 65 +- mods/mesecons/mesecons_solarpanel/init.lua | 4 +- mods/mesecons/mesecons_switch/init.lua | 44 +- mods/mesecons/mesecons_torch/init.lua | 18 +- mods/mesecons/mesecons_walllever/init.lua | 66 +- mods/pipeworks/.gitignore | 1 + mods/pipeworks/LICENSE | 17 + mods/pipeworks/README | 22 + mods/pipeworks/autocrafter.lua | 184 ++++ mods/pipeworks/autoplace_pipes.lua | 200 +++++ mods/pipeworks/autoplace_tubes.lua | 130 +++ mods/pipeworks/changelog.txt | 93 ++ mods/pipeworks/common.lua | 146 +++ mods/pipeworks/compat.lua | 130 +++ mods/pipeworks/crafts.lua | 321 +++++++ mods/pipeworks/default_settings.txt | 19 + mods/pipeworks/depends.txt | 3 + mods/pipeworks/devices.lua | 702 +++++++++++++++ mods/pipeworks/flowing_logic.lua | 121 +++ mods/pipeworks/init.lua | 130 +++ mods/pipeworks/item_transport.lua | 487 ++++++++++ mods/pipeworks/legacy.lua | 60 ++ mods/pipeworks/luaentity.lua | 334 +++++++ mods/pipeworks/models.lua | 202 +++++ mods/pipeworks/pipes.lua | 226 +++++ mods/pipeworks/teleport_tube.lua | 181 ++++ .../textures/homedecor_oil_extract.png | Bin 0 -> 383 bytes .../pipeworks/textures/homedecor_paraffin.png | Bin 0 -> 600 bytes .../textures/homedecor_plastic_sheeting.png | Bin 0 -> 380 bytes .../pipeworks_accelerator_tube_end.png | Bin 0 -> 1272 bytes .../pipeworks_accelerator_tube_inv.png | Bin 0 -> 721 bytes .../pipeworks_accelerator_tube_noctr.png | Bin 0 -> 1063 bytes .../pipeworks_accelerator_tube_plain.png | Bin 0 -> 1240 bytes .../pipeworks_accelerator_tube_short.png | Bin 0 -> 690 bytes .../textures/pipeworks_autocrafter.png | Bin 0 -> 163 bytes mods/pipeworks/textures/pipeworks_black.png | Bin 0 -> 100 bytes mods/pipeworks/textures/pipeworks_blue.png | Bin 0 -> 100 bytes .../textures/pipeworks_conductor_tube_end.png | Bin 0 -> 2805 bytes .../textures/pipeworks_conductor_tube_inv.png | Bin 0 -> 2067 bytes .../pipeworks_conductor_tube_noctr.png | Bin 0 -> 2133 bytes .../pipeworks_conductor_tube_on_end.png | Bin 0 -> 2778 bytes .../pipeworks_conductor_tube_on_noctr.png | Bin 0 -> 2113 bytes .../pipeworks_conductor_tube_on_plain.png | Bin 0 -> 2657 bytes .../pipeworks_conductor_tube_plain.png | Bin 0 -> 2596 bytes .../pipeworks_conductor_tube_short.png | Bin 0 -> 1192 bytes .../textures/pipeworks_crossing_tube_end.png | Bin 0 -> 1438 bytes .../textures/pipeworks_crossing_tube_inv.png | Bin 0 -> 1263 bytes .../pipeworks_crossing_tube_noctr.png | Bin 0 -> 1236 bytes .../pipeworks_crossing_tube_plain.png | Bin 0 -> 1718 bytes .../pipeworks_crossing_tube_short.png | Bin 0 -> 755 bytes .../textures/pipeworks_deployer_back.png | Bin 0 -> 512 bytes .../textures/pipeworks_deployer_bottom.png | Bin 0 -> 819 bytes .../textures/pipeworks_deployer_front_off.png | Bin 0 -> 685 bytes .../textures/pipeworks_deployer_front_on.png | Bin 0 -> 560 bytes .../textures/pipeworks_deployer_side.png | Bin 0 -> 841 bytes .../textures/pipeworks_deployer_side1.png | Bin 0 -> 841 bytes .../textures/pipeworks_deployer_side2.png | Bin 0 -> 841 bytes .../textures/pipeworks_deployer_top.png | Bin 0 -> 819 bytes .../textures/pipeworks_detector_tube_end.png | Bin 0 -> 1393 bytes .../textures/pipeworks_detector_tube_inv.png | Bin 0 -> 853 bytes .../pipeworks_detector_tube_noctr.png | Bin 0 -> 1169 bytes .../pipeworks_detector_tube_plain.png | Bin 0 -> 1586 bytes .../pipeworks_detector_tube_short.png | Bin 0 -> 760 bytes .../textures/pipeworks_dispenser_back.png | Bin 0 -> 2031 bytes .../textures/pipeworks_dispenser_bottom.png | Bin 0 -> 4508 bytes .../pipeworks_dispenser_front_off.png | Bin 0 -> 4722 bytes .../textures/pipeworks_dispenser_front_on.png | Bin 0 -> 4676 bytes .../textures/pipeworks_dispenser_side1.png | Bin 0 -> 4519 bytes .../textures/pipeworks_dispenser_side2.png | Bin 0 -> 4518 bytes .../textures/pipeworks_dispenser_top.png | Bin 0 -> 4501 bytes .../textures/pipeworks_filter_input.png | Bin 0 -> 210 bytes .../textures/pipeworks_filter_output.png | Bin 0 -> 193 bytes .../textures/pipeworks_filter_side.png | Bin 0 -> 212 bytes .../textures/pipeworks_filter_top.png | Bin 0 -> 212 bytes .../textures/pipeworks_fountainhead_top.png | Bin 0 -> 1814 bytes .../textures/pipeworks_grating_sides.png | Bin 0 -> 4498 bytes .../textures/pipeworks_grating_top.png | Bin 0 -> 4452 bytes mods/pipeworks/textures/pipeworks_green.png | Bin 0 -> 100 bytes .../textures/pipeworks_mese_filter_input.png | Bin 0 -> 210 bytes .../textures/pipeworks_mese_filter_output.png | Bin 0 -> 193 bytes .../textures/pipeworks_mese_filter_side.png | Bin 0 -> 212 bytes .../textures/pipeworks_mese_filter_top.png | Bin 0 -> 212 bytes .../textures/pipeworks_mese_sand_tube_end.png | Bin 0 -> 1191 bytes .../textures/pipeworks_mese_sand_tube_inv.png | Bin 0 -> 699 bytes .../pipeworks_mese_sand_tube_noctr.png | Bin 0 -> 983 bytes .../pipeworks_mese_sand_tube_plain.png | Bin 0 -> 2464 bytes .../pipeworks_mese_sand_tube_short.png | Bin 0 -> 628 bytes .../textures/pipeworks_mese_tube_end.png | Bin 0 -> 1272 bytes .../textures/pipeworks_mese_tube_inv.png | Bin 0 -> 721 bytes .../textures/pipeworks_mese_tube_noctr_1.png | Bin 0 -> 1131 bytes .../textures/pipeworks_mese_tube_noctr_2.png | Bin 0 -> 1136 bytes .../textures/pipeworks_mese_tube_noctr_3.png | Bin 0 -> 1135 bytes .../textures/pipeworks_mese_tube_noctr_4.png | Bin 0 -> 1136 bytes .../textures/pipeworks_mese_tube_noctr_5.png | Bin 0 -> 1136 bytes .../textures/pipeworks_mese_tube_noctr_6.png | Bin 0 -> 1136 bytes .../textures/pipeworks_mese_tube_plain_1.png | Bin 0 -> 1314 bytes .../textures/pipeworks_mese_tube_plain_2.png | Bin 0 -> 1319 bytes .../textures/pipeworks_mese_tube_plain_3.png | Bin 0 -> 1320 bytes .../textures/pipeworks_mese_tube_plain_4.png | Bin 0 -> 1314 bytes .../textures/pipeworks_mese_tube_plain_5.png | Bin 0 -> 1314 bytes .../textures/pipeworks_mese_tube_plain_6.png | Bin 0 -> 1320 bytes .../textures/pipeworks_mese_tube_short.png | Bin 0 -> 690 bytes .../textures/pipeworks_nodebreaker_back.png | Bin 0 -> 651 bytes .../pipeworks_nodebreaker_bottom_off.png | Bin 0 -> 657 bytes .../pipeworks_nodebreaker_bottom_on.png | Bin 0 -> 660 bytes .../pipeworks_nodebreaker_front_off.png | Bin 0 -> 607 bytes .../pipeworks_nodebreaker_front_on.png | Bin 0 -> 563 bytes .../pipeworks_nodebreaker_side1_off.png | Bin 0 -> 598 bytes .../pipeworks_nodebreaker_side1_on.png | Bin 0 -> 608 bytes .../pipeworks_nodebreaker_side2_off.png | Bin 0 -> 601 bytes .../pipeworks_nodebreaker_side2_on.png | Bin 0 -> 610 bytes .../pipeworks_nodebreaker_top_off.png | Bin 0 -> 656 bytes .../textures/pipeworks_nodebreaker_top_on.png | Bin 0 -> 659 bytes .../textures/pipeworks_one_way_tube_input.png | Bin 0 -> 839 bytes .../pipeworks_one_way_tube_output.png | Bin 0 -> 839 bytes .../textures/pipeworks_one_way_tube_side.png | Bin 0 -> 1665 bytes .../textures/pipeworks_one_way_tube_top.png | Bin 0 -> 1704 bytes .../pipeworks/textures/pipeworks_pipe_end.png | Bin 0 -> 388 bytes .../textures/pipeworks_pipe_end_empty.png | Bin 0 -> 374 bytes .../textures/pipeworks_pipe_end_loaded.png | Bin 0 -> 427 bytes .../pipeworks/textures/pipeworks_pipe_inv.png | Bin 0 -> 1610 bytes mods/pipeworks/textures/pipeworks_plain.png | Bin 0 -> 330 bytes .../textures/pipeworks_plastic_sheeting.png | Bin 0 -> 169 bytes .../textures/pipeworks_pump_bottom.png | Bin 0 -> 4498 bytes .../pipeworks/textures/pipeworks_pump_off.png | Bin 0 -> 3621 bytes mods/pipeworks/textures/pipeworks_pump_on.png | Bin 0 -> 3867 bytes .../textures/pipeworks_pump_sides.png | Bin 0 -> 3742 bytes .../pipeworks/textures/pipeworks_pump_top.png | Bin 0 -> 4504 bytes mods/pipeworks/textures/pipeworks_red.png | Bin 0 -> 100 bytes .../textures/pipeworks_sand_tube_end.png | Bin 0 -> 1201 bytes .../textures/pipeworks_sand_tube_inv.png | Bin 0 -> 693 bytes .../textures/pipeworks_sand_tube_noctr.png | Bin 0 -> 1004 bytes .../textures/pipeworks_sand_tube_plain.png | Bin 0 -> 1176 bytes .../textures/pipeworks_sand_tube_short.png | Bin 0 -> 638 bytes .../textures/pipeworks_sensor_sides_on.png | Bin 0 -> 293 bytes .../textures/pipeworks_spigot_bottom2.png | Bin 0 -> 2444 bytes .../textures/pipeworks_spigot_sides.png | Bin 0 -> 229 bytes .../textures/pipeworks_spigot_sides2.png | Bin 0 -> 226 bytes .../textures/pipeworks_storage_tank_back.png | Bin 0 -> 558 bytes .../pipeworks_storage_tank_fittings.png | Bin 0 -> 602 bytes .../pipeworks_storage_tank_front_0.png | Bin 0 -> 3791 bytes .../pipeworks_storage_tank_front_1.png | Bin 0 -> 739 bytes .../pipeworks_storage_tank_front_10.png | Bin 0 -> 669 bytes .../pipeworks_storage_tank_front_2.png | Bin 0 -> 727 bytes .../pipeworks_storage_tank_front_3.png | Bin 0 -> 716 bytes .../pipeworks_storage_tank_front_4.png | Bin 0 -> 718 bytes .../pipeworks_storage_tank_front_5.png | Bin 0 -> 704 bytes .../pipeworks_storage_tank_front_6.png | Bin 0 -> 691 bytes .../pipeworks_storage_tank_front_7.png | Bin 0 -> 691 bytes .../pipeworks_storage_tank_front_8.png | Bin 0 -> 692 bytes .../pipeworks_storage_tank_front_9.png | Bin 0 -> 670 bytes .../textures/pipeworks_teleport_tube_end.png | Bin 0 -> 1737 bytes .../textures/pipeworks_teleport_tube_inv.png | Bin 0 -> 903 bytes .../pipeworks_teleport_tube_noctr.png | Bin 0 -> 1487 bytes .../pipeworks_teleport_tube_plain.png | Bin 0 -> 1716 bytes .../pipeworks_teleport_tube_short.png | Bin 0 -> 990 bytes .../textures/pipeworks_testobject.png | Bin 0 -> 4083 bytes .../textures/pipeworks_trashcan_bottom.png | Bin 0 -> 186 bytes .../textures/pipeworks_trashcan_side.png | Bin 0 -> 100 bytes .../pipeworks_tube_connection_metallic.png | Bin 0 -> 164 bytes .../pipeworks_tube_connection_stony.png | Bin 0 -> 189 bytes .../pipeworks_tube_connection_wooden.png | Bin 0 -> 180 bytes .../pipeworks/textures/pipeworks_tube_end.png | Bin 0 -> 1393 bytes .../pipeworks/textures/pipeworks_tube_inv.png | Bin 0 -> 752 bytes .../textures/pipeworks_tube_noctr.png | Bin 0 -> 1169 bytes .../textures/pipeworks_tube_plain.png | Bin 0 -> 1362 bytes .../textures/pipeworks_tube_short.png | Bin 0 -> 760 bytes .../textures/pipeworks_tube_transparent.png | Bin 0 -> 112 bytes .../textures/pipeworks_valvebody_bottom.png | Bin 0 -> 2914 bytes .../textures/pipeworks_valvebody_ends.png | Bin 0 -> 3562 bytes .../textures/pipeworks_valvebody_sides.png | Bin 0 -> 3756 bytes .../textures/pipeworks_valvebody_top_off.png | Bin 0 -> 3538 bytes .../textures/pipeworks_valvebody_top_on.png | Bin 0 -> 3539 bytes mods/pipeworks/textures/pipeworks_white.png | Bin 0 -> 100 bytes .../textures/pipeworks_windowed_empty.png | Bin 0 -> 388 bytes .../textures/pipeworks_windowed_loaded.png | Bin 0 -> 427 bytes mods/pipeworks/textures/pipeworks_yellow.png | Bin 0 -> 100 bytes mods/pipeworks/trashcan.lua | 49 + mods/pipeworks/tubes.lua | 594 ++++++++++++ mods/pipeworks/wielder.lua | 423 +++++++++ mods/plantlife_modpack/mushroom/crafting.lua | 2 +- mods/sprint/README.md | 17 +- mods/sprint/esprint.lua | 123 +++ mods/sprint/esprint.lua~ | 123 +++ mods/sprint/init.lua | 136 +-- mods/sprint/wsprint.lua | 121 +++ mods/u_skins/u_skins/init.lua | 5 +- 279 files changed, 7543 insertions(+), 1338 deletions(-) create mode 100644 mods/bobblocks/blocks.lua create mode 100644 mods/bobblocks/depends.txt create mode 100644 mods/bobblocks/health.lua create mode 100644 mods/bobblocks/health.lua~ create mode 100644 mods/bobblocks/init.lua create mode 100644 mods/bobblocks/init.lua~ create mode 100644 mods/bobblocks/readme.txt create mode 100644 mods/bobblocks/sounds/bobblocks_glassblock.ogg create mode 100644 mods/bobblocks/sounds/bobblocks_health.ogg create mode 100644 mods/bobblocks/sounds/bobblocks_trap_fall.ogg create mode 100644 mods/bobblocks/sounds/bobblocks_trap_fall_major.ogg create mode 100644 mods/bobblocks/textures/bobblocks_blueblock.png create mode 100644 mods/bobblocks/textures/bobblocks_btm.png create mode 100644 mods/bobblocks/textures/bobblocks_btm_sides.png create mode 100644 mods/bobblocks/textures/bobblocks_greenblock.png create mode 100644 mods/bobblocks/textures/bobblocks_greyblock.png create mode 100644 mods/bobblocks/textures/bobblocks_health_off.png create mode 100644 mods/bobblocks/textures/bobblocks_health_on.png create mode 100644 mods/bobblocks/textures/bobblocks_health_one_sides.png create mode 100644 mods/bobblocks/textures/bobblocks_indigoblock.png create mode 100644 mods/bobblocks/textures/bobblocks_invbluepole.png create mode 100644 mods/bobblocks/textures/bobblocks_invgreenpole.png create mode 100644 mods/bobblocks/textures/bobblocks_invgreypole.png create mode 100644 mods/bobblocks/textures/bobblocks_invindigopole.png create mode 100644 mods/bobblocks/textures/bobblocks_invorangepole.png create mode 100644 mods/bobblocks/textures/bobblocks_invredpole.png create mode 100644 mods/bobblocks/textures/bobblocks_invvioletpole.png create mode 100644 mods/bobblocks/textures/bobblocks_invwhitepole.png create mode 100644 mods/bobblocks/textures/bobblocks_invyellowpole.png create mode 100644 mods/bobblocks/textures/bobblocks_majorspike.png create mode 100644 mods/bobblocks/textures/bobblocks_minorspike.png create mode 100644 mods/bobblocks/textures/bobblocks_orangeblock.png create mode 100644 mods/bobblocks/textures/bobblocks_redblock.png create mode 100644 mods/bobblocks/textures/bobblocks_redblock_off.png create mode 100644 mods/bobblocks/textures/bobblocks_trap_set.png create mode 100644 mods/bobblocks/textures/bobblocks_violetblock.png create mode 100644 mods/bobblocks/textures/bobblocks_whiteblock.png create mode 100644 mods/bobblocks/textures/bobblocks_yellowblock.png create mode 100644 mods/bobblocks/trap.lua delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_crossing_off.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_crossing_on.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_curved_off.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_curved_on.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_inverter_off.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_inverter_on.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_on.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_plug.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_socket_off.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_socket_on.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_t_junction_off.png delete mode 100644 mods/mesecons/mesecons/textures/jeija_mesecon_t_junction_on.png rename mods/mesecons/mesecons/textures/{jeija_mesecon_off.png => mesecons_wire_inv.png} (100%) rename mods/mesecons/mesecons/textures/{wires_full_off.png => mesecons_wire_off.png} (100%) rename mods/mesecons/mesecons/textures/{wires_full_on.png => mesecons_wire_on.png} (100%) delete mode 100644 mods/mesecons/mesecons/textures/wires_bump_off.png delete mode 100644 mods/mesecons/mesecons/textures/wires_bump_on.png delete mode 100644 mods/mesecons/mesecons/textures/wires_inv.png delete mode 100644 mods/mesecons/mesecons/textures/wires_off.png delete mode 100644 mods/mesecons/mesecons/textures/wires_on.png delete mode 100644 mods/mesecons/mesecons/textures/wires_vertical_off.png delete mode 100644 mods/mesecons/mesecons/textures/wires_vertical_on.png create mode 100644 mods/pipeworks/.gitignore create mode 100644 mods/pipeworks/LICENSE create mode 100644 mods/pipeworks/README create mode 100644 mods/pipeworks/autocrafter.lua create mode 100644 mods/pipeworks/autoplace_pipes.lua create mode 100644 mods/pipeworks/autoplace_tubes.lua create mode 100644 mods/pipeworks/changelog.txt create mode 100644 mods/pipeworks/common.lua create mode 100644 mods/pipeworks/compat.lua create mode 100644 mods/pipeworks/crafts.lua create mode 100644 mods/pipeworks/default_settings.txt create mode 100644 mods/pipeworks/depends.txt create mode 100644 mods/pipeworks/devices.lua create mode 100644 mods/pipeworks/flowing_logic.lua create mode 100644 mods/pipeworks/init.lua create mode 100644 mods/pipeworks/item_transport.lua create mode 100644 mods/pipeworks/legacy.lua create mode 100644 mods/pipeworks/luaentity.lua create mode 100644 mods/pipeworks/models.lua create mode 100644 mods/pipeworks/pipes.lua create mode 100644 mods/pipeworks/teleport_tube.lua create mode 100644 mods/pipeworks/textures/homedecor_oil_extract.png create mode 100644 mods/pipeworks/textures/homedecor_paraffin.png create mode 100644 mods/pipeworks/textures/homedecor_plastic_sheeting.png create mode 100644 mods/pipeworks/textures/pipeworks_accelerator_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_accelerator_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_accelerator_tube_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_accelerator_tube_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_accelerator_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_autocrafter.png create mode 100644 mods/pipeworks/textures/pipeworks_black.png create mode 100644 mods/pipeworks/textures/pipeworks_blue.png create mode 100644 mods/pipeworks/textures/pipeworks_conductor_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_conductor_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_conductor_tube_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_conductor_tube_on_end.png create mode 100644 mods/pipeworks/textures/pipeworks_conductor_tube_on_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_conductor_tube_on_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_conductor_tube_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_conductor_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_crossing_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_crossing_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_crossing_tube_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_crossing_tube_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_crossing_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_deployer_back.png create mode 100644 mods/pipeworks/textures/pipeworks_deployer_bottom.png create mode 100644 mods/pipeworks/textures/pipeworks_deployer_front_off.png create mode 100644 mods/pipeworks/textures/pipeworks_deployer_front_on.png create mode 100644 mods/pipeworks/textures/pipeworks_deployer_side.png create mode 100644 mods/pipeworks/textures/pipeworks_deployer_side1.png create mode 100644 mods/pipeworks/textures/pipeworks_deployer_side2.png create mode 100644 mods/pipeworks/textures/pipeworks_deployer_top.png create mode 100644 mods/pipeworks/textures/pipeworks_detector_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_detector_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_detector_tube_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_detector_tube_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_detector_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_dispenser_back.png create mode 100644 mods/pipeworks/textures/pipeworks_dispenser_bottom.png create mode 100644 mods/pipeworks/textures/pipeworks_dispenser_front_off.png create mode 100644 mods/pipeworks/textures/pipeworks_dispenser_front_on.png create mode 100644 mods/pipeworks/textures/pipeworks_dispenser_side1.png create mode 100644 mods/pipeworks/textures/pipeworks_dispenser_side2.png create mode 100644 mods/pipeworks/textures/pipeworks_dispenser_top.png create mode 100644 mods/pipeworks/textures/pipeworks_filter_input.png create mode 100644 mods/pipeworks/textures/pipeworks_filter_output.png create mode 100644 mods/pipeworks/textures/pipeworks_filter_side.png create mode 100644 mods/pipeworks/textures/pipeworks_filter_top.png create mode 100644 mods/pipeworks/textures/pipeworks_fountainhead_top.png create mode 100644 mods/pipeworks/textures/pipeworks_grating_sides.png create mode 100644 mods/pipeworks/textures/pipeworks_grating_top.png create mode 100644 mods/pipeworks/textures/pipeworks_green.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_filter_input.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_filter_output.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_filter_side.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_filter_top.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_sand_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_sand_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_sand_tube_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_sand_tube_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_sand_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_noctr_1.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_noctr_2.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_noctr_3.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_noctr_4.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_noctr_5.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_noctr_6.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_plain_1.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_plain_2.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_plain_3.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_plain_4.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_plain_5.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_plain_6.png create mode 100644 mods/pipeworks/textures/pipeworks_mese_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_back.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_bottom_off.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_bottom_on.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_front_off.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_front_on.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_side1_off.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_side1_on.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_side2_off.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_side2_on.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_top_off.png create mode 100644 mods/pipeworks/textures/pipeworks_nodebreaker_top_on.png create mode 100644 mods/pipeworks/textures/pipeworks_one_way_tube_input.png create mode 100644 mods/pipeworks/textures/pipeworks_one_way_tube_output.png create mode 100644 mods/pipeworks/textures/pipeworks_one_way_tube_side.png create mode 100644 mods/pipeworks/textures/pipeworks_one_way_tube_top.png create mode 100644 mods/pipeworks/textures/pipeworks_pipe_end.png create mode 100644 mods/pipeworks/textures/pipeworks_pipe_end_empty.png create mode 100644 mods/pipeworks/textures/pipeworks_pipe_end_loaded.png create mode 100644 mods/pipeworks/textures/pipeworks_pipe_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_plastic_sheeting.png create mode 100644 mods/pipeworks/textures/pipeworks_pump_bottom.png create mode 100644 mods/pipeworks/textures/pipeworks_pump_off.png create mode 100644 mods/pipeworks/textures/pipeworks_pump_on.png create mode 100644 mods/pipeworks/textures/pipeworks_pump_sides.png create mode 100644 mods/pipeworks/textures/pipeworks_pump_top.png create mode 100644 mods/pipeworks/textures/pipeworks_red.png create mode 100644 mods/pipeworks/textures/pipeworks_sand_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_sand_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_sand_tube_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_sand_tube_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_sand_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_sensor_sides_on.png create mode 100644 mods/pipeworks/textures/pipeworks_spigot_bottom2.png create mode 100644 mods/pipeworks/textures/pipeworks_spigot_sides.png create mode 100644 mods/pipeworks/textures/pipeworks_spigot_sides2.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_back.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_fittings.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_0.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_1.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_10.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_2.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_3.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_4.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_5.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_6.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_7.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_8.png create mode 100644 mods/pipeworks/textures/pipeworks_storage_tank_front_9.png create mode 100644 mods/pipeworks/textures/pipeworks_teleport_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_teleport_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_teleport_tube_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_teleport_tube_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_teleport_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_testobject.png create mode 100644 mods/pipeworks/textures/pipeworks_trashcan_bottom.png create mode 100644 mods/pipeworks/textures/pipeworks_trashcan_side.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_connection_metallic.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_connection_stony.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_connection_wooden.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_end.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_inv.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_noctr.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_plain.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_short.png create mode 100644 mods/pipeworks/textures/pipeworks_tube_transparent.png create mode 100644 mods/pipeworks/textures/pipeworks_valvebody_bottom.png create mode 100644 mods/pipeworks/textures/pipeworks_valvebody_ends.png create mode 100644 mods/pipeworks/textures/pipeworks_valvebody_sides.png create mode 100644 mods/pipeworks/textures/pipeworks_valvebody_top_off.png create mode 100644 mods/pipeworks/textures/pipeworks_valvebody_top_on.png create mode 100644 mods/pipeworks/textures/pipeworks_white.png create mode 100644 mods/pipeworks/textures/pipeworks_windowed_empty.png create mode 100644 mods/pipeworks/textures/pipeworks_windowed_loaded.png create mode 100644 mods/pipeworks/textures/pipeworks_yellow.png create mode 100644 mods/pipeworks/trashcan.lua create mode 100644 mods/pipeworks/tubes.lua create mode 100644 mods/pipeworks/wielder.lua create mode 100644 mods/sprint/esprint.lua create mode 100644 mods/sprint/esprint.lua~ create mode 100644 mods/sprint/wsprint.lua diff --git a/mods/bobblocks/blocks.lua b/mods/bobblocks/blocks.lua new file mode 100644 index 00000000..91310bd6 --- /dev/null +++ b/mods/bobblocks/blocks.lua @@ -0,0 +1,844 @@ +-- BobBlocks mod by RabbiBob +-- State Changes + +local update_bobblock = function (pos, node) + local nodename="" + local param2="" + --Switch Block State + if + -- Start Blocks + node.name == 'bobblocks:redblock_off' then nodename = 'bobblocks:redblock' + elseif node.name == 'bobblocks:redblock' then nodename = 'bobblocks:redblock_off' + elseif node.name == 'bobblocks:orangeblock_off' then nodename = 'bobblocks:orangeblock' + elseif node.name == 'bobblocks:orangeblock' then nodename = 'bobblocks:orangeblock_off' + elseif node.name == 'bobblocks:yellowblock_off' then nodename = 'bobblocks:yellowblock' + elseif node.name == 'bobblocks:yellowblock' then nodename = 'bobblocks:yellowblock_off' + elseif node.name == 'bobblocks:greenblock_off' then nodename = 'bobblocks:greenblock' + elseif node.name == 'bobblocks:greenblock' then nodename = 'bobblocks:greenblock_off' + elseif node.name == 'bobblocks:blueblock_off' then nodename = 'bobblocks:blueblock' + elseif node.name == 'bobblocks:blueblock' then nodename = 'bobblocks:blueblock_off' + elseif node.name == 'bobblocks:indigoblock_off' then nodename = 'bobblocks:indigoblock' + elseif node.name == 'bobblocks:indigoblock' then nodename = 'bobblocks:indigoblock_off' + elseif node.name == 'bobblocks:violetblock_off' then nodename = 'bobblocks:violetblock' + elseif node.name == 'bobblocks:violetblock' then nodename = 'bobblocks:violetblock_off' + elseif node.name == 'bobblocks:whiteblock_off' then nodename = 'bobblocks:whiteblock' + elseif node.name == 'bobblocks:whiteblock' then nodename = 'bobblocks:whiteblock_off' + -- Start Poles + elseif node.name == 'bobblocks:redpole_off' then nodename = 'bobblocks:redpole' + elseif node.name == 'bobblocks:redpole' then nodename = 'bobblocks:redpole_off' + elseif node.name == 'bobblocks:orangepole_off' then nodename = 'bobblocks:orangepole' + elseif node.name == 'bobblocks:orangepole' then nodename = 'bobblocks:orangepole_off' + elseif node.name == 'bobblocks:yellowpole_off' then nodename = 'bobblocks:yellowpole' + elseif node.name == 'bobblocks:yellowpole' then nodename = 'bobblocks:yellowpole_off' + elseif node.name == 'bobblocks:greenpole_off' then nodename = 'bobblocks:greenpole' + elseif node.name == 'bobblocks:greenpole' then nodename = 'bobblocks:greenpole_off' + elseif node.name == 'bobblocks:bluepole_off' then nodename = 'bobblocks:bluepole' + elseif node.name == 'bobblocks:bluepole' then nodename = 'bobblocks:bluepole_off' + elseif node.name == 'bobblocks:indigopole_off' then nodename = 'bobblocks:indigopole' + elseif node.name == 'bobblocks:indigopole' then nodename = 'bobblocks:indigopole_off' + elseif node.name == 'bobblocks:violetpole_off' then nodename = 'bobblocks:violetpole' + elseif node.name == 'bobblocks:violetpole' then nodename = 'bobblocks:violetpole_off' + elseif node.name == 'bobblocks:whitepole_off' then nodename = 'bobblocks:whitepole' + elseif node.name == 'bobblocks:whitepole' then nodename = 'bobblocks:whitepole_off' + end + minetest.env:add_node(pos, {name = nodename}) + minetest.sound_play("bobblocks_glassblock", + {pos = pos, gain = 1.0, max_hear_distance = 32,}) +end + + +-- Punch Blocks +local on_bobblock_punched = function (pos, node, puncher) + if + -- Start Blocks + node.name == 'bobblocks:redblock_off' or node.name == 'bobblocks:redblock' or + node.name == 'bobblocks:orangeblock_off' or node.name == 'bobblocks:orangeblock' or + node.name == 'bobblocks:yellowblock_off' or node.name == 'bobblocks:yellowblock' or + node.name == 'bobblocks:greenblock_off' or node.name == 'bobblocks:greenblock' or + node.name == 'bobblocks:blueblock_off' or node.name == 'bobblocks:blueblock' or + node.name == 'bobblocks:indigoblock_off' or node.name == 'bobblocks:indigoblock' or + node.name == 'bobblocks:violetblock_off' or node.name == 'bobblocks:violetblock' or + node.name == 'bobblocks:whiteblock_off' or node.name == 'bobblocks:whiteblock' or + --Start Poles + node.name == 'bobblocks:redpole_off' or node.name == 'bobblocks:redpole' or + node.name == 'bobblocks:orangepole_off' or node.name == 'bobblocks:orangepole' or + node.name == 'bobblocks:yellowpole_off' or node.name == 'bobblocks:yellowpole' or + node.name == 'bobblocks:greenpole_off' or node.name == 'bobblocks:greenpole' or + node.name == 'bobblocks:bluepole_off' or node.name == 'bobblocks:bluepole' or + node.name == 'bobblocks:indigopole_off' or node.name == 'bobblocks:indigopole' or + node.name == 'bobblocks:violetpole_off' or node.name == 'bobblocks:violetpole' or + node.name == 'bobblocks:whitepole_off' or node.name == 'bobblocks:whitepole' + then + update_bobblock(pos, node) + end +end + +minetest.register_on_punchnode(on_bobblock_punched) + +-- Nodes +-- Misc Node + +minetest.register_node("bobblocks:btm", { + description = "Bobs TransMorgifier v5", + tile_images = {"bobblocks_btm_sides.png", "bobblocks_btm_sides.png", "bobblocks_btm_sides.png", + "bobblocks_btm_sides.png", "bobblocks_btm_sides.png", "bobblocks_btm.png"}, + inventory_image = "bobblocks_btm.png", + paramtype2 = "facedir", + material = minetest.digprop_dirtlike(1.0), + legacy_facedir_simple = true, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + +}) + + +-- Start Block Nodes +minetest.register_node("bobblocks:redblock", { + description = "Red Block", + drawtype = "glasslike", + tile_images = {"bobblocks_redblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_redblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:redblock_off" + }} +}) + +minetest.register_node("bobblocks:redblock_off", { + description = "Red Block", + tile_images = {"bobblocks_redblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:redblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:redblock" + }} + +}) + +minetest.register_node("bobblocks:orangeblock", { + description = "Orange Block", + drawtype = "glasslike", + tile_images = {"bobblocks_orangeblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_orangeblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:orangeblock_off" + }} +}) + +minetest.register_node("bobblocks:orangeblock_off", { + description = "Orange Block", + tile_images = {"bobblocks_orangeblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:orangeblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:orangeblock" + }} + +}) + +minetest.register_node("bobblocks:yellowblock", { + description = "Yellow Block", + drawtype = "glasslike", + tile_images = {"bobblocks_yellowblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_yellowblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:yellowblock_off" + }} +}) + +minetest.register_node("bobblocks:yellowblock_off", { + description = "Yellow Block", + tile_images = {"bobblocks_yellowblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:yellowblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:yellowblock" + }} + +}) + +minetest.register_node("bobblocks:greenblock", { + description = "Green Block", + drawtype = "glasslike", + tile_images = {"bobblocks_greenblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_greenblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:greenblock_off" + }} +}) + +minetest.register_node("bobblocks:greenblock_off", { + description = "Green Block", + tile_images = {"bobblocks_greenblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:greenblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:greenblock" + }} + +}) + + +minetest.register_node("bobblocks:blueblock", { + description = "Blue Block", + drawtype = "glasslike", + tile_images = {"bobblocks_blueblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_blueblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:blueblock_off" + }} +}) + +minetest.register_node("bobblocks:blueblock_off", { + description = "Blue Block", + tile_images = {"bobblocks_blueblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:blueblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:blueblock" + }} + +}) + +minetest.register_node("bobblocks:indigoblock", { + description = "Indigo Block", + drawtype = "glasslike", + tile_images = {"bobblocks_indigoblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_indigoblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:indigoblock_off" + }} +}) + +minetest.register_node("bobblocks:indigoblock_off", { + description = "Indigo Block", + tile_images = {"bobblocks_indigoblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:indigoblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:indigoblock" + }} + +}) + + +minetest.register_node("bobblocks:violetblock", { + description = "Violet Block", + drawtype = "glasslike", + tile_images = {"bobblocks_violetblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_violetblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:violetblock_off" + }} +}) + +minetest.register_node("bobblocks:violetblock_off", { + description = "Violet Block", + tile_images = {"bobblocks_violetblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:violetblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:violetblock" + }} + +}) + +minetest.register_node("bobblocks:whiteblock", { + description = "White Block", + drawtype = "glasslike", + tile_images = {"bobblocks_whiteblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_whiteblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:whiteblock_off" + }} +}) + +minetest.register_node("bobblocks:whiteblock_off", { + description = "White Block", + tile_images = {"bobblocks_whiteblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:whiteblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:whiteblock" + }} + +}) + + +minetest.register_node("bobblocks:greyblock", { + description = "Grey Block", + drawtype = "glasslike", + tile_images = {"bobblocks_greyblock.png"}, + inventory_image = minetest.inventorycube("bobblocks_greyblock.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:greyblock_off" + }} +}) + +minetest.register_node("bobblocks:greyblock_off", { + description = "Grey Block", + tile_images = {"bobblocks_greyblock.png"}, + is_ground_content = true, + alpha = WATER_ALPHA, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:greyblock', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:greyblock" + }} + +}) + + +-- Block Poles +minetest.register_node("bobblocks:redpole", { + description = "Red Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_redblock.png"}, + inventory_image = ("bobblocks_invredpole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:redpole_off" + }} +}) + +minetest.register_node("bobblocks:redpole_off", { + description = "Red Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_redblock.png"}, + inventory_image = ("bobblocks_invredpole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-10, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:redpole', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:redpole" + }} + +}) + +minetest.register_node("bobblocks:orangepole", { + description = "Orange Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_orangeblock.png"}, + inventory_image = ("bobblocks_invorangepole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:orangepole_off" + }} +}) + +minetest.register_node("bobblocks:orangepole_off", { + description = "Orange Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_orangeblock.png"}, + inventory_image = ("bobblocks_invorangepole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-10, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:orangepole', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:orangepole" + }} + +}) + +minetest.register_node("bobblocks:yellowpole", { + description = "Yellow Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_yellowblock.png"}, + inventory_image = ("bobblocks_invyellowpole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:yellowpole_off" + }} +}) + +minetest.register_node("bobblocks:yellowpole_off", { + description = "Yellow Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_yellowblock.png"}, + inventory_image = ("bobblocks_invyellowpole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-10, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:yellowpole', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:yellowpole" + }} + +}) + +minetest.register_node("bobblocks:greenpole", { + description = "Green Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_greenblock.png"}, + inventory_image = ("bobblocks_invgreenpole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:greenpole_off" + }} +}) + +minetest.register_node("bobblocks:greenpole_off", { + description = "Green Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_greenblock.png"}, + inventory_image = ("bobblocks_invgreenpole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-10, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:greenpole', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:greenpole" + }} + +}) + +minetest.register_node("bobblocks:bluepole", { + description = "Blue Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_blueblock.png"}, + inventory_image = ("bobblocks_invbluepole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:bluepole_off" + }} +}) + +minetest.register_node("bobblocks:bluepole_off", { + description = "Blue Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_blueblock.png"}, + inventory_image = ("bobblocks_invbluepole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-10, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:bluepole', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:bluepole" + }} + +}) + +minetest.register_node("bobblocks:indigopole", { + description = "Indigo Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_indigoblock.png"}, + inventory_image = ("bobblocks_invindigopole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:indigopole_off" + }} +}) + +minetest.register_node("bobblocks:indigopole_off", { + description = "Indigo Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_indigoblock.png"}, + inventory_image = ("bobblocks_invindigopole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-10, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:indigopole', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:indigopole" + }} + +}) + +minetest.register_node("bobblocks:violetpole", { + description = "Violet Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_violetblock.png"}, + inventory_image = ("bobblocks_invvioletpole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:violetpole_off" + }} +}) + +minetest.register_node("bobblocks:violetpole_off", { + description = "Violet Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_violetblock.png"}, + inventory_image = ("bobblocks_invvioletpole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-10, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:violetpole', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:violetpole" + }} + +}) + +minetest.register_node("bobblocks:whitepole", { + description = "White Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_whiteblock.png"}, + inventory_image = ("bobblocks_invwhitepole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:whitepole_off" + }} +}) + +minetest.register_node("bobblocks:whitepole_off", { + description = "White Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_whiteblock.png"}, + inventory_image = ("bobblocks_invwhitepole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + light_source = LIGHT_MAX-10, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3,not_in_creative_inventory=1}, + drop = 'bobblocks:whitepole', + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:whitepole" + }} + +}) + +minetest.register_node("bobblocks:greypole", { + description = "Grey Pole", + drawtype = "fencelike", + tile_images = {"bobblocks_greyblock.png"}, + inventory_image = ("bobblocks_invgreypole.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_glass_defaults(), + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + --light_source = LIGHT_MAX-0, +}) + + + +-- Crafts +-- BTM +minetest.register_craft({ + output = 'NodeItem "bobblocks:btm" 1', + recipe = { + {'node "default:glass" 1', 'node "default:torch" 1', 'node "default:leaves" 1', + 'node "default:mese" 1','node "default:rat" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:greyblock" 2', + recipe = { + {'node "default:glass" 1', 'node "default:torch" 1', 'node "default:cobble" 1'}, + }, +}) + +-- Red / Yellow / Blue / White +-- Red / Yellow -> Orange +-- Red / Blue -> Violet +-- Blue / Yellow -> Green +-- Red / Yellow / White -> Indigo + +minetest.register_craft({ + output = 'NodeItem "bobblocks:redblock" 2', + recipe = { + {'node "default:glass" 1', 'node "default:torch" 1', 'node "default:brick" 1'}, + }, +}) +minetest.register_craft({ + output = 'NodeItem "bobblocks:yellowblock" 2', + recipe = { + {'node "default:glass" 1', 'node "default:torch" 1', 'node "default:sand" 1'}, + }, +}) +minetest.register_craft({ + output = 'NodeItem "bobblocks:blueblock" 2', + recipe = { + {'node "default:glass" 1', 'node "default:torch" 1', 'node "default:gravel" 1'}, + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:whiteblock" 2', + recipe = { + {'node "default:glass" 1', 'node "default:torch" 1', 'node "default:dirt" 1'}, + }, +}) + + +minetest.register_craft({ + output = 'NodeItem "bobblocks:orangeblock" 2', + recipe = { + {'node "bobblocks:redblock" 1', 'node "bobblocks:yellowblock" 1'}, + + }, +}) + + +minetest.register_craft({ + output = 'NodeItem "bobblocks:violetblock" 2', + recipe = { + {'node "bobblocks:redblock" 1', 'node "bobblocks:blueblock" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:greenblock" 2', + recipe = { + {'node "bobblocks:blueblock" 1', 'node "bobblocks:yellowblock" 1'}, + + }, +}) + + +minetest.register_craft({ + output = 'NodeItem "bobblocks:indigoblock" 3', + recipe = { + {'node "bobblocks:redblock" 1', 'node "bobblocks:blueblock" 1', 'node "bobblocks:whiteblock" 1'}, + + }, +}) + +-- Poles + +minetest.register_craft({ + output = 'NodeItem "bobblocks:redpole" 1', + recipe = { + {'node "bobblocks:redblock" 1', 'node "default:stick" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:yellowpole" 1', + recipe = { + {'node "bobblocks:yellowblock" 1', 'node "default:stick" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:bluepole" 1', + recipe = { + {'node "bobblocks:blueblock" 1', 'node "default:stick" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:whitepole" 1', + recipe = { + {'node "bobblocks:whiteblock" 1', 'node "default:stick" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:orangepole" 1', + recipe = { + {'node "bobblocks:orangeblock" 1', 'node "default:stick" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:violetpole" 1', + recipe = { + {'node "bobblocks:violetblock" 1', 'node "default:stick" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:greenpole" 1', + recipe = { + {'node "bobblocks:greenblock" 1', 'node "default:stick" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:indigopole" 1', + recipe = { + {'node "bobblocks:indigoblock" 1', 'node "default:stick" 1'}, + + }, +}) + +minetest.register_craft({ + output = 'NodeItem "bobblocks:greypole" 1', + recipe = { + {'node "bobblocks:greyblock" 1', 'node "default:stick" 1'}, + + }, +}) + + +-- MESECON +-- Add jeija to bobblocks\default.txt and paste the below in at the bottom of bobblocks\blocks.lua + diff --git a/mods/bobblocks/depends.txt b/mods/bobblocks/depends.txt new file mode 100644 index 00000000..aca967d6 --- /dev/null +++ b/mods/bobblocks/depends.txt @@ -0,0 +1,2 @@ +default +mesecons diff --git a/mods/bobblocks/health.lua b/mods/bobblocks/health.lua new file mode 100644 index 00000000..419fd113 --- /dev/null +++ b/mods/bobblocks/health.lua @@ -0,0 +1,95 @@ +local is_healthpack = function(node) + if node.name == 'bobblocks:health_off' or node.name == 'health_on' then + return true + end + return false +end + +local update_healthpack = function (pos, node) + local nodename="" + local param2="" + --Switch HealthPack State + if node.name == 'bobblocks:health_off' then + nodename = 'bobblocks:health_on' + elseif node.name == 'bobblocks:health_on' then + nodename = 'bobblocks:health_off' + end + minetest.env:add_node(pos, {name = nodename}) +end + +local toggle_healthpack = function (pos, node) + if not is_healthgate(node) then return end + update_healthpack (pos, node, state) +end + +local on_healthpack_punched = function (pos, node, puncher) + if node.name == 'bobblocks:health_off' or node.name == 'bobblocks:health_on' then + update_healthpack(pos, node) + end +end + +-- Healing Node + +minetest.register_node("bobblocks:health_off", { + description = "Health Pack 1 Off", + tile_images = {"bobblocks_health_off.png"}, + inventory_image = "bobblocks_health_off.png", + paramtype2 = "facedir", + legacy_facedir_simple = true, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + is_ground_content = true, + walkable = false, + climbable = false, + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:health_on" + }} +}) + +minetest.register_node("bobblocks:health_on", { + description = "Health Pack 1 On", + tile_images = {"bobblocks_health_on.png"}, + paramtype2 = "facedir", + legacy_facedir_simple = true, + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + is_ground_content = true, + walkable = false, + climbable = false, + drop = "bobblocks:health_off", + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:health_off" + }} +}) + + +minetest.register_abm( + {nodenames = {"bobblocks:health_on"}, + interval = 1.0, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local objs = minetest.env:get_objects_inside_radius(pos, 1) + for k, obj in pairs(objs) do + minetest.sound_play("bobblocks_health", + {pos = pos, gain = 1.0, max_hear_distance = 32,}) + obj:set_hp(obj:get_hp()+5) -- give 2.5HP + minetest.env:remove_node(pos) -- remove the node after use + end + end, + +}) + +--- Health + +minetest.register_craft({ + output = 'NodeItem "bobblocks:health_off" 1', + recipe = { + {'node "default:dirt" 1', 'node "default:paper" 1', 'node "default:apple" 2'}, + + }, +}) + + +minetest.register_on_punchnode(on_healthpack_punched) + diff --git a/mods/bobblocks/health.lua~ b/mods/bobblocks/health.lua~ new file mode 100644 index 00000000..4d917780 --- /dev/null +++ b/mods/bobblocks/health.lua~ @@ -0,0 +1,95 @@ +local is_healthpack = function(node) + if node.name == 'bobblocks:health_off' or node.name == 'health_on' then + return true + end + return false +end + +local update_healthpack = function (pos, node) + local nodename="" + local param2="" + --Switch HealthPack State + if node.name == 'bobblocks:health_off' then + nodename = 'bobblocks:health_on' + elseif node.name == 'bobblocks:health_on' then + nodename = 'bobblocks:health_off' + end + minetest.env:add_node(pos, {name = nodename}) +end + +local toggle_healthpack = function (pos, node) + if not is_healthgate(node) then return end + update_healthpack (pos, node, state) +end + +local on_healthpack_punched = function (pos, node, puncher) + if node.name == 'bobblocks:health_off' or node.name == 'bobblocks:health_on' then + update_healthpack(pos, node) + end +end + +-- Healing Node + +minetest.register_node("bobblocks:health_off", { + description = "Health Pack 1 Off", + tile_images = {"bobblocks_health_off.png"}, + inventory_image = "bobblocks_health_off.png", + paramtype2 = "facedir", + legacy_facedir_simple = true, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + is_ground_content = true, + walkable = false, + climbable = false, + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "bobblocks:health_on" + }} +}) + +minetest.register_node("bobblocks:health_on", { + description = "Health Pack 1 On", + tile_images = {"bobblocks_health_on.png"}, + paramtype2 = "facedir", + legacy_facedir_simple = true, + light_source = LIGHT_MAX-0, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + is_ground_content = true, + walkable = false, + climbable = false, + drop = "bobblocks:health_off", + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "bobblocks:health_off" + }} +}) + + +minetest.register_abm( + {nodenames = {"bobblocks:health_on"}, + interval = 1.0, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local objs = minetest.env:get_objects_inside_radius(pos, 1) + for k, obj in pairs(objs) do + minetest.sound_play("bobblocks_health", + {pos = pos, gain = 1.0, max_hear_distance = 32,}) + obj:set_hp(obj:get_hp()+3) -- give 3HP + minetest.env:remove_node(pos) -- remove the node after use + end + end, + +}) + +--- Health + +minetest.register_craft({ + output = 'NodeItem "bobblocks:health_off" 1', + recipe = { + {'node "default:dirt" 1', 'node "default:paper" 1', 'node "default:apple" 2'}, + + }, +}) + + +minetest.register_on_punchnode(on_healthpack_punched) + diff --git a/mods/bobblocks/init.lua b/mods/bobblocks/init.lua new file mode 100644 index 00000000..f3a84e6b --- /dev/null +++ b/mods/bobblocks/init.lua @@ -0,0 +1,8 @@ +print("[BobBlocks By minetest@rabbibob.com] Version 0.0.8 loading....") +dofile(minetest.get_modpath("bobblocks") .. "/blocks.lua") +print("[BobBlocks] loaded Blocks") +dofile(minetest.get_modpath("bobblocks") .. "/health.lua") +print("[BobBlocks] loaded Health") +dofile(minetest.get_modpath("bobblocks") .. "/trap.lua") +print("[BobBlocks] loaded Traps") +print("[BobBlocks By minetest@rabbibob.com] Version 0.0.8 loaded!") diff --git a/mods/bobblocks/init.lua~ b/mods/bobblocks/init.lua~ new file mode 100644 index 00000000..3bcf03f4 --- /dev/null +++ b/mods/bobblocks/init.lua~ @@ -0,0 +1,11 @@ +print("[BobBlocks By minetest@rabbibob.com] Version 0.0.8 loading....") +print("[BobBlocks] loading Blocks") +dofile(minetest.get_modpath("bobblocks") .. "/blocks.lua") +print("[BobBlocks] loaded Blocks") +print("[BobBlocks] loading Health") +dofile(minetest.get_modpath("bobblocks") .. "/health.lua") +print("[BobBlocks] loaded Health") +print("[BobBlocks] loading Traps") +dofile(minetest.get_modpath("bobblocks") .. "/trap.lua") +print("[BobBlocks] loaded Traps") +print("[BobBlocks By minetest@rabbibob.com] Version 0.0.8 loaded!") \ No newline at end of file diff --git a/mods/bobblocks/readme.txt b/mods/bobblocks/readme.txt new file mode 100644 index 00000000..947ae5e7 --- /dev/null +++ b/mods/bobblocks/readme.txt @@ -0,0 +1,53 @@ +-- BobBlocks v0.0.8 +-- (Minetest 0.4.5 compatible 20130315) +-- http://forum.minetest.net/viewtopic.php?id=1274 +-------------------------------------------------------------------------- +-------------------------------------------------------------------------- +-- Requirements: Mesecons -- +-- http://forum.minetest.net/viewtopic.php?id=628 -- +-- -- +-- Does not support jeija or older version of Mesecons -- +-- before 1/20/2013 -- +-- http://forum.minetest.net/viewtopic.php?pid=64976#p64976 -- +-------------------------------------------------------------------------- +-------------------------------------------------------------------------- +-- Colored Lit Blocks +---- Default state = Solid lit block +---- Secondary state (punch) = transparent unlit block +---- Mesecons activation [CONDUCTOR] +-- Colored Lit Poles +---- Default state = Solid lit block +---- Secondary state (punch) = unlit block +---- Mesecons activation [CONDUCTOR] +-- Health Kit +---- Default state = health kit inactive +---- Secondary state (punch) = health kit active +10HP when walked through +---- Mesecons activation [CONDUCTOR] +-- Trap +---- Default Grass (walkable off) +---- Spike Minor (1HP per hit) +------ Spikes can be 'set' and activated when walked over +---- Spike Major (100HP per hit) +------ Spikes can be 'set' and activated when walked over + +# [ATTRIBUTION] +# Unless otherwise noted, all graphics & sounds +# created by Rabbi Bob +# Licensed under the GPLv2/later + +# [GRAPHICS] +# minor & major spikes by Death Dealer +# License: WTFPL +# http://minetest.net/forum/viewtopic.php?id=1582 + +# [SOUNDS] +# bobblocks_glass + # Author: Ch0cchi + # http://www.freesound.org/people/Ch0cchi/sounds/15285/ + # Edited by rabbibob +# bobblocks_trap_fall & bobblocks_trap_fall_major + # Author: Rock Savage + # http://www.freesound.org/people/Rock%20Savage/sounds/65924/# + # Edited by rabbibob +# bobblocks_health + # http://hamsterrepublic.com/ohrrpgce/Free_Sound_Effects.html \ No newline at end of file diff --git a/mods/bobblocks/sounds/bobblocks_glassblock.ogg b/mods/bobblocks/sounds/bobblocks_glassblock.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d60859f15018ca00cad94f873940fa1b9ad73b2c GIT binary patch literal 15029 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 literal 0 HcmV?d00001 diff --git a/mods/bobblocks/sounds/bobblocks_health.ogg b/mods/bobblocks/sounds/bobblocks_health.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4a0148bc816ffbae2c4043dc31ae5f641679c929 GIT binary patch literal 8811 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 literal 0 HcmV?d00001 diff --git a/mods/bobblocks/sounds/bobblocks_trap_fall.ogg b/mods/bobblocks/sounds/bobblocks_trap_fall.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a49efb34966fa99747dbbba40fae0b1bfa6907fe GIT binary patch literal 12025 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 D0m^i< literal 0 HcmV?d00001 diff --git a/mods/bobblocks/sounds/bobblocks_trap_fall_major.ogg b/mods/bobblocks/sounds/bobblocks_trap_fall_major.ogg new file mode 100644 index 0000000000000000000000000000000000000000..b6bdea65fdc965ab408b419322c58cf0e7d8289c GIT binary patch literal 23782 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 literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_btm.png b/mods/bobblocks/textures/bobblocks_btm.png new file mode 100644 index 0000000000000000000000000000000000000000..7e14d084028de79606b22319fa2f694d3804b849 GIT binary patch literal 3193 zcmb_e*>4?J89)21ck^`}$4iqYPC}NZElsM@LPQ~yhKEuicz_2){{tjm5D!Qo@qlArzRS$qnK>)p*iJ~xBOIMObMDNX z@ArMb^KCzT>dDX7!l@7;R6Fs+@h`!BXZ7<5T=nGIb8rj3`NUVhg;3P4ei%LT>?A_* z!4tPO^4;e06#8 z>8HMMMu^LctHdJ89SsbP4DzidNGg)$bdG6q$gLnCVXTn@M%5o56w#6@(-RHu82Wm$IY!F@B-pw6|rQ_RxG^1@}mm%_Id05}C>NCehm!|R5`z<#Bw)Epl?Bo7`3=%vlEKq%WV2vVV z8dx`BS``I`13t$nVAj%=K&n#Rq;d;jjhXpC-U!PcE0F*_ohoo9X_ArtkPL?;&9FAN z_1{8a8pRej5NR4x(g#p_g8AK8^UlDo>K>0MQiJtMhNdSUmfpQ71$&$44oHXN7 zZCHC-|BVG0Asmmbt|?KIV1)LC<PLfyXwLY~?TGe{iwP+m_|F(4GxW7{9%@iwXZ#riN8oRvvv3}GxQSBvyY zYJ6O-mjFP$NNgY9Jv;HS&f*|uVzOOZ@612@YoS#AzP)RI`CIw&Ywaw_e)Ga`Zu-i1 ze>`*aVE3obtmL_R{Y>ZND|bDx-$p`TxS0Ip7u(vkY@(H1Jb&%NKNoDK`>V_A>r0j4 zD%C|dFPBr@&zVCWWh#63;=Jqk*tMl(etz)YyXTJ1y?XWibMIYR&j#7C!)LBte%mCk zEMEM>Z(sC$hTnc`_58cbrc9C4re74x>FCBt4sOK(0-HyLOGhX#kTL=HIMp}T^trQ3 z%hy-OCU<`J(b*8!;64C<>78VNT)r9SMC;K76$G(Bbm;f4aKbE1KhNKW-^ysK+L!x9{1z zV{BsX;YS{xX`cMi&pT6-xmHR!#sh&p4@BX}$AW|G>I`Og?%R9lfz;^Mw&wPk)?4S7 zPn~{4(B)M6r{7rEH~Yq+1Hp|o|HYRsrt7DMdDv<VdgcOV^gygpSMPPddJohqv?%sV-#^t!r^-D zo*1a|dyvGpQiT;w4KB`5+0Rz-h(io-#`B#Rw%fqs>eExHnXWAP^FB_A<9dt(zPuB zUg%&@#Jxny4)Us$ODw^fSS_>?GUp|f`;V4`N_S`v0xm->W1~W8xQ0@PMM-o|qS6zi zDh?`&e1n^cC`o+~pq>o9T&@_Wb@a@)s?xyNo>ZaKs%^C>> zBj67OaV0ky{a{pA-hryP!3QkOHGa+R_?Cna=l_Ex$E-~qO&vMR$6-JC*`0Yq8H>`1u8gNgbD z8Y#9}+CW;wD}o+t_E5q47_}Ndg{g3UVrE6 z3JAyh?%i|b;MBP{-*1Pt!LWd%q>$@`#U8XFz-!e@ZI)=bx($G;z2sZI4=z`gY!k_;hx7#2bhb@0@*IcQ}Znyh?Y~Lp)COq!V dFU)`K{I7oY*Z6wXBB2wXd-C}6pZUi3{|&C{yea?y literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_btm_sides.png b/mods/bobblocks/textures/bobblocks_btm_sides.png new file mode 100644 index 0000000000000000000000000000000000000000..0e1ca0d791722120469417c741cb94e09834ca75 GIT binary patch literal 3193 zcmb_eORHp872bQT{Wzyi)vao8(!|>>#7>%!j>ac~r~##oX$MIV2Rc)Kf#5`(DTw$N z#F_I91O*!hBH{xHXfhDf&!iu>?<=>?sq@-z*S>YT?a)S|oyD$G4{EP(ueHDRt@YEF zU;N5!vNd6h%`Uuf{%iF9czzW?Pyg7#FX*lO?hD`i9%I#JesT7*pFhUf^qC9izxeg< zzri1$UR&`GJ#p&!^Uq(ocJ=SC{Vjw*dmi2p@ng?^{D}{rx%k_QVsrD6z3uDYe)+3^ zRqD$1J%|it!ZKhLSP>&I>!2I3AH--d1WxdXsVu^z^pnDCnRsMufY75KM0AX{Bo#mR zk<)M14LKJ(yLVOx+n+gi_OqY=#3!F_0GO=2oI6~2RtC>_JBZ~z@16Q>QVoof{j;iNY)CrFL99CgbSA zMJ1dDtI#N(a{eGBuueFmqpi5rA~Fq0ODCme(p$K*-=98r?$xWWlXF2EK3Hvj;mo=5 z*0s>>sEUh<;e<0qnAmzTwQ6GZ)Tx1Cc2Abr#PNk?o0cs+uh64nY{G)$&U2Tbu|2-q6Y46+&3%1g`nQKG!~L|F`)2>UdSMdC^!|>yLeyY5r$4d z_<+tM5mf}m2y&11OR-P?$pB$Q*GRLk$HO=p7&1N38RQ<0*mU3JuD!nF$=L|LL!%K& z!3!T%9BZw>Q*9puxRvW}4b6>Jv)3C7mX?D=n(+=t|LqGMVE`6obSi2UOy6qZ&D-V} zz&5Vi9-8Z2v)%XrL`T|?74v^I@<#_VnC#eEisS9OGEv zRZ!fn?gB99SwFJ2XH72d_rYABNbd}>XiaY^SXr>DWYdbR_3U9l5+{l0it{Ls0YoMA zqorB=gLrh+?-7O0lQm98 zwPsOA8XgXvVprAxGew zm?nux7NJ+rXjNNP8`&E9Ks#X6`lrIrwWYP8-2{WAWE##4z|u0KRe!e*ioh2RoW;Tc z6N%CmWg1gzinz3)R@m4?%%7O)t-y z;?z)jTT%WQbs}nfigyy02ulu2z_z2G{_UTpn>@K}gvA^dGngomc|B6~%FyA>-WaD2 zh^A|RBEsCtvMEXab9grAx4}r2jpTx~6Urb?Eprq?2E)2rA z(zRk3z+@8Lm1_d7d2C&D9jEG+NJ9oCDkc$ol~$S-TaK)EV$E3cR>_Gw&D7E~1@{PLh0$5Nqjb?^Yssc;wX9umAj)*WSEC&iPXxJ^SfrwqAer(&l7V zHzVB(iUf*!H;o~b*E~y6|1lQVU5E~q$4i+TOD-`?oZ`xT05VrY7R%{W{_w{?xcJ9E zz4EKy39a2~XW`J3NQH#f;SpPVS3JoBV+W_Ne@eH`CUo;<0gzI^raOW)~!a_-XMH!?pi OeEG%muYBoSKl&HM{0fc$ literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_greenblock.png b/mods/bobblocks/textures/bobblocks_greenblock.png new file mode 100644 index 0000000000000000000000000000000000000000..0acebc5df8a225b4e822305fe139889add1f9e37 GIT binary patch literal 3193 zcmbuB&2JTD6vpSBnS19_3W8v*Sfqv0#1PcPjV?67R0K`XAZpzC2e>fN7`M8!I~Q(@ zJGaJ!4MCJ8aYY0ok{AkMK}<+YNC@0J-~OI+W^UUxXWE(fo;l}v&e!|i`|W$D-r6y< zZzhVO9Vbt$p60oz|541nn*Z-79@{=U@$u(Tw0)2ML-fOs^HDT=TB`dwliy`t4g+uU)C@8lT6PBuQR;;iW@M2QU17A>FfQZ;@25eDLb&Pv2krc`bwx zafJ}aF?K0elCXx=m0Fug8?`9grtO49)bch>)AirhUwixY`*-gH9-diz`oNLJaWpyh z&at!S&N_OCb+Hx=R~&;bfrX`gQlda2JQ^)zFWY!_I6J;QzH#;M*_rL>!-o&=-nqN@ z^3tUnm&Uut4!v*0fDit2z#fhmb=+!>jgz^k@(fNJ6BFM=5YhQ;?x00N%6#AIg9p z8*W0W8zzECRrg56+#;K1rOSZOhQpye@oCyR)C$SO!vtBerwMA%WoF@Hq8{{@yAYEv zxLXEoRMk~gR&Cl2vms=pAqzL7g-t{HN-o4*5Is6pXe36W>MD78yI2Ns7>!2hj576Mobv_=I1f6M2$ij;6U~3s-9F6Isqs` z!$o7Fy=UR7I0iIG1|bQ!Xg{|NI`Y;r#pvm?cDVam4{R$bv?wMnd}ucdG~luaNn3C2 zq=bW4C|QtVGz6)Sqiz%y2SHKyI@`(0-i~r0a07iZp3H2UAtG=&7^Jjwh~Ub+o+g|nTmWE$0HjUplVjgD zmW#4UqQrt$k&M8P(lmXPKN@A68Y3zL4ROf=>?A4j0#Ku<;J^R~hCH-4%E7dHPJ}bR#c3t@Ybi>y?DEYV~Xa3Y9F^4OnU%I%NLpzkbY1T z^|;j_ZVsvsP6biuepigP7PhEx^zd1CQ-o^#XgqGl4yV25KZp7l-BbBlO~hpA=%qwr zOHTOutcQud8bN0OIfbZ+M-2$Ei-V2}N`4#A<|!p=LzKdK?A)^VmR6U6ak6J9i}oQi zV1o{sMxIR$k;_J89UnH`8;=@m(@c}lCfc=k*U{&XUi|Cg(*7l^frCJMwXU&dpQ#f7 zS{x3iyCDN8tZ5!Hiteo6;V8rb@O18}xx>#LK5+2B_3y8*oLM0Wu)vM0?x$nmShH}a zK}|VG+IWqQbp7X3h?i%VuT|F;78kN~m}bKaqqQ&B>VK;%=l-<1de!?$aQG?ebYbQ4 z%+SfP&tqZV!u~@GAHMt1`Sa((%r literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_greyblock.png b/mods/bobblocks/textures/bobblocks_greyblock.png new file mode 100644 index 0000000000000000000000000000000000000000..c3728787cb0284dffd88a9010bafac1725eb95b3 GIT binary patch literal 3193 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 literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_health_one_sides.png b/mods/bobblocks/textures/bobblocks_health_one_sides.png new file mode 100644 index 0000000000000000000000000000000000000000..ac24409cf411e3504ffce212bbaf717a95de728f GIT binary patch literal 3193 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WI14-?iy0WWg+Z8+Vb&Z81_mB& zPZ!6Kid&2dJoi5{0u?nhGyqAeg9BgyGWPT5&;MxvAnpeF_WASYzkdCqx(^@*f-ImZ z7`1?4@Qw!2Xb=$$0fGufQ_*M;5exx>3Pw}WXb=$$0fGufQ_;W&5ev`>@87?dmX;>y z7V;E;EZDJQ$Bi2|I5;@SGXkqFplOdDJ;EwQWkKg_c|9*vUo8h2>*?y}vd$@?2>>*N BgZ%&i literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_indigoblock.png b/mods/bobblocks/textures/bobblocks_indigoblock.png new file mode 100644 index 0000000000000000000000000000000000000000..0dbf7fdad22f7bbdbc983e1e63f85f48c428bd72 GIT binary patch literal 3193 zcmbuBO^6*u6otFGt6xuECV$3ECehJMCJ{wZ7j6}lNz51xk{`rP5W%eoB1qhbJC|9A zBH6iCL9z%zvJnvx`~$O)m}~|ifhiuB|?M^4;Iv zzWHmn-O|c^hgT2(aqa3azy92|Ek6H$6h-mG<4>+E@4xu&=B9 zKmWlgx;)Pvzq}~C{d275&Sfk*=9=2*7+I!k7i^lbjmNo*=T00wb$R_V;BL>p-A_OE z%nrBx_|fB+E?fddNQNUcmlugmp#8F<=ts{Hf`W>HRmFE#zyJ29Z?a+Lw(gogxOniT zr(Rsywi5noT{IzN3zaAGB@y}BlJ`7$n0kV&v%k=V6hh{1wYOhC`$pp?`7rm`VO>>o z-uv>NO%}e%k@T>z#K&I-*PtAb6oRxZvIN{szT6w56boT=YZM{a6#)Ydg7nTydJPeE z=Ho0vpumNIJtC$Z+NKRbfGHb`pGW>eXxWG(WkC3Ysw%q@ehNlx3fO+JdaAY!)`%S| zA=!uq5!n`;^6G~Oux*;Au4}0@7?j>q3CoJB8btc4Bn4MeQ4l7Mwk>8j#70z3?WWlJ zAp!)Mo15D*KVRjQ5(pvVJfM+mrIyc2J(?eZCpd#hkK(a}%*g7M7>vN0zpfiRApk4( zP)^)==+syp+DFyoH;p`jh+DgnBW=$R$i+D-)3geXGIppDfh;m7ojMiXz~u^7j2O7I zp88aq(ZDiR1`G(KaaQ1nC`@%#W^BknQgD>0LD#9hgl`N}O6^516Io6gi2$>*EURpQ zn;`>>eH=mUN2(PuQ;2wh7Txk9ZX5EWT>&{|c;+HV@S z9&O3wmjZ^0vC`LE>>_}Z9#wZ|p`J|YsDsPOazI)-Sr$b`gPJTlab2#{BnlC7*mNlr z5d!$KRE{=8z%oaav$@fX@Z}tU+|X1WXJHaS#8yUDEFI}0rz;q=HH)ke4HNX>8qv9$ zL?mHGy0eS@wpIJTOmos7o_49;C#gAlY48K{o3=xilY z^hE}*>rj9q2|a}IcnlAgDqjnEk3^n!K;(>c zB0%yTjueDL~j*OwkxB3OML=_u1+hC?;+|y37pm#NWRdjexD)dl#2ime-EGaQ?zqZn$Ia x!2Sc{dVJ%?4HTcj`R`L?UszbE%IeD1EBT@2N4`9B_I;tP9Xhu9#dEKH@DIVfG;;s| literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_invbluepole.png b/mods/bobblocks/textures/bobblocks_invbluepole.png new file mode 100644 index 0000000000000000000000000000000000000000..e60d3eb09e4a86d398544b0e7bac0102cec1ef43 GIT binary patch literal 3211 zcmb_e&ui2`6rP#PB-!nj+Sc7IMaohU3RWydmLh^b+G2ZXk+ulE75@Mc^x(PR!J{`R z-jsqDj|DH{Nhqb@LJuN{Ei6kBnyuY!lWcyBUlP3tP3EwVY$j|b?|bik-@KWZ4;JtD z=7;lykly*ZnI(*s=w~wA{h_0`81!dLi^~{ck2j517;;bMR-Y2mGZ_6S*?2QVNa5=I z%-xme-)W`rvqj_C88^LGP)c&STo{I!${4e4n^L;6@X)fXt*xz;?|I6*8D#auS`tLTh=Mu2_Z*E%bV}( zcy?Vk9YCo>gT-p;;sPNfmgS*Vt=8{S=||&m`_k}np-`yRYAG1m8Q|l-z6&EGmo;rb z*Bz7|Oh~DN%yQYt%s>es4iKIh=Nj%JGOlSFAzn)C$tyJgO5sk|b;BUw7%BqQl7Q`O zi$tDj2%eCz)A4Y@F_3^IxXAnv6Vx)m5<~Pxk8PX4YBo6%NY+Fqh7y3_95Evg&-38d zwjIOpy9t0W5jbNs2twcYg20cLn-T{~8AOCiU@%PsXOVuuGi6HrDFKjJFep(hP+^+6 zNTv)j%{C=~gi_!4&(3Usg&|4=*WD{o5J<;yId|b2bU>`&8+h6AE6Nl#H%)_59t45s z1&-qg5uj~%4FD2~s|2T@md0xU_32)T(A*GvqEso-HaJwISR$n~|E*ifxiE|zWQruP z^i)cu1OP{|Mmc1PRM0f?`8-pTsS*IZ!(A8#=>EEnB#anQB>}Z&hlPyx0F8oS7@pCv zmE0@J6db@3Eur7JZl}xZAnrmMk1Rw67@(qV$`soTJc8j^I5OTW3HD``Dyj7%g8D>z zy=|YNZJ;BWrYFPh0U%PSGYmWENO+F*%D}3^_+1J?-!BpPU>U7D#myW5A22F{F$a-{Tkc1*_g z>(^FsvOCXp@_%-T>h-$gwV4Q*=={BOpNbX}%~Gk9C@KXbo2zQITKo1DvHy2`2N_;F eKnCr0I|ZQpaqaV!cQ0;4Q|4zEXFl9pTmJ)^<#);e literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_invgreenpole.png b/mods/bobblocks/textures/bobblocks_invgreenpole.png new file mode 100644 index 0000000000000000000000000000000000000000..72b83c70d529abc36e1625e2e3489d1f1e9b9610 GIT binary patch literal 3211 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 literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_invwhitepole.png b/mods/bobblocks/textures/bobblocks_invwhitepole.png new file mode 100644 index 0000000000000000000000000000000000000000..3f3540130d6f7879b4d482af6b5a04f592043ef0 GIT binary patch literal 3211 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 Zv%|gl?A7h;#>UJ3WvSJ4a(nsa!(aDK%98*9 literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_orangeblock.png b/mods/bobblocks/textures/bobblocks_orangeblock.png new file mode 100644 index 0000000000000000000000000000000000000000..40e34f9727284be93689177ee1768dc12f6f10d4 GIT binary patch literal 3193 zcmbuBJ&aUU6vy9vA2ZABBH+5qf^67bR)R5tt&I`0;!+3-5@WQmv9mC-F|jdr(i@F2 zHpa%n#F!96&<10RK(sJ?#7Ln;5~6{fnRnm2{{H9QH!Q8**?I4Nob&&muX|=cc;VP{ zTL-%bS(a@*y1sUT_maL-IZwZE>vLXP-dca;JgLeGea5J972_t`fd%db5l3;}sw<3@305=` zFkP7-5`87I2^|^BLGJqfsjXYfsZd*R0raRN4T;68ur!!m!Z9$kZAe91T5#BfHy#=R zAn?|8?fg)|mTBPTZL4eqdunDXhLdJ#E`9ETG2d@Kaw*ARlC;|6f!rjO!T=IYnWgfG zzDF9_+fk+coJt_!b|NR!NCX%`8p}}1M@FG=TRc-DP$3tf8!D&Zr>OdorRcoqXCB0b5*~jg5^qjH;^VsC1Wb~<|?Wrjhe6kb7ll>ONLvL$|Q`v5(|Dt$?{QE#8f~cIPOFqvI1eQ zjp8H*0&6uYqP(gm__2zt!_cdT<00uS3075kUz^ni9vxsBP0d|ZRHTTyU{H9VqF7ZW z9>eLzy5Ug6V>uv!T>4T0X>gF6UKX?(`5A(5y!wQ7N^D0+wl^Nos@LmDBswOLrlAhQ zc+{k=u1s0#f@sh-%Hrqy8rj!J(5ep542qHn0 zr61m%vVpu>rGiUJX|ct4JQjf{fL3-4R_#;>0^wm;>8U-YmV-<_0x?5FRa7O-VT>5h z;b;W%81P!n%4%0qeDy+>Kl9bxkmK=)rQ3tf)nU8iIIspU@I=WGu|-=>h;t^ zCHFPj;OntMA_?k*>a;;DER}K9#VD=1<)-*>l5#*Mt4gg7PgH6|$1;gG@O21!#|3gs z;&XDUWy-|86C<#mOfT|&!&*B(s!jZLPT-hr{moz#U%~(pAz2X_%?MMAy5>9Am7h#v zqTd6xYnmiaIEcG6lGh13nhYr%X>fv|8smL3oW>C8-x=kWOXlels<}8wFYp{ipv~H5 zvIKS0IEX$VXE!*WihxVBYj*qUqmSRZ@ZI9#GFvnSdVwyhZz>nKgAk-lY)VKnKZYps zch5Ulf2#`D5C(EPKR3Uy_mP$5y&r%0^Qn{jxxv^1LE9)${4<(yF;uXO&Md>0#mZP3 z)_QfX+5G##)lqY4acNJ@|0w;QF4(K@p1$#y|MT31Nnqvsy?`eC4o&Y4x_evmiP74* zd(Xa=J?k&N{LQy#++fGl>dNY<9^Jfolj7M7@t@~}eSUtvU-hqCyK?3Dp>X5En_mj- O=(ESxzIx{M_x}a$`$eDt literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_redblock.png b/mods/bobblocks/textures/bobblocks_redblock.png new file mode 100644 index 0000000000000000000000000000000000000000..096d3f1d77cc07d6fb375e430b3f9007d5a27ccc GIT binary patch literal 3193 zcmbuBPiP%g6vk)XoA)O#FKHwuCMKat8ncnAxDi2wNLm||BDGfBb?3s3;6}IZ%)+(! zXXRcfh>Kvmvmh?iNGp`4rBp!!idgBJc{B6I-*?W;%WG3`;ce#5{d3Ouo%7vu=kxgh91zO}h=_T6jY za`)z)aOv2>$<32{H*fs7`$L}R`27D?uh*Y^;;CaRt2S-!7aZNO02Q7wh}izbt!>2tff$4xz`>GY!K2&#w%7aS+SPDsJe-{A zu63tgT3lI;GGHk%F6%PGurj|rPnT+Z8K2Svb8I=!6& zW-vLT`k`|Wh=83u%hD{1iUJyRASjv1R=dFA;s*#H(@{9ani_$SD?QEI2#}=JZg-=o zm8R~TWf`X4&==8tY=nk160Zwb#&3#Y?CA7<$SU(RO^Y~oYr&C)PB)asJ~bzRhM74E zn;Iw!iQ|hUUqzq|PAyAQvk5s#3`-z9#ZwHO?}PAl8C&t#dx&otutb!Aatkq1fTA&Qhl9ODWoz!a4u0^wL#;wXCx7veC?@X2#_g^Obp zkp#ho6*t!98IXjMs?``!P6Jbk6|4tY=3y!hS8OogRst$L&BlX8gMwNwiUd|)s%|oi z`jq2Oki^o9<4&i;_X9H+ebHs<`(8PqY5&<(TlYW03QB792CO!hBi<1Os#G&a(tsD(P z@W9bTN$h&mv|&vI%qa$;S>UWN_C@ML;$~St;p86hUjj!LhygLhS$)M}1Qjs>fyNA2R=}nrG?e@aA<;D~2YXD)0)w%76_Jkwv9a z-osKZD0RcF4HMGLz}WRvhR_PJ+>{kj*5{|D){h_m?c&9yl@*q}M#+f+B|8kHRhe}e z;X&*patqJeueWaT0pSkf8_mwl&aXYTa`fm&SFW60U*{gVnpq_j&_nbJL2rdw9g_I0 zI<#J^_14zX-QA^y#jMkeTFn;upZ{?CmmvG|r|jz`hdnYEP{-+1qC zSe)8?5EeR5U0AvB>t^?-+dq!SV{HC=i{tq0bLTqGEZz9_Mlv%qd#u`6J@W%Jk{eSJv0>KR5t94%O&Xv-SH%_l5K4 z`~Chf%SL%lpO%9WgDe~7xy$MKrPgc7l+};NX%vxxah~70d2_$j`ny@XyS16@@9+0^ zcHVvK>UY;td~gRZq}} zo6SbMJ?Qlo7Z!*eEbq})mXxOg5a?>PijOSMv+n4&+S@tJ1!Jbnla^ZjlilotKVD3qm znc0g@Iq;EVX>9UhT83g`6@{l#UhL3}d%fO4ujeHU1r5vwf8u3&GKQMX9moXazX(Mu zwrAy**&d{+&W$j+bB05d+ifkB=k5&aX1(#<#wL& zN8ynZBt+~1k%_$DS05jW06L_lQLnqwbi3_v$})vZ5|ac7FrX$R8|XAz1o#t8Bdbok zQv{|6EH@SS;+9I~)3y20)n7;El~;N7h{;?6-(q3UK4vqm)t3vGp%YMr|X^l5=G^(6Al8Lu4|el?V*qnaubS*Uz7xG7lt1}LGZ-{QH5yd&~fSUp}Y&E zM0afO3#lefnJc~)MGgK>h5&JGq3?m~gGeo@R79m{Dk}R5y3QnUP0fDdg#h3Jt~;oa z0R0V%bch=B^MBsEm(I>kcRCoroDEV2g}c%dir4W*KgaeUcUU<_3H#-$;3tRaTaSMD-4749cEk#Bt^&{CL+L1H_IAv z+*+7VTeYNKt9Q+4^B^L1z)ZJb;>IT#IgcXzb`|3@RMb8~a`YJH=-v9tQYmA8NS=$LTVRxho5{?eQ8 F{{wBAm*D^a literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_trap_set.png b/mods/bobblocks/textures/bobblocks_trap_set.png new file mode 100644 index 0000000000000000000000000000000000000000..55d1cf9e862cfca202aceeecee5f0ac9a4160d31 GIT binary patch literal 3211 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={W*h+%@f`K#;L2&6a*JR*x3 z7`TN&n2}-D90>*n9&Jw-$B>F!j0!yWKZ6yI5`!=V3^g^Vv5S4c<*ND@>DR4{OU|>e$lg-stRgn}G5#Zr|@#YO-L(;-RiOffY&BCez z=vg4ZDn+Uw_MEINEgjd6ZMijpZXu`w|*KYR6xJi7_&A||n6Pep{y2CEoN dY(xeWer1I$qCeSX-p&T8@^tlcS?83{1OOF?EWZE% literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_violetblock.png b/mods/bobblocks/textures/bobblocks_violetblock.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a98ca86bb224f99cdf708e021256ce8d54ac9c GIT binary patch literal 3193 zcmb`JONbps6o#w%aeHPm35k=8F_XlZWDq47gBx+-A~NQI8a0aGLU83;q6-(UTnM^w zr5h19?gIhEIH)THMTI;RNyvji6b)n*$2)zyyV~zR)qN)k?zHaQzFk%4{Qo)sIbA(( zKYi@*#;F}s&bf_8k1QSMcV6F#gloP1`p5iCzH;P+SDo81qpx=#e7N1Y>3v6+4nFt# zML$1%^@iWIcka;Aq03jVoIQ7@X&QX~`$*IDf&B;eF6>$UVmX_c+3L&U$p>G2`H9y) zdgo-~!S~)LN#ZjMGhLXm99OyZP9N9uaqapDuEo#e^4;ank34kz&l@WOzia-^d*=?c zf8~b{KK|*c(}v>`3==@0Ns`pA1`7!YFfn65AR2}XT%vuN_{r(wkKvUw7k`-CoM)@6 ztH1ufvVZ5pXTP~n47XUAf>5Norr;Bl%`{g^Nv6F>Kt1{-EI0*{gy!2Hzi#s;tmau% zq$mb{ly2RAhdeRSFbYL)=_q2-Px5>~PDI=UMQzI%=odGUg?8B9U}Aqx1ln>*Ms69X zlElDcgxYJ7*R||Z6XFN92{Z&0aG;~N-sp33u5ls4a zD6Zn_hX|0Rn3&v`aa%>Q5KqcOisYhB`FxC^N zv7f>bhX6PZBBFxScWfpmxv;3N)`q4cU`A69hh-?+d@$hf2?1+8`WzUBs-Wx-bMrMpfl2oH6Ce$n)HcfnrT~4AgWfy$f_lVl^^c zH3w?u0MHN&O&vV^kIW- zwXY3+rIHDv$dydo(Y2F^e07AjD9+igHv)FZif7p%NnMsDHWpZi8!<45L=jr|QMR6= zD{{=ZsnmGXn&iuJ6rIrV0%|%F!b?5*J%{F}Izd;(yF6PK>FQf?6>}@+7 z4y&Q0UcqSij(dXbqphK^g$X1{UK zP<3$eZ=3S9(D`|Ni?R778Bo~dYmbV(*3g3q*GaccUhk(tqo5_WTG@aSJ zZQuR(egEZ8yB2n1!2tk4Q&*7Tje+t&$MHvDOAd{jtMb~l oYtrQZ7$`G4J6q(%r7M@tpLpc03%{JcAl##m9a}p2=u2<@1N7umP5=M^ literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_whiteblock.png b/mods/bobblocks/textures/bobblocks_whiteblock.png new file mode 100644 index 0000000000000000000000000000000000000000..857fa47b6ad81d30b1537946815733fa00c26a10 GIT binary patch literal 3193 zcmbuB%WGX#6vp>?-Fp+0v?ZEHr6r~{83;C02MS7zxvdltQ?Y{hCkP@26bFv9|9}si z2@XXRC$)}rAV}+D;ESXMi&kRm0~>PB+uyhLIXAac-N`*?@3q(Z*0&ye-~0MwryrRd zKRoW7o9wTzKF)hVpI*qbn7i>Vud(OWpL*W8+otsi+}rQWIX7`nfAzs9Hh&5hCa(Mw z965I9+UnZ&mCN6J`*m5C*!=$yMbU|SSB~Aac>coqczXKw1Cs||e&MCr+1X1MzYK!F z1wj~u8c`IZ8%3cB*MyNLiVdST5`5p6NEroG{?VgV6;%ien@u3TQqAinhpg}5Pn8r#y z!;Jh6Pa|2WCe$MeS)mfc==Vq#)27>HU`6|V3}vHp&A3_7Ocr2o00cN32X+Z$jsz4sk9o z@!$ju%2iN@B#g|dkH$uZZKmkHv7zJ! zen_iAj@Z0nZ8&;JB1Eu!W|idDt0JJSsW6~SvMdjrDuKMy>BLE*QVSjs(u3TR=_2*2 zT|#U!(BYm#HhPET3sYzkLb zRzl_A;VBtObAUPANe5(^C=WW$lvJ>#sG`yoA2n^(B@7cHbcu0L7a=S-tgcGa%;ygs zE3yEDZk^AK6AlJ@V`Jll0$(x*D1^C)V3(V*?&pfzDU1^ka9MK|*iAzsYR;3W4O8R^ z5@5GGR;U=&VA&@pDLG+I4G@y?<|h{- zgEx%U5M&7(wn&>;y`xqOoTkWZ(?uLH4x)D{Yr8N2VhiC&^+p5XYoh5M(^0I#S4?{A z7|qYmFD)-!zkXwCY6?pFsilUa7;=+V5+;%=u) z2F^b7^wq0BU;F*HhLc`=1no!rZkBo}3H!q=8tb{axy8E|`~Ch$AAcB(AL<=nJf7z1 s&d!c6z`oIcosssLnVD|V-MYN>%6rRye6Y6tgRuG!pI&|cp=V$H7wMQiQ2+n{ literal 0 HcmV?d00001 diff --git a/mods/bobblocks/textures/bobblocks_yellowblock.png b/mods/bobblocks/textures/bobblocks_yellowblock.png new file mode 100644 index 0000000000000000000000000000000000000000..975ffe8c9f5f376d1fe2e50e1b1f3dbb7a08613e GIT binary patch literal 3193 zcmbuB%a2r55XSGhkM5@D;bWj@a6&Q+ldvFBATco^Q8Xhm8)A$bToA*KgoVb9ZegQt zS*V1#nM7T=F)k!T{sLblM&!BF41qXdx~Fg77r(F0=|;ACdhWgF)~WMV)mK&L&L?l4 zcw?sfTsMlMnYH7qZ}D8x)rq;63-{M~?0E0^$q%AvYEGAnE?!!QqUi%`tFONO;SIMm zefOc;vv2X(>ap8*@BDV{*Q%=6^Z!SZBriOFaNpkL%U3R^b8|aqXEx8C$@cF*_s8`w zT;yEroQvW(Mla!(Cb5Z-GBl4JPBe|(cr;Pn)Q!Ef#*RxDZ=64W@`o!ofBI#o+r2b@ zIS!=taXit^^6!?Qw?o^JlKKoTzmKTXm!O(Ml$qhTiR^}{({BDb~G|McUZ|GEcu zlOknvyUngN%Tned$%rxw3PD1Hfh<^K9aicp(830bT1Yj<>S}W{PqPFtHpu|P@5DDB zBX_h})}={ZH&Nmg3>+f^y)3a%YaMtXWXGbAwhSqvD6$CRILlhCR=cb+BeSt`@_v&* zX{Je%Wf=wtrmC_cumzR%K2;c_5zVr9D+aAs**217oHse4~gw zG9!lVd7w z@a|BWiv>_l06Bo+62z z%hIgV>6oKNNKoJ*blrhd-O8#hj)~{R3&zfn6H7MIMn(ZBs&Y8o9t;K)D6iCsRj1b@ zJOLp0D;S!*E5X!QAcyp-fs6y0V3#NYZIq8FZcRob7C=HyYf$@2Z-m4e0Er}u zGl?RyCay`GKuKpSt9fW4R8bPcKECJqkVZ{Yx-O%rycsYjq^e{oL&`46XnvZxRKzu` z(dBm1#ArKL_<(}}LdJdkz__AlI0NJ$U?Qa|Egs4n5Ya^^H%*B;U7586C089CL=VZW ze3VzE;tK|BX4NhT$2VX&7mlod#jTUBMA=RCkP7yaHb zx`{*(7akdJo}XYqX6Xhyv_ZiV98d|~Pke_H3rbc^*KSN@FZ7(RC7p=A0YV#u)6}IL z6iHfTnLL165(#AmoxgKi9ccEu{E0+XD9_P%tpuoDAY7xH1?}bC}Vj|%P0*V zXT0x8REy(ZBCjP!{Ez_#{A_P;_Xk@(LK;T@4k^igox68S@##fuOV&8BywKi7TcF8n zLaSmD9bBVAEcj!WhrYluSmU7mmS9q~;!DQ_*pnSIZ#KerEks~TIwvR@{^>D9oj?>7 z4oq?outOrjk#{Np{tQ|Ie!LL89Iezu^Yg8}OMCC#-<*4P4+>BNV{{c2rPqWc8v?t> z4vH_&HWNR*0SVpT<^5i7@Xy0xl0<25S8s9gz@dXjKl}W`>C;CD0{`fBY9Cdf2KfWZ z*hhJ3#i#-E}M c`_`RXn;*SDSU$e+Kxk{PpIH6&wRg`w0v>CIwg3PC literal 0 HcmV?d00001 diff --git a/mods/bobblocks/trap.lua b/mods/bobblocks/trap.lua new file mode 100644 index 00000000..0c41ecfe --- /dev/null +++ b/mods/bobblocks/trap.lua @@ -0,0 +1,183 @@ +-- State Changes + +local update_bobtrap = function (pos, node) + local nodename="" + local param2="" + --Switch Trap State + if + -- Swap Traps + node.name == 'bobblocks:trap_spike' then nodename = 'bobblocks:trap_spike_set' + elseif node.name == 'bobblocks:trap_spike_set' then nodename = 'bobblocks:trap_spike' + elseif node.name == 'bobblocks:trap_spike_major' then nodename = 'bobblocks:trap_spike_major_set' + elseif node.name == 'bobblocks:trap_spike_major_set' then nodename = 'bobblocks:trap_spike_major' + end + minetest.env:add_node(pos, {name = nodename}) +end + +-- Punch Traps +local on_bobtrap_punched = function (pos, node, puncher) + if + -- Start Traps + node.name == 'bobblocks:trap_spike' or node.name == 'bobblocks:trap_spike_set' or + node.name == 'bobblocks:trap_spike_major' or node.name == 'bobblocks:trap_spike_major_set' + then + update_bobtrap(pos, node) + end +end + +minetest.register_on_punchnode(on_bobtrap_punched) + + +--ABM (Spring The Traps) + +minetest.register_abm( + {nodenames = {"bobblocks:trap_spike_set"}, + interval = 1.0, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local objs = minetest.env:get_objects_inside_radius(pos, 1) + for k, obj in pairs(objs) do + + update_bobtrap(pos, node) + end + end, + +}) + +minetest.register_abm( + {nodenames = {"bobblocks:trap_spike_major_set"}, + interval = 1.0, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local objs = minetest.env:get_objects_inside_radius(pos, 1) + for k, obj in pairs(objs) do + + update_bobtrap(pos, node) + end + end, + +}) + + + + +-- Nodes +minetest.register_node("bobblocks:trap_grass", { + description = "Trap Grass", + tile_images = {"default_grass.png"}, + paramtype2 = "facedir", + legacy_facedir_simple = true, + groups = {snappy=2,cracky=3,oddly_breakable_by_hand=3}, + is_ground_content = false, + walkable = false, + climbable = false, +}) + +minetest.register_node("bobblocks:trap_spike", { + description = "Trap Spike Minor", + drawtype = "plantlike", + visual_scale = 1, + tile_images = {"bobblocks_minorspike.png"}, + inventory_image = ("bobblocks_minorspike.png"), + paramtype = "light", + walkable = false, + sunlight_propagates = true, + groups = {cracky=3,melty=3}, +}) + +minetest.register_node("bobblocks:trap_spike_set", { + description = "Trap Spike Minor Set", + drawtype = "raillike", + visual_scale = 1, + tile_images = {"bobblocks_trap_set.png"}, + paramtype = "light", + walkable = false, + sunlight_propagates = true, + groups = {cracky=3,melty=3,not_in_creative_inventory=1}, + drop = 'bobblocks:trap_spike', +}) + + +minetest.register_node("bobblocks:trap_spike_major", { + description = "Trap Spike Major", + drawtype = "plantlike", + visual_scale = 1, + tile_images = {"bobblocks_majorspike.png"}, + inventory_image = ("bobblocks_majorspike.png"), + paramtype = "light", + walkable = false, + sunlight_propagates = true, + groups = {cracky=2,melty=2}, +}) + +minetest.register_node("bobblocks:trap_spike_major_set", { + description = "Trap Spike Major Set", + drawtype = "raillike", + visual_scale = 1, + tile_images = {"bobblocks_trap_set.png"}, + paramtype = "light", + walkable = false, + sunlight_propagates = true, + groups = {cracky=3,melty=3,not_in_creative_inventory=1}, + drop = 'bobblocks:trap_spike_major', +}) + + +-- Crafting + +minetest.register_craft({ + output = 'bobblocks:trap_spike', + recipe = { + {'', '', ''}, + {'', 'default:cobble', ''}, + {'default:cobble', 'default:apple', 'default:cobble'}, + } +}) + +minetest.register_craft({ + output = 'bobblocks:trap_spike_major', + recipe = { + {'', 'default:cobble', ''}, + {'', 'default:apple', ''}, + {'default:cobble', 'default:apple', 'default:cobble'}, + } +}) + +minetest.register_craft({ + output = 'bobblocks:trap_grass', + recipe = { + {'', '', ''}, + {'', 'default:dirt', ''}, + {'', 'default:stick', ''}, + } +}) + +-- ABM +minetest.register_abm( + {nodenames = {"bobblocks:trap_spike"}, + interval = 1.0, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local objs = minetest.env:get_objects_inside_radius(pos, 1) + for k, obj in pairs(objs) do + obj:set_hp(obj:get_hp()-1) + minetest.sound_play("bobblocks_trap_fall", + {pos = pos, gain = 1.0, max_hear_distance = 3,}) + end + end, +}) + +minetest.register_abm( + {nodenames = {"bobblocks:trap_spike_major"}, + interval = 1.0, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local objs = minetest.env:get_objects_inside_radius(pos, 1) + for k, obj in pairs(objs) do + obj:set_hp(obj:get_hp()-100) + minetest.sound_play("bobblocks_trap_fall", + {pos = pos, gain = 1.0, max_hear_distance = 3,}) + end + end, + +}) diff --git a/mods/maptools/init.lua b/mods/maptools/init.lua index 712d2d78..0acad937 100644 --- a/mods/maptools/init.lua +++ b/mods/maptools/init.lua @@ -428,23 +428,28 @@ minetest.register_node("maptools:igniter", { minetest.register_node("maptools:superapple", { description = S("Super Apple"), range = 12, - stack_max = 10000, + stack_max = 99, drawtype = "plantlike", visual_scale = 1.0, tiles = {"maptools_superapple.png"}, inventory_image = "maptools_superapple.png", paramtype = "light", sunlight_propagates = true, + walkable = false, selection_box = { type = "fixed", fixed = {-0.2, -0.5, -0.2, 0.2, 0, 0.2} }, - walkable = false, - groups = {fleshy=3, dig_immediate=3, not_in_creative_inventory = 0}, + is_ground_content = true, + groups = {fleshy = 3, dig_immediate = 3, not_in_creative_inventory = 0, flammable = 2, leafdecay = 3, leafdecay_drop = 1}, on_use = minetest.item_eat(20), - sounds = default.node_sound_defaults(), + sounds = default.node_sound_leaves_defaults(), + after_place_node = function(pos, placer, itemstack) + if placer:is_player() then + minetest.set_node(pos, {name = "maptools:superapple", param2= 1}) + end + end, }) - -- Items minetest.register_craftitem("maptools:copper_coin", { diff --git a/mods/mesecons/mesecons/actionqueue.lua b/mods/mesecons/mesecons/actionqueue.lua index a5daf887..fa4079ff 100644 --- a/mods/mesecons/mesecons/actionqueue.lua +++ b/mods/mesecons/mesecons/actionqueue.lua @@ -12,19 +12,19 @@ function mesecon.queue:add_action(pos, func, params, time, overwritecheck, prior -- Create Action Table: time = time or 0 -- time <= 0 --> execute, time > 0 --> wait time until execution priority = priority or 1 - local action = { pos=mesecon:tablecopy(pos), + local action = { pos=mesecon.tablecopy(pos), func=func, - params=mesecon:tablecopy(params), + params=mesecon.tablecopy(params or {}), time=time, - owcheck=(overwritecheck and mesecon:tablecopy(overwritecheck)) or nil, + owcheck=(overwritecheck and mesecon.tablecopy(overwritecheck)) or nil, priority=priority} local toremove = nil -- Otherwise, add the action to the queue if overwritecheck then -- check if old action has to be overwritten / removed: for i, ac in ipairs(mesecon.queue.actions) do - if(mesecon:cmpPos(pos, ac.pos) - and mesecon:cmpAny(overwritecheck, ac.owcheck)) then + if(mesecon.cmpPos(pos, ac.pos) + and mesecon.cmpAny(overwritecheck, ac.owcheck)) then toremove = i break end @@ -44,7 +44,8 @@ end -- However, even that does not work in some cases, that's why we delay the time the globalsteps -- start to be execute by 5 seconds local get_highest_priority = function (actions) - local highestp = -1, highesti + local highestp = -1 + local highesti for i, ac in ipairs(actions) do if ac.priority > highestp then highestp = ac.priority @@ -56,10 +57,13 @@ local get_highest_priority = function (actions) end local m_time = 0 +local resumetime = mesecon.setting("resumetime", 4) minetest.register_globalstep(function (dtime) m_time = m_time + dtime - if (m_time < MESECONS_RESUMETIME) then return end -- don't even try if server has not been running for XY seconds - local actions = mesecon:tablecopy(mesecon.queue.actions) + -- don't even try if server has not been running for XY seconds; resumetime = time to wait + -- after starting the server before processing the ActionQueue, don't set this too low + if (m_time < resumetime) then return end + local actions = mesecon.tablecopy(mesecon.queue.actions) local actions_now={} mesecon.queue.actions = {} diff --git a/mods/mesecons/mesecons/init.lua b/mods/mesecons/mesecons/init.lua index 3132955a..096e509f 100644 --- a/mods/mesecons/mesecons/init.lua +++ b/mods/mesecons/mesecons/init.lua @@ -47,15 +47,14 @@ mesecon.queue.funcs={} -- contains all ActionQueue functions -- Settings dofile(minetest.get_modpath("mesecons").."/settings.lua") --- Presets (eg default rules) -dofile(minetest.get_modpath("mesecons").."/presets.lua"); - - -- Utilities like comparing positions, -- adding positions and rules, -- mostly things that make the source look cleaner dofile(minetest.get_modpath("mesecons").."/util.lua"); +-- Presets (eg default rules) +dofile(minetest.get_modpath("mesecons").."/presets.lua"); + -- The ActionQueue -- Saves all the actions that have to be execute in the future dofile(minetest.get_modpath("mesecons").."/actionqueue.lua"); @@ -67,11 +66,6 @@ dofile(minetest.get_modpath("mesecons").."/actionqueue.lua"); -- like calling action_on/off/change dofile(minetest.get_modpath("mesecons").."/internal.lua"); --- Deprecated stuff --- To be removed in future releases --- Currently there is nothing here -dofile(minetest.get_modpath("mesecons").."/legacy.lua"); - -- API -- these are the only functions you need to remember @@ -79,8 +73,8 @@ mesecon.queue:add_function("receptor_on", function (pos, rules) rules = rules or mesecon.rules.default -- if area (any of the rule targets) is not loaded, keep trying and call this again later - for _, rule in ipairs(mesecon:flattenrules(rules)) do - local np = mesecon:addPosRule(pos, rule) + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, rule) -- if area is not loaded, keep trying if minetest.get_node_or_nil(np) == nil then mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) @@ -89,16 +83,16 @@ mesecon.queue:add_function("receptor_on", function (pos, rules) end -- execute action - for _, rule in ipairs(mesecon:flattenrules(rules)) do - local np = mesecon:addPosRule(pos, rule) - local rulenames = mesecon:rules_link_rule_all(pos, rule) + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, rule) + local rulenames = mesecon.rules_link_rule_all(pos, rule) for _, rulename in ipairs(rulenames) do - mesecon:turnon(np, rulename) + mesecon.turnon(np, rulename) end end end) -function mesecon:receptor_on(pos, rules) +function mesecon.receptor_on(pos, rules) mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) end @@ -106,34 +100,38 @@ mesecon.queue:add_function("receptor_off", function (pos, rules) rules = rules or mesecon.rules.default -- if area (any of the rule targets) is not loaded, keep trying and call this again later - for _, rule in ipairs(mesecon:flattenrules(rules)) do - local np = mesecon:addPosRule(pos, rule) + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, rule) if minetest.get_node_or_nil(np) == nil then mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) return end end - for _, rule in ipairs(mesecon:flattenrules(rules)) do - local np = mesecon:addPosRule(pos, rule) - local rulenames = mesecon:rules_link_rule_all(pos, rule) + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = mesecon.addPosRule(pos, rule) + local rulenames = mesecon.rules_link_rule_all(pos, rule) for _, rulename in ipairs(rulenames) do - if not mesecon:connected_to_receptor(np, mesecon:invertRule(rule)) then - mesecon:turnoff(np, rulename) + if not mesecon.connected_to_receptor(np, mesecon.invertRule(rule)) then + mesecon.turnoff(np, rulename) else - mesecon:changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2) + mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2) end end end end) -function mesecon:receptor_off(pos, rules) +function mesecon.receptor_off(pos, rules) mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) end print("[OK] Mesecons") +-- Deprecated stuff +-- To be removed in future releases +dofile(minetest.get_modpath("mesecons").."/legacy.lua"); + --The actual wires dofile(minetest.get_modpath("mesecons").."/wires.lua"); diff --git a/mods/mesecons/mesecons/internal.lua b/mods/mesecons/mesecons/internal.lua index 6ed8f742..7d598f0b 100644 --- a/mods/mesecons/mesecons/internal.lua +++ b/mods/mesecons/mesecons/internal.lua @@ -1,62 +1,58 @@ -- Internal.lua - The core of mesecons -- --- For more practical developer resources see mesecons.tk +-- For more practical developer resources see http://mesecons.net/developers.php -- -- Function overview --- mesecon:get_effector(nodename) --> Returns the mesecons.effector -specifictation in the nodedef by the nodename --- mesecon:get_receptor(nodename) --> Returns the mesecons.receptor -specifictation in the nodedef by the nodename --- mesecon:get_conductor(nodename) --> Returns the mesecons.conductor-specifictation in the nodedef by the nodename --- mesecon:get_any_inputrules (node) --> Returns the rules of a node if it is a conductor or an effector --- mesecon:get_any_outputrules (node) --> Returns the rules of a node if it is a conductor or a receptor +-- mesecon.get_effector(nodename) --> Returns the mesecons.effector -specifictation in the nodedef by the nodename +-- mesecon.get_receptor(nodename) --> Returns the mesecons.receptor -specifictation in the nodedef by the nodename +-- mesecon.get_conductor(nodename) --> Returns the mesecons.conductor-specifictation in the nodedef by the nodename +-- mesecon.get_any_inputrules (node) --> Returns the rules of a node if it is a conductor or an effector +-- mesecon.get_any_outputrules (node) --> Returns the rules of a node if it is a conductor or a receptor -- RECEPTORS --- mesecon:is_receptor(nodename) --> Returns true if nodename is a receptor --- mesecon:is_receptor_on(nodename) --> Returns true if nodename is an receptor with state = mesecon.state.on --- mesecon:is_receptor_off(nodename) --> Returns true if nodename is an receptor with state = mesecon.state.off --- mesecon:receptor_get_rules(node) --> Returns the rules of the receptor (mesecon.rules.default if none specified) +-- mesecon.is_receptor(nodename) --> Returns true if nodename is a receptor +-- mesecon.is_receptor_on(nodename --> Returns true if nodename is an receptor with state = mesecon.state.on +-- mesecon.is_receptor_off(nodename) --> Returns true if nodename is an receptor with state = mesecon.state.off +-- mesecon.receptor_get_rules(node) --> Returns the rules of the receptor (mesecon.rules.default if none specified) -- EFFECTORS --- mesecon:is_effector(nodename) --> Returns true if nodename is an effector --- mesecon:is_effector_on(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_off --- mesecon:is_effector_off(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_on --- mesecon:effector_get_rules(node) --> Returns the input rules of the effector (mesecon.rules.default if none specified) +-- mesecon.is_effector(nodename) --> Returns true if nodename is an effector +-- mesecon.is_effector_on(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_off +-- mesecon.is_effector_off(nodename) --> Returns true if nodename is an effector with nodedef.mesecons.effector.action_on +-- mesecon.effector_get_rules(node) --> Returns the input rules of the effector (mesecon.rules.default if none specified) -- SIGNALS --- mesecon:activate(pos, node, recdepth) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher recdepths are executed later --- mesecon:deactivate(pos, node, recdepth) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), " --- mesecon:changesignal(pos, node, rulename, newstate) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change), " - --- RULES --- mesecon:add_rules(name, rules) | deprecated? --> Saves rules table by name --- mesecon:get_rules(name, rules) | deprecated? --> Loads rules table with name +-- mesecon.activate(pos, node, depth) --> Activates the effector node at the specific pos (calls nodedef.mesecons.effector.action_on), higher depths are executed later +-- mesecon.deactivate(pos, node, depth) --> Deactivates the effector node at the specific pos (calls nodedef.mesecons.effector.action_off), higher depths are executed later +-- mesecon.changesignal(pos, node, rulename, newstate, depth) --> Changes the effector node at the specific pos (calls nodedef.mesecons.effector.action_change), higher depths are executed later -- CONDUCTORS --- mesecon:is_conductor(nodename) --> Returns true if nodename is a conductor --- mesecon:is_conductor_on(node) --> Returns true if node is a conductor with state = mesecon.state.on --- mesecon:is_conductor_off(node) --> Returns true if node is a conductor with state = mesecon.state.off --- mesecon:get_conductor_on(node_off) --> Returns the onstate nodename of the conductor --- mesecon:get_conductor_off(node_on) --> Returns the offstate nodename of the conductor --- mesecon:conductor_get_rules(node) --> Returns the input+output rules of a conductor (mesecon.rules.default if none specified) +-- mesecon.is_conductor(nodename) --> Returns true if nodename is a conductor +-- mesecon.is_conductor_on(node --> Returns true if node is a conductor with state = mesecon.state.on +-- mesecon.is_conductor_off(node) --> Returns true if node is a conductor with state = mesecon.state.off +-- mesecon.get_conductor_on(node_off) --> Returns the onstate nodename of the conductor +-- mesecon.get_conductor_off(node_on) --> Returns the offstate nodename of the conductor +-- mesecon.conductor_get_rules(node) --> Returns the input+output rules of a conductor (mesecon.rules.default if none specified) -- HIGH-LEVEL Internals --- mesecon:is_power_on(pos) --> Returns true if pos emits power in any way --- mesecon:is_power_off(pos) --> Returns true if pos does not emit power in any way --- mesecon:turnon(pos, rulename) --> Returns true whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnon; Uses third parameter recdepth internally to determine how far away the current node is from the initial pos as it uses recursion --- mesecon:turnoff(pos, rulename) --> Turns off whatever there is at pos. Calls itself for connected nodes (if pos is a conductor) --> recursive, the rulename is the name of the input rule that caused calling turnoff; Uses third parameter recdepth internally to determine how far away the current node is from the initial pos as it uses recursion --- mesecon:connected_to_receptor(pos) --> Returns true if pos is connected to a receptor directly or via conductors; calls itself if pos is a conductor --> recursive --- mesecon:rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect) --- mesecon:rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon:rules_link but also returns true if output and input are swapped --- mesecon:is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor +-- mesecon.is_power_on(pos) --> Returns true if pos emits power in any way +-- mesecon.is_power_off(pos) --> Returns true if pos does not emit power in any way +-- mesecon.turnon(pos, link) --> link is the input rule that caused calling turnon, turns on every connected node, iterative +-- mesecon.turnoff(pos, link) --> link is the input rule that caused calling turnoff, turns off every connected node, iterative +-- mesecon.connected_to_receptor(pos, link) --> Returns true if pos is connected to a receptor directly or via conductors, iterative +-- mesecon.rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect) +-- mesecon.rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon.rules_link but also returns true if output and input are swapped +-- mesecon.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor --- RULES ROTATION helpsers --- mesecon:rotate_rules_right(rules) --- mesecon:rotate_rules_left(rules) --- mesecon:rotate_rules_up(rules) --- mesecon:rotate_rules_down(rules) +-- RULES ROTATION helpers +-- mesecon.rotate_rules_right(rules) +-- mesecon.rotate_rules_left(rules) +-- mesecon.rotate_rules_up(rules) +-- mesecon.rotate_rules_down(rules) -- These functions return rules that have been rotated in the specific direction -- General -function mesecon:get_effector(nodename) +function mesecon.get_effector(nodename) if minetest.registered_nodes[nodename] and minetest.registered_nodes[nodename].mesecons and minetest.registered_nodes[nodename].mesecons.effector then @@ -64,7 +60,7 @@ function mesecon:get_effector(nodename) end end -function mesecon:get_receptor(nodename) +function mesecon.get_receptor(nodename) if minetest.registered_nodes[nodename] and minetest.registered_nodes[nodename].mesecons and minetest.registered_nodes[nodename].mesecons.receptor then @@ -72,7 +68,7 @@ function mesecon:get_receptor(nodename) end end -function mesecon:get_conductor(nodename) +function mesecon.get_conductor(nodename) if minetest.registered_nodes[nodename] and minetest.registered_nodes[nodename].mesecons and minetest.registered_nodes[nodename].mesecons.conductor then @@ -80,52 +76,55 @@ function mesecon:get_conductor(nodename) end end -function mesecon:get_any_outputrules (node) - if mesecon:is_conductor(node.name) then - return mesecon:conductor_get_rules(node) - elseif mesecon:is_receptor(node.name) then - return mesecon:receptor_get_rules(node) +function mesecon.get_any_outputrules (node) + if mesecon.is_conductor(node.name) then + return mesecon.conductor_get_rules(node) + elseif mesecon.is_receptor(node.name) then + return mesecon.receptor_get_rules(node) end - return false end -function mesecon:get_any_inputrules (node) - if mesecon:is_conductor(node.name) then - return mesecon:conductor_get_rules(node) - elseif mesecon:is_effector(node.name) then - return mesecon:effector_get_rules(node) +function mesecon.get_any_inputrules (node) + if mesecon.is_conductor(node.name) then + return mesecon.conductor_get_rules(node) + elseif mesecon.is_effector(node.name) then + return mesecon.effector_get_rules(node) end - return false +end + +function mesecon.get_any_rules (node) + return mesecon.mergetable(mesecon.get_any_inputrules(node) or {}, + mesecon.get_any_outputrules(node) or {}) end -- Receptors -- Nodes that can power mesecons -function mesecon:is_receptor_on(nodename) - local receptor = mesecon:get_receptor(nodename) +function mesecon.is_receptor_on(nodename) + local receptor = mesecon.get_receptor(nodename) if receptor and receptor.state == mesecon.state.on then return true end return false end -function mesecon:is_receptor_off(nodename) - local receptor = mesecon:get_receptor(nodename) +function mesecon.is_receptor_off(nodename) + local receptor = mesecon.get_receptor(nodename) if receptor and receptor.state == mesecon.state.off then return true end return false end -function mesecon:is_receptor(nodename) - local receptor = mesecon:get_receptor(nodename) +function mesecon.is_receptor(nodename) + local receptor = mesecon.get_receptor(nodename) if receptor then return true end return false end -function mesecon:receptor_get_rules(node) - local receptor = mesecon:get_receptor(node.name) +function mesecon.receptor_get_rules(node) + local receptor = mesecon.get_receptor(node.name) if receptor then local rules = receptor.rules if type(rules) == 'function' then @@ -140,32 +139,32 @@ end -- Effectors -- Nodes that can be powered by mesecons -function mesecon:is_effector_on(nodename) - local effector = mesecon:get_effector(nodename) +function mesecon.is_effector_on(nodename) + local effector = mesecon.get_effector(nodename) if effector and effector.action_off then return true end return false end -function mesecon:is_effector_off(nodename) - local effector = mesecon:get_effector(nodename) +function mesecon.is_effector_off(nodename) + local effector = mesecon.get_effector(nodename) if effector and effector.action_on then return true end return false end -function mesecon:is_effector(nodename) - local effector = mesecon:get_effector(nodename) +function mesecon.is_effector(nodename) + local effector = mesecon.get_effector(nodename) if effector then return true end return false end -function mesecon:effector_get_rules(node) - local effector = mesecon:get_effector(node.name) +function mesecon.effector_get_rules(node) + local effector = mesecon.get_effector(node.name) if effector then local rules = effector.rules if type(rules) == 'function' then @@ -183,159 +182,147 @@ end -- Activation: mesecon.queue:add_function("activate", function (pos, rulename) - node = minetest.get_node(pos) - effector = mesecon:get_effector(node.name) + local node = minetest.get_node(pos) + local effector = mesecon.get_effector(node.name) if effector and effector.action_on then effector.action_on(pos, node, rulename) end end) -function mesecon:activate(pos, node, rulename, recdepth) +function mesecon.activate(pos, node, rulename, depth) if rulename == nil then - for _,rule in ipairs(mesecon:effector_get_rules(node)) do - mesecon:activate(pos, node, rule, recdepth + 1) + for _,rule in ipairs(mesecon.effector_get_rules(node)) do + mesecon.activate(pos, node, rule, depth + 1) end return end - mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / recdepth) + mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / depth) end -- Deactivation mesecon.queue:add_function("deactivate", function (pos, rulename) - node = minetest.get_node(pos) - effector = mesecon:get_effector(node.name) + local node = minetest.get_node(pos) + local effector = mesecon.get_effector(node.name) if effector and effector.action_off then effector.action_off(pos, node, rulename) end end) -function mesecon:deactivate(pos, node, rulename, recdepth) +function mesecon.deactivate(pos, node, rulename, depth) if rulename == nil then - for _,rule in ipairs(mesecon:effector_get_rules(node)) do - mesecon:deactivate(pos, node, rule, recdepth + 1) + for _,rule in ipairs(mesecon.effector_get_rules(node)) do + mesecon.deactivate(pos, node, rule, depth + 1) end return end - mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / recdepth) + mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / depth) end -- Change mesecon.queue:add_function("change", function (pos, rulename, changetype) - node = minetest.get_node(pos) - effector = mesecon:get_effector(node.name) + local node = minetest.get_node(pos) + local effector = mesecon.get_effector(node.name) if effector and effector.action_change then effector.action_change(pos, node, rulename, changetype) end end) -function mesecon:changesignal(pos, node, rulename, newstate, recdepth) +function mesecon.changesignal(pos, node, rulename, newstate, depth) if rulename == nil then - for _,rule in ipairs(mesecon:effector_get_rules(node)) do - mesecon:changesignal(pos, node, rule, newstate, recdepth + 1) + for _,rule in ipairs(mesecon.effector_get_rules(node)) do + mesecon.changesignal(pos, node, rule, newstate, depth + 1) end return end - mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename, 1 / recdepth) -end - --- ######### --- # Rules # "Database" for rulenames --- ######### - -function mesecon:add_rules(name, rules) - mesecon.rules[name] = rules -end - -function mesecon:get_rules(name) - return mesecon.rules[name] + mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, rulename, 1 / depth) end -- Conductors -function mesecon:is_conductor_on(node, rulename) - local conductor = mesecon:get_conductor(node.name) +function mesecon.is_conductor_on(node, rulename) + local conductor = mesecon.get_conductor(node.name) if conductor then if conductor.state then return conductor.state == mesecon.state.on end if conductor.states then if not rulename then - return mesecon:getstate(node.name, conductor.states) ~= 1 + return mesecon.getstate(node.name, conductor.states) ~= 1 end - local bit = mesecon:rule2bit(rulename, mesecon:conductor_get_rules(node)) - local binstate = mesecon:getbinstate(node.name, conductor.states) - return mesecon:get_bit(binstate, bit) + local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node)) + local binstate = mesecon.getbinstate(node.name, conductor.states) + return mesecon.get_bit(binstate, bit) end end return false end -function mesecon:is_conductor_off(node, rulename) - local conductor = mesecon:get_conductor(node.name) +function mesecon.is_conductor_off(node, rulename) + local conductor = mesecon.get_conductor(node.name) if conductor then if conductor.state then return conductor.state == mesecon.state.off end if conductor.states then if not rulename then - return mesecon:getstate(node.name, conductor.states) == 1 + return mesecon.getstate(node.name, conductor.states) == 1 end - local bit = mesecon:rule2bit(rulename, mesecon:conductor_get_rules(node)) - local binstate = mesecon:getbinstate(node.name, conductor.states) - return not mesecon:get_bit(binstate, bit) + local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node)) + local binstate = mesecon.getbinstate(node.name, conductor.states) + return not mesecon.get_bit(binstate, bit) end end return false end -function mesecon:is_conductor(nodename) - local conductor = mesecon:get_conductor(nodename) +function mesecon.is_conductor(nodename) + local conductor = mesecon.get_conductor(nodename) if conductor then return true end return false end -function mesecon:get_conductor_on(node_off, rulename) - local conductor = mesecon:get_conductor(node_off.name) +function mesecon.get_conductor_on(node_off, rulename) + local conductor = mesecon.get_conductor(node_off.name) if conductor then if conductor.onstate then return conductor.onstate end if conductor.states then - local bit = mesecon:rule2bit(rulename, mesecon:conductor_get_rules(node_off)) - local binstate = mesecon:getbinstate(node_off.name, conductor.states) - binstate = mesecon:set_bit(binstate, bit, "1") + local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node_off)) + local binstate = mesecon.getbinstate(node_off.name, conductor.states) + binstate = mesecon.set_bit(binstate, bit, "1") return conductor.states[tonumber(binstate,2)+1] end end return offstate end -function mesecon:get_conductor_off(node_on, rulename) - local conductor = mesecon:get_conductor(node_on.name) +function mesecon.get_conductor_off(node_on, rulename) + local conductor = mesecon.get_conductor(node_on.name) if conductor then if conductor.offstate then return conductor.offstate end if conductor.states then - local bit = mesecon:rule2bit(rulename, mesecon:conductor_get_rules(node_on)) - local binstate = mesecon:getbinstate(node_on.name, conductor.states) - binstate = mesecon:set_bit(binstate, bit, "0") + local bit = mesecon.rule2bit(rulename, mesecon.conductor_get_rules(node_on)) + local binstate = mesecon.getbinstate(node_on.name, conductor.states) + binstate = mesecon.set_bit(binstate, bit, "0") return conductor.states[tonumber(binstate,2)+1] end end return onstate end -function mesecon:conductor_get_rules(node) - local conductor = mesecon:get_conductor(node.name) +function mesecon.conductor_get_rules(node) + local conductor = mesecon.get_conductor(node.name) if conductor then local rules = conductor.rules if type(rules) == 'function' then @@ -349,128 +336,127 @@ end -- some more general high-level stuff -function mesecon:is_power_on(pos, rulename) +function mesecon.is_power_on(pos, rulename) local node = minetest.get_node(pos) - if mesecon:is_conductor_on(node, rulename) or mesecon:is_receptor_on(node.name) then + if mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name) then return true end return false end -function mesecon:is_power_off(pos, rulename) +function mesecon.is_power_off(pos, rulename) local node = minetest.get_node(pos) - if mesecon:is_conductor_off(node, rulename) or mesecon:is_receptor_off(node.name) then + if mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name) then return true end return false end -function mesecon:turnon(pos, rulename, recdepth) - recdepth = recdepth or 2 - if (recdepth > STACK_SIZE) then return end - local node = minetest.get_node(pos) +function mesecon.turnon(pos, link) + local frontiers = {{pos = pos, link = link}} - if(node.name == "ignore") then - -- try turning on later again - mesecon.queue:add_action( - pos, "turnon", {rulename, recdepth + 1}, nil, true) - end - - if mesecon:is_conductor_off(node, rulename) then - local rules = mesecon:conductor_get_rules(node) + local depth = 1 + while frontiers[depth] do + local f = frontiers[depth] + local node = minetest.get_node_or_nil(f.pos) - if not rulename then - for _, rule in ipairs(mesecon:flattenrules(rules)) do - if mesecon:connected_to_receptor(pos, rule) then - mesecon:turnon(pos, rule, recdepth + 1) + -- area not loaded, postpone action + if not node then + mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true) + elseif mesecon.is_conductor_off(node, f.link) then + local rules = mesecon.conductor_get_rules(node) + + minetest.swap_node(f.pos, {name = mesecon.get_conductor_on(node, f.link), + param2 = node.param2}) + + -- call turnon on neighbors: normal rules + for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + local np = mesecon.addPosRule(f.pos, r) + + -- area not loaded, postpone action + if not minetest.get_node_or_nil(np) then + mesecon.queue:add_action(np, "turnon", {rulename}, + nil, true) + else + local links = mesecon.rules_link_rule_all(f.pos, r) + for _, l in ipairs(links) do + table.insert(frontiers, {pos = np, link = l}) + end end end - return - end - - minetest.swap_node(pos, {name = mesecon:get_conductor_on(node, rulename), param2 = node.param2}) - - for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do - local np = mesecon:addPosRule(pos, rule) - if(minetest.get_node(np).name == "ignore") then - -- try turning on later again - mesecon.queue:add_action( - np, "turnon", {rulename, recdepth + 1}, nil, true) - else - local rulenames = mesecon:rules_link_rule_all(pos, rule) - - for _, rulename in ipairs(rulenames) do - mesecon:turnon(np, rulename, recdepth + 1) - end + elseif mesecon.is_effector(node.name) then + mesecon.changesignal(f.pos, node, f.link, mesecon.state.on, depth) + if mesecon.is_effector_off(node.name) then + mesecon.activate(f.pos, node, f.link, depth) end end - elseif mesecon:is_effector(node.name) then - mesecon:changesignal(pos, node, rulename, mesecon.state.on, recdepth) - if mesecon:is_effector_off(node.name) then - mesecon:activate(pos, node, rulename, recdepth) - end + depth = depth + 1 end end mesecon.queue:add_function("turnon", function (pos, rulename, recdepth) - mesecon:turnon(pos, rulename, recdepth) + mesecon.turnon(pos, rulename, recdepth) end) -function mesecon:turnoff(pos, rulename, recdepth) - recdepth = recdepth or 2 - if (recdepth > STACK_SIZE) then return end - local node = minetest.get_node(pos) +function mesecon.turnoff(pos, link) + local frontiers = {{pos = pos, link = link}} - if(node.name == "ignore") then - -- try turning on later again - mesecon.queue:add_action( - pos, "turnoff", {rulename, recdepth + 1}, nil, true) - end + local depth = 1 + while frontiers[depth] do + local f = frontiers[depth] + local node = minetest.get_node_or_nil(f.pos) - if mesecon:is_conductor_on(node, rulename) then - local rules = mesecon:conductor_get_rules(node) - minetest.swap_node(pos, {name = mesecon:get_conductor_off(node, rulename), param2 = node.param2}) + -- area not loaded, postpone action + if not node then + mesecon.queue:add_action(f.pos, "turnoff", {link}, nil, true) + elseif mesecon.is_conductor_on(node, f.link) then + local rules = mesecon.conductor_get_rules(node) - for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do - local np = mesecon:addPosRule(pos, rule) - if(minetest.get_node(np).name == "ignore") then - -- try turning on later again - mesecon.queue:add_action( - np, "turnoff", {rulename, recdepth + 1}, nil, true) - else - local rulenames = mesecon:rules_link_rule_all(pos, rule) + minetest.swap_node(f.pos, {name = mesecon.get_conductor_off(node, f.link), + param2 = node.param2}) - for _, rulename in ipairs(rulenames) do - mesecon:turnoff(np, rulename, recdepth + 1) + -- call turnoff on neighbors: normal rules + for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + local np = mesecon.addPosRule(f.pos, r) + + -- area not loaded, postpone action + if not minetest.get_node_or_nil(np) then + mesecon.queue:add_action(np, "turnoff", {rulename}, + nil, true) + else + local links = mesecon.rules_link_rule_all(f.pos, r) + for _, l in ipairs(links) do + table.insert(frontiers, {pos = np, link = l}) + end end end + elseif mesecon.is_effector(node.name) then + mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth) + if mesecon.is_effector_on(node.name) and not mesecon.is_powered(f.pos) then + mesecon.deactivate(f.pos, node, f.link, depth) + end end - elseif mesecon:is_effector(node.name) then - mesecon:changesignal(pos, node, rulename, mesecon.state.off, recdepth) - if mesecon:is_effector_on(node.name) - and not mesecon:is_powered(pos) then - mesecon:deactivate(pos, node, rulename, recdepth + 1) - end + depth = depth + 1 end end mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth) - mesecon:turnoff(pos, rulename, recdepth) + mesecon.turnoff(pos, rulename, recdepth) end) -function mesecon:connected_to_receptor(pos, rulename) +function mesecon.connected_to_receptor(pos, link) local node = minetest.get_node(pos) -- Check if conductors around are connected - local rules = mesecon:get_any_inputrules(node) + local rules = mesecon.get_any_inputrules(node) if not rules then return false end - for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do - local rulenames = mesecon:rules_link_rule_all_inverted(pos, rule) - for _, rname in ipairs(rulenames) do - local np = mesecon:addPosRule(pos, rname) - if mesecon:find_receptor_on(np, {}, mesecon:invertRule(rname)) then + for _, rule in ipairs(mesecon.rule2meta(link, rules)) do + local links = mesecon.rules_link_rule_all_inverted(pos, rule) + for _, l in ipairs(links) do + local np = mesecon.addPosRule(pos, l) + if mesecon.find_receptor_on(np, mesecon.invertRule(l)) then return true end end @@ -479,66 +465,57 @@ function mesecon:connected_to_receptor(pos, rulename) return false end -function mesecon:find_receptor_on(pos, checked, rulename, recdepth) - recdepth = recdepth or 2 - if (recdepth > STACK_SIZE) then return true end -- ignore request - local node = minetest.get_node(pos) +function mesecon.find_receptor_on(pos, link) + local frontiers = {{pos = pos, link = link}} + local checked = {} - if mesecon:is_receptor_on(node.name) then - -- add current position to checked - table.insert(checked, {x=pos.x, y=pos.y, z=pos.z}) - return true - end + -- List of positions that have been searched for onstate receptors + local depth = 1 + while frontiers[depth] do + local f = frontiers[depth] + local node = minetest.get_node_or_nil(f.pos) - if mesecon:is_conductor(node.name) then - local rules = mesecon:conductor_get_rules(node) - local metaindex = mesecon:rule2metaindex(rulename, rules) - -- find out if node has already been checked (to prevent from endless loop) - for _, cp in ipairs(checked) do - if mesecon:cmpPos(cp, pos) and cp.metaindex == metaindex then - return false, checked - end - end - -- add current position to checked - table.insert(checked, {x=pos.x, y=pos.y, z=pos.z, metaindex = metaindex}) - for _, rule in ipairs(mesecon:rule2meta(rulename, rules)) do - local rulenames = mesecon:rules_link_rule_all_inverted(pos, rule) - for _, rname in ipairs(rulenames) do - local np = mesecon:addPosRule(pos, rname) - if mesecon:find_receptor_on(np, checked, mesecon:invertRule(rname), recdepth + 1) then - return true + if not node then return false end + if mesecon.is_receptor_on(node.name) then return true end + if mesecon.is_conductor_on(node, f.link) then + local rules = mesecon.conductor_get_rules(node) + + -- call turnoff on neighbors: normal rules + for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + local np = mesecon.addPosRule(f.pos, r) + + local links = mesecon.rules_link_rule_all_inverted(f.pos, r) + for _, l in ipairs(links) do + local checkedstring = np.x..np.y..np.z..l.x..l.y..l.z + if not checked[checkedstring] then + table.insert(frontiers, {pos = np, link = l}) + checked[checkedstring] = true + end end end + end - else - -- find out if node has already been checked (to prevent from endless loop) - for _, cp in ipairs(checked) do - if mesecon:cmpPos(cp, pos) then - return false, checked - end - end - table.insert(checked, {x=pos.x, y=pos.y, z=pos.z}) + depth = depth + 1 end - - return false end -function mesecon:rules_link(output, input, dug_outputrules) --output/input are positions (outputrules optional, used if node has been dug), second return value: the name of the affected input rule +function mesecon.rules_link(output, input, dug_outputrules) --output/input are positions (outputrules optional, used if node has been dug), second return value: the name of the affected input rule local outputnode = minetest.get_node(output) local inputnode = minetest.get_node(input) - local outputrules = dug_outputrules or mesecon:get_any_outputrules (outputnode) - local inputrules = mesecon:get_any_inputrules (inputnode) + local outputrules = dug_outputrules or mesecon.get_any_outputrules (outputnode) + local inputrules = mesecon.get_any_inputrules (inputnode) if not outputrules or not inputrules then return end - for _, outputrule in ipairs(mesecon:flattenrules(outputrules)) do + for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do -- Check if output sends to input - if mesecon:cmpPos(mesecon:addPosRule(output, outputrule), input) then - for _, inputrule in ipairs(mesecon:flattenrules(inputrules)) do + if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then + for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do -- Check if input accepts from output - if mesecon:cmpPos(mesecon:addPosRule(input, inputrule), output) then - if inputrule.sx == nil or outputrule.sx == nil or mesecon:cmpSpecial(inputrule, outputrule) then + if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then + if inputrule.sx == nil or outputrule.sx == nil + or mesecon.cmpSpecial(inputrule, outputrule) then return true, inputrule end end @@ -548,82 +525,91 @@ function mesecon:rules_link(output, input, dug_outputrules) --output/input are p return false end -function mesecon:rules_link_rule_all(output, rule) --output/input are positions (outputrules optional, used if node has been dug), second return value: affected input rules - local input = mesecon:addPosRule(output, rule) +function mesecon.rules_link_rule_all(output, rule) + local input = mesecon.addPosRule(output, rule) local inputnode = minetest.get_node(input) - local inputrules = mesecon:get_any_inputrules (inputnode) + local inputrules = mesecon.get_any_inputrules (inputnode) if not inputrules then return {} end local rules = {} - for _, inputrule in ipairs(mesecon:flattenrules(inputrules)) do + for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do -- Check if input accepts from output - if mesecon:cmpPos(mesecon:addPosRule(input, inputrule), output) then - if inputrule.sx == nil or rule.sx == nil or mesecon:cmpSpecial(inputrule, rule) then - rules[#rules+1] = inputrule + if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then + if inputrule.sx == nil or rule.sx == nil + or mesecon.cmpSpecial(inputrule, rule) then + table.insert(rules, inputrule) end end end return rules end -function mesecon:rules_link_rule_all_inverted(input, rule) - --local irule = mesecon:invertRule(rule) - local output = mesecon:addPosRule(input, rule) +function mesecon.rules_link_rule_all_inverted(input, rule) + --local irule = mesecon.invertRule(rule) + local output = mesecon.addPosRule(input, rule) local outputnode = minetest.get_node(output) - local outputrules = mesecon:get_any_outputrules (outputnode) + local outputrules = mesecon.get_any_outputrules (outputnode) if not outputrules then return {} end local rules = {} - for _, outputrule in ipairs(mesecon:flattenrules(outputrules)) do - if mesecon:cmpPos(mesecon:addPosRule(output, outputrule), input) then - if outputrule.sx == nil or rule.sx == nil or mesecon:cmpSpecial(outputrule, rule) then - rules[#rules+1] = mesecon:invertRule(outputrule) + for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do + if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then + if outputrule.sx == nil or rule.sx == nil + or mesecon.cmpSpecial(outputrule, rule) then + table.insert(rules, mesecon.invertRule(outputrule)) end end end return rules end -function mesecon:rules_link_anydir(pos1, pos2) - return mesecon:rules_link(pos1, pos2) or mesecon:rules_link(pos2, pos1) +function mesecon.rules_link_anydir(pos1, pos2) + return mesecon.rules_link(pos1, pos2) or mesecon.rules_link(pos2, pos1) end -function mesecon:is_powered(pos, rule) +function mesecon.is_powered(pos, rule) local node = minetest.get_node(pos) - local rules = mesecon:get_any_inputrules(node) + local rules = mesecon.get_any_inputrules(node) if not rules then return false end + -- List of nodes that send out power to pos + local sourcepos = {} + if not rule then - for _, rule in ipairs(mesecon:flattenrules(rules)) do - local rulenames = mesecon:rules_link_rule_all_inverted(pos, rule) + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule) for _, rname in ipairs(rulenames) do - local np = mesecon:addPosRule(pos, rname) + local np = mesecon.addPosRule(pos, rname) local nn = minetest.get_node(np) - if (mesecon:is_conductor_on (nn, mesecon:invertRule(rname)) or mesecon:is_receptor_on (nn.name)) then - return true + if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname)) + or mesecon.is_receptor_on (nn.name)) then + table.insert(sourcepos, np) end end end else - local rulenames = mesecon:rules_link_rule_all_inverted(pos, rule) + local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule) for _, rname in ipairs(rulenames) do - local np = mesecon:addPosRule(pos, rname) + local np = mesecon.addPosRule(pos, rname) local nn = minetest.get_node(np) - if (mesecon:is_conductor_on (nn, mesecon:invertRule(rname)) or mesecon:is_receptor_on (nn.name)) then - return true + if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname)) + or mesecon.is_receptor_on (nn.name)) then + sourcepos.insert(np) end end end - - return false + + -- Return FALSE if not powered, return list of sources if is powered + if (#sourcepos == 0) then return false + else return sourcepos end end --Rules rotation Functions: -function mesecon:rotate_rules_right(rules) +function mesecon.rotate_rules_right(rules) local nr = {} for i, rule in ipairs(rules) do if rule.sx then @@ -644,7 +630,7 @@ function mesecon:rotate_rules_right(rules) return nr end -function mesecon:rotate_rules_left(rules) +function mesecon.rotate_rules_left(rules) local nr = {} for i, rule in ipairs(rules) do if rule.sx then @@ -665,7 +651,7 @@ function mesecon:rotate_rules_left(rules) return nr end -function mesecon:rotate_rules_down(rules) +function mesecon.rotate_rules_down(rules) local nr = {} for i, rule in ipairs(rules) do if rule.sx then @@ -686,7 +672,7 @@ function mesecon:rotate_rules_down(rules) return nr end -function mesecon:rotate_rules_up(rules) +function mesecon.rotate_rules_up(rules) local nr = {} for i, rule in ipairs(rules) do if rule.sx then diff --git a/mods/mesecons/mesecons/legacy.lua b/mods/mesecons/mesecons/legacy.lua index 89c87cab..a881c253 100644 --- a/mods/mesecons/mesecons/legacy.lua +++ b/mods/mesecons/mesecons/legacy.lua @@ -1,32 +1,29 @@ -minetest.swap_node = minetest.swap_node or function(pos, node) - local data = minetest.get_meta(pos):to_table() - minetest.add_node(pos, node) - minetest.get_meta(pos):from_table(data) +-- Ugly hack to prevent breaking compatibility with other mods +-- Just remove the following two functions to delete the hack, to be done when other mods have updated +function mesecon.receptor_on(self, pos, rules) + if (self.receptor_on) then + print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.") + print("[Mesecons] If you are the programmer of this mod, please update it ") + print("[Mesecons] to use mesecon.receptor_on instead. mesecon:* is deprecated") + print("[Mesecons] Otherwise, please make sure you're running the latest version") + print("[Mesecons] of that mod and inform the mod creator.") + else + rules = pos + pos = self + end + mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) end -local rules = {} -rules.a = {x = -1, y = 0, z = 0, name="A"} -rules.b = {x = 0, y = 0, z = 1, name="B"} -rules.c = {x = 1, y = 0, z = 0, name="C"} -rules.d = {x = 0, y = 0, z = -1, name="D"} - -function legacy_update_ports(pos) - local meta = minetest.get_meta(pos) - L = { - a = mesecon:is_power_on(mesecon:addPosRule(pos, rules.a), - mesecon:invertRule(rules.a)) and - mesecon:rules_link(mesecon:addPosRule(pos, rules.a), pos), - b = mesecon:is_power_on(mesecon:addPosRule(pos, rules.b), - mesecon:invertRule(rules.b)) and - mesecon:rules_link(mesecon:addPosRule(pos, rules.b), pos), - c = mesecon:is_power_on(mesecon:addPosRule(pos, rules.c), - mesecon:invertRule(rules.c)) and - mesecon:rules_link(mesecon:addPosRule(pos, rules.c), pos), - d = mesecon:is_power_on(mesecon:addPosRule(pos, rules.d), - mesecon:invertRule(rules.d)) and - mesecon:rules_link(mesecon:addPosRule(pos, rules.d), pos), - } - local n = (L.a and 1 or 0) + (L.b and 2 or 0) + (L.c and 4 or 0) + (L.d and 8 or 0) + 1 - meta:set_int("real_portstates", n) - return L +function mesecon.receptor_off(self, pos, rules) + if (self.receptor_off) then + print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.") + print("[Mesecons] If you are the programmer of this mod, please update it ") + print("[Mesecons] to use mesecon.receptor_off instead. mesecon:* is deprecated") + print("[Mesecons] Otherwise, please make sure you're running the latest version") + print("[Mesecons] of that mod and inform the mod creator.") + else + rules = pos + pos = self + end + mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) end diff --git a/mods/mesecons/mesecons/presets.lua b/mods/mesecons/mesecons/presets.lua index 6c8d3eac..ea4bd65a 100644 --- a/mods/mesecons/mesecons/presets.lua +++ b/mods/mesecons/mesecons/presets.lua @@ -15,6 +15,8 @@ mesecon.rules.default = {x=0, y=1, z=-1}, {x=0, y=-1, z=-1}} +mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.default, {{x=0, y=-2, z=0}}) + mesecon.rules.buttonlike = {{x = 1, y = 0, z = 0}, {x = 1, y = 1, z = 0}, @@ -32,11 +34,11 @@ mesecon.rules.flat = mesecon.rules.buttonlike_get = function(node) local rules = mesecon.rules.buttonlike if node.param2 == 2 then - rules=mesecon:rotate_rules_left(rules) + rules=mesecon.rotate_rules_left(rules) elseif node.param2 == 3 then - rules=mesecon:rotate_rules_right(mesecon:rotate_rules_right(rules)) + rules=mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) elseif node.param2 == 0 then - rules=mesecon:rotate_rules_right(rules) + rules=mesecon.rotate_rules_right(rules) end return rules end diff --git a/mods/mesecons/mesecons/services.lua b/mods/mesecons/mesecons/services.lua index b0b45e01..36d9b805 100644 --- a/mods/mesecons/mesecons/services.lua +++ b/mods/mesecons/mesecons/services.lua @@ -1,44 +1,53 @@ -- Dig and place services mesecon.on_placenode = function (pos, node) + mesecon.update_autoconnect(pos, node) + -- Receptors: Send on signal when active - if mesecon:is_receptor_on(node.name) then - mesecon:receptor_on(pos, mesecon:receptor_get_rules(node)) + if mesecon.is_receptor_on(node.name) then + mesecon.receptor_on(pos, mesecon.receptor_get_rules(node)) end -- Conductors: Send turnon signal when powered or replace by respective offstate conductor -- if placed conductor is an onstate one - if mesecon:is_conductor(node.name) then - if mesecon:is_powered(pos) then + if mesecon.is_conductor(node.name) then + local sources = mesecon.is_powered(pos) + if sources then -- also call receptor_on if itself is powered already, so that neighboring -- conductors will be activated (when pushing an on-conductor with a piston) - mesecon:turnon (pos) - mesecon:receptor_on (pos, mesecon:conductor_get_rules(node)) - elseif mesecon:is_conductor_off(node.name) then - minetest.swap_node(pos, {name = mesecon:get_conductor_off(node)}) + for _, s in ipairs(sources) do + local rule = {x = pos.x - s.x, y = pos.y - s.y, z = pos.z - s.z} + mesecon.turnon(pos, rule) + end + --mesecon.receptor_on (pos, mesecon.conductor_get_rules(node)) + elseif mesecon.is_conductor_on(node) then + minetest.swap_node(pos, {name = mesecon.get_conductor_off(node)}) end end -- Effectors: Send changesignal and activate or deactivate - if mesecon:is_effector(node.name) then - if mesecon:is_powered(pos) then - mesecon:changesignal(pos, node, mesecon:effector_get_rules(node), "on", 1) - mesecon:activate(pos, node, nil, 1) + if mesecon.is_effector(node.name) then + if mesecon.is_powered(pos) then + mesecon.changesignal(pos, node, mesecon.effector_get_rules(node), "on", 1) + mesecon.activate(pos, node, nil, 1) else - mesecon:changesignal(pos, node, mesecon:effector_get_rules(node), "off", 1) - mesecon:deactivate(pos, node, nil, 1) + mesecon.changesignal(pos, node, mesecon.effector_get_rules(node), "off", 1) + mesecon.deactivate(pos, node, nil, 1) end end end mesecon.on_dignode = function (pos, node) - if mesecon:is_conductor_on(node) then - mesecon:receptor_off(pos, mesecon:conductor_get_rules(node)) - elseif mesecon:is_receptor_on(node.name) then - mesecon:receptor_off(pos, mesecon:receptor_get_rules(node)) + if mesecon.is_conductor_on(node) then + mesecon.receptor_off(pos, mesecon.conductor_get_rules(node)) + elseif mesecon.is_receptor_on(node.name) then + mesecon.receptor_off(pos, mesecon.receptor_get_rules(node)) end + mesecon.queue:add_action(pos, "update_autoconnect", {node}) end +mesecon.queue:add_function("update_autoconnect", mesecon.update_autoconnect) + minetest.register_on_placenode(mesecon.on_placenode) minetest.register_on_dignode(mesecon.on_dignode) @@ -52,7 +61,7 @@ mesecon.do_overheat = function(pos) heat = heat + 1 meta:set_int("heat", heat) - if heat < OVERHEAT_MAX then + if heat < mesecon.setting("overheat_max", 20) then mesecon.queue:add_action(pos, "cooldown", {}, 1, nil, 0) else return true diff --git a/mods/mesecons/mesecons/settings.lua b/mods/mesecons/mesecons/settings.lua index 147fd71d..fb03dff8 100644 --- a/mods/mesecons/mesecons/settings.lua +++ b/mods/mesecons/mesecons/settings.lua @@ -1,14 +1,10 @@ -- SETTINGS -BLINKY_PLANT_INTERVAL = 3 -NEW_STYLE_WIRES = true -- true = new nodebox wires, false = old raillike wires -PRESSURE_PLATE_INTERVAL = 0.1 -OBJECT_DETECTOR_RADIUS = 6 -PISTON_MAXIMUM_PUSH = 15 -MOVESTONE_MAXIMUM_PUSH = 100 -MESECONS_RESUMETIME = 4 -- time to wait when starting the server before - -- processing the ActionQueue, don't set this too low -OVERHEAT_MAX = 20 -- maximum heat of any component that directly sends an output - -- signal when the input changes (e.g. luacontroller, gates) - -- Unit: actions per second, checks are every 1 second -STACK_SIZE = 3000 -- Recursive functions will abort when this is reached. Therefore, - -- this is also limits the maximum circuit size. +function mesecon.setting(setting, default) + if type(default) == "bool" then + return minetest.setting_getbool("mesecon."..setting) or default + elseif type(default) == "string" then + return minetest.setting_get("mesecon."..setting) or default + elseif type(default) == "number" then + return tonumber(minetest.setting_get("mesecon."..setting) or default) + end +end diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_crossing_off.png b/mods/mesecons/mesecons/textures/jeija_mesecon_crossing_off.png deleted file mode 100644 index 4e3ca032e76db7e22b7b44245f1427c953c6e62b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 341 zcmV-b0jmCqP)Px#32;bRa{vGgP5=N469IKCxxWAa00(qQO+^RX1P>MhD}w5TVgLXD=Sf6CR5;6} zlCe$#VGxABT~J~)flg~0uZD)Fp{L~uJQ7O6+gVf55rZdq=-rORnb_!$z}N0(c6W9l z!EEMw%3Y}*=LmjDT?kz?APlp#L_1ZiBOo|mU@&;3C|bbt=_f1}H#!`;Y&Nefmk)p5 zVR`N{0}0H8JM8z@tk;I*n2F)=j-q&@s!9|FE)4tGpz&Hn7~^2cL>I_F5aL_r7pBuIZMVT_bkAz_!hHU2oXU9I)@0Js*|*o n*6}1J1Px#32;bRa{vGgP5=N469IKCxxWAa00(qQO+^RX1P>MhBaAT&Pyhe`=1D|BR5;6} zlRrxXK@i1%Gu&P{!r|Gdg$e!%Ns-ptd|REuyn_1g~#1>-BC>J>`9Q z_wN|u{kb6m1|pzptkwmpm*n{cNdj56V^ckox)Oqd)DBs#f$Y}|p?-_P;oJ#E;3z+% z+LnY+)t}@?Ujvfiu>8aBPv$R~i5%1Kr&QYoeYNS9gAin| mOS>q4JJUYO()kvekKqgSKtxEI5%^dD0000Eak-ar*7Vy?l&?0!Qkr_c?+aQmp$mhDzP{q*WSzCx?DS!SzuD2DA#oy5`< zvrj)jM2Us@OKmU1q{L^|1*~TZlK!1wJby~YhQaQw*Jc~771w|sV(@hJb6Mw<&;$Ve C!*VqM diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_curved_on.png b/mods/mesecons/mesecons/textures/jeija_mesecon_curved_on.png deleted file mode 100644 index fa882e43b979fcec2d621f79f7f356326dbf42f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 307 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0Vr z{1_Oxg&9kAckTxYvX^-Jy0YJ4;TL024B+Jd2NXK$>Eak-ar*59TdqS6049a$Z7Tml@qZ5uWk8jE>mhPl3xnUQwy%=b3-Kd-l!?sF-! zaZS1%Sa~STS|Hgf;MCD~24`9?Y<`$>OZ@uE#W8sf*$X1}JeJZ=KTVCi?)$opiJJ#))k$+g#_I=B$TtMEza1B2lUvjxg2XWs!m#Ng@b=d#Wzp$Pzw C{&Cd+ diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_inverter_off.png b/mods/mesecons/mesecons/textures/jeija_mesecon_inverter_off.png deleted file mode 100644 index bd4de1b0837fd7718a189e61c113dee7120f2a1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 743 zcmV?P)Px#32;bRa{vGgP5=N469IKCxxWAa00(qQO+^RX1P=iqAgkl9KL7v%c}YY;R5;6R zlRHaXQ51#0^SXCNG;@g$5F0@RyVO$%v9YtWQpCm-$zMnl2&7GZfC$=XNE~}hK_rD> zLIM^kq9AH;$e`Ytxt>>wi5G?JY8Pi67JGe5G#ZTHP%{`QV1b%&h>NvjYgxirj({ub2OW;>2^C@Uj9Jq4}{P} zYtyr>HQU?UD5X%>*Vk`atrkm5D@;s`b9#Ep&!6u&K5p~t*A>mCV`Ky_E)L1E=hW+U zYPAt|c0O}*a?-oO!|~oTIH*X|r<|YvVSM}v-bXqe&;Ld)FE5j28Q;GjvbVQKnpQ}X zmt0-_20X*V2^SYFYPAA4 zd#Y8KoP5RT=r~2uEjiIzb8~Zpz8Br+Erg)kZ8J19$jr=JoO4tvRlIkPIPu;ir9|H6 z3OvYJ5M!iXuQNS8O}E=Y2vKsPlmh5+V2mj_c$hOlo;&i~p|yU*iTAyO8e@80P)e0O z08mP?wYA0S>S|f0#l^+4Ox}Bh5WQQp+imhZ$2nIP1z>h|mfhXma?kS|?|mtjQj+I6 Ze*q~YZ0!3HA7KCh002ovPDHLkV1oCML1h2{ diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_inverter_on.png b/mods/mesecons/mesecons/textures/jeija_mesecon_inverter_on.png deleted file mode 100644 index be41599e30a65c04c847072a33f406b29bb01833..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 725 zcmV;`0xJE9P)Px#32;bRa{vGgP5=N469IKCxxWAa00(qQO+^RX1P=irBP;RF!~g&SXGugsR5;6R zlQByiQ51#0dGF24I-0m)NyH{X2sRe6P=A8mZbYoK^@qg&A)+?gxS&-qrQ{dbWLJ`i zq!Dx(&{5yMdGDr}?4Xd_+*`cEJNKS*qHebL{VNfJba5CV^nj~HVN zAq3($rYuX+G{rf``uaMHi;Do9ot*&?MN$3MIY%7F80Q>mni4|5drt@f5y4tZtJSK3 zqaH;O!{HF66yAFbfVGw+Nr>aPp1t=RA0MNXLMera)YPA|F-j=_M%_6_2%h=*CuU}T z<4WPz&kywb)d90CBZNR%mK6@5+wK0N<}gO{X+GxNRF|>rJz5X>IQyNsxe{YcMcWvT zj*ie;qjq<9$@83rg#}htK2w$+rS};OUU74Cg>z$Q)#UBeSG3l2IvtjlmdNv*larI` z2G2`Gc+(ssNv46o#6$~g?-8;5uk_Z|)|Xzd$K>QB=jZ1Dyna24(%*1y$oP0h@$iE` zS8WD^m|m~P_4PFu7ZZ5Zt18vTC4NOI>K z#u)DI?l2>eh}1eiJy|XG+^TH>i-{Uy0vY@rDa{!>V=J4>4?d|P4OdA^;b(p;O zL{U`T;^EFH?6b0V<8myF}C<^`p=TdB!Ri9a700000NkvXX Hu0mjffN)I- diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_on.png b/mods/mesecons/mesecons/textures/jeija_mesecon_on.png deleted file mode 100644 index d7ebeecb1f0e3fe24caa72bb865cd6c878abd8e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0Vr z{1_Oxg&9kAckTxYvX^-Jy0YJ4;TK~x-+Qe49Z)FD)5S5w;`H92gS-bEIG8S*=KbIK zO6d;Ug_b3Ch8+wEY2RPmRo?#DV!{byz7X#Zt%+P;_*oew=4{dQ=!)#wf9}UIm!B@L qi-VV#u^LTwVO?XBaQ8^gAy%IoB2UW8ChrB>z~JfX=d#Wzp$PylPC{`2 diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_plug.png b/mods/mesecons/mesecons/textures/jeija_mesecon_plug.png deleted file mode 100644 index 8a4d28171fb7c4df848b8b1874db486ac9d6f590..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 713 zcmV;)0yh1LP)Px#32;bRa{vGgP5=N469IKCxxWAa00(qQO+^RX1P=iMBH~|(GXMYrTS-JgR5;6B zlD|tFK^TUg`L*lmCEG|Ky&+&@Es2Vp_90bL=buVz8;G?i=yeLwE|rayBqW@==kBeu zv-3@g!$tEpGXwJt?>q0K_V@Rbh#(?_5Lj4PAjXLIo|Tmq0IsgC=(>)@#YMdL!CX)%)TBg$}S(Z^%6(T~@G-zurB7(J+uIu`BG#XJ9 z1w~OX8jS!@O7(Y@QaI<(Aq4U~2O!3Xh>%iZJRYO9Mno8o$Nd9JDcZJ0DMgGC3*fyc z%QBpE{XRzF`1qKoN+}^C&)jIOH2_*`j4`B?2q97w4e#ImU~TOJkr_%ELI@aRP)gBt z-Fz;kMBBEkudma#Eyh@ummNz>UqJgb>hLqfSpx6F^ZE z0Gynh;M^Y9*S{GIGPKsLt-avpX2{*$C$_h@5fRF=oI7}$(OQdhEw5hXtggPsxyYM0 z1tBQBkAzV3zx3thCFkeo02~|~kkS%={(NLI`Gr!#^6~=HX~lH`9nK6be%b866GMjy4I5Z3fpK)$T2rYS@6GFgR%l-X5_Hihs)c5TD1H<7< zhQlv}5O8ilO7e`87$aJ1^kc98_Y8@RjSY5pcWIiYC(nD2F$Q4Hfpf0s;AziWTU%(Y zNhz_jv-6CT7$d+OWos?Q7(}E;+8D#p(Gg`?QkEr$hlf47S(f#2LkQT}Y(`zzbX|vt v@aV{U-$#3Rc)%D#jFA{4N-4C~)OF227^GudGF(=#00000NkvXXu0mjf852OP diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_socket_off.png b/mods/mesecons/mesecons/textures/jeija_mesecon_socket_off.png deleted file mode 100644 index ad3f60145dbacfad7ec86caf68d101a38d607a71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 751 zcmVPx#32;bRa{vGgP5=N469IKCxxWAa00(qQO+^RX1P=it7^uueVgLXFfk{L`R5;6R zlRs-6M-;_>Gdr{U^e~dJjKHW-qbeAL;1vS30fP&HK1Qk(h7@V?4U(^*R-k7RRH>61 zfj~$Glis$3d2vMKr`>%!JA3b>czFwg6vLf=ckVfJ&NbulIH@YCN{o@gV1S6wwk>&{ zPx#32;bRa{vGgP5=N469IKCxxWAa00(qQO+^RX1P=iu3u7~qdjJ3eb4f%&R5;63 zlCf$fHx!0Hozc~d9TV(XNC+$`vPs#2Jn`~vslcdc%(x@a=ApT zwWuoAT2e~WdUSLIfT~V=W6Y#A#xR@BkQgI%T?3GFrj&v)hMSuk`o5>{d#;9Nu7wx}u>7Z=#g!)+?Y z#NO@}&V2zWJ3G$^!J{Rx!3D6^t`TC4oS&cLz32A!miznP`S;yxy#JM9_={3{R^dlO zYb{StPgqr@s;ZALmdh0(w7h!tBc&An`1?0XQBq2iHs_3ptQ%}fRS6+rjKNxq$m~PI z<;1*Nt#Hm!N^8nLRF_oiwIX& zSJS^=US3X7-?$rNh%sUpiv`0lkWxZb*-R8dpzAtHDa06AEEZFgjWLJ_!!YnaGL(U* Ty3c`O00000NkvXXu0mjfeJxU9 diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_t_junction_off.png b/mods/mesecons/mesecons/textures/jeija_mesecon_t_junction_off.png deleted file mode 100644 index 71318465fac1ae668eddc2324b211d5deae70e0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 330 zcmV-Q0k!^#P)Px#32;bRa{vGgP5=N469IKCxxWAa00(qQO+^RX1P>Mh6+?@e$p8QV+(|@1R5;6} zl08oXVGx9$eGh_06D>%zrtxZM_%-yjRFpzON%(ivlr+TPNj&u2vA_}*;ilY=+1cHJ z0MlvG>m(_vNt{8dlNUm@2Do7sQ#7LFk2^Tm6Lh;T6h#IsFJECkztw*Kz-IH#V)1-( z4?7kdk8iYI3n{})^m_Lc#RpYYA~#6F{#uVJXtzbD^GK`pMV{YLmdW$g#)3_9aK|{k~rmMe@=Z>p}52{MI8w7rgt*rA-3<=B#&ipS0 c99|aS7yPnT6UNDv1^@s607*qoM6N<$f|D78@Bjb+ diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_t_junction_on.png b/mods/mesecons/mesecons/textures/jeija_mesecon_t_junction_on.png deleted file mode 100644 index a6609ee190d9af7d6a98d77d99e83331b2af2955..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0Vr z{1_Oxg&9kAckTxYvX^-Jy0YJ4;TL1#QGZ~_2^6~M>Eak-aeC?GynpMS)zu8sF&1NTh!32A=6 z+vC0Z7psrv5qq-D-hZw#{xSbZ+3U39jn`P#<_4rSoM21cw6FD1as`vRj@4#a{@i~+ P&oOwq`njxgN@xNA6q9*n diff --git a/mods/mesecons/mesecons/textures/jeija_mesecon_off.png b/mods/mesecons/mesecons/textures/mesecons_wire_inv.png similarity index 100% rename from mods/mesecons/mesecons/textures/jeija_mesecon_off.png rename to mods/mesecons/mesecons/textures/mesecons_wire_inv.png diff --git a/mods/mesecons/mesecons/textures/wires_full_off.png b/mods/mesecons/mesecons/textures/mesecons_wire_off.png similarity index 100% rename from mods/mesecons/mesecons/textures/wires_full_off.png rename to mods/mesecons/mesecons/textures/mesecons_wire_off.png diff --git a/mods/mesecons/mesecons/textures/wires_full_on.png b/mods/mesecons/mesecons/textures/mesecons_wire_on.png similarity index 100% rename from mods/mesecons/mesecons/textures/wires_full_on.png rename to mods/mesecons/mesecons/textures/mesecons_wire_on.png diff --git a/mods/mesecons/mesecons/textures/wires_bump_off.png b/mods/mesecons/mesecons/textures/wires_bump_off.png deleted file mode 100644 index 1e0bd7473fb04724c1d3414afbc4c0910ea7d467..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 347 zcmV-h0i^zkP)ZKzpqVmeD}|PXcFwznkPw3FDY%w&9W-~>Re z^?0tLF_x;r3GFJDrC_alfRjPDtLXJQ?HPEU0@VK*?DunlE7G)Px%?!{p5=HHqUc3k zxPs`0crk#Z5jV)i2wiq07*qoM6N<$f|m=VI{*Lx diff --git a/mods/mesecons/mesecons/textures/wires_inv.png b/mods/mesecons/mesecons/textures/wires_inv.png deleted file mode 100644 index 626f8d4fecc3c0c295f1be6a464bc627e0421a89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>{XE z)7O>#4hILDu8!B__!OX!o2QFoh{fsT1PP80FD5?wZ=62mzp;UV!G;NoBO_+at(m>Q z&h*EBkWAp&#k1I_r-`w#v9*P-uQLQHGB|NEHhoF;ITnUJ7xP))&*OUvG?Bs6)z4*} HQ$iB}67V%l diff --git a/mods/mesecons/mesecons/textures/wires_off.png b/mods/mesecons/mesecons/textures/wires_off.png deleted file mode 100644 index 757d339bf13de9437e7ab2f00d66bc00630efcc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 454 zcmV;%0XhDOP)*{tL=yl20aHmt zK~y-)b(6tv8!-$-A1Qi$$+`A776B6fN0J_D=O5d90NX2Za*&k(@h*>|9xV$1{b9m zN^yAlXZ)y_*I)7ihv)xyz2j*wrSR57#9beNQjG27i@m{lt)jK%0bW?G!FkF!pL6k2 zlyA>JYj9yEHY*k+tqvHR{XOoK0{8AY6XvUWjJJ5*4eSIP@W(@rgWgrz{X9-Wz?oBC-oB#{XvjCmGgLE_`1 wFU!M&VSIn(;)c-IkUHODHqn}xCd1wM1Z!H%u3zy%;s5{u07*qoM6N<$f*vux1^@s6 diff --git a/mods/mesecons/mesecons/textures/wires_on.png b/mods/mesecons/mesecons/textures/wires_on.png deleted file mode 100644 index 57bb82d0ab6148e1920ccb568a920a1809887db3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 492 zcmV%oRlC0r4$DoGbfhf#3-Z$DG4B`f;+sv8X_P9W{zq= z#Bq0O?OcpeF>|i3e+&Pehle|lQMkGJa}qlo?%mAMd2Xbnj800zW)p_7h0}S4T8BBr z*hd-{=$y9Zyu6fQ(rTrE4`T}#RUzl`EoNgFx}BT_+3$DW+G0X!&3SukEG_|i$ zy3U*fwc2+VTB~zBHq5$Lk-sh0>XhP`ff>xR(V9_fj~$PVn6r>l@$sCW5Km6iC zxxGEr`24){lw$8d^ zVrR!&IN9%idabZp2{8(_I@8op72Nx$+HUpB5~S3@Zp?{?L&F`et`e$32+n#PNJ+jS ik$-p5)vnk5-FyP^jq20daEyik0000b&FE2ZD*Ie zhOzkYG#LvfdAcdglww()E$Z+otiLu-a1Jl~t%E7O4ZrW$T15LKOtTdU(zPfxn!6yv zE~;QxzJrjRO4NMmnQPluT{(mscALM?&TF%D# z{3HBZ({wfG;B@-_&vMr)d4 zG`7u}+B_$G-wPr5X4Z#8J)y#Bj7DRQ@E%0k6^MY&bH>%9CTDoPtkIjD)0C{)L=mCy zT{A`y{5UGh(wg_&d|u&Xn!YSX=sLlBd3RS;FaxvQob&!KLfFBa4H3iNZV5BETmq_s qbH*?@LXbBk^0yazw8J2Tp!@>Zjj7!t$pZ-h0000 01000100) +local nid_inc = function() end +nid_inc = function (nid) + local i = 0 + while nid[i-1] ~= 1 do + nid[i] = (nid[i] ~= 1) and 1 or 0 + i = i + 1 end - local nodebox = {} - local adjx = false - local adjz = false - if xp == 1 then table.insert(nodebox, box_xp) adjx = true end - if zp == 1 then table.insert(nodebox, box_zp) adjz = true end - if xm == 1 then table.insert(nodebox, box_xm) adjx = true end - if zm == 1 then table.insert(nodebox, box_zm) adjz = true end - if xpy == 1 then table.insert(nodebox, box_xpy) end - if zpy == 1 then table.insert(nodebox, box_zpy) end - if xmy == 1 then table.insert(nodebox, box_xmy) end - if zmy == 1 then table.insert(nodebox, box_zmy) end - - if adjx and adjz and (xp + zp + xm + zm > 2) then - table.insert(nodebox, box_bump1) - tiles_off = { - "wires_bump_off.png", - "wires_bump_off.png", - "wires_vertical_off.png", - "wires_vertical_off.png", - "wires_vertical_off.png", - "wires_vertical_off.png" - } - tiles_on = { - "wires_bump_on.png", - "wires_bump_on.png", - "wires_vertical_on.png", - "wires_vertical_on.png", - "wires_vertical_on.png", - "wires_vertical_on.png" - } - else - table.insert(nodebox, box_center) - tiles_off = { - "wires_off.png", - "wires_off.png", - "wires_vertical_off.png", - "wires_vertical_off.png", - "wires_vertical_off.png", - "wires_vertical_off.png" - } - tiles_on = { - "wires_on.png", - "wires_on.png", - "wires_vertical_on.png", - "wires_vertical_on.png", - "wires_vertical_on.png", - "wires_vertical_on.png" - } + -- BUT: Skip impossible nodeids: + if ((nid[0] == 0 and nid[4] == 1) or (nid[1] == 0 and nid[5] == 1) + or (nid[2] == 0 and nid[6] == 1) or (nid[3] == 0 and nid[7] == 1)) then + return nid_inc(nid) end - if nodeid == "00000000" then - nodebox = {-8/16, -.5, -1/16, 8/16, -.5+1/16, 1/16} - end + return i <= 8 +end - minetest.register_node("mesecons:wire_"..nodeid.."_off", { - description = wiredesc, - drawtype = "nodebox", - tiles = tiles_off, --- inventory_image = "wires_inv.png", --- wield_image = "wires_inv.png", - inventory_image = "jeija_mesecon_off.png", - wield_image = "jeija_mesecon_off.png", - paramtype = "light", - paramtype2 = "facedir", - sunlight_propagates = true, - selection_box = { - type = "fixed", - fixed = {-.5, -.5, -.5, .5, -.5+4/16, .5} - }, - node_box = { - type = "fixed", - fixed = nodebox - }, - groups = groups, - walkable = false, - stack_max = 99, - drop = "mesecons:wire_00000000_off", - mesecons = {conductor={ +register_wires = function() + local nid = {} + while true do + -- Create group specifiction and nodeid string (see note above for details) + local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0") + ..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0") + + -- Calculate nodebox + local nodebox = {type = "fixed", fixed={box_center}} + for i=0,7 do + if nid[i] == 1 then + table.insert(nodebox.fixed, nbox_nid[i]) + end + end + + -- Add bump to nodebox if curved + if (nid[0] == 1 and nid[1] == 1) or (nid[1] == 1 and nid[2] == 1) + or (nid[2] == 1 and nid[3] == 1) or (nid[3] == 1 and nid[0] == 1) then + table.insert(nodebox.fixed, box_bump1) + end + + -- If nothing to connect to, still make a nodebox of a straight wire + if nodeid == "00000000" then + nodebox.fixed = {-8/16, -.5, -1/16, 8/16, -.5+1/16, 1/16} + end + + local rules = {} + if (nid[0] == 1) then table.insert(rules, vector.new( 1, 0, 0)) end + if (nid[1] == 1) then table.insert(rules, vector.new( 0, 0, 1)) end + if (nid[2] == 1) then table.insert(rules, vector.new(-1, 0, 0)) end + if (nid[3] == 1) then table.insert(rules, vector.new( 0, 0, -1)) end + + if (nid[0] == 1) then table.insert(rules, vector.new( 1, -1, 0)) end + if (nid[1] == 1) then table.insert(rules, vector.new( 0, -1, 1)) end + if (nid[2] == 1) then table.insert(rules, vector.new(-1, -1, 0)) end + if (nid[3] == 1) then table.insert(rules, vector.new( 0, -1, -1)) end + + if (nid[4] == 1) then table.insert(rules, vector.new( 1, 1, 0)) end + if (nid[5] == 1) then table.insert(rules, vector.new( 0, 1, 1)) end + if (nid[6] == 1) then table.insert(rules, vector.new(-1, 1, 0)) end + if (nid[7] == 1) then table.insert(rules, vector.new( 0, 1, -1)) end + + local meseconspec_off = { conductor = { + rules = rules, state = mesecon.state.off, onstate = "mesecons:wire_"..nodeid.."_on" }} - }) - minetest.register_node("mesecons:wire_"..nodeid.."_on", { - description = "Wire ID:"..nodeid, - drawtype = "nodebox", - tiles = tiles_on, --- inventory_image = "wires_inv.png", --- wield_image = "wires_inv.png", - inventory_image = "jeija_mesecon_off.png", - wield_image = "jeija_mesecon_off.png", - paramtype = "light", - paramtype2 = "facedir", - sunlight_propagates = true, - selection_box = { - type = "fixed", - fixed = {-.5, -.5, -.5, .5, -.5+4/16, .5} - }, - node_box = { - type = "fixed", - fixed = nodebox - }, - groups = {dig_immediate = 3, mesecon = 2, not_in_creative_inventory = 1}, - walkable = false, - stack_max = 99, - drop = "mesecons:wire_00000000_off", - mesecons = {conductor={ + local meseconspec_on = { conductor = { + rules = rules, state = mesecon.state.on, offstate = "mesecons:wire_"..nodeid.."_off" }} - }) -end -end -end -end -end -end -end -end --- Updating the wires: --- Place the right connection wire + local groups_on = {dig_immediate = 3, mesecon_conductor_craftable = 1, + not_in_creative_inventory = 1} + local groups_off = {dig_immediate = 3, mesecon_conductor_craftable = 1} + if nodeid ~= "00000000" then + groups_off["not_in_creative_inventory"] = 1 + end -local update_on_place_dig = function (pos, node) - if minetest.registered_nodes[node.name] - and minetest.registered_nodes[node.name].mesecons then - mesecon:update_autoconnect(pos) + mesecon.register_node("mesecons:wire_"..nodeid, { + description = "Mesecon", + drawtype = "nodebox", + inventory_image = "mesecons_wire_inv.png", + wield_image = "mesecons_wire_inv.png", + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + selection_box = selectionbox, + node_box = nodebox, + walkable = false, + drop = "mesecons:wire_00000000_off", + mesecon_wire = true + }, {tiles = tiles_off, mesecons = meseconspec_off, groups = groups_off}, + {tiles = tiles_on, mesecons = meseconspec_on, groups = groups_on}) + + if (nid_inc(nid) == false) then return end end end +register_wires() -minetest.register_on_placenode(update_on_place_dig) -minetest.register_on_dignode(update_on_place_dig) - -function mesecon:update_autoconnect(pos, secondcall, replace_old) - local xppos = {x=pos.x+1, y=pos.y, z=pos.z} - local zppos = {x=pos.x, y=pos.y, z=pos.z+1} - local xmpos = {x=pos.x-1, y=pos.y, z=pos.z} - local zmpos = {x=pos.x, y=pos.y, z=pos.z-1} - - local xpympos = {x=pos.x+1, y=pos.y-1, z=pos.z} - local zpympos = {x=pos.x, y=pos.y-1, z=pos.z+1} - local xmympos = {x=pos.x-1, y=pos.y-1, z=pos.z} - local zmympos = {x=pos.x, y=pos.y-1, z=pos.z-1} - - local xpypos = {x=pos.x+1, y=pos.y+1, z=pos.z} - local zpypos = {x=pos.x, y=pos.y+1, z=pos.z+1} - local xmypos = {x=pos.x-1, y=pos.y+1, z=pos.z} - local zmypos = {x=pos.x, y=pos.y+1, z=pos.z-1} - - if secondcall == nil then - mesecon:update_autoconnect(xppos, true) - mesecon:update_autoconnect(zppos, true) - mesecon:update_autoconnect(xmpos, true) - mesecon:update_autoconnect(zmpos, true) - - mesecon:update_autoconnect(xpypos, true) - mesecon:update_autoconnect(zpypos, true) - mesecon:update_autoconnect(xmypos, true) - mesecon:update_autoconnect(zmypos, true) - - mesecon:update_autoconnect(xpympos, true) - mesecon:update_autoconnect(zpympos, true) - mesecon:update_autoconnect(xmympos, true) - mesecon:update_autoconnect(zmympos, true) - end - - nodename = minetest.get_node(pos).name - if string.find(nodename, "mesecons:wire_") == nil and not replace_old then return nil end - - if mesecon:rules_link_anydir(pos, xppos) then xp = 1 else xp = 0 end - if mesecon:rules_link_anydir(pos, xmpos) then xm = 1 else xm = 0 end - if mesecon:rules_link_anydir(pos, zppos) then zp = 1 else zp = 0 end - if mesecon:rules_link_anydir(pos, zmpos) then zm = 1 else zm = 0 end - - if mesecon:rules_link_anydir(pos, xpympos) then xp = 1 end - if mesecon:rules_link_anydir(pos, xmympos) then xm = 1 end - if mesecon:rules_link_anydir(pos, zpympos) then zp = 1 end - if mesecon:rules_link_anydir(pos, zmympos) then zm = 1 end - - if mesecon:rules_link_anydir(pos, xpypos) then xpy = 1 else xpy = 0 end - if mesecon:rules_link_anydir(pos, zpypos) then zpy = 1 else zpy = 0 end - if mesecon:rules_link_anydir(pos, xmypos) then xmy = 1 else xmy = 0 end - if mesecon:rules_link_anydir(pos, zmypos) then zmy = 1 else zmy = 0 end - - if xpy == 1 then xp = 1 end - if zpy == 1 then zp = 1 end - if xmy == 1 then xm = 1 end - if zmy == 1 then zm = 1 end - - local nodeid = tostring(xp )..tostring(zp )..tostring(xm )..tostring(zm ).. - tostring(xpy)..tostring(zpy)..tostring(xmy)..tostring(zmy) - - - if string.find(nodename, "_off") ~= nil then - minetest.set_node(pos, {name = "mesecons:wire_"..nodeid.."_off"}) - else - minetest.set_node(pos, {name = "mesecons:wire_"..nodeid.."_on" }) - end -end - -if not minetest.registered_nodes["default:stone_with_mese"] then --before MESE update, use old recipes - minetest.register_craft({ - output = "mesecons:wire_00000000_off 18", - recipe = { - {"default:mese"}, - } - }) -else - - minetest.register_craft({ - type = "cooking", - output = "mesecons:wire_00000000_off 2", - recipe = "default:mese_crystal_fragment", - cooktime = 3, - }) - - minetest.register_craft({ - type = "cooking", - output = "mesecons:wire_00000000_off 18", - recipe = "default:mese_crystal", - cooktime = 15, - }) - - minetest.register_craft({ - type = "cooking", - output = "mesecons:wire_00000000_off 162", - recipe = "default:mese", - cooktime = 30, - }) - -end +-- ############## +-- ## Crafting ## +-- ############## +minetest.register_craft({ + type = "cooking", + output = "mesecons:wire_00000000_off 2", + recipe = "default:mese_crystal_fragment", + cooktime = 3, +}) minetest.register_craft({ type = "cooking", - output = "mesecons:wire_00000000_off 16", + output = "mesecons:wire_00000000_off 18", recipe = "default:mese_crystal", + cooktime = 15, +}) + +minetest.register_craft({ + type = "cooking", + output = "mesecons:wire_00000000_off 162", + recipe = "default:mese", + cooktime = 30, }) diff --git a/mods/mesecons/mesecons_blinkyplant/init.lua b/mods/mesecons/mesecons_blinkyplant/init.lua index f0ab81f9..c3bb3f74 100644 --- a/mods/mesecons/mesecons_blinkyplant/init.lua +++ b/mods/mesecons/mesecons_blinkyplant/init.lua @@ -1,98 +1,51 @@ -- The BLINKY_PLANT -minetest.register_node("mesecons_blinkyplant:blinky_plant", { - drawtype = "plantlike", - visual_scale = 1, - tiles = {"jeija_blinky_plant_off.png"}, - inventory_image = "jeija_blinky_plant_off.png", - walkable = false, - groups = {dig_immediate=3, not_in_creative_inventory=1}, - drop="mesecons_blinkyplant:blinky_plant_off 1", - description="Deactivated Blinky Plant", - sounds = default.node_sound_leaves_defaults(), - selection_box = { - type = "fixed", - fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3}, - }, - mesecons = {receptor = { - state = mesecon.state.off - }}, - on_rightclick = function(pos, node, clicker) - minetest.set_node(pos, {name="mesecons_blinkyplant:blinky_plant_off"}) - end -}) -minetest.register_node("mesecons_blinkyplant:blinky_plant_off", { - drawtype = "plantlike", - visual_scale = 1, - tiles = {"jeija_blinky_plant_off.png"}, - inventory_image = "jeija_blinky_plant_off.png", - paramtype = "light", - walkable = false, - groups = {dig_immediate=3, mesecon=2}, - description="Blinky Plant", - sounds = default.node_sound_leaves_defaults(), - selection_box = { - type = "fixed", - fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3}, - }, - mesecons = {receptor = { - state = mesecon.state.off - }}, - on_rightclick = function(pos, node, clicker) - minetest.set_node(pos, {name="mesecons_blinkyplant:blinky_plant"}) - end -}) - -minetest.register_node("mesecons_blinkyplant:blinky_plant_on", { - drawtype = "plantlike", - visual_scale = 1, - tiles = {"jeija_blinky_plant_on.png"}, - inventory_image = "jeija_blinky_plant_off.png", - paramtype = "light", - walkable = false, - groups = {dig_immediate=3, not_in_creative_inventory=1, mesecon=2}, - drop="mesecons_blinkyplant:blinky_plant_off 1", - light_source = LIGHT_MAX-7, - description = "Blinky Plant", - sounds = default.node_sound_leaves_defaults(), - selection_box = { - type = "fixed", - fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3}, - }, - mesecons = {receptor = { - state = mesecon.state.on - }}, - on_rightclick = function(pos, node, clicker) - minetest.set_node(pos, {name = "mesecons_blinkyplant:blinky_plant"}) - mesecon:receptor_off(pos) +local toggle_timer = function (pos) + local timer = minetest.get_node_timer(pos) + if timer:is_started() then + timer:stop() + else + timer:start(mesecon.setting("blinky_plant_interval", 3)) end +end + +local on_timer = function (pos) + local node = minetest.get_node(pos) + if(mesecon.flipstate(pos, node) == "on") then + mesecon.receptor_on(pos) + else + mesecon.receptor_off(pos) + end + toggle_timer(pos) +end + +mesecon.register_node("mesecons_blinkyplant:blinky_plant", { + description="Blinky Plant", + drawtype = "plantlike", + inventory_image = "jeija_blinky_plant_off.png", + paramtype = "light", + walkable = false, + sounds = default.node_sound_leaves_defaults(), + selection_box = { + type = "fixed", + fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3}, + }, + on_timer = on_timer, + on_rightclick = toggle_timer, + on_construct = toggle_timer +},{ + tiles = {"jeija_blinky_plant_off.png"}, + groups = {dig_immediate=3}, + mesecons = {receptor = { state = mesecon.state.off }} +},{ + tiles = {"jeija_blinky_plant_on.png"}, + groups = {dig_immediate=3, not_in_creative_inventory=1}, + mesecons = {receptor = { state = mesecon.state.on }} }) minetest.register_craft({ output = "mesecons_blinkyplant:blinky_plant_off 1", - recipe = { - {"","group:mesecon_conductor_craftable",""}, - {"","group:mesecon_conductor_craftable",""}, - {"default:sapling","default:sapling","default:sapling"}, - } + recipe = { {"","group:mesecon_conductor_craftable",""}, + {"","group:mesecon_conductor_craftable",""}, + {"default:sapling","default:sapling","default:sapling"}} }) - -minetest.register_abm({ - nodenames = { - "mesecons_blinkyplant:blinky_plant_off", - "mesecons_blinkyplant:blinky_plant_on" - }, - interval = BLINKY_PLANT_INTERVAL, - chance = 1, - action = function(pos, node, active_object_count, active_object_count_wider) - if node.name == "mesecons_blinkyplant:blinky_plant_off" then - minetest.add_node(pos, {name="mesecons_blinkyplant:blinky_plant_on"}) - mesecon:receptor_on(pos) - else - minetest.add_node(pos, {name="mesecons_blinkyplant:blinky_plant_off"}) - mesecon:receptor_off(pos) - end - nodeupdate(pos) - end, -}) - diff --git a/mods/mesecons/mesecons_button/init.lua b/mods/mesecons/mesecons_button/init.lua index f4a91984..f147d8f5 100644 --- a/mods/mesecons/mesecons_button/init.lua +++ b/mods/mesecons/mesecons_button/init.lua @@ -8,7 +8,7 @@ mesecon.button_turnoff = function (pos) minetest.swap_node(pos, {name = "mesecons_button:button_off", param2=node.param2}) minetest.sound_play("mesecons_button_pop", {pos=pos}) local rules = mesecon.rules.buttonlike_get(node) - mesecon:receptor_off(pos, rules) + mesecon.receptor_off(pos, rules) end end @@ -42,7 +42,7 @@ minetest.register_node("mesecons_button:button_off", { description = "Button", on_punch = function (pos, node) minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2}) - mesecon:receptor_on(pos, mesecon.rules.buttonlike_get(node)) + mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node)) minetest.sound_play("mesecons_button_push", {pos=pos}) minetest.after(1, mesecon.button_turnoff, pos) end, diff --git a/mods/mesecons/mesecons_compatibility/init.lua b/mods/mesecons/mesecons_compatibility/init.lua index 5bdce27b..0ad04b2a 100644 --- a/mods/mesecons/mesecons_compatibility/init.lua +++ b/mods/mesecons/mesecons_compatibility/init.lua @@ -15,6 +15,17 @@ doors = {} -- selection_box_top -- only_placer_can_open: if true only the player who placed the door can -- open it +local function is_right(pos) + local r1 = minetest.get_node({x=pos.x-1, y=pos.y, z=pos.z}) + local r2 = minetest.get_node({x=pos.x, y=pos.y, z=pos.z-1}) + if string.find(r1.name, "door_") or string.find(r2.name, "door_") then + if string.find(r1.name, "_1") or string.find(r2.name, "_1") then + return true + else + return false + end + end +end function doors:register_door(name, def) def.groups.not_in_creative_inventory = 1 @@ -59,6 +70,19 @@ function doors:register_door(name, def) meta = minetest.get_meta(pos):to_table() minetest.set_node(pos, {name=replace, param2=p2}) minetest.get_meta(pos):from_table(meta) + + local snd_1 = "_close" + local snd_2 = "_open" + if params[1] == 3 then + snd_1 = "_open" + snd_2 = "_close" + end + + if is_right(pos) then + minetest.sound_play("door"..snd_1, {pos = pos, gain = 0.3, max_hear_distance = 10}) + else + minetest.sound_play("door"..snd_2, {pos = pos, gain = 0.3, max_hear_distance = 10}) + end end local function on_mesecons_signal_open (pos, node) diff --git a/mods/mesecons/mesecons_delayer/init.lua b/mods/mesecons/mesecons_delayer/init.lua index 239d3784..ba4067f8 100644 --- a/mods/mesecons/mesecons_delayer/init.lua +++ b/mods/mesecons/mesecons_delayer/init.lua @@ -2,7 +2,7 @@ local delayer_get_output_rules = function(node) local rules = {{x = 0, y = 0, z = 1}} for i = 0, node.param2 do - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) end return rules end @@ -10,7 +10,7 @@ end local delayer_get_input_rules = function(node) local rules = {{x = 0, y = 0, z = -1}} for i = 0, node.param2 do - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) end return rules end diff --git a/mods/mesecons/mesecons_detector/init.lua b/mods/mesecons/mesecons_detector/init.lua index 8d2f53c9..1a8595d4 100644 --- a/mods/mesecons/mesecons_detector/init.lua +++ b/mods/mesecons/mesecons_detector/init.lua @@ -23,7 +23,7 @@ end -- returns true if player was found, false if not local object_detector_scan = function (pos) - local objs = minetest.get_objects_inside_radius(pos, OBJECT_DETECTOR_RADIUS) + local objs = minetest.get_objects_inside_radius(pos, mesecon.setting("detector_radius", 6)) for k, obj in pairs(objs) do local isname = obj:get_player_name() -- "" is returned if it is not a player; "" ~= nil! local scanname = minetest.get_meta(pos):get_string("scanname") @@ -55,7 +55,8 @@ minetest.register_node("mesecons_detector:object_detector_off", { groups = {cracky=3}, description="Player Detector", mesecons = {receptor = { - state = mesecon.state.off + state = mesecon.state.off, + rules = mesecon.rules.pplate }}, on_construct = object_detector_make_formspec, on_receive_fields = object_detector_on_receive_fields, @@ -70,7 +71,8 @@ minetest.register_node("mesecons_detector:object_detector_on", { groups = {cracky=3,not_in_creative_inventory=1}, drop = 'mesecons_detector:object_detector_off', mesecons = {receptor = { - state = mesecon.state.on + state = mesecon.state.on, + rules = mesecon.rules.pplate }}, on_construct = object_detector_make_formspec, on_receive_fields = object_detector_on_receive_fields, @@ -94,7 +96,7 @@ minetest.register_abm( action = function(pos) if object_detector_scan(pos) then minetest.swap_node(pos, {name = "mesecons_detector:object_detector_on"}) - mesecon:receptor_on(pos) + mesecon.receptor_on(pos, mesecon.rules.pplate) end end, }) @@ -106,7 +108,7 @@ minetest.register_abm( action = function(pos) if not object_detector_scan(pos) then minetest.swap_node(pos, {name = "mesecons_detector:object_detector_off"}) - mesecon:receptor_off(pos) + mesecon.receptor_off(pos, mesecon.rules.pplate) end end, }) @@ -248,7 +250,7 @@ minetest.register_abm( action = function(pos, node) if node_detector_scan(pos) then minetest.swap_node(pos, {name = "mesecons_detector:node_detector_on", param2 = node.param2}) - mesecon:receptor_on(pos) + mesecon.receptor_on(pos) end end, }) @@ -260,7 +262,7 @@ minetest.register_abm( action = function(pos, node) if not node_detector_scan(pos) then minetest.swap_node(pos, {name = "mesecons_detector:node_detector_off", param2 = node.param2}) - mesecon:receptor_off(pos) + mesecon.receptor_off(pos) end end, }) diff --git a/mods/mesecons/mesecons_extrawires/corner.lua b/mods/mesecons/mesecons_extrawires/corner.lua index d7f7a029..003275a4 100644 --- a/mods/mesecons/mesecons_extrawires/corner.lua +++ b/mods/mesecons/mesecons_extrawires/corner.lua @@ -15,7 +15,7 @@ local corner_get_rules = function (node) {x = 0, y = 0, z = -1}} for i = 0, node.param2 do - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) end return rules diff --git a/mods/mesecons/mesecons_extrawires/mesewire.lua b/mods/mesecons/mesecons_extrawires/mesewire.lua index cbb882ea..150178c1 100644 --- a/mods/mesecons/mesecons_extrawires/mesewire.lua +++ b/mods/mesecons/mesecons_extrawires/mesewire.lua @@ -8,12 +8,7 @@ local mesewire_rules = {x = 0, y = 0, z =-1}, } -minetest.register_node(":default:mese", { - description = "Mese Block", - tiles = {minetest.registered_nodes["default:mese"].tiles[1]}, - is_ground_content = true, - groups = {cracky=1}, - sounds = default.node_sound_stone_defaults(), +minetest.override_item("default:mese", { mesecons = {conductor = { state = mesecon.state.off, onstate = "mesecons_extrawires:mese_powered", diff --git a/mods/mesecons/mesecons_extrawires/tjunction.lua b/mods/mesecons/mesecons_extrawires/tjunction.lua index c5f36a21..680dc99a 100644 --- a/mods/mesecons/mesecons_extrawires/tjunction.lua +++ b/mods/mesecons/mesecons_extrawires/tjunction.lua @@ -16,7 +16,7 @@ local tjunction_get_rules = function (node) {x = 0, y = 0, z = -1}} for i = 0, node.param2 do - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) end return rules diff --git a/mods/mesecons/mesecons_extrawires/vertical.lua b/mods/mesecons/mesecons_extrawires/vertical.lua index 16de55e1..cac2ae23 100644 --- a/mods/mesecons/mesecons_extrawires/vertical.lua +++ b/mods/mesecons/mesecons_extrawires/vertical.lua @@ -18,7 +18,7 @@ local bottom_box = { local vertical_rules = { {x=0, y=1, z=0}, - {x=0, y=-1, z=0}, + {x=0, y=-1, z=0} } local top_rules = { @@ -26,7 +26,7 @@ local top_rules = { {x=-1,y=0, z=0}, {x=0,y=0, z=1}, {x=0,y=0, z=-1}, - {x=0,y=-1, z=0}, + {x=0,y=-1, z=0} } local bottom_rules = { @@ -35,107 +35,79 @@ local bottom_rules = { {x=0, y=0, z=1}, {x=0, y=0, z=-1}, {x=0, y=1, z=0}, + {x=0, y=2, z=0} -- receive power from pressure plate / detector / ... 2 nodes above } local vertical_updatepos = function (pos) local node = minetest.get_node(pos) - if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].is_vertical_conductor then - local node_above = minetest.get_node(mesecon:addPosRule(pos, vertical_rules[1])) - local node_below = minetest.get_node(mesecon:addPosRule(pos, vertical_rules[2])) + if minetest.registered_nodes[node.name] + and minetest.registered_nodes[node.name].is_vertical_conductor then + local node_above = minetest.get_node(mesecon.addPosRule(pos, vertical_rules[1])) + local node_below = minetest.get_node(mesecon.addPosRule(pos, vertical_rules[2])) local namestate = minetest.registered_nodes[node.name].vertical_conductor_state - local above = minetest.registered_nodes[node_above.name] and minetest.registered_nodes[node_above.name].is_vertical_conductor - local below = minetest.registered_nodes[node_below.name] and minetest.registered_nodes[node_below.name].is_vertical_conductor + local above = minetest.registered_nodes[node_above.name] + and minetest.registered_nodes[node_above.name].is_vertical_conductor + local below = minetest.registered_nodes[node_below.name] + and minetest.registered_nodes[node_below.name].is_vertical_conductor + local basename = "mesecons_extrawires:vertical_" if above and below then -- above and below: vertical mesecon - minetest.add_node(pos, {name = "mesecons_extrawires:vertical_" .. namestate}) + minetest.add_node(pos, {name = basename .. namestate}) elseif above and not below then -- above only: bottom - minetest.add_node(pos, {name = "mesecons_extrawires:vertical_bottom_" .. namestate}) + minetest.add_node(pos, {name = basename .. "bottom_" .. namestate}) elseif not above and below then -- below only: top - minetest.add_node(pos, {name = "mesecons_extrawires:vertical_top_" .. namestate}) - else -- no vertical wire above, no vertical wire below: use default wire - minetest.add_node(pos, {name = "mesecons_extrawires:vertical_" .. namestate}) + minetest.add_node(pos, {name = basename .. "top_" .. namestate}) + else -- no vertical wire above, no vertical wire below: use bottom + minetest.add_node(pos, {name = basename .. "bottom_" .. namestate}) end + mesecon.update_autoconnect(pos) end end local vertical_update = function (pos, node) vertical_updatepos(pos) -- this one - vertical_updatepos(mesecon:addPosRule(pos, vertical_rules[1])) -- above - vertical_updatepos(mesecon:addPosRule(pos, vertical_rules[2])) -- below + vertical_updatepos(mesecon.addPosRule(pos, vertical_rules[1])) -- above + vertical_updatepos(mesecon.addPosRule(pos, vertical_rules[2])) -- below end -- Vertical wire -minetest.register_node("mesecons_extrawires:vertical_on", { +mesecon.register_node("mesecons_extrawires:vertical", { description = "Vertical mesecon", drawtype = "nodebox", - tiles = {"wires_vertical_on.png"}, walkable = false, paramtype = "light", sunlight_propagates = true, - groups = {dig_immediate=3, not_in_creative_inventory=1}, selection_box = vertical_box, node_box = vertical_box, is_vertical_conductor = true, - vertical_conductor_state = "on", - mesecons = {conductor = { - state = mesecon.state.on, - offstate = "mesecons_extrawires:vertical_off", - rules = vertical_rules, - }}, drop = "mesecons_extrawires:vertical_off", after_place_node = vertical_update, - after_dig_node = vertical_update, -}) - -minetest.register_node("mesecons_extrawires:vertical_off", { - description = "Vertical mesecon", - drawtype = "nodebox", - tiles = {"wires_vertical_off.png"}, - walkable = false, - paramtype = "light", - sunlight_propagates = true, + after_dig_node = vertical_update +},{ + tiles = {"mesecons_wire_off.png"}, groups = {dig_immediate=3}, - selection_box = vertical_box, - node_box = vertical_box, - is_vertical_conductor = true, vertical_conductor_state = "off", mesecons = {conductor = { state = mesecon.state.off, onstate = "mesecons_extrawires:vertical_on", rules = vertical_rules, - }}, - after_place_node = vertical_update, - after_dig_node = vertical_update, -}) - --- Vertical wire top -minetest.register_node("mesecons_extrawires:vertical_top_on", { - description = "Vertical mesecon", - drawtype = "nodebox", - tiles = {"wires_full_on.png","wires_full_on.png","wires_vertical_on.png"}, - walkable = false, - paramtype = "light", - sunlight_propagates = true, + }} +},{ + tiles = {"mesecons_wire_on.png"}, groups = {dig_immediate=3, not_in_creative_inventory=1}, - selection_box = top_box, - node_box = top_box, - is_vertical_conductor = true, vertical_conductor_state = "on", mesecons = {conductor = { state = mesecon.state.on, - offstate = "mesecons_extrawires:vertical_top_off", - rules = top_rules, - }}, - drop = "mesecons_extrawires:vertical_off", - after_place_node = vertical_update, - after_dig_node = vertical_update, + offstate = "mesecons_extrawires:vertical_off", + rules = vertical_rules, + }} }) -minetest.register_node("mesecons_extrawires:vertical_top_off", { +-- Vertical wire top +mesecon.register_node("mesecons_extrawires:vertical_top", { description = "Vertical mesecon", drawtype = "nodebox", - tiles = {"wires_full_off.png","wires_full_off.png","wires_vertical_off.png"}, walkable = false, paramtype = "light", sunlight_propagates = true, @@ -143,43 +115,31 @@ minetest.register_node("mesecons_extrawires:vertical_top_off", { selection_box = top_box, node_box = top_box, is_vertical_conductor = true, + drop = "mesecons_extrawires:vertical_off", + after_place_node = vertical_update, + after_dig_node = vertical_update +},{ + tiles = {"mesecons_wire_off.png"}, vertical_conductor_state = "off", mesecons = {conductor = { state = mesecon.state.off, onstate = "mesecons_extrawires:vertical_top_on", rules = top_rules, - }}, - drop = "mesecons_extrawires:vertical_off", - after_place_node = vertical_update, - after_dig_node = vertical_update, + }} +},{ + tiles = {"mesecons_wire_on.png"}, + vertical_conductor_state = "on", + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_extrawires:vertical_top_off", + rules = top_rules, + }} }) -- Vertical wire bottom -minetest.register_node("mesecons_extrawires:vertical_bottom_on", { +mesecon.register_node("mesecons_extrawires:vertical_bottom", { description = "Vertical mesecon", drawtype = "nodebox", - tiles = {"wires_full_on.png","wires_full_on.png","wires_vertical_on.png"}, - walkable = false, - paramtype = "light", - sunlight_propagates = true, - vertical_conductor_state = "on", - groups = {dig_immediate = 3, not_in_creative_inventory = 1}, - selection_box = bottom_box, - node_box = bottom_box, - mesecons = {conductor = { - state = mesecon.state.on, - offstate = "mesecons_extrawires:vertical_bottom_off", - rules = bottom_rules, - }}, - drop = "mesecons_extrawires:vertical_off", - after_place_node = vertical_update, - after_dig_node = vertical_update, -}) - -minetest.register_node("mesecons_extrawires:vertical_bottom_off", { - description = "Vertical mesecon", - drawtype = "nodebox", - tiles = {"wires_full_off.png","wires_full_off.png","wires_vertical_off.png"}, walkable = false, paramtype = "light", sunlight_propagates = true, @@ -187,15 +147,25 @@ minetest.register_node("mesecons_extrawires:vertical_bottom_off", { selection_box = bottom_box, node_box = bottom_box, is_vertical_conductor = true, + drop = "mesecons_extrawires:vertical_off", + after_place_node = vertical_update, + after_dig_node = vertical_update +},{ + tiles = {"mesecons_wire_off.png"}, vertical_conductor_state = "off", mesecons = {conductor = { state = mesecon.state.off, onstate = "mesecons_extrawires:vertical_bottom_on", rules = bottom_rules, - }}, - drop = "mesecons_extrawires:vertical_off", - after_place_node = vertical_update, - after_dig_node = vertical_update, + }} +},{ + tiles = {"mesecons_wire_on.png"}, + vertical_conductor_state = "on", + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_extrawires:vertical_bottom_off", + rules = bottom_rules, + }} }) minetest.register_craft({ diff --git a/mods/mesecons/mesecons_gates/init.lua b/mods/mesecons/mesecons_gates/init.lua index a22edf68..345c32c5 100644 --- a/mods/mesecons/mesecons_gates/init.lua +++ b/mods/mesecons/mesecons_gates/init.lua @@ -1,6 +1,6 @@ function gate_rotate_rules(node) for rotations = 0, node.param2 - 1 do - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) end return rules end @@ -53,11 +53,11 @@ function set_gate(pos, on) local node = minetest.get_node(pos) if on then minetest.swap_node(pos, {name = "mesecons_gates:"..gate.."_on", param2=node.param2}) - mesecon:receptor_on(pos, + mesecon.receptor_on(pos, gate_get_output_rules(node)) else minetest.swap_node(pos, {name = "mesecons_gates:"..gate.."_off", param2=node.param2}) - mesecon:receptor_off(pos, + mesecon.receptor_off(pos, gate_get_output_rules(node)) end end @@ -77,7 +77,7 @@ function pop_gate(pos) gate = get_gate(pos) minetest.remove_node(pos) minetest.after(0.2, function (pos) - mesecon:receptor_off(pos, mesecon.rules.flat) + mesecon.receptor_off(pos, mesecon.rules.flat) end , pos) -- wait for pending parsings minetest.add_item(pos, "mesecons_gates:"..gate.."_off") end diff --git a/mods/mesecons/mesecons_hydroturbine/init.lua b/mods/mesecons/mesecons_hydroturbine/init.lua index ef5ccae8..36bd4986 100644 --- a/mods/mesecons/mesecons_hydroturbine/init.lua +++ b/mods/mesecons/mesecons_hydroturbine/init.lua @@ -66,7 +66,7 @@ nodenames = {"mesecons_hydroturbine:hydro_turbine_off"}, if minetest.get_node(waterpos).name=="default:water_flowing" then minetest.add_node(pos, {name="mesecons_hydroturbine:hydro_turbine_on"}) nodeupdate(pos) - mesecon:receptor_on(pos) + mesecon.receptor_on(pos) end end, }) @@ -80,7 +80,7 @@ nodenames = {"mesecons_hydroturbine:hydro_turbine_on"}, if minetest.get_node(waterpos).name~="default:water_flowing" then minetest.add_node(pos, {name="mesecons_hydroturbine:hydro_turbine_off"}) nodeupdate(pos) - mesecon:receptor_off(pos) + mesecon.receptor_off(pos) end end, }) diff --git a/mods/mesecons/mesecons_insulated/init.lua b/mods/mesecons/mesecons_insulated/init.lua index 9fdf494e..c6fc05ee 100644 --- a/mods/mesecons/mesecons_insulated/init.lua +++ b/mods/mesecons/mesecons_insulated/init.lua @@ -2,7 +2,7 @@ function insulated_wire_get_rules(node) local rules = {{x = 1, y = 0, z = 0}, {x =-1, y = 0, z = 0}} if node.param2 == 1 or node.param2 == 3 then - return mesecon:rotate_rules_right(rules) + return mesecon.rotate_rules_right(rules) end return rules end @@ -41,7 +41,7 @@ minetest.register_node("mesecons_insulated:insulated_on", { minetest.register_node("mesecons_insulated:insulated_off", { drawtype = "nodebox", - description = "insulated mesecons", + description = "Insulated Mesecon", tiles = { "jeija_insulated_wire_sides_off.png", "jeija_insulated_wire_sides_off.png", @@ -78,7 +78,3 @@ minetest.register_craft({ {"mesecons_materials:fiber", "mesecons_materials:fiber", "mesecons_materials:fiber"}, } }) - -mesecon:add_rules("insulated", { -{x = 1, y = 0, z = 0}, -{x =-1, y = 0, z = 0}}) diff --git a/mods/mesecons/mesecons_lightstone/init.lua b/mods/mesecons/mesecons_lightstone/init.lua index 7bb550d1..5ed8f15b 100644 --- a/mods/mesecons/mesecons_lightstone/init.lua +++ b/mods/mesecons/mesecons_lightstone/init.lua @@ -14,7 +14,7 @@ local lightstone_rules = { {x=0, y=-1, z=0}, } -function mesecon:lightstone_add(name, base_item, texture_off, texture_on) +function mesecon.lightstone_add(name, base_item, texture_off, texture_on) minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_off", { tiles = {texture_off}, groups = {cracky=2, mesecon_effector_off = 1, mesecon = 2}, @@ -52,9 +52,9 @@ function mesecon:lightstone_add(name, base_item, texture_off, texture_on) end -mesecon:lightstone_add("red", "default:clay_brick", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png") -mesecon:lightstone_add("green", "default:cactus", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png") -mesecon:lightstone_add("blue", "mesecons_materials:fiber", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png") -mesecon:lightstone_add("gray", "default:cobble", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png") -mesecon:lightstone_add("darkgray", "default:gravel", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png") -mesecon:lightstone_add("yellow", "default:mese_crystal_fragment", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png") +mesecon.lightstone_add("red", "default:clay_brick", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png") +mesecon.lightstone_add("green", "default:cactus", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png") +mesecon.lightstone_add("blue", "mesecons_materials:fiber", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png") +mesecon.lightstone_add("gray", "default:cobble", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png") +mesecon.lightstone_add("darkgray", "default:gravel", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png") +mesecon.lightstone_add("yellow", "default:mese_crystal_fragment", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png") diff --git a/mods/mesecons/mesecons_luacontroller/init.lua b/mods/mesecons/mesecons_luacontroller/init.lua index f4869b51..637b2e5e 100644 --- a/mods/mesecons/mesecons_luacontroller/init.lua +++ b/mods/mesecons/mesecons_luacontroller/init.lua @@ -38,10 +38,6 @@ function lc_update_real_portstates(pos, rulename, newstate) return end local n = meta:get_int("real_portstates") - 1 - if n < 0 then - legacy_update_ports(pos) - n = meta:get_int("real_portstates") - 1 - end local L = {} for i = 1, 4 do L[i] = n%2 @@ -63,9 +59,6 @@ local get_real_portstates = function(pos) -- determine if ports are powered (by local meta = minetest.get_meta(pos) local L = {} local n = meta:get_int("real_portstates") - 1 - if n < 0 then - return legacy_update_ports(pos) - end for _, index in ipairs({"a", "b", "c", "d"}) do L[index] = ((n%2) == 1) n = math.floor(n/2) @@ -83,7 +76,6 @@ local merge_portstates = function (ports, vports) end local generate_name = function (ports) - local overwrite = overwrite or {} local d = ports.d and 1 or 0 local c = ports.c and 1 or 0 local b = ports.b and 1 or 0 @@ -93,9 +85,9 @@ end local setport = function (pos, rule, state) if state then - mesecon:receptor_on(pos, {rule}) + mesecon.receptor_on(pos, {rule}) else - mesecon:receptor_off(pos, {rule}) + mesecon.receptor_off(pos, {rule}) end end @@ -123,7 +115,7 @@ end -------------------- local overheat_off = function(pos) - mesecon:receptor_off(pos, mesecon.rules.flat) + mesecon.receptor_off(pos, mesecon.rules.flat) end ------------------- @@ -168,7 +160,7 @@ local safe_serialize = function(value) return minetest.serialize(deep_copy(value)) end -mesecon.queue:add_function("lc_interrupt", function (pos, iid, luac_id) +mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid) -- There is no luacontroller anymore / it has been reprogrammed / replaced if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end lc_update(pos, {type="interrupt", iid = iid}) @@ -177,8 +169,8 @@ end) local getinterrupt = function(pos) local interrupt = function (time, iid) -- iid = interrupt id if type(time) ~= "number" then return end - luac_id = minetest.get_meta(pos):get_int("luac_id") - mesecon.queue:add_action(pos, "lc_interrupt", {iid, luac_id}, time, iid, 1) + local luac_id = minetest.get_meta(pos):get_int("luac_id") + mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1) end return interrupt end @@ -209,7 +201,8 @@ local create_environment = function(pos, mem, event) tostring = tostring, tonumber = tonumber, heat = minetest.get_meta(pos):get_int("heat"), - heat_max = OVERHEAT_MAX, + -- overheat_max Unit: actions per second, checks are every 1 second + heat_max = mesecon.setting("overheat_max", 20), string = { byte = string.byte, char = string.char, @@ -271,7 +264,7 @@ local create_sandbox = function (code, env) if code:byte(1) == 27 then return _, "You Hacker You! Don't use binary code!" end - f, msg = loadstring(code) + local f, msg = loadstring(code) if not f then return _, msg end setfenv(f, env) return f @@ -321,7 +314,7 @@ lc_update = function (pos, event) -- create the sandbox and execute code local chunk, msg = create_sandbox (code, env) if not chunk then return msg end - local success, msg = pcall(f) + local success, msg = pcall(chunk) if not success then return msg end if ports_invalid(env.port) then return ports_invalid(env.port) end @@ -477,7 +470,6 @@ minetest.register_node(nodename, { reset_meta(pos, fields.code, err) end end, - on_timer = handle_timer, sounds = default.node_sound_stone_defaults(), mesecons = mesecons, digiline = digiline, @@ -486,7 +478,7 @@ minetest.register_node(nodename, { c = c == 1, -- controller powers itself d = d == 1},-- so those that light up after_dig_node = function (pos, node) - mesecon:receptor_off(pos, output_rules) + mesecon.receptor_off(pos, output_rules) end, is_luacontroller = true, }) diff --git a/mods/mesecons/mesecons_microcontroller/init.lua b/mods/mesecons/mesecons_microcontroller/init.lua index 8c9f3b8c..7e290a36 100644 --- a/mods/mesecons/mesecons_microcontroller/init.lua +++ b/mods/mesecons/mesecons_microcontroller/init.lua @@ -1,5 +1,7 @@ EEPROM_SIZE = 255 +local microc_rules = {} + for a = 0, 1 do for b = 0, 1 do for c = 0, 1 do @@ -34,7 +36,7 @@ if (a == 0) then table.insert(input_rules, {x = -1, y = 0, z = 0, name = "A"}) if (b == 0) then table.insert(input_rules, {x = 0, y = 0, z = 1, name = "B"}) end if (c == 0) then table.insert(input_rules, {x = 1, y = 0, z = 0, name = "C"}) end if (d == 0) then table.insert(input_rules, {x = 0, y = 0, z = -1, name = "D"}) end -mesecon:add_rules(nodename, rules) +microc_rules[nodename] = rules local mesecons = {effector = { @@ -131,8 +133,8 @@ minetest.register_node(nodename, { sounds = default.node_sound_stone_defaults(), mesecons = mesecons, after_dig_node = function (pos, node) - rules = mesecon:get_rules(node.name) - mesecon:receptor_off(pos, rules) + rules = microc_rules[node.name] + mesecon.receptor_off(pos, rules) end, }) end @@ -164,7 +166,7 @@ function update_yc(pos) if (mesecon.do_overheat(pos)) then minetest.remove_node(pos) minetest.after(0.2, function (pos) - mesecon:receptor_off(pos, mesecon.rules.flat) + mesecon.receptor_off(pos, mesecon.rules.flat) end , pos) -- wait for pending parsings minetest.add_item(pos, "mesecons_microcontroller:microcontroller0000") end @@ -183,7 +185,7 @@ end --Code Parsing function yc_code_remove_commentary(code) - is_string = false + local is_string = false for i = 1, #code do if code:sub(i, i) == '"' then is_string = not is_string --toggle is_string @@ -203,15 +205,17 @@ function yc_parsecode(code, pos) local c local eeprom = meta:get_string("eeprom") while true do + local command, params command, endi = parse_get_command(code, endi) if command == nil then return nil end if command == true then break end --end of code if command == "if" then + local r r, endi = yc_command_if(code, endi, yc_merge_portstates(Lreal, Lvirtual), eeprom) if r == nil then return nil end if r == true then -- nothing elseif r == false then - endi_new = yc_skip_to_else (code, endi) + local endi_new = yc_skip_to_else (code, endi) if endi_new == nil then --else > not found endi = yc_skip_to_endif(code, endi) else @@ -221,7 +225,7 @@ function yc_parsecode(code, pos) end else params, endi = parse_get_params(code, endi) - if params == nil then return nil end + if not params then return nil end end if command == "on" then L = yc_command_on (params, Lvirtual) @@ -234,6 +238,7 @@ function yc_parsecode(code, pos) local su = yc_command_after(params, pos) if su == nil then return nil end elseif command == "sbi" then + local new_eeprom new_eeprom, Lvirtual = yc_command_sbi (params, eeprom, yc_merge_portstates(Lreal, Lvirtual), Lvirtual) if new_eeprom == nil then return nil else eeprom = new_eeprom end @@ -251,7 +256,7 @@ end function parse_get_command(code, starti) i = starti - s = nil + local s while s ~= "" do s = string.sub(code, i, i) if s == "(" then @@ -277,7 +282,7 @@ end function parse_get_params(code, starti) i = starti - s = nil + local s local params = {} local is_string = false while s ~= "" do @@ -300,7 +305,7 @@ end function yc_parse_get_eeprom_param(cond, starti) i = starti - s = nil + local s local addr while s ~= "" do s = string.sub(cond, i, i) @@ -403,7 +408,7 @@ function yc_command_sbi(params, eeprom, L, Lv) end --is an eeprom address - new_eeprom = ""; + local new_eeprom = ""; for i=1, #eeprom do if tonumber(params[1])==i then new_eeprom = new_eeprom..status @@ -457,17 +462,17 @@ function yc_command_if(code, starti, L, eeprom) cond = yc_command_parsecondition(cond, L, eeprom) + local result if cond == "0" then result = false - elseif cond == "1" then result = true - else result = nil end - if result == nil then end + elseif cond == "1" then result = true end + if not result then end return result, endi --endi from local cond, endi = yc_command_if_getcondition(code, starti) end --Condition parsing function yc_command_if_getcondition(code, starti) i = starti - s = nil + local s local brackets = 1 --1 Bracket to close while s ~= "" do s = string.sub(code, i, i) @@ -501,8 +506,8 @@ function yc_command_parsecondition(cond, L, eeprom) while i<=l do local s = cond:sub(i,i) if s == "#" then - addr, endi = yc_parse_get_eeprom_param(cond, i+1) - buf = yc_eeprom_read(tonumber(addr), eeprom) + local addr, endi = yc_parse_get_eeprom_param(cond, i+1) + local buf = yc_eeprom_read(tonumber(addr), eeprom) if buf == nil then return nil end local call = cond:sub(i, endi-1) cond = string.gsub(cond, call, buf) @@ -576,10 +581,8 @@ end --Virtual-Hardware functions function yc_eeprom_read(number, eeprom) - if number == nil then return nil, nil end - value = eeprom:sub(number, number) - if value == nil then return nil, nil end - return value, endi + if not number then return end + return eeprom:sub(number, number) end --Real I/O functions @@ -600,24 +603,24 @@ function yc_action_setports(pos, L, Lv) local name = "mesecons_microcontroller:microcontroller" local rules if Lv.a ~= L.a then - rules = mesecon:get_rules(name.."0001") - if L.a == true then mesecon:receptor_on(pos, rules) - else mesecon:receptor_off(pos, rules) end + rules = microc_rules[name.."0001"] + if L.a == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end end if Lv.b ~= L.b then - rules = mesecon:get_rules(name.."0010") - if L.b == true then mesecon:receptor_on(pos, rules) - else mesecon:receptor_off(pos, rules) end + rules = microc_rules[name.."0010"] + if L.b == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end end if Lv.c ~= L.c then - rules = mesecon:get_rules(name.."0100") - if L.c == true then mesecon:receptor_on(pos, rules) - else mesecon:receptor_off(pos, rules) end + rules = microc_rules[name.."0100"] + if L.c == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end end if Lv.d ~= L.d then - rules = mesecon:get_rules(name.."1000") - if L.d == true then mesecon:receptor_on(pos, rules) - else mesecon:receptor_off(pos, rules) end + rules = microc_rules[name.."1000"] + if L.d == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end end end @@ -637,10 +640,6 @@ function yc_update_real_portstates(pos, node, rulename, newstate) return end local n = meta:get_int("real_portstates") - 1 - if n < 0 then - legacy_update_ports(pos) - n = meta:get_int("real_portstates") - 1 - end local L = {} for i = 1, 4 do L[i] = n%2 @@ -662,9 +661,6 @@ function yc_get_real_portstates(pos) -- determine if ports are powered (by itsel local meta = minetest.get_meta(pos) local L = {} local n = meta:get_int("real_portstates") - 1 - if n < 0 then - return legacy_update_ports(pos) - end for _, index in ipairs({"a", "b", "c", "d"}) do L[index] = ((n%2) == 1) n = math.floor(n/2) @@ -673,12 +669,12 @@ function yc_get_real_portstates(pos) -- determine if ports are powered (by itsel end function yc_get_virtual_portstates(pos) -- portstates according to the name - name = minetest.get_node(pos).name - b, a = string.find(name, ":microcontroller") + local name = minetest.get_node(pos).name + local b, a = string.find(name, ":microcontroller") if a == nil then return nil end a = a + 1 - Lvirtual = {a=false, b=false, c=false, d=false} + local Lvirtual = {a=false, b=false, c=false, d=false} if name:sub(a , a ) == "1" then Lvirtual.d = true end if name:sub(a+1, a+1) == "1" then Lvirtual.c = true end if name:sub(a+2, a+2) == "1" then Lvirtual.b = true end diff --git a/mods/mesecons/mesecons_movestones/init.lua b/mods/mesecons/mesecons_movestones/init.lua index e31f2d27..dcbb00bd 100644 --- a/mods/mesecons/mesecons_movestones/init.lua +++ b/mods/mesecons/mesecons_movestones/init.lua @@ -8,7 +8,7 @@ -- Pushes all block in front of it -- Pull all blocks in its back -function mesecon:get_movestone_direction(pos) +function mesecon.get_movestone_direction(pos) getactivated = 0 local lpos local getactivated = 0 @@ -28,28 +28,28 @@ function mesecon:get_movestone_direction(pos) lpos = {x=pos.x+1, y=pos.y, z=pos.z} for n = 1, 3 do - if mesecon:is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then + if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then return {x=0, y=0, z=-1} end end lpos = {x = pos.x-1, y = pos.y, z = pos.z} for n=4, 6 do - if mesecon:is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then + if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then return {x=0, y=0, z=1} end end lpos = {x = pos.x, y = pos.y, z = pos.z+1} for n=7, 9 do - if mesecon:is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then + if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then return {x=-1, y=0, z=0} end end lpos = {x = pos.x, y = pos.y, z = pos.z-1} for n=10, 12 do - if mesecon:is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then + if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then return {x=1, y=0, z=0} end end @@ -64,10 +64,10 @@ minetest.register_node("mesecons_movestones:movestone", { sounds = default.node_sound_stone_defaults(), mesecons = {effector = { action_on = function (pos, node) - local direction=mesecon:get_movestone_direction(pos) + local direction=mesecon.get_movestone_direction(pos) if not direction then return end minetest.remove_node(pos) - mesecon:update_autoconnect(pos) + mesecon.update_autoconnect(pos) minetest.add_entity(pos, "mesecons_movestones:movestone_entity") end }} @@ -89,15 +89,16 @@ minetest.register_entity("mesecons_movestones:movestone_entity", { on_step = function(self, dtime) local pos = self.object:getpos() pos.x, pos.y, pos.z = math.floor(pos.x+0.5), math.floor(pos.y+0.5), math.floor(pos.z+0.5) - local direction = mesecon:get_movestone_direction(pos) + local direction = mesecon.get_movestone_direction(pos) + local maxpush = mesecon.setting("movestone_max_push", 50) if not direction then -- no mesecon power --push only solid nodes local name = minetest.get_node(pos).name if name ~= "air" and name ~= "ignore" and ((not minetest.registered_nodes[name]) or minetest.registered_nodes[name].liquidtype == "none") then - mesecon:mvps_push(pos, self.lastdir, MOVESTONE_MAXIMUM_PUSH) + mesecon.mvps_push(pos, self.lastdir, maxpush) end minetest.add_node(pos, {name="mesecons_movestones:movestone"}) self.object:remove() @@ -105,14 +106,14 @@ minetest.register_entity("mesecons_movestones:movestone_entity", { end local success, stack, oldstack = - mesecon:mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH) + mesecon.mvps_push(pos, direction, maxpush) if not success then -- Too large stack/stopper in the way minetest.add_node(pos, {name="mesecons_movestones:movestone"}) self.object:remove() return else - mesecon:mvps_process_stack (stack) - mesecon:mvps_move_objects (pos, direction, oldstack) + mesecon.mvps_process_stack (stack) + mesecon.mvps_move_objects (pos, direction, oldstack) self.lastdir = direction end @@ -143,10 +144,10 @@ minetest.register_node("mesecons_movestones:sticky_movestone", { sounds = default.node_sound_stone_defaults(), mesecons = {effector = { action_on = function (pos, node) - local direction=mesecon:get_movestone_direction(pos) + local direction=mesecon.get_movestone_direction(pos) if not direction then return end minetest.remove_node(pos) - mesecon:update_autoconnect(pos) + mesecon.update_autoconnect(pos) minetest.add_entity(pos, "mesecons_movestones:sticky_movestone_entity") end }} @@ -175,7 +176,7 @@ minetest.register_entity("mesecons_movestones:sticky_movestone_entity", { on_step = function(self, dtime) local pos = self.object:getpos() pos.x, pos.y, pos.z = math.floor(pos.x+0.5), math.floor(pos.y+0.5), math.floor(pos.z+0.5) - local direction = mesecon:get_movestone_direction(pos) + local direction = mesecon.get_movestone_direction(pos) if not direction then -- no mesecon power --push only solid nodes @@ -183,9 +184,9 @@ minetest.register_entity("mesecons_movestones:sticky_movestone_entity", { if name ~= "air" and name ~= "ignore" and ((not minetest.registered_nodes[name]) or minetest.registered_nodes[name].liquidtype == "none") then - mesecon:mvps_push(pos, self.lastdir, MOVESTONE_MAXIMUM_PUSH) + mesecon.mvps_push(pos, self.lastdir, MOVESTONE_MAXIMUM_PUSH) --STICKY - mesecon:mvps_pull_all(pos, self.lastdir) + mesecon.mvps_pull_all(pos, self.lastdir) end minetest.add_node(pos, {name="mesecons_movestones:sticky_movestone"}) self.object:remove() @@ -193,24 +194,24 @@ minetest.register_entity("mesecons_movestones:sticky_movestone_entity", { end local success, stack, oldstack = - mesecon:mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH) + mesecon.mvps_push(pos, direction, MOVESTONE_MAXIMUM_PUSH) if not success then -- Too large stack/stopper in the way minetest.add_node(pos, {name="mesecons_movestones:sticky_movestone"}) self.object:remove() return else - mesecon:mvps_process_stack (stack) - mesecon:mvps_move_objects (pos, direction, oldstack) + mesecon.mvps_process_stack (stack) + mesecon.mvps_move_objects (pos, direction, oldstack) self.lastdir = direction end self.object:setvelocity({x=direction.x*2, y=direction.y*2, z=direction.z*2}) --STICKY - mesecon:mvps_pull_all(pos, direction) + mesecon.mvps_pull_all(pos, direction) end, }) -mesecon:register_mvps_unmov("mesecons_movestones:movestone_entity") -mesecon:register_mvps_unmov("mesecons_movestones:sticky_movestone_entity") +mesecon.register_mvps_unmov("mesecons_movestones:movestone_entity") +mesecon.register_mvps_unmov("mesecons_movestones:sticky_movestone_entity") diff --git a/mods/mesecons/mesecons_mvps/init.lua b/mods/mesecons/mesecons_mvps/init.lua index 0079f1aa..163ad28e 100644 --- a/mods/mesecons/mesecons_mvps/init.lua +++ b/mods/mesecons/mesecons_mvps/init.lua @@ -4,7 +4,7 @@ mesecon.mvps_stoppers = {} mesecon.mvps_unmov = {} mesecon.on_mvps_move = {} -function mesecon:is_mvps_stopper(node, pushdir, stack, stackid) +function mesecon.is_mvps_stopper(node, pushdir, stack, stackid) local get_stopper = mesecon.mvps_stoppers[node.name] if type (get_stopper) == "function" then get_stopper = get_stopper(node, pushdir, stack, stackid) @@ -12,7 +12,7 @@ function mesecon:is_mvps_stopper(node, pushdir, stack, stackid) return get_stopper end -function mesecon:register_mvps_stopper(nodename, get_stopper) +function mesecon.register_mvps_stopper(nodename, get_stopper) if get_stopper == nil then get_stopper = true end @@ -20,16 +20,16 @@ function mesecon:register_mvps_stopper(nodename, get_stopper) end -- Objects that cannot be moved (e.g. movestones) -function mesecon:register_mvps_unmov(objectname) +function mesecon.register_mvps_unmov(objectname) mesecon.mvps_unmov[objectname] = true; end -function mesecon:is_mvps_unmov(objectname) +function mesecon.is_mvps_unmov(objectname) return mesecon.mvps_unmov[objectname] end -- Functions to be called on mvps movement -function mesecon:register_on_mvps_move(callback) +function mesecon.register_on_mvps_move(callback) mesecon.on_mvps_move[#mesecon.on_mvps_move+1] = callback end @@ -39,16 +39,14 @@ local function on_mvps_move(moved_nodes) end end -function mesecon:mvps_process_stack(stack) +function mesecon.mvps_process_stack(stack) -- update mesecons for placed nodes ( has to be done after all nodes have been added ) for _, n in ipairs(stack) do - nodeupdate(n.pos) mesecon.on_placenode(n.pos, minetest.get_node(n.pos)) - mesecon:update_autoconnect(n.pos) end end -function mesecon:mvps_get_stack(pos, dir, maximum) +function mesecon.mvps_get_stack(pos, dir, maximum) -- determine the number of nodes to be pushed local np = {x = pos.x, y = pos.y, z = pos.z} local nodes = {} @@ -67,18 +65,18 @@ function mesecon:mvps_get_stack(pos, dir, maximum) table.insert (nodes, {node = nn, pos = np}) - np = mesecon:addPosRule(np, dir) + np = mesecon.addPosRule(np, dir) end return nodes end -function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: direction of push; maximum: maximum nodes to be pushed - local nodes = mesecon:mvps_get_stack(pos, dir, maximum) +function mesecon.mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: direction of push; maximum: maximum nodes to be pushed + local nodes = mesecon.mvps_get_stack(pos, dir, maximum) if not nodes then return end -- determine if one of the nodes blocks the push for id, n in ipairs(nodes) do - if mesecon:is_mvps_stopper(n.node, dir, nodes, id) then + if mesecon.is_mvps_stopper(n.node, dir, nodes, id) then return end end @@ -92,22 +90,21 @@ function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: directio -- update mesecons for removed nodes ( has to be done after all nodes have been removed ) for _, n in ipairs(nodes) do mesecon.on_dignode(n.pos, n.node) - mesecon:update_autoconnect(n.pos) end -- add nodes for _, n in ipairs(nodes) do - np = mesecon:addPosRule(n.pos, dir) + np = mesecon.addPosRule(n.pos, dir) minetest.add_node(np, n.node) minetest.get_meta(np):from_table(n.meta) end local moved_nodes = {} - local oldstack = mesecon:tablecopy(nodes) + local oldstack = mesecon.tablecopy(nodes) for i in ipairs(nodes) do moved_nodes[i] = {} moved_nodes[i].oldpos = nodes[i].pos - nodes[i].pos = mesecon:addPosRule(nodes[i].pos, dir) + nodes[i].pos = mesecon.addPosRule(nodes[i].pos, dir) moved_nodes[i].pos = nodes[i].pos moved_nodes[i].node = nodes[i].node moved_nodes[i].meta = nodes[i].meta @@ -118,20 +115,20 @@ function mesecon:mvps_push(pos, dir, maximum) -- pos: pos of mvps; dir: directio return true, nodes, oldstack end -mesecon:register_on_mvps_move(function(moved_nodes) +mesecon.register_on_mvps_move(function(moved_nodes) for _, n in ipairs(moved_nodes) do mesecon.on_placenode(n.pos, n.node) - mesecon:update_autoconnect(n.pos) + mesecon.update_autoconnect(n.pos) end end) -function mesecon:mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: direction of pull (matches push direction for sticky pistons) - np = mesecon:addPosRule(pos, dir) +function mesecon.mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: direction of pull (matches push direction for sticky pistons) + np = mesecon.addPosRule(pos, dir) nn = minetest.get_node(np) if ((not minetest.registered_nodes[nn.name]) --unregistered node or minetest.registered_nodes[nn.name].liquidtype == "none") --non-liquid node - and not mesecon:is_mvps_stopper(nn, {x = -dir.x, y = -dir.y, z = -dir.z}, {{pos = np, node = nn}}, 1) then --non-stopper node + and not mesecon.is_mvps_stopper(nn, {x = -dir.x, y = -dir.y, z = -dir.z}, {{pos = np, node = nn}}, 1) then --non-stopper node local meta = minetest.get_meta(np):to_table() minetest.remove_node(np) minetest.add_node(pos, nn) @@ -140,13 +137,13 @@ function mesecon:mvps_pull_single(pos, dir) -- pos: pos of mvps; direction: dire nodeupdate(np) nodeupdate(pos) mesecon.on_dignode(np, nn) - mesecon:update_autoconnect(np) + mesecon.update_autoconnect(np) on_mvps_move({{pos = pos, oldpos = np, node = nn, meta = meta}}) end return {{pos = np, node = {param2 = 0, name = "air"}}, {pos = pos, node = nn}} end -function mesecon:mvps_pull_all(pos, direction) -- pos: pos of mvps; direction: direction of pull +function mesecon.mvps_pull_all(pos, direction) -- pos: pos of mvps; direction: direction of pull local lpos = {x=pos.x-direction.x, y=pos.y-direction.y, z=pos.z-direction.z} -- 1 away local lnode = minetest.get_node(lpos) local lpos2 = {x=pos.x-direction.x*2, y=pos.y-direction.y*2, z=pos.z-direction.z*2} -- 2 away @@ -188,15 +185,15 @@ function mesecon:mvps_pull_all(pos, direction) -- pos: pos of mvps; direction: d and minetest.registered_nodes[lnode.name].liquidtype ~= "none") minetest.remove_node(oldpos) mesecon.on_dignode(oldpos, lnode2) - mesecon:update_autoconnect(oldpos) + mesecon.update_autoconnect(oldpos) on_mvps_move(moved_nodes) end -function mesecon:mvps_move_objects(pos, dir, nodestack) +function mesecon.mvps_move_objects(pos, dir, nodestack) local objects_to_move = {} -- Move object at tip of stack - local pushpos = mesecon:addPosRule(pos, -- get pos at tip of stack + local pushpos = mesecon.addPosRule(pos, -- get pos at tip of stack {x = dir.x * #nodestack, y = dir.y * #nodestack, z = dir.z * #nodestack}) @@ -211,7 +208,7 @@ function mesecon:mvps_move_objects(pos, dir, nodestack) if tonumber(minetest.setting_get("movement_gravity")) > 0 and dir.y == 0 then -- If gravity positive and dir horizontal, push players standing on the stack for _, n in ipairs(nodestack) do - local p_above = mesecon:addPosRule(n.pos, {x=0, y=1, z=0}) + local p_above = mesecon.addPosRule(n.pos, {x=0, y=1, z=0}) local objects = minetest.get_objects_inside_radius(p_above, 1) for _, obj in ipairs(objects) do table.insert(objects_to_move, obj) @@ -221,8 +218,8 @@ function mesecon:mvps_move_objects(pos, dir, nodestack) for _, obj in ipairs(objects_to_move) do local entity = obj:get_luaentity() - if not entity or not mesecon:is_mvps_unmov(entity.name) then - local np = mesecon:addPosRule(obj:getpos(), dir) + if not entity or not mesecon.is_mvps_unmov(entity.name) then + local np = mesecon.addPosRule(obj:getpos(), dir) --move only if destination is not solid local nn = minetest.get_node(np) @@ -234,5 +231,5 @@ function mesecon:mvps_move_objects(pos, dir, nodestack) end end -mesecon:register_mvps_stopper("default:chest_locked") -mesecon:register_mvps_stopper("default:furnace") +mesecon.register_mvps_stopper("default:chest_locked") +mesecon.register_mvps_stopper("default:furnace") diff --git a/mods/mesecons/mesecons_noteblock/init.lua b/mods/mesecons/mesecons_noteblock/init.lua index 39710760..d63b93ea 100644 --- a/mods/mesecons/mesecons_noteblock/init.lua +++ b/mods/mesecons/mesecons_noteblock/init.lua @@ -2,7 +2,6 @@ minetest.register_node("mesecons_noteblock:noteblock", { description = "Noteblock", tiles = {"mesecons_noteblock.png"}, groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}, - drawtype = "allfaces_optional", visual_scale = 1.3, paramtype="light", after_place_node = function(pos) diff --git a/mods/mesecons/mesecons_pistons/init.lua b/mods/mesecons/mesecons_pistons/init.lua index 7780fc97..b247039c 100644 --- a/mods/mesecons/mesecons_pistons/init.lua +++ b/mods/mesecons/mesecons_pistons/init.lua @@ -33,7 +33,7 @@ local piston_down_rules = local piston_get_rules = function (node) local rules = piston_rules for i = 1, node.param2 do - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) end return rules end @@ -41,7 +41,7 @@ end piston_facedir_direction = function (node) local rules = {{x = 0, y = 0, z = -1}} for i = 1, node.param2 do - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) end return rules[1] end @@ -56,14 +56,15 @@ end local piston_remove_pusher = function(pos, node) pistonspec = minetest.registered_nodes[node.name].mesecons_piston - if pushername == pistonspec.pusher then --make sure there actually is a pusher (for compatibility reasons mainly) + dir = piston_get_direction(pistonspec.dir, node) + local pusherpos = mesecon.addPosRule(pos, dir) + local pushername = minetest.get_node(pusherpos).name + + -- make sure there actually is a pusher (for compatibility reasons mainly) + if pushername ~= pistonspec.pusher then return end - dir = piston_get_direction(pistonspec.dir, node) - local pusherpos = mesecon:addPosRule(pos, dir) - local pushername = minetest.get_node(pusherpos).name - minetest.remove_node(pusherpos) minetest.sound_play("piston_retract", { pos = pos, @@ -77,8 +78,9 @@ local piston_on = function(pos, node) local pistonspec = minetest.registered_nodes[node.name].mesecons_piston local dir = piston_get_direction(pistonspec.dir, node) - local np = mesecon:addPosRule(pos, dir) - local success, stack, oldstack = mesecon:mvps_push(np, dir, PISTON_MAXIMUM_PUSH) + local np = mesecon.addPosRule(pos, dir) + local maxpush = mesecon.setting("piston_max_push", 15) + local success, stack, oldstack = mesecon.mvps_push(np, dir, maxpush) if success then minetest.add_node(pos, {param2 = node.param2, name = pistonspec.onname}) minetest.add_node(np, {param2 = node.param2, name = pistonspec.pusher}) @@ -87,8 +89,8 @@ local piston_on = function(pos, node) max_hear_distance = 20, gain = 0.3, }) - mesecon:mvps_process_stack (stack) - mesecon:mvps_move_objects (np, dir, oldstack) + mesecon.mvps_process_stack (stack) + mesecon.mvps_move_objects (np, dir, oldstack) end end @@ -99,9 +101,9 @@ local piston_off = function(pos, node) if pistonspec.sticky then dir = piston_get_direction(pistonspec.dir, node) - pullpos = mesecon:addPosRule(pos, dir) - stack = mesecon:mvps_pull_single(pullpos, dir) - mesecon:mvps_process_stack(pos, dir, stack) + pullpos = mesecon.addPosRule(pos, dir) + stack = mesecon.mvps_pull_single(pullpos, dir) + mesecon.mvps_process_stack(pos, dir, stack) end end @@ -692,14 +694,14 @@ local piston_pusher_up_down_get_stopper = function (node, dir, stack, stackid) return true end -mesecon:register_mvps_stopper("mesecons_pistons:piston_pusher_normal", piston_pusher_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_pusher_sticky", piston_pusher_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_normal", piston_pusher_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_sticky", piston_pusher_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_up_pusher_normal", piston_pusher_up_down_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_up_pusher_sticky", piston_pusher_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_up_pusher_normal", piston_pusher_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_up_pusher_sticky", piston_pusher_up_down_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_down_pusher_normal", piston_pusher_up_down_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_down_pusher_sticky", piston_pusher_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_down_pusher_normal", piston_pusher_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_down_pusher_sticky", piston_pusher_up_down_get_stopper) -- Register pistons as stoppers if they would be seperated from the stopper @@ -716,12 +718,12 @@ end local piston_get_stopper = function (node, dir, stack, stackid) pistonspec = minetest.registered_nodes[node.name].mesecons_piston dir = piston_get_direction(pistonspec.dir, node) - local pusherpos = mesecon:addPosRule(stack[stackid].pos, dir) + local pusherpos = mesecon.addPosRule(stack[stackid].pos, dir) local pushernode = minetest.get_node(pusherpos) if minetest.registered_nodes[node.name].mesecons_piston.pusher == pushernode.name then for _, s in ipairs(stack) do - if mesecon:cmpPos(s.pos, pusherpos) -- pusher is also to be pushed + if mesecon.cmpPos(s.pos, pusherpos) -- pusher is also to be pushed and s.node.param2 == node.param2 then return false end @@ -730,14 +732,14 @@ local piston_get_stopper = function (node, dir, stack, stackid) return true end -mesecon:register_mvps_stopper("mesecons_pistons:piston_normal_on", piston_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_sticky_on", piston_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_normal_on", piston_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_sticky_on", piston_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_up_normal_on", piston_up_down_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_up_sticky_on", piston_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_up_normal_on", piston_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_up_sticky_on", piston_up_down_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_down_normal_on", piston_up_down_get_stopper) -mesecon:register_mvps_stopper("mesecons_pistons:piston_down_sticky_on", piston_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_down_normal_on", piston_up_down_get_stopper) +mesecon.register_mvps_stopper("mesecons_pistons:piston_down_sticky_on", piston_up_down_get_stopper) --craft recipes minetest.register_craft({ diff --git a/mods/mesecons/mesecons_pressureplates/init.lua b/mods/mesecons/mesecons_pressureplates/init.lua index ec8d7893..d01e6e5a 100644 --- a/mods/mesecons/mesecons_pressureplates/init.lua +++ b/mods/mesecons/mesecons_pressureplates/init.lua @@ -9,31 +9,31 @@ local pp_box_on = { } pp_on_timer = function (pos, elapsed) - local node = minetest.get_node(pos) - local ppspec = minetest.registered_nodes[node.name].pressureplate + local node = minetest.get_node(pos) + local basename = minetest.registered_nodes[node.name].pressureplate_basename -- This is a workaround for a strange bug that occurs when the server is started -- For some reason the first time on_timer is called, the pos is wrong - if not ppspec then return end + if not basename then return end local objs = minetest.get_objects_inside_radius(pos, 1) - local two_below = mesecon:addPosRule(pos, {x = 0, y = -2, z = 0}) + local two_below = mesecon.addPosRule(pos, {x = 0, y = -2, z = 0}) - if objs[1] == nil and node.name == ppspec.onstate then - minetest.add_node(pos, {name = ppspec.offstate}) - mesecon:receptor_off(pos) + if objs[1] == nil and node.name == basename .. "_on" then + minetest.add_node(pos, {name = basename .. "_off"}) + mesecon.receptor_off(pos, mesecon.rules.pplate) -- force deactivation of mesecon two blocks below (hacky) - if not mesecon:connected_to_receptor(two_below) then - mesecon:turnoff(two_below) + if not mesecon.connected_to_receptor(two_below) then + mesecon.turnoff(two_below) end else for k, obj in pairs(objs) do local objpos = obj:getpos() if objpos.y > pos.y-1 and objpos.y < pos.y then - minetest.add_node(pos, {name=ppspec.onstate}) - mesecon:receptor_on(pos) + minetest.add_node(pos, {name = basename .. "_on"}) + mesecon.receptor_on(pos, mesecon.rules.pplate ) -- force activation of mesecon two blocks below (hacky) - mesecon:turnon(two_below) + mesecon.turnon(two_below) end end end @@ -49,66 +49,40 @@ end -- image: inventory and wield image of the pressure plate -- recipe: crafting recipe of the pressure plate -function mesecon:register_pressure_plate(offstate, onstate, description, textures_off, textures_on, image_w, image_i, recipe) - local ppspec = { - offstate = offstate, - onstate = onstate - } - - minetest.register_node(offstate, { +function mesecon.register_pressure_plate(basename, description, textures_off, textures_on, image_w, image_i, recipe) + mesecon.register_node(basename, { drawtype = "nodebox", - tiles = textures_off, inventory_image = image_i, wield_image = image_w, paramtype = "light", - selection_box = pp_box_off, - node_box = pp_box_off, - groups = {snappy = 2, oddly_breakable_by_hand = 3}, description = description, - pressureplate = ppspec, + pressureplate_basename = basename, on_timer = pp_on_timer, - mesecons = {receptor = { - state = mesecon.state.off - }}, on_construct = function(pos) - minetest.get_node_timer(pos):start(PRESSURE_PLATE_INTERVAL) + minetest.get_node_timer(pos):start(mesecon.setting("pplate_interval", 0.1)) end, - }) - - minetest.register_node(onstate, { - drawtype = "nodebox", - tiles = textures_on, - paramtype = "light", - selection_box = pp_box_on, + },{ + mesecons = {receptor = { state = mesecon.state.off, rules = mesecon.rules.pplate }}, + node_box = pp_box_off, + selection_box = pp_box_off, + groups = {snappy = 2, oddly_breakable_by_hand = 3}, + tiles = textures_off + },{ + mesecons = {receptor = { state = mesecon.state.on, rules = mesecon.rules.pplate }}, node_box = pp_box_on, + selection_box = pp_box_on, groups = {snappy = 2, oddly_breakable_by_hand = 3, not_in_creative_inventory = 1}, - drop = offstate, - pressureplate = ppspec, - on_timer = pp_on_timer, - sounds = default.node_sound_wood_defaults(), - mesecons = {receptor = { - state = mesecon.state.on - }}, - on_construct = function(pos) - minetest.get_node_timer(pos):start(PRESSURE_PLATE_INTERVAL) - end, - after_dig_node = function(pos) - local two_below = mesecon:addPosRule(pos, {x = 0, y = -2, z = 0}) - if not mesecon:connected_to_receptor(two_below) then - mesecon:turnoff(two_below) - end - end + tiles = textures_on }) minetest.register_craft({ - output = offstate, + output = basename .. "_off", recipe = recipe, }) end -mesecon:register_pressure_plate( - "mesecons_pressureplates:pressure_plate_wood_off", - "mesecons_pressureplates:pressure_plate_wood_on", +mesecon.register_pressure_plate( + "mesecons_pressureplates:pressure_plate_wood", "Wooden Pressure Plate", {"jeija_pressure_plate_wood_off.png","jeija_pressure_plate_wood_off.png","jeija_pressure_plate_wood_off_edges.png"}, {"jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on_edges.png"}, @@ -116,9 +90,8 @@ mesecon:register_pressure_plate( "jeija_pressure_plate_wood_inv.png", {{"group:wood", "group:wood"}}) -mesecon:register_pressure_plate( - "mesecons_pressureplates:pressure_plate_stone_off", - "mesecons_pressureplates:pressure_plate_stone_on", +mesecon.register_pressure_plate( + "mesecons_pressureplates:pressure_plate_stone", "Stone Pressure Plate", {"jeija_pressure_plate_stone_off.png","jeija_pressure_plate_stone_off.png","jeija_pressure_plate_stone_off_edges.png"}, {"jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on_edges.png"}, diff --git a/mods/mesecons/mesecons_random/init.lua b/mods/mesecons/mesecons_random/init.lua index 670bea40..01363092 100644 --- a/mods/mesecons/mesecons_random/init.lua +++ b/mods/mesecons/mesecons_random/init.lua @@ -9,7 +9,7 @@ minetest.register_node("mesecons_random:removestone", { mesecons = {effector = { action_on = function (pos, node) minetest.remove_node(pos) - mesecon:update_autoconnect(pos) + mesecon.update_autoconnect(pos) end }} }) diff --git a/mods/mesecons/mesecons_receiver/init.lua b/mods/mesecons/mesecons_receiver/init.lua index 3b1108ef..b06baa5d 100644 --- a/mods/mesecons/mesecons_receiver/init.lua +++ b/mods/mesecons/mesecons_receiver/init.lua @@ -9,11 +9,11 @@ local receiver_get_rules = function (node) local rules = { {x = 1, y = 0, z = 0}, {x = -2, y = 0, z = 0}} if node.param2 == 2 then - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) elseif node.param2 == 3 then - rules = mesecon:rotate_rules_right(mesecon:rotate_rules_right(rules)) + rules = mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) elseif node.param2 == 0 then - rules = mesecon:rotate_rules_right(rules) + rules = mesecon.rotate_rules_right(rules) end return rules end @@ -81,83 +81,76 @@ minetest.register_node("mesecons_receiver:receiver_off", { }} }) -mesecon:add_rules("receiver_pos", {{x = 2, y = 0, z = 0}}) - -mesecon:add_rules("receiver_pos_all", { -{x = 2, y = 0, z = 0}, -{x =-2, y = 0, z = 0}, -{x = 0, y = 0, z = 2}, -{x = 0, y = 0, z =-2}}) - -function mesecon:receiver_get_pos_from_rcpt(pos, param2) - local rules = mesecon:get_rules("receiver_pos") +function mesecon.receiver_get_pos_from_rcpt(pos, param2) + local rules = {{x = 2, y = 0, z = 0}} if param2 == nil then param2 = minetest.get_node(pos).param2 end if param2 == 2 then - rules = mesecon:rotate_rules_left(rules) + rules = mesecon.rotate_rules_left(rules) elseif param2 == 3 then - rules = mesecon:rotate_rules_right(mesecon:rotate_rules_right(rules)) + rules = mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) elseif param2 == 0 then - rules = mesecon:rotate_rules_right(rules) + rules = mesecon.rotate_rules_right(rules) end - np = { - x = pos.x + rules[1].x, - y = pos.y + rules[1].y, - z = pos.z + rules[1].z} + local np = { x = pos.x + rules[1].x, + y = pos.y + rules[1].y, + z = pos.z + rules[1].z} return np end -function mesecon:receiver_place(rcpt_pos) +function mesecon.receiver_place(rcpt_pos) local node = minetest.get_node(rcpt_pos) - local pos = mesecon:receiver_get_pos_from_rcpt(rcpt_pos, node.param2) + local pos = mesecon.receiver_get_pos_from_rcpt(rcpt_pos, node.param2) local nn = minetest.get_node(pos) if string.find(nn.name, "mesecons:wire_") ~= nil then minetest.dig_node(pos) - if mesecon:is_power_on(rcpt_pos) then + if mesecon.is_power_on(rcpt_pos) then minetest.add_node(pos, {name = "mesecons_receiver:receiver_on", param2 = node.param2}) - mesecon:receptor_on(pos, receiver_get_rules(node)) + mesecon.receptor_on(pos, receiver_get_rules(node)) else minetest.add_node(pos, {name = "mesecons_receiver:receiver_off", param2 = node.param2}) end - mesecon:update_autoconnect(pos) + mesecon.update_autoconnect(pos) end end -function mesecon:receiver_remove(rcpt_pos, dugnode) - local pos = mesecon:receiver_get_pos_from_rcpt(rcpt_pos, dugnode.param2) +function mesecon.receiver_remove(rcpt_pos, dugnode) + local pos = mesecon.receiver_get_pos_from_rcpt(rcpt_pos, dugnode.param2) local nn = minetest.get_node(pos) if string.find(nn.name, "mesecons_receiver:receiver_") ~=nil then minetest.dig_node(pos) local node = {name = "mesecons:wire_00000000_off"} minetest.add_node(pos, node) - mesecon:update_autoconnect(pos) + mesecon.update_autoconnect(pos) mesecon.on_placenode(pos, node) end end minetest.register_on_placenode(function (pos, node) if minetest.get_item_group(node.name, "mesecon_needs_receiver") == 1 then - mesecon:receiver_place(pos) + mesecon.receiver_place(pos) end end) minetest.register_on_dignode(function(pos, node) if minetest.get_item_group(node.name, "mesecon_needs_receiver") == 1 then - mesecon:receiver_remove(pos, node) + mesecon.receiver_remove(pos, node) end end) minetest.register_on_placenode(function (pos, node) if string.find(node.name, "mesecons:wire_") ~=nil then - rules = mesecon:get_rules("receiver_pos_all") + local rules = { {x = 2, y = 0, z = 0}, + {x =-2, y = 0, z = 0}, + {x = 0, y = 0, z = 2}, + {x = 0, y = 0, z =-2}} local i = 1 while rules[i] ~= nil do - np = { - x = pos.x + rules[i].x, - y = pos.y + rules[i].y, - z = pos.z + rules[i].z} + local np = { x = pos.x + rules[i].x, + y = pos.y + rules[i].y, + z = pos.z + rules[i].z} if minetest.get_item_group(minetest.get_node(np).name, "mesecon_needs_receiver") == 1 then - mesecon:receiver_place(np) + mesecon.receiver_place(np) end i = i + 1 end diff --git a/mods/mesecons/mesecons_solarpanel/init.lua b/mods/mesecons/mesecons_solarpanel/init.lua index c30fe12c..bc5a408e 100644 --- a/mods/mesecons/mesecons_solarpanel/init.lua +++ b/mods/mesecons/mesecons_solarpanel/init.lua @@ -75,7 +75,7 @@ minetest.register_abm( if light >= 12 then minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_on", param2=node.param2}) - mesecon:receptor_on(pos) + mesecon.receptor_on(pos) end end, }) @@ -89,7 +89,7 @@ minetest.register_abm( if light < 12 then minetest.set_node(pos, {name="mesecons_solarpanel:solar_panel_off", param2=node.param2}) - mesecon:receptor_off(pos) + mesecon.receptor_off(pos) end end, }) diff --git a/mods/mesecons/mesecons_switch/init.lua b/mods/mesecons/mesecons_switch/init.lua index 1b7f4788..2b3c3ee1 100644 --- a/mods/mesecons/mesecons_switch/init.lua +++ b/mods/mesecons/mesecons_switch/init.lua @@ -1,35 +1,29 @@ -- MESECON_SWITCH -minetest.register_node("mesecons_switch:mesecon_switch_off", { - tiles = {"jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_off.png"}, +mesecon.register_node("mesecons_switch:mesecon_switch", { paramtype2="facedir", - groups = {dig_immediate=2}, description="Switch", sounds = default.node_sound_stone_defaults(), - mesecons = {receptor = { - state = mesecon.state.off - }}, - on_punch = function(pos, node) - minetest.swap_node(pos, {name = "mesecons_switch:mesecon_switch_on", param2 = node.param2}) - mesecon:receptor_on(pos) - minetest.sound_play("mesecons_switch", {pos=pos}) - end -}) - -minetest.register_node("mesecons_switch:mesecon_switch_on", { - tiles = {"jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_on.png"}, - paramtype2="facedir", - groups = {dig_immediate=2,not_in_creative_inventory=1}, - drop="mesecons_switch:mesecon_switch_off 1", - sounds = default.node_sound_stone_defaults(), - mesecons = {receptor = { - state = mesecon.state.on - }}, - on_punch = function(pos, node) - minetest.swap_node(pos, {name = "mesecons_switch:mesecon_switch_off", param2 = node.param2}) - mesecon:receptor_off(pos) + on_punch = function (pos, node) + if(mesecon.flipstate(pos, node) == "on") then + mesecon.receptor_on(pos) + else + mesecon.receptor_off(pos) + end minetest.sound_play("mesecons_switch", {pos=pos}) end +},{ + groups = {dig_immediate=2}, + tiles = { "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", + "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", + "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_off.png"}, + mesecons = {receptor = { state = mesecon.state.off }} +},{ + groups = {dig_immediate=2, not_in_creative_inventory=1}, + tiles = { "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", + "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_side.png", + "jeija_mesecon_switch_side.png", "jeija_mesecon_switch_on.png"}, + mesecons = {receptor = { state = mesecon.state.on }} }) minetest.register_craft({ diff --git a/mods/mesecons/mesecons_torch/init.lua b/mods/mesecons/mesecons_torch/init.lua index 97a29910..91f8e65b 100644 --- a/mods/mesecons/mesecons_torch/init.lua +++ b/mods/mesecons/mesecons_torch/init.lua @@ -2,15 +2,15 @@ local rotate_torch_rules = function (rules, param2) if param2 == 5 then - return mesecon:rotate_rules_right(rules) + return mesecon.rotate_rules_right(rules) elseif param2 == 2 then - return mesecon:rotate_rules_right(mesecon:rotate_rules_right(rules)) --180 degrees + return mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) --180 degrees elseif param2 == 4 then - return mesecon:rotate_rules_left(rules) + return mesecon.rotate_rules_left(rules) elseif param2 == 1 then - return mesecon:rotate_rules_down(rules) + return mesecon.rotate_rules_down(rules) elseif param2 == 0 then - return mesecon:rotate_rules_up(rules) + return mesecon.rotate_rules_up(rules) else return rules end @@ -91,8 +91,8 @@ minetest.register_abm({ action = function(pos, node) local is_powered = false for _, rule in ipairs(torch_get_input_rules(node)) do - local src = mesecon:addPosRule(pos, rule) - if mesecon:is_power_on(src) then + local src = mesecon.addPosRule(pos, rule) + if mesecon.is_power_on(src) then is_powered = true end end @@ -100,11 +100,11 @@ minetest.register_abm({ if is_powered then if node.name == "mesecons_torch:mesecon_torch_on" then minetest.swap_node(pos, {name = "mesecons_torch:mesecon_torch_off", param2 = node.param2}) - mesecon:receptor_off(pos, torch_get_output_rules(node)) + mesecon.receptor_off(pos, torch_get_output_rules(node)) end elseif node.name == "mesecons_torch:mesecon_torch_off" then minetest.swap_node(pos, {name = "mesecons_torch:mesecon_torch_on", param2 = node.param2}) - mesecon:receptor_on(pos, torch_get_output_rules(node)) + mesecon.receptor_on(pos, torch_get_output_rules(node)) end end }) diff --git a/mods/mesecons/mesecons_walllever/init.lua b/mods/mesecons/mesecons_walllever/init.lua index a35d9f17..bd71871b 100644 --- a/mods/mesecons/mesecons_walllever/init.lua +++ b/mods/mesecons/mesecons_walllever/init.lua @@ -1,16 +1,9 @@ -- WALL LEVER -- Basically a switch that can be attached to a wall -- Powers the block 2 nodes behind (using a receiver) -minetest.register_node("mesecons_walllever:wall_lever_off", { +mesecon.register_node("mesecons_walllever:wall_lever", { + description="Lever", drawtype = "nodebox", - tiles = { - "jeija_wall_lever_tb.png", - "jeija_wall_lever_bottom.png", - "jeija_wall_lever_sides.png", - "jeija_wall_lever_sides.png", - "jeija_wall_lever_back.png", - "jeija_wall_lever_off.png", - }, inventory_image = "jeija_wall_lever_off.png", wield_image = "jeija_wall_lever_off.png", paramtype = "light", @@ -21,29 +14,34 @@ minetest.register_node("mesecons_walllever:wall_lever_off", { type = "fixed", fixed = { -8/16, -8/16, 3/16, 8/16, 8/16, 8/16 }, }, + sounds = default.node_sound_wood_defaults(), + on_punch = function (pos, node) + if(mesecon.flipstate(pos, node) == "on") then + mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node)) + else + mesecon.receptor_off(pos, mesecon.rules.buttonlike_get(node)) + end + minetest.sound_play("mesecons_lever", {pos=pos}) + end +},{ + tiles = { "jeija_wall_lever_tb.png", "jeija_wall_lever_bottom.png", + "jeija_wall_lever_sides.png", "jeija_wall_lever_sides.png", + "jeija_wall_lever_back.png", "jeija_wall_lever_off.png", + }, node_box = { type = "fixed", fixed = {{ -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the base "slab" { -5/16, -3/16, 5/16, 5/16, 3/16, 6/16 }, -- the lighted ring area - { -4/16, -2/16, 4/16, 4/16, 2/16, 5/16 }, -- the raised bit that the lever "sits" on + { -4/16, -2/16, 4/16, 4/16, 2/16, 5/16 }, -- the raised bit { -2/16, -1/16, 3/16, 2/16, 1/16, 4/16 }, -- the lever "hinge" { -1/16, -8/16, 4/16, 1/16, 0, 6/16 }} -- the lever itself. }, - groups = {dig_immediate=2, mesecon_needs_receiver = 1}, - description="Lever", - on_punch = function (pos, node) - minetest.swap_node(pos, {name = "mesecons_walllever:wall_lever_on", param2 = node.param2}) - mesecon:receptor_on(pos, mesecon.rules.buttonlike_get(node)) - minetest.sound_play("mesecons_lever", {pos=pos}) - end, - sounds = default.node_sound_wood_defaults(), mesecons = {receptor = { rules = mesecon.rules.buttonlike_get, state = mesecon.state.off - }} -}) -minetest.register_node("mesecons_walllever:wall_lever_on", { - drawtype = "nodebox", + }}, + groups = {dig_immediate = 2, mesecon_needs_receiver = 1} +},{ tiles = { "jeija_wall_lever_top.png", "jeija_wall_lever_tb.png", @@ -52,37 +50,19 @@ minetest.register_node("mesecons_walllever:wall_lever_on", { "jeija_wall_lever_back.png", "jeija_wall_lever_on.png", }, - inventory_image = "jeija_wall_lever_on.png", - paramtype = "light", - paramtype2 = "facedir", - sunlight_propagates = true, - walkable = false, - light_source = LIGHT_MAX-7, - selection_box = { - type = "fixed", - fixed = { -8/16, -8/16, 3/16, 8/16, 8/16, 8/16 }, - }, node_box = { type = "fixed", fixed = {{ -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the base "slab" { -5/16, -3/16, 5/16, 5/16, 3/16, 6/16 }, -- the lighted ring area - { -4/16, -2/16, 4/16, 4/16, 2/16, 5/16 }, -- the raised bit that the lever "sits" on + { -4/16, -2/16, 4/16, 4/16, 2/16, 5/16 }, -- the raised bit { -2/16, -1/16, 3/16, 2/16, 1/16, 4/16 }, -- the lever "hinge" { -1/16, 0, 4/16, 1/16, 8/16, 6/16 }} -- the lever itself. }, - groups = {dig_immediate = 2, not_in_creative_inventory = 1, mesecon_needs_receiver = 1}, - drop = "mesecons_walllever:wall_lever_off 1", - description="Lever", - on_punch = function (pos, node) - minetest.swap_node(pos, {name = "mesecons_walllever:wall_lever_off", param2 = node.param2}) - mesecon:receptor_off(pos, mesecon.rules.buttonlike_get(node)) - minetest.sound_play("mesecons_lever", {pos=pos}) - end, - sounds = default.node_sound_wood_defaults(), mesecons = {receptor = { rules = mesecon.rules.buttonlike_get, state = mesecon.state.on - }} + }}, + groups = {dig_immediate = 2, mesecon_needs_receiver = 1, not_in_creative_inventory = 1} }) minetest.register_craft({ diff --git a/mods/pipeworks/.gitignore b/mods/pipeworks/.gitignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/mods/pipeworks/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/mods/pipeworks/LICENSE b/mods/pipeworks/LICENSE new file mode 100644 index 00000000..eb930e91 --- /dev/null +++ b/mods/pipeworks/LICENSE @@ -0,0 +1,17 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + +---------- + +This license is commonly known as "WTFPL". diff --git a/mods/pipeworks/README b/mods/pipeworks/README new file mode 100644 index 00000000..b9c68f95 --- /dev/null +++ b/mods/pipeworks/README @@ -0,0 +1,22 @@ +This mod uses nodeboxes to supply a complete set of 3D pipes and tubes, +along devices that work with them. + +See http://vanessae.github.io/pipeworks/ for detailed information about usage of this mod. + +Unlike the previous version of this mod, these pipes are rounded, and when +placed, they'll automatically join together as needed. Pipes can go vertically +or horizontally, and there are enough nodes defined to allow for all possible +connections. Valves and pumps can only be placed horizontally, and will +automatically rotate and join with neighboring pipes as objects are added, as +well as joining with each other under certain circumstances. + +Pipes come in two variants: one type bears one or more dark windows on each +pipe, suggesting they're empty, while the other type bears green-tinted +windows, as if full (the two colors should also be easy to select if you want +to change them in a paint program). These windows only appear on straight +lengths and on certain junctions. + +This mod is a work in progress. + +Please note that owing to the nature of this mod, I have opted to use 64px +textures. Anything less just looks terrible. diff --git a/mods/pipeworks/autocrafter.lua b/mods/pipeworks/autocrafter.lua new file mode 100644 index 00000000..a6d8ad12 --- /dev/null +++ b/mods/pipeworks/autocrafter.lua @@ -0,0 +1,184 @@ +local autocrafterCache = {} -- caches some recipe data to avoid to call the slow function minetest.get_craft_result() every second + +local function make_inventory_cache(invlist) + local l = {} + for _, stack in ipairs(invlist) do + l[stack:get_name()] = (l[stack:get_name()] or 0) + stack:get_count() + end + return l +end + +local function autocraft(inventory, pos) + local recipe = inventory:get_list("recipe") + local recipe_last + local result + local new + + if autocrafterCache[minetest.hash_node_position(pos)] == nil then + recipe_last = {} + for i = 1, 9 do + recipe_last[i] = recipe[i] + recipe[i] = ItemStack({name = recipe[i]:get_name(), count = 1}) + end + result, new = minetest.get_craft_result({method = "normal", width = 3, items = recipe}) + autocrafterCache[minetest.hash_node_position(pos)] = {["recipe"] = recipe, ["result"] = result, ["new"] = new} + else + local autocrafterCacheEntry = autocrafterCache[minetest.hash_node_position(pos)] + recipe_last = autocrafterCacheEntry["recipe"] + result = autocrafterCacheEntry["result"] + new = autocrafterCacheEntry["new"] + local recipeUnchanged = true + for i = 1, 9 do + if recipe[i]:get_name() ~= recipe_last[i]:get_name() then + recipeUnchanged = false + break + end + if recipe[i]:get_count() ~= recipe_last[i]:get_count() then + recipeUnchanged = false + break + end + end + if recipeUnchanged then + else + for i = 1, 9 do + recipe_last[i] = recipe[i] + recipe[i] = ItemStack({name = recipe[i]:get_name(), count = 1}) + end + result, new = minetest.get_craft_result({method = "normal", width = 3, items = recipe}) + autocrafterCache[minetest.hash_node_position(pos)] = {["recipe"] = recipe, ["result"] = result, ["new"] = new} + end + end + + if result.item:is_empty() then return end + result = result.item + if not inventory:room_for_item("dst", result) then return end + local to_use = {} + for _, item in ipairs(recipe) do + if item~= nil and not item:is_empty() then + if to_use[item:get_name()] == nil then + to_use[item:get_name()] = 1 + else + to_use[item:get_name()] = to_use[item:get_name()]+1 + end + end + end + local invcache = make_inventory_cache(inventory:get_list("src")) + for itemname, number in pairs(to_use) do + if (not invcache[itemname]) or invcache[itemname] < number then return end + end + for itemname, number in pairs(to_use) do + for i = 1, number do -- We have to do that since remove_item does not work if count > stack_max + inventory:remove_item("src", ItemStack(itemname)) + end + end + inventory:add_item("dst", result) + for i = 1, 9 do + inventory:add_item("dst", new.items[i]) + end +end + +local function update_autocrafter(pos) + local meta = minetest.get_meta(pos) + if meta:get_string("virtual_items") == "" then + meta:set_string("virtual_items", "1") + local inv = meta:get_inventory() + for _, stack in ipairs(inv:get_list("recipe")) do + minetest.item_drop(stack, "", pos) + end + end +end + +minetest.register_node("pipeworks:autocrafter", { + description = "Autocrafter", + drawtype = "normal", + tiles = {"pipeworks_autocrafter.png"}, + groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1}, + tube = {insert_object = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:add_item("src", stack) + end, + can_insert = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:room_for_item("src", stack) + end, + input_inventory = "dst", + connect_sides = {left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1}}, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", + "size[8,11]".. + "list[current_name;recipe;0,0;3,3;]".. + "list[current_name;src;0,3.5;8,3;]".. + "list[current_name;dst;4,0;4,3;]".. + "list[current_player;main;0,7;8,4;]") + meta:set_string("infotext", "Autocrafter") + meta:set_string("virtual_items", "1") + local inv = meta:get_inventory() + inv:set_size("src", 3*8) + inv:set_size("recipe", 3*3) + inv:set_size("dst", 4*3) + end, + on_punch = update_autocrafter, + can_dig = function(pos, player) + update_autocrafter(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return (inv:is_empty("src") and inv:is_empty("dst")) + end, + after_place_node = function(pos) + pipeworks.scan_for_tube_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_tube_objects(pos) + autocrafterCache[minetest.hash_node_position(pos)] = nil + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + update_autocrafter(pos) + local inv = minetest.get_meta(pos):get_inventory() + if listname == "recipe" then + local stack_copy = ItemStack(stack) + stack_copy:set_count(1) + inv:set_stack(listname, index, stack_copy) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + update_autocrafter(pos) + local inv = minetest.get_meta(pos):get_inventory() + if listname == "recipe" then + inv:set_stack(listname, index, ItemStack("")) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + update_autocrafter(pos) + local inv = minetest.get_meta(pos):get_inventory() + local stack = inv:get_stack(from_list, from_index) + stack:set_count(count) + if from_list == "recipe" then + inv:set_stack(from_list, from_index, ItemStack("")) + return 0 + elseif to_list == "recipe" then + local stack_copy = ItemStack(stack) + stack_copy:set_count(1) + inv:set_stack(to_list, to_index, stack_copy) + return 0 + else + return stack:get_count() + end + end, +}) + +minetest.register_abm({nodenames = {"pipeworks:autocrafter"}, interval = 1, chance = 1, + action = function(pos, node) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + autocraft(inv, pos) + end +}) diff --git a/mods/pipeworks/autoplace_pipes.lua b/mods/pipeworks/autoplace_pipes.lua new file mode 100644 index 00000000..69bd90e4 --- /dev/null +++ b/mods/pipeworks/autoplace_pipes.lua @@ -0,0 +1,200 @@ +-- autorouting for pipes +local tube_table = {[0] = 1, 2, 2, 4, 2, 4, 4, 5, 2, 3, 4, 6, 4, 6, 5, 7, 2, 4, 3, 6, 4, 5, 6, 7, 4, 6, 6, 8, 5, 7, 7, 9, 2, 4, 4, 5, 3, 6, 6, 7, 4, 6, 5, 7, 6, 8, 7, 9, 4, 5, 6, 7, 6, 7, 8, 9, 5, 7, 7, 9, 7, 9, 9, 10} +local tube_table_facedirs = {[0] = 0, 0, 5, 0, 3, 4, 3, 0, 2, 0, 2, 0, 6, 4, 3, 0, 7, 12, 5, 12, 7, 4, 5, 5, 18, 20, 16, 0, 7, 4, 7, 0, 1, 8, 1, 1, 1, 13, 1, 1, 10, 8, 2, 2, 17, 4, 3, 6, 9, 9, 9, 9, 21, 13, 1, 1, 10, 10, 11, 2, 19, 4, 3, 0} +local function autoroute_pipes(pos) + local nctr = minetest.get_node(pos) + local state = "_empty" + if (string.find(nctr.name, "pipeworks:pipe_") == nil) then return end + if (string.find(nctr.name, "_loaded") ~= nil) then state = "_loaded" end + local nsurround = pipeworks.scan_pipe_surroundings(pos) + + if nsurround == 0 then nsurround = 9 end + minetest.add_node(pos, {name = "pipeworks:pipe_"..tube_table[nsurround]..state, + param2 = tube_table_facedirs[nsurround]}) +end + +function pipeworks.scan_for_pipe_objects(pos) + autoroute_pipes({ x=pos.x-1, y=pos.y , z=pos.z }) + autoroute_pipes({ x=pos.x+1, y=pos.y , z=pos.z }) + autoroute_pipes({ x=pos.x , y=pos.y-1, z=pos.z }) + autoroute_pipes({ x=pos.x , y=pos.y+1, z=pos.z }) + autoroute_pipes({ x=pos.x , y=pos.y , z=pos.z-1 }) + autoroute_pipes({ x=pos.x , y=pos.y , z=pos.z+1 }) + autoroute_pipes(pos) +end + +-- auto-rotation code for various devices the tubes attach to + +function pipeworks.scan_pipe_surroundings(pos) + local pxm=0 + local pxp=0 + local pym=0 + local pyp=0 + local pzm=0 + local pzp=0 + + local nxm = minetest.get_node({ x=pos.x-1, y=pos.y , z=pos.z }) + local nxp = minetest.get_node({ x=pos.x+1, y=pos.y , z=pos.z }) + local nym = minetest.get_node({ x=pos.x , y=pos.y-1, z=pos.z }) + local nyp = minetest.get_node({ x=pos.x , y=pos.y+1, z=pos.z }) + local nzm = minetest.get_node({ x=pos.x , y=pos.y , z=pos.z-1 }) + local nzp = minetest.get_node({ x=pos.x , y=pos.y , z=pos.z+1 }) + + if (string.find(nxm.name, "pipeworks:pipe_") ~= nil) then pxm=1 end + if (string.find(nxp.name, "pipeworks:pipe_") ~= nil) then pxp=1 end + if (string.find(nym.name, "pipeworks:pipe_") ~= nil) then pym=1 end + if (string.find(nyp.name, "pipeworks:pipe_") ~= nil) then pyp=1 end + if (string.find(nzm.name, "pipeworks:pipe_") ~= nil) then pzm=1 end + if (string.find(nzp.name, "pipeworks:pipe_") ~= nil) then pzp=1 end + +-- Special handling for valves... + + if (string.find(nxm.name, "pipeworks:valve") ~= nil) + and (nxm.param2 == 0 or nxm.param2 == 2) then + pxm=1 + end + + if (string.find(nxp.name, "pipeworks:valve") ~= nil) + and (nxp.param2 == 0 or nxp.param2 == 2) then + pxp=1 + end + + if (string.find(nzm.name, "pipeworks:valve") ~= nil) + and (nzm.param2 == 1 or nzm.param2 == 3) then + pzm=1 + end + + if (string.find(nzp.name, "pipeworks:valve") ~= nil) + and (nzp.param2 == 1 or nzp.param2 == 3) then + pzp=1 + end + +-- ...flow sensors... + + if (string.find(nxm.name, "pipeworks:flow_sensor") ~= nil) + and (nxm.param2 == 0 or nxm.param2 == 2) then + pxm=1 + end + + if (string.find(nxp.name, "pipeworks:flow_sensor") ~= nil) + and (nxp.param2 == 0 or nxp.param2 == 2) then + pxp=1 + end + + if (string.find(nzm.name, "pipeworks:flow_sensor") ~= nil) + and (nzm.param2 == 1 or nzm.param2 == 3) then + pzm=1 + end + + if (string.find(nzp.name, "pipeworks:flow_sensor") ~= nil) + and (nzp.param2 == 1 or nzp.param2 == 3) then + pzp=1 + end + +-- ...spigots... + + if (string.find(nxm.name, "pipeworks:spigot") ~= nil) + and nxm.param2 == 1 then + pxm=1 + end + + if (string.find(nxp.name, "pipeworks:spigot") ~= nil) + and nxp.param2 == 3 then + pxp=1 + end + + if (string.find(nzm.name, "pipeworks:spigot") ~= nil) + and nzm.param2 == 0 then + pzm=1 + end + + if (string.find(nzp.name, "pipeworks:spigot") ~= nil) + and nzp.param2 == 2 then + pzp=1 + end + +-- ...sealed pipe entry/exit... + + if (string.find(nxm.name, "pipeworks:entry_panel") ~= nil) + and (nxm.param2 == 1 or nxm.param2 == 3) then + pxm=1 + end + + if (string.find(nxp.name, "pipeworks:entry_panel") ~= nil) + and (nxp.param2 == 1 or nxp.param2 == 3) then + pxp=1 + end + + if (string.find(nzm.name, "pipeworks:entry_panel") ~= nil) + and (nzm.param2 == 0 or nzm.param2 == 2) then + pzm=1 + end + + if (string.find(nzp.name, "pipeworks:entry_panel") ~= nil) + and (nzp.param2 == 0 or nzp.param2 == 2) then + pzp=1 + end + + if (string.find(nym.name, "pipeworks:entry_panel") ~= nil) + and nym.param2 == 13 then + pym=1 + end + + if (string.find(nyp.name, "pipeworks:entry_panel") ~= nil) + and nyp.param2 == 13 then + pyp=1 + end + + +-- ...pumps, grates... + + if (string.find(nym.name, "pipeworks:grating") ~= nil) or + (string.find(nym.name, "pipeworks:pump") ~= nil) then + pym=1 + end + +-- ...fountainheads... + + if (string.find(nyp.name, "pipeworks:fountainhead") ~= nil) then + pyp=1 + end + +-- ... and storage tanks. + + if (string.find(nym.name, "pipeworks:storage_tank_") ~= nil) then + pym=1 + end + + if (string.find(nyp.name, "pipeworks:storage_tank_") ~= nil) then + pyp=1 + end + +-- ...extra devices specified via the function's parameters +-- ...except that this part is not implemented yet +-- +-- xxx = nxm, nxp, nym, nyp, nzm, or nzp depending on the direction to check +-- yyy = pxm, pxp, pym, pyp, pzm, or pzp accordingly. +-- +-- if string.find(xxx.name, "modname:nodename") ~= nil then +-- yyy = 1 +-- end +-- +-- for example: +-- +-- if string.find(nym.name, "aero:outlet") ~= nil then +-- pym = 1 +-- end +-- + + return pxm+8*pxp+2*pym+16*pyp+4*pzm+32*pzp +end + +function pipeworks.look_for_stackable_tanks(pos) + local tym = minetest.get_node({ x=pos.x , y=pos.y-1, z=pos.z }) + + if string.find(tym.name, "pipeworks:storage_tank_") ~= nil or + string.find(tym.name, "pipeworks:expansion_tank_") ~= nil then + minetest.add_node(pos, { name = "pipeworks:expansion_tank_0", param2 = tym.param2}) + end +end + diff --git a/mods/pipeworks/autoplace_tubes.lua b/mods/pipeworks/autoplace_tubes.lua new file mode 100644 index 00000000..b6ed8b75 --- /dev/null +++ b/mods/pipeworks/autoplace_tubes.lua @@ -0,0 +1,130 @@ +-- autorouting for pneumatic tubes + +local function is_tube(nodename) + return table.contains(pipeworks.tubenodes, nodename) +end + +--a function for determining which side of the node we are on +local function nodeside(node, tubedir) + if node.param2 < 0 or node.param2 > 23 then + node.param2 = 0 + end + + local backdir = minetest.facedir_to_dir(node.param2) + local back = vector.dot(backdir, tubedir) + if back == 1 then + return "back" + elseif back == -1 then + return "front" + end + + local topdir = minetest.facedir_to_top_dir(node.param2) + local top = vector.dot(topdir, tubedir) + if top == 1 then + return "top" + elseif top == -1 then + return "bottom" + end + + local rightdir = minetest.facedir_to_right_dir(node.param2) + local right = vector.dot(rightdir, tubedir) + if right == 1 then + return "right" + else + return "left" + end +end + +local vts = {0, 3, 1, 4, 2, 5} +local tube_table = {[0] = 1, 2, 2, 4, 2, 4, 4, 5, 2, 3, 4, 6, 4, 6, 5, 7, 2, 4, 3, 6, 4, 5, 6, 7, 4, 6, 6, 8, 5, 7, 7, 9, 2, 4, 4, 5, 3, 6, 6, 7, 4, 6, 5, 7, 6, 8, 7, 9, 4, 5, 6, 7, 6, 7, 8, 9, 5, 7, 7, 9, 7, 9, 9, 10} +local tube_table_facedirs = {[0] = 0, 0, 5, 0, 3, 4, 3, 0, 2, 0, 2, 0, 6, 4, 3, 0, 7, 12, 5, 12, 7, 4, 5, 5, 18, 20, 16, 0, 7, 4, 7, 0, 1, 8, 1, 1, 1, 13, 1, 1, 10, 8, 2, 2, 17, 4, 3, 6, 9, 9, 9, 9, 21, 13, 1, 1, 10, 10, 11, 2, 19, 4, 3, 0} +local function tube_autoroute(pos) + local active = {0, 0, 0, 0, 0, 0} + local nctr = minetest.get_node(pos) + if not is_tube(nctr.name) then return end + + local adjustments = { + {x = -1, y = 0, z = 0}, + {x = 1, y = 0, z = 0}, + {x = 0, y = -1, z = 0}, + {x = 0, y = 1, z = 0}, + {x = 0, y = 0, z = -1}, + {x = 0, y = 0, z = 1} + } + -- xm = 1, xp = 2, ym = 3, yp = 4, zm = 5, zp = 6 + + local positions = {} + local nodes = {} + for i, adj in ipairs(adjustments) do + positions[i] = vector.add(pos, adj) + nodes[i] = minetest.get_node(positions[i]) + end + + for i, node in ipairs(nodes) do + local idef = minetest.registered_nodes[node.name] + -- handle the tubes themselves + if is_tube(node.name) then + active[i] = 1 + -- handle new style connectors + elseif idef and idef.tube and idef.tube.connect_sides then + local dir = adjustments[i] + if idef.tube.connect_sides[nodeside(node, vector.multiply(dir, -1))] then + active[i] = 1 + end + end + end + + -- all sides checked, now figure which tube to use. + + local nodedef = minetest.registered_nodes[nctr.name] + local basename = nodedef.basename + if nodedef.style == "old" then + local nsurround = "" + for i, n in ipairs(active) do + nsurround = nsurround..n + end + nctr.name = basename.."_"..nsurround + elseif nodedef.style == "6d" then + local s = 0 + for i, n in ipairs(active) do + if n == 1 then + s = s + 2^vts[i] + end + end + nctr.name = basename.."_"..tube_table[s] + nctr.param2 = tube_table_facedirs[s] + end + minetest.swap_node(pos, nctr) +end + +function pipeworks.scan_for_tube_objects(pos) + for side = 0, 6 do + tube_autoroute(vector.add(pos, directions.side_to_dir(side))) + end +end + +minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack) + if minetest.registered_items[newnode.name] + and minetest.registered_items[newnode.name].tube + and minetest.registered_items[newnode.name].tube.connect_sides then + pipeworks.scan_for_tube_objects(pos) + end +end) + +minetest.register_on_dignode(function(pos, oldnode, digger) + if minetest.registered_items[oldnode.name] + and minetest.registered_items[oldnode.name].tube + and minetest.registered_items[oldnode.name].tube.connect_sides then + pipeworks.scan_for_tube_objects(pos) + end +end) + +if minetest.get_modpath("mesecons_mvps") then + mesecon.register_on_mvps_move(function(moved_nodes) + for _, n in ipairs(moved_nodes) do + pipeworks.scan_for_tube_objects(n.pos) + pipeworks.scan_for_tube_objects(n.oldpos) + end + end) +end + diff --git a/mods/pipeworks/changelog.txt b/mods/pipeworks/changelog.txt new file mode 100644 index 00000000..251df29b --- /dev/null +++ b/mods/pipeworks/changelog.txt @@ -0,0 +1,93 @@ +Changelog +--------- + +2013-01-13: Tubes can transport items now! Namely, I added Novatux/Nore's item +transport mod as a default part of this mod, to make tubes do something useful! +Thanks to Nore and RealBadAngel for the code contributions! + +2013-01-05: made storage tanks connect from top/bottom, made storage tank and +pipe textures use the ^ combine operator so they can show the actual liquid +going through the pipes/tanks. + +2013-01-04 (a bit later): Made pipes able to carry water! It was just a minor +logic error resulting from moving the water flowing code into it's own file +when I originally imported it. Many thanks to Mauvebic for writing it! + +2013-01-04: First stage of integrating Mauvebic's water flowing code. This is +experimental and doesn't move water yet - but at least it doesn't break +anything :-) + +2013-01-01: Various minor tweaks to textures, facedir settings, some other +stuff. Changed crafting recipes to account for revamped pumps, valves, etc. +Now requires the moreores mod and most recent git (for mese crystal fragments) +to craft a pump. Added a "sealed" entry/exit panel (really just a horizontal +pipe with a metal panel overlayed into the middle). Also, tweaked pipes to +always drop the empty ones. Revamped pumps so that now they should sit in/on +liquid and be connected only from the top, relegated grates to decorational- +only, added outlet spigot. Got rid of a few obsolete textures. Got rid of +that whole _x and _z naming thing - now all directional devices (pumps, valves, +spigots, tanks) use facedir. Valves, spigots no longer auto-rotate to find +nearby pipes. + +2012-09-17: Added test object for pneumatic tube autorouting code, made tubes +connect to it and any object that bears groups={tubedevice=1} (connects to any +side) + +2012-09-05: All recipes doubled except for junglegrass -> plastic sheet (since +that is derived from home decor) + +2012-09-02: Fixed plastic sheeting recipe. Added crafting recipes for various +objects, with options: If homedecor is installed, use the plastic sheeting +therein. If not, we define it manually. If the Technic mod is installed, +don't define any recipes at all. Also removed the extra "loaded!" messages and +tweaked the default pipe alias to point to something that is actually visible +:-) + +2012-09-01: flattened wielded pipe segment. + +2012-08-24: Added square-ish pneumatic tubes with their own autoplace code +(does not connect to steel pipes or pipe-oriented devices), then revised their +textures shortly after. Fixed a recursion bug that sometimes caused a stack +overflow. Old pipes were overriding the pipeworks:pipe defintion that belongs +with the new pipes. + +2012-08-22: Added outlet grate, made it participate in autoplace algorithm. +Extended storage tank to show fill level in 10% steps (0% to 100%). Added +"expansion tank" that appears if the user stacks tanks upwards. (Downwards is +not checked). + +2012-08-21: Made storage tank participate in autoplace algorithm. Tuned API a +little to allow for more flexible placement. Re-organized code a bit to allow +for some upcoming rules changes. Made storage tanks' upper/lower fittins and +intake grate participate in autoplace algorithm. + +2012-08-20: Added temporary nodes for storage tank and intake grating, but +without autoplace. + +2012-08-19: Pumps and valves now fully participate in the +auto-rotate/auto-place algorithm. + +2012-08-18: Total rewrite again. All pipes are now nice and round-looking, and +they auto-connect! Also added temporary nodes for pump and valve (each with an +on/off setting - punch to change). No crafting recipes yet and the pipes still +don't do anything useful yet. Soon. + +2012-08-06: Moved this changelog off the forum post and into a separate file. + +2012-08-05 (multiple updates): Rewrote pipeworks to use loops and tables to +create the nodes. Requires far less code now. Added -X, +X, -Y, +Y, -Z, +Z +capped stubs and a short centered horizontal segment. Changed node definitions +so that the aforementioned "short centered" segment is given on dig/drop. +Renamed it to just "pipeworks:pipe" (and pipe_loaded). Added empty/loaded +indicator images to the capped ends, removed some redundant comments. Made the +empty/loaded indication at the capped end more prominent. + +2012-07-21: Added screenshot showing pipes as they look now that nodebox +texture rotation is fixed. + +2012-07-18: Changed the mod name and all internals to 'pipeworks' instead of +'pipes'... after a couple of mistakes :-) + +2012-07-12: moved project to github. + +2012-06-23: Initial release, followed by reworking the textures a bit. diff --git a/mods/pipeworks/common.lua b/mods/pipeworks/common.lua new file mode 100644 index 00000000..b50b7337 --- /dev/null +++ b/mods/pipeworks/common.lua @@ -0,0 +1,146 @@ +---------------------- +-- Vector functions -- +---------------------- + +function vector.cross(a, b) + return { + x = a.y * b.z - a.z * b.y, + y = a.z * b.x - a.x * b.z, + z = a.x * b.y - a.y * b.x + } +end + +function vector.dot(a, b) + return a.x * b.x + a.y * b.y + a.z * b.z +end + +----------------------- +-- Facedir functions -- +----------------------- + +function minetest.facedir_to_top_dir(facedir) + return ({[0] = {x = 0, y = 1, z = 0}, + {x = 0, y = 0, z = 1}, + {x = 0, y = 0, z = -1}, + {x = 1, y = 0, z = 0}, + {x = -1, y = 0, z = 0}, + {x = 0, y = -1, z = 0}}) + [math.floor(facedir / 4)] +end + +function minetest.facedir_to_right_dir(facedir) + return vector.cross( + minetest.facedir_to_top_dir(facedir), + minetest.facedir_to_dir(facedir) + ) +end + +directions = {} +function directions.side_to_dir(side) + return ({[0] = vector.new(), + vector.new( 0, 1, 0), + vector.new( 0, -1, 0), + vector.new( 1, 0, 0), + vector.new(-1, 0, 0), + vector.new( 0, 0, 1), + vector.new( 0, 0, -1) + })[side] +end + +function directions.dir_to_side(dir) + local c = vector.dot(dir, vector.new(1, 2, 3)) + 4 + return ({6, 2, 4, 0, 3, 1, 5})[c] +end + +---------------------- +-- String functions -- +---------------------- + +--[[function string.split(str, sep) + local fields = {} + local index = 1 + local expr = "([^"..sep.."])+" + string.gsub(str, expr, function(substring) + fields[index] = substring + index = index + 1 + end) + return fields +end]] + +function string.startswith(str, substr) + return str:sub(1, substr:len()) == substr +end + +--------------------- +-- Table functions -- +--------------------- + +function table.contains(tbl, element) + for _, elt in pairs(tbl) do + if elt == element then + return true + end + end + return false +end + +function table.extend(tbl, tbl2) + local index = #tbl + 1 + for _, elt in ipairs(tbl2) do + tbl[index] = elt + index = index + 1 + end +end + +function table.recursive_replace(tbl, pattern, replace_with) + if type(tbl) == "table" then + local tbl2 = {} + for key, value in pairs(tbl) do + tbl2[key] = table.recursive_replace(value, pattern, replace_with) + end + return tbl2 + elseif type(tbl) == "string" then + return tbl:gsub(pattern, replace_with) + else + return tbl + end +end + +------------------------ +-- Formspec functions -- +------------------------ + +fs_helpers = {} +function fs_helpers.on_receive_fields(pos, fields) + local meta = minetest.get_meta(pos) + for field, value in pairs(fields) do + if field:startswith("fs_helpers_cycling:") then + local l = field:split(":") + local new_value = tonumber(l[2]) + local meta_name = l[3] + meta:set_int(meta_name, new_value) + end + end +end + +function fs_helpers.cycling_button(meta, base, meta_name, values) + local current_value = meta:get_int(meta_name) + local new_value = (current_value + 1) % (#values) + local text = values[current_value + 1] + local field = "fs_helpers_cycling:"..new_value..":"..meta_name + return base..";"..field..";"..minetest.formspec_escape(text).."]" +end + +--------- +-- Env -- +--------- + +function minetest.load_position(pos) + if pos.x < -30912 or pos.y < -30912 or pos.z < -30912 or + pos.x > 30927 or pos.y > 30927 or pos.z > 30927 then return end + if minetest.get_node_or_nil(pos) then + return + end + local vm = minetest.get_voxel_manip() + vm:read_from_map(pos, pos) +end diff --git a/mods/pipeworks/compat.lua b/mods/pipeworks/compat.lua new file mode 100644 index 00000000..a1c1d453 --- /dev/null +++ b/mods/pipeworks/compat.lua @@ -0,0 +1,130 @@ +-- this bit of code modifies the default chests and furnaces to be compatible +-- with pipeworks. + +minetest.override_item("default:furnace", { + tiles = { + "default_furnace_top.png^pipeworks_tube_connection_stony.png", + "default_furnace_bottom.png^pipeworks_tube_connection_stony.png", + "default_furnace_side.png^pipeworks_tube_connection_stony.png", + "default_furnace_side.png^pipeworks_tube_connection_stony.png", + "default_furnace_side.png^pipeworks_tube_connection_stony.png", + "default_furnace_front.png" + }, + groups = {cracky = 2, tubedevice = 1, tubedevice_receiver = 1}, + tube = { + insert_object = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if direction.y == 1 then + return inv:add_item("fuel",stack) + else + return inv:add_item("src",stack) + end + end, + can_insert = function(pos,node,stack,direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if direction.y == 1 then + return inv:room_for_item("fuel", stack) + else + return inv:room_for_item("src", stack) + end + end, + input_inventory = "dst", + connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1} + }, +}) + +minetest.override_item("default:furnace_active", { + tiles = { + "default_furnace_top.png^pipeworks_tube_connection_stony.png", + "default_furnace_bottom.png^pipeworks_tube_connection_stony.png", + "default_furnace_side.png^pipeworks_tube_connection_stony.png", + "default_furnace_side.png^pipeworks_tube_connection_stony.png", + "default_furnace_side.png^pipeworks_tube_connection_stony.png", + { + image = "default_furnace_front_active.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 1.5 + }, + } + }, + groups = {cracky = 2, tubedevice = 1, tubedevice_receiver = 1, not_in_creative_inventory = 1}, + tube = { + insert_object = function(pos,node,stack,direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if direction.y == 1 then + return inv:add_item("fuel", stack) + else + return inv:add_item("src", stack) + end + end, + can_insert = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + if direction.y == 1 then + return inv:room_for_item("fuel", stack) + else + return inv:room_for_item("src", stack) + end + end, + input_inventory = "dst", + connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1} + }, +}) + +minetest.override_item("default:chest", { + tiles = { + "default_chest_top.png^pipeworks_tube_connection_wooden.png", + "default_chest_top.png^pipeworks_tube_connection_wooden.png", + "default_chest_side.png^pipeworks_tube_connection_wooden.png", + "default_chest_side.png^pipeworks_tube_connection_wooden.png", + "default_chest_side.png^pipeworks_tube_connection_wooden.png", + "default_chest_front.png" + }, + groups = {choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1, tubedevice_receiver = 1}, + tube = { + insert_object = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:add_item("main", stack) + end, + can_insert = function(pos, node, stack, direction) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:room_for_item("main", stack) + end, + input_inventory = "main", + connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1} + }, +}) + +minetest.override_item("default:chest_locked", { + tiles = { + "default_chest_top.png^pipeworks_tube_connection_wooden.png", + "default_chest_top.png^pipeworks_tube_connection_wooden.png", + "default_chest_side.png^pipeworks_tube_connection_wooden.png", + "default_chest_side.png^pipeworks_tube_connection_wooden.png", + "default_chest_side.png^pipeworks_tube_connection_wooden.png", + "default_chest_lock.png" + }, + groups = {choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1, tubedevice_receiver = 1}, + tube = { + insert_object = function(pos, node, stack, direction) + local meta = minetest.env:get_meta(pos) + local inv = meta:get_inventory() + return inv:add_item("main", stack) + end, + can_insert = function(pos, node, stack, direction) + local meta = minetest.env:get_meta(pos) + local inv = meta:get_inventory() + return inv:room_for_item("main", stack) + end, + connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1} + }, +}) diff --git a/mods/pipeworks/crafts.lua b/mods/pipeworks/crafts.lua new file mode 100644 index 00000000..e83718f9 --- /dev/null +++ b/mods/pipeworks/crafts.lua @@ -0,0 +1,321 @@ +-- Crafting recipes for pipes + +minetest.register_craft( { + output = "pipeworks:pipe_1_empty 12", + recipe = { + { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }, + { "", "", "" }, + { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:spigot 3", + recipe = { + { "pipeworks:pipe_1_empty", "" }, + { "", "pipeworks:pipe_1_empty" }, + }, +}) + +minetest.register_craft( { + output = "pipeworks:entry_panel_empty 2", + recipe = { + { "", "default:steel_ingot", "" }, + { "", "pipeworks:pipe_1_empty", "" }, + { "", "default:steel_ingot", "" }, + }, +}) + +-- Various ancillary pipe devices + +minetest.register_craft( { + output = "pipeworks:pump_off 2", + recipe = { + { "default:stone", "default:steel_ingot", "default:stone" }, + { "default:copper_ingot", "default:mese_crystal_fragment", "default:copper_ingot" }, + { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:valve_off_empty 2", + recipe = { + { "", "group:stick", "" }, + { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }, + { "", "default:steel_ingot", "" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:storage_tank_0 2", + recipe = { + { "", "default:steel_ingot", "default:steel_ingot" }, + { "default:steel_ingot", "default:glass", "default:steel_ingot" }, + { "default:steel_ingot", "default:steel_ingot", "" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:grating 2", + recipe = { + { "default:steel_ingot", "", "default:steel_ingot" }, + { "", "pipeworks:pipe_1_empty", "" }, + { "default:steel_ingot", "", "default:steel_ingot" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:flow_sensor_empty 2", + recipe = { + { "pipeworks:pipe_1_empty", "mesecons:mesecon", "pipeworks:pipe_1_empty" }, + }, +}) + +minetest.register_craft( { + output = "pipeworks:fountainhead 2", + recipe = { + { "pipeworks:pipe_1_empty" }, + { "pipeworks:pipe_1_empty" } + }, +}) + + +-- Crafting recipes for pneumatic tubes + +-- If homedecor is not installed, we need to register its crafting chain for +-- plastic sheeting so that pipeworks remains compatible with it. + +if minetest.get_modpath("homedecor") == nil then + + minetest.register_craftitem(":homedecor:oil_extract", { + description = "Oil extract", + inventory_image = "homedecor_oil_extract.png", + }) + + minetest.register_craftitem(":homedecor:paraffin", { + description = "Unprocessed paraffin", + inventory_image = "homedecor_paraffin.png", + }) + + minetest.register_alias("homedecor:plastic_base", "homedecor:paraffin") + + minetest.register_craftitem(":homedecor:plastic_sheeting", { + description = "Plastic sheet", + inventory_image = "homedecor_plastic_sheeting.png", + }) + + minetest.register_craft({ + type = "shapeless", + output = "homedecor:oil_extract 4", + recipe = { + "group:leaves", + "group:leaves", + "group:leaves", + "group:leaves", + "group:leaves", + "group:leaves" + } + }) + + minetest.register_craft({ + type = "cooking", + output = "homedecor:paraffin", + recipe = "homedecor:oil_extract", + }) + + minetest.register_craft({ + type = "cooking", + output = "homedecor:plastic_sheeting", + recipe = "homedecor:paraffin", + }) + + minetest.register_craft({ + type = "fuel", + recipe = "homedecor:oil_extract", + burntime = 30, + }) + + minetest.register_craft({ + type = "fuel", + recipe = "homedecor:paraffin", + burntime = 30, + }) + + minetest.register_craft({ + type = "fuel", + recipe = "homedecor:plastic_sheeting", + burntime = 30, + }) +end + +minetest.register_craft( { + output = "pipeworks:one_way_tube 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "group:stick", "default:mese_crystal", "homedecor:plastic_sheeting" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + + +minetest.register_craft( { + output = "pipeworks:tube_1 6", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "", "", "" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:mese_tube_1 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "", "default:mese_crystal", "" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + type = "shapeless", + output = "pipeworks:mese_tube_000000", + recipe = { + "pipeworks:tube_1", + "default:mese_crystal_fragment", + "default:mese_crystal_fragment", + "default:mese_crystal_fragment", + "default:mese_crystal_fragment" + }, +}) + +minetest.register_craft( { + output = "pipeworks:conductor_tube_off_1 6", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "mesecons:mesecon", "mesecons:mesecon", "mesecons:mesecon" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:detector_tube_off_1 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "mesecons:mesecon", "mesecons_materials:silicon", "mesecons:mesecon" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:accelerator_tube_1 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "default:mese_crystal_fragment", "default:steel_ingot", "default:mese_crystal_fragment" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:teleport_tube_1 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "default:desert_stone", "default:mese_block", "default:desert_stone" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:sand_tube_1 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "default:sand", "default:sand", "default:sand" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:sand_tube_1 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "default:desert_sand", "default:desert_sand", "default:desert_sand" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:sand_tube_1", + recipe = { + { "default:desert_sand", "pipeworks:tube_1", "default:desert_sand" }, + }, +}) + +minetest.register_craft( { + output = "pipeworks:mese_sand_tube_1 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "default:sand", "default:mese_crystal", "default:sand" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:mese_sand_tube_1 2", + recipe = { + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }, + { "default:desert_sand", "default:mese_crystal", "default:desert_sand" }, + { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:crossing_tube_1 5", + recipe = { + { "", "pipeworks:tube_1", "" }, + { "pipeworks:tube_1", "pipeworks:tube_1", "pipeworks:tube_1" }, + { "", "pipeworks:tube_1", "" } + }, +}) + + +minetest.register_craft( { + type = "shapeless", + output = "pipeworks:mese_sand_tube_1", + recipe = { + "pipeworks:sand_tube_1", + "default:mese_crystal_fragment", + "default:mese_crystal_fragment", + "default:mese_crystal_fragment", + "default:mese_crystal_fragment" + }, +}) + +-- Various ancillary tube devices + +minetest.register_craft( { + output = "pipeworks:filter 2", + recipe = { + { "default:steel_ingot", "default:steel_ingot", "homedecor:plastic_sheeting" }, + { "group:stick", "default:mese_crystal", "homedecor:plastic_sheeting" }, + { "default:steel_ingot", "default:steel_ingot", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:mese_filter 2", + recipe = { + { "default:steel_ingot", "default:steel_ingot", "homedecor:plastic_sheeting" }, + { "group:stick", "default:mese", "homedecor:plastic_sheeting" }, + { "default:steel_ingot", "default:steel_ingot", "homedecor:plastic_sheeting" } + }, +}) + +minetest.register_craft( { + output = "pipeworks:autocrafter 2", + recipe = { + { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" }, + { "homedecor:plastic_sheeting", "default:steel_ingot", "homedecor:plastic_sheeting" }, + { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" } + }, +}) + + diff --git a/mods/pipeworks/default_settings.txt b/mods/pipeworks/default_settings.txt new file mode 100644 index 00000000..4aa41508 --- /dev/null +++ b/mods/pipeworks/default_settings.txt @@ -0,0 +1,19 @@ +-- Various settings + +pipeworks.enable_pipes = true +pipeworks.enable_autocrafter = true +pipeworks.enable_deployer = true +pipeworks.enable_dispenser = true +pipeworks.enable_node_breaker = true +pipeworks.enable_teleport_tube = true +pipeworks.enable_pipe_devices = true +pipeworks.enable_redefines = true +pipeworks.enable_mese_tube = true +pipeworks.enable_detector_tube = true +pipeworks.enable_conductor_tube = true +pipeworks.enable_accelerator_tube = true +pipeworks.enable_crossing_tube = true +pipeworks.enable_sand_tube = true +pipeworks.enable_mese_sand_tube = true +pipeworks.enable_one_way_tube = true +pipeworks.enable_cyclic_mode = true diff --git a/mods/pipeworks/depends.txt b/mods/pipeworks/depends.txt new file mode 100644 index 00000000..02a542cb --- /dev/null +++ b/mods/pipeworks/depends.txt @@ -0,0 +1,3 @@ +default +mesecons? +mesecons_mvps? diff --git a/mods/pipeworks/devices.lua b/mods/pipeworks/devices.lua new file mode 100644 index 00000000..fc279883 --- /dev/null +++ b/mods/pipeworks/devices.lua @@ -0,0 +1,702 @@ +-- List of devices that should participate in the autoplace algorithm + +local pipereceptor_on = nil +local pipereceptor_off = nil + +if mesecon then + pipereceptor_on = { + receptor = { + state = mesecon.state.on, + rules = pipeworks.mesecons_rules + } + } + + pipereceptor_off = { + receptor = { + state = mesecon.state.off, + rules = pipeworks.mesecons_rules + } + } +end + +local pipes_devicelist = { + "pump", + "valve", + "storage_tank_0", + "storage_tank_1", + "storage_tank_2", + "storage_tank_3", + "storage_tank_4", + "storage_tank_5", + "storage_tank_6", + "storage_tank_7", + "storage_tank_8", + "storage_tank_9", + "storage_tank_10" +} + +-- Now define the nodes. + +local states = { "on", "off" } +local dgroups = "" +local pumpboxes = {} + +for s in ipairs(states) do + + if states[s] == "off" then + dgroups = {snappy=3, pipe=1} + else + dgroups = {snappy=3, pipe=1, not_in_creative_inventory=1} + end + + pumpboxes = {} + + pipeworks.add_node_box(pumpboxes, pipeworks.pipe_pumpbody) + pipeworks.add_node_box(pumpboxes, pipeworks.pipe_topstub) + + minetest.register_node("pipeworks:pump_"..states[s], { + description = "Pump/Intake Module", + drawtype = "nodebox", + tiles = { + "pipeworks_pump_top.png", + "pipeworks_pump_bottom.png", + "pipeworks_pump_sides.png", + "pipeworks_pump_sides.png", + "pipeworks_pump_sides.png", + "pipeworks_pump_"..states[s]..".png" + }, + paramtype = "light", + paramtype2 = "facedir", + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 } + }, + node_box = { + type = "fixed", + fixed = pumpboxes + }, + groups = dgroups, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + drop = "pipeworks:pump_off", + mesecons = {effector = { + action_on = function (pos, node) + minetest.add_node(pos,{name="pipeworks:pump_on", param2 = node.param2}) + end, + action_off = function (pos, node) + minetest.add_node(pos,{name="pipeworks:pump_off", param2 = node.param2}) + end + }}, + on_punch = function(pos, node, puncher) + local fdir = minetest.get_node(pos).param2 + minetest.add_node(pos, { name = "pipeworks:pump_"..states[3-s], param2 = fdir }) + end + }) + + local valveboxes = {} + pipeworks.add_node_box(valveboxes, pipeworks.pipe_leftstub) + pipeworks.add_node_box(valveboxes, pipeworks.pipe_valvebody) + if states[s] == "off" then + pipeworks.add_node_box(valveboxes, pipeworks.pipe_valvehandle_off) + else + pipeworks.add_node_box(valveboxes, pipeworks.pipe_valvehandle_on) + end + pipeworks.add_node_box(valveboxes, pipeworks.pipe_rightstub) + local tilex = "pipeworks_valvebody_ends.png" + local tilez = "pipeworks_valvebody_sides.png" + + minetest.register_node("pipeworks:valve_"..states[s].."_empty", { + description = "Valve", + drawtype = "nodebox", + tiles = { + "pipeworks_valvebody_top_"..states[s]..".png", + "pipeworks_valvebody_bottom.png", + tilex, + tilex, + tilez, + tilez, + }, + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + selection_box = { + type = "fixed", + fixed = { -8/16, -4/16, -5/16, 8/16, 5/16, 5/16 } + }, + node_box = { + type = "fixed", + fixed = valveboxes + }, + groups = dgroups, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + drop = "pipeworks:valve_off_empty", + mesecons = {effector = { + action_on = function (pos, node) + minetest.add_node(pos,{name="pipeworks:valve_on_empty", param2 = node.param2}) + end, + action_off = function (pos, node) + minetest.add_node(pos,{name="pipeworks:valve_off_empty", param2 = node.param2}) + end + }}, + on_punch = function(pos, node, puncher) + local fdir = minetest.get_node(pos).param2 + minetest.add_node(pos, { name = "pipeworks:valve_"..states[3-s].."_empty", param2 = fdir }) + end + }) +end + +local valveboxes = {} +pipeworks.add_node_box(valveboxes, pipeworks.pipe_leftstub) +pipeworks.add_node_box(valveboxes, pipeworks.pipe_valvebody) +pipeworks.add_node_box(valveboxes, pipeworks.pipe_rightstub) +pipeworks.add_node_box(valveboxes, pipeworks.pipe_valvehandle_on) + +minetest.register_node("pipeworks:valve_on_loaded", { + description = "Valve", + drawtype = "nodebox", + tiles = { + "pipeworks_valvebody_top_on.png", + "pipeworks_valvebody_bottom.png", + "pipeworks_valvebody_ends.png", + "pipeworks_valvebody_ends.png", + "pipeworks_valvebody_sides.png", + "pipeworks_valvebody_sides.png", + }, + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + selection_box = { + type = "fixed", + fixed = { -8/16, -4/16, -5/16, 8/16, 5/16, 5/16 } + }, + node_box = { + type = "fixed", + fixed = valveboxes + }, + groups = {snappy=3, pipe=1, not_in_creative_inventory=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + drop = "pipeworks:valve_off_empty", + mesecons = {effector = { + action_on = function (pos, node) + minetest.add_node(pos,{name="pipeworks:valve_on_empty", param2 = node.param2}) + end, + action_off = function (pos, node) + minetest.add_node(pos,{name="pipeworks:valve_off_empty", param2 = node.param2}) + end + }}, + on_punch = function(pos, node, puncher) + local fdir = minetest.get_node(pos).param2 + minetest.add_node(pos, { name = "pipeworks:valve_off_empty", param2 = fdir }) + end +}) + +-- grating + +minetest.register_node("pipeworks:grating", { + description = "Decorative grating", + tiles = { + "pipeworks_grating_top.png", + "pipeworks_grating_sides.png", + "pipeworks_grating_sides.png", + "pipeworks_grating_sides.png", + "pipeworks_grating_sides.png", + "pipeworks_grating_sides.png" + }, + sunlight_propagates = true, + paramtype = "light", + groups = {snappy=3, pipe=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, +}) + +-- outlet spigot + + local spigotboxes = {} + pipeworks.add_node_box(spigotboxes, pipeworks.pipe_backstub) + pipeworks.add_node_box(spigotboxes, pipeworks.spigot_bottomstub) + pipeworks.add_node_box(spigotboxes, pipeworks.pipe_bendsphere) + + local spigotboxes_pouring = {} + pipeworks.add_node_box(spigotboxes_pouring, pipeworks.spigot_stream) + pipeworks.add_node_box(spigotboxes_pouring, pipeworks.pipe_backstub) + pipeworks.add_node_box(spigotboxes_pouring, pipeworks.spigot_bottomstub) + pipeworks.add_node_box(spigotboxes_pouring, pipeworks.pipe_bendsphere) + +minetest.register_node("pipeworks:spigot", { + description = "Spigot outlet", + drawtype = "nodebox", + tiles = { + "pipeworks_spigot_sides.png", + "pipeworks_pipe_end_empty.png", + "pipeworks_spigot_sides.png", + "pipeworks_spigot_sides.png", + "pipeworks_pipe_end_empty.png", + "pipeworks_spigot_sides.png" + }, + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + groups = {snappy=3, pipe=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + node_box = { + type = "fixed", + fixed = spigotboxes, + }, + selection_box = { + type = "fixed", + fixed = { -2/16, -6/16, -2/16, 2/16, 2/16, 8/16 } + } +}) + +minetest.register_node("pipeworks:spigot_pouring", { + description = "Spigot outlet", + drawtype = "nodebox", + tiles = { + "pipeworks_spigot_sides.png", + "default_water.png^pipeworks_spigot_bottom2.png", + { name = "default_water_flowing_animated.png^pipeworks_spigot_sides2.png", + animation = { + type = "vertical_frames", + aspect_w=16, + aspect_h=16, + length=0.8 + } + }, + { name = "default_water_flowing_animated.png^pipeworks_spigot_sides2.png", + animation = { + type = "vertical_frames", + aspect_w=16, + aspect_h=16, + length=0.8 + } + }, + { name = "default_water_flowing_animated.png^pipeworks_spigot_sides2.png", + animation = { + type = "vertical_frames", + aspect_w=16, + aspect_h=16, + length=0.8 + } + }, + { name = "default_water_flowing_animated.png^pipeworks_spigot_sides2.png", + animation = { + type = "vertical_frames", + aspect_w=16, + aspect_h=16, + length=0.8 + } + }, + }, + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + groups = {snappy=3, pipe=1, not_in_creative_inventory=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + node_box = { + type = "fixed", + fixed = spigotboxes_pouring, + }, + selection_box = { + type = "fixed", + fixed = { -2/16, -6/16, -2/16, 2/16, 2/16, 8/16 } + }, + drop = "pipeworks:spigot", +}) + +-- sealed pipe entry/exit (horizontal pipe passing through a metal +-- wall, for use in places where walls should look like they're airtight) + +local airtightboxes = {} +pipeworks.add_node_box(airtightboxes, pipeworks.pipe_frontstub) +pipeworks.add_node_box(airtightboxes, pipeworks.pipe_backstub) +pipeworks.add_node_box(airtightboxes, pipeworks.entry_panel) + +minetest.register_node("pipeworks:entry_panel_empty", { + description = "Airtight Pipe entry/exit", + drawtype = "nodebox", + tiles = { + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_pipe_end_empty.png", + "pipeworks_pipe_end_empty.png" + }, + paramtype = "light", + paramtype2 = "facedir", + groups = {snappy=3, pipe=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + node_box = { + type = "fixed", + fixed = airtightboxes, + }, + selection_box = { + type = "fixed", + fixed = { + { -2/16, -2/16, -8/16, 2/16, 2/16, 8/16 }, + { -8/16, -8/16, -1/16, 8/16, 8/16, 1/16 } + } + }, + on_place = function(itemstack, placer, pointed_thing) + if not pipeworks.node_is_owned(pointed_thing.under, placer) + and not pipeworks.node_is_owned(pointed_thing.above, placer) then + local node = minetest.get_node(pointed_thing.under) + + if not minetest.registered_nodes[node.name] + or not minetest.registered_nodes[node.name].on_rightclick then + local pitch = placer:get_look_pitch() + local above = pointed_thing.above + local under = pointed_thing.under + local fdir = minetest.dir_to_facedir(placer:get_look_dir()) + local undernode = minetest.get_node(under) + local abovenode = minetest.get_node(above) + local uname = undernode.name + local aname = abovenode.name + local isabove = (above.x == under.x) and (above.z == under.z) and (pitch > 0) + local pos1 = above + + if above.x == under.x + and above.z == under.z + and ( string.find(uname, "pipeworks:pipe_") + or string.find(uname, "pipeworks:storage_") + or string.find(uname, "pipeworks:expansion_") + or ( string.find(uname, "pipeworks:grating") and not isabove ) + or ( string.find(uname, "pipeworks:pump_") and not isabove ) + or ( string.find(uname, "pipeworks:entry_panel") + and undernode.param2 == 13 ) + ) + then + fdir = 13 + end + + if minetest.registered_nodes[uname]["buildable_to"] then + pos1 = under + end + + if not minetest.registered_nodes[minetest.get_node(pos1).name]["buildable_to"] then return end + + minetest.add_node(pos1, {name = "pipeworks:entry_panel_empty", param2 = fdir }) + pipeworks.scan_for_pipe_objects(pos1) + + if not pipeworks.expect_infinite_stacks then + itemstack:take_item() + end + + else + minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) + end + end + return itemstack + end +}) + +minetest.register_node("pipeworks:entry_panel_loaded", { + description = "Airtight Pipe entry/exit", + drawtype = "nodebox", + tiles = { + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_pipe_end_empty.png", + "pipeworks_pipe_end_empty.png" + }, + paramtype = "light", + paramtype2 = "facedir", + groups = {snappy=3, pipe=1, not_in_creative_inventory=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + node_box = { + type = "fixed", + fixed = airtightboxes, + }, + selection_box = { + type = "fixed", + fixed = { + { -2/16, -2/16, -8/16, 2/16, 2/16, 8/16 }, + { -8/16, -8/16, -1/16, 8/16, 8/16, 1/16 } + } + }, + drop = "pipeworks:entry_panel_empty" +}) + +local sensorboxes = {} +pipeworks.add_node_box(sensorboxes, pipeworks.pipe_leftstub) +pipeworks.add_node_box(sensorboxes, pipeworks.pipe_sensorbody) +pipeworks.add_node_box(sensorboxes, pipeworks.pipe_rightstub) + +minetest.register_node("pipeworks:flow_sensor_empty", { + description = "Flow Sensor", + drawtype = "nodebox", + tiles = { + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_windowed_empty.png", + "pipeworks_windowed_empty.png" + }, + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + groups = {snappy=3, pipe=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + on_construct = function(pos) + if mesecon then + mesecon.receptor_off(pos, rules) + end + end, + node_box = { + type = "fixed", + fixed = sensorboxes, + }, + selection_box = { + type = "fixed", + fixed = { + { -8/16, -2/16, -2/16, 8/16, 2/16, 2/16 }, + } + }, + mesecons = pipereceptor_off +}) + +minetest.register_node("pipeworks:flow_sensor_loaded", { + description = "Flow sensor (on)", + drawtype = "nodebox", + tiles = { + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_plain.png", + "pipeworks_sensor_sides_on.png", + "pipeworks_sensor_sides_on.png" + }, + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + groups = {snappy=3, pipe=1, not_in_creative_inventory=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + on_construct = function(pos) + if mesecon then + mesecon.receptor_on(pos, rules) + end + end, + node_box = { + type = "fixed", + fixed = sensorboxes, + }, + selection_box = { + type = "fixed", + fixed = { + { -8/16, -2/16, -2/16, 8/16, 2/16, 2/16 }, + } + }, + drop = "pipeworks:flow_sensor_empty", + mesecons = pipereceptor_on +}) + +-- tanks + +for fill = 0, 10 do + local filldesc="empty" + local sgroups = {snappy=3, pipe=1, tankfill=fill+1} + local image = nil + + if fill ~= 0 then + filldesc=fill.."0% full" + sgroups = {snappy=3, pipe=1, tankfill=fill+1, not_in_creative_inventory=1} + image = "pipeworks_storage_tank_fittings.png" + end + + minetest.register_node("pipeworks:expansion_tank_"..fill, { + description = "Expansion Tank ("..filldesc..")... You hacker, you.", + tiles = { + "pipeworks_storage_tank_fittings.png", + "pipeworks_storage_tank_fittings.png", + "pipeworks_storage_tank_back.png", + "pipeworks_storage_tank_back.png", + "pipeworks_storage_tank_back.png", + pipeworks.liquid_texture.."^pipeworks_storage_tank_front_"..fill..".png" + }, + inventory_image = image, + paramtype = "light", + paramtype2 = "facedir", + groups = {snappy=3, pipe=1, tankfill=fill+1, not_in_creative_inventory=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + drop = "pipeworks:storage_tank_0", + after_place_node = function(pos) + pipeworks.look_for_stackable_tanks(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + }) + + minetest.register_node("pipeworks:storage_tank_"..fill, { + description = "Fluid Storage Tank ("..filldesc..")", + tiles = { + "pipeworks_storage_tank_fittings.png", + "pipeworks_storage_tank_fittings.png", + "pipeworks_storage_tank_back.png", + "pipeworks_storage_tank_back.png", + "pipeworks_storage_tank_back.png", + pipeworks.liquid_texture.."^pipeworks_storage_tank_front_"..fill..".png" + }, + inventory_image = image, + paramtype = "light", + paramtype2 = "facedir", + groups = sgroups, + sounds = default.node_sound_wood_defaults(), + walkable = true, + drop = "pipeworks:storage_tank_0", + after_place_node = function(pos) + pipeworks.look_for_stackable_tanks(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + }) +end + +-- fountainhead + +minetest.register_node("pipeworks:fountainhead", { + description = "Fountainhead", + drawtype = "nodebox", + tiles = { + "pipeworks_fountainhead_top.png", + "pipeworks_pipe_end.png", + "pipeworks_plain.png", + }, + sunlight_propagates = true, + paramtype = "light", + groups = {snappy=3, pipe=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + on_construct = function(pos) + if mesecon then + mesecon.receptor_on(pos, rules) + end + end, + node_box = { + type = "fixed", + fixed = pipeworks.fountainhead_model , + }, + selection_box = { + type = "fixed", + fixed = { -2/16, -8/16, -2/16, 2/16, 8/16, 2/16 } + }, +}) + +minetest.register_node("pipeworks:fountainhead_pouring", { + description = "Fountainhead", + drawtype = "nodebox", + tiles = { + "pipeworks_fountainhead_top.png", + "pipeworks_pipe_end.png", + "pipeworks_plain.png", + }, + sunlight_propagates = true, + paramtype = "light", + groups = {snappy=3, pipe=1, not_in_creative_inventory=1}, + sounds = default.node_sound_wood_defaults(), + walkable = true, + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + on_construct = function(pos) + if mesecon then + mesecon.receptor_on(pos, rules) + end + end, + node_box = { + type = "fixed", + fixed = pipeworks.fountainhead_model, + }, + selection_box = { + type = "fixed", + fixed = { -2/16, -8/16, -2/16, 2/16, 8/16, 2/16 }, + }, + drop = "pipeworks:fountainhead" +}) + +minetest.register_alias("pipeworks:valve_off_loaded", "pipeworks:valve_off_empty") + diff --git a/mods/pipeworks/flowing_logic.lua b/mods/pipeworks/flowing_logic.lua new file mode 100644 index 00000000..e0a6236d --- /dev/null +++ b/mods/pipeworks/flowing_logic.lua @@ -0,0 +1,121 @@ +-- This file provides the actual flow and pathfinding logic that makes water +-- move through the pipes. +-- +-- Contributed by mauvebic, 2013-01-03, rewritten a bit by Vanessa Ezekowitz +-- + +local finitewater = minetest.setting_getbool("liquid_finite") + +pipeworks.check_for_liquids = function(pos) + local coords = { + {x=pos.x,y=pos.y-1,z=pos.z}, + {x=pos.x,y=pos.y+1,z=pos.z}, + {x=pos.x-1,y=pos.y,z=pos.z}, + {x=pos.x+1,y=pos.y,z=pos.z}, + {x=pos.x,y=pos.y,z=pos.z-1}, + {x=pos.x,y=pos.y,z=pos.z+1}, } + for i =1,6 do + local name = minetest.get_node(coords[i]).name + if name and string.find(name,"water") then + if finitewater then minetest.remove_node(coords[i]) end + return true + end + end + return false +end + +pipeworks.check_for_inflows = function(pos,node) + local coords = { + {x=pos.x,y=pos.y-1,z=pos.z}, + {x=pos.x,y=pos.y+1,z=pos.z}, + {x=pos.x-1,y=pos.y,z=pos.z}, + {x=pos.x+1,y=pos.y,z=pos.z}, + {x=pos.x,y=pos.y,z=pos.z-1}, + {x=pos.x,y=pos.y,z=pos.z+1}, } + local newnode = false + local source = false + for i =1,6 do + if newnode then break end + local name = minetest.get_node(coords[i]).name + if name and (name == "pipeworks:pump_on" and pipeworks.check_for_liquids(coords[i])) or string.find(name,"_loaded") then + if string.find(name,"_loaded") then + source = minetest.get_meta(coords[i]):get_string("source") + if source == minetest.pos_to_string(pos) then break end + end + newnode = string.gsub(node.name,"empty","loaded") + source = {x=coords[i].x,y=coords[i].y,z=coords[i].z} + end + end + if newnode then + minetest.add_node(pos,{name=newnode, param2 = node.param2}) + minetest.get_meta(pos):set_string("source",minetest.pos_to_string(source)) + end +end + +pipeworks.check_sources = function(pos,node) + local sourcepos = minetest.string_to_pos(minetest.get_meta(pos):get_string("source")) + if not sourcepos then return end + local source = minetest.get_node(sourcepos).name + local newnode = false + if source and not ((source == "pipeworks:pump_on" and pipeworks.check_for_liquids(sourcepos)) or string.find(source,"_loaded") or source == "ignore" ) then + newnode = string.gsub(node.name,"loaded","empty") + end + + if newnode then + minetest.add_node(pos,{name=newnode, param2 = node.param2}) + minetest.get_meta(pos):set_string("source","") + end +end + +pipeworks.spigot_check = function(pos, node) + local belowname = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name + if belowname and (belowname == "air" or belowname == "default:water_flowing" or belowname == "default:water_source") then + local spigotname = minetest.get_node(pos).name + local fdir=node.param2 + local check = { + {x=pos.x,y=pos.y,z=pos.z+1}, + {x=pos.x+1,y=pos.y,z=pos.z}, + {x=pos.x,y=pos.y,z=pos.z-1}, + {x=pos.x-1,y=pos.y,z=pos.z} + } + local near_node = minetest.get_node(check[fdir+1]) + if near_node and string.find(near_node.name, "_loaded") then + if spigotname and spigotname == "pipeworks:spigot" then + minetest.add_node(pos,{name = "pipeworks:spigot_pouring", param2 = fdir}) + if finitewater or belowname ~= "default:water_source" then + minetest.add_node({x=pos.x,y=pos.y-1,z=pos.z},{name = "default:water_source"}) + end + end + else + if spigotname == "pipeworks:spigot_pouring" then + minetest.add_node({x=pos.x,y=pos.y,z=pos.z},{name = "pipeworks:spigot", param2 = fdir}) + if belowname == "default:water_source" and not finitewater then + minetest.remove_node({x=pos.x,y=pos.y-1,z=pos.z}) + end + end + end + end +end + +pipeworks.fountainhead_check = function(pos, node) + local abovename = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}).name + if abovename and (abovename == "air" or abovename == "default:water_flowing" or abovename == "default:water_source") then + local fountainhead_name = minetest.get_node(pos).name + local near_node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}) + if near_node and string.find(near_node.name, "_loaded") then + if fountainhead_name and fountainhead_name == "pipeworks:fountainhead" then + minetest.add_node(pos,{name = "pipeworks:fountainhead_pouring"}) + if finitewater or abovename ~= "default:water_source" then + minetest.add_node({x=pos.x,y=pos.y+1,z=pos.z},{name = "default:water_source"}) + end + end + else + if fountainhead_name == "pipeworks:fountainhead_pouring" then + minetest.add_node({x=pos.x,y=pos.y,z=pos.z},{name = "pipeworks:fountainhead"}) + if abovename == "default:water_source" and not finitewater then + minetest.remove_node({x=pos.x,y=pos.y+1,z=pos.z}) + end + end + end + end +end diff --git a/mods/pipeworks/init.lua b/mods/pipeworks/init.lua new file mode 100644 index 00000000..b6c91d6c --- /dev/null +++ b/mods/pipeworks/init.lua @@ -0,0 +1,130 @@ +-- Pipeworks mod by Vanessa Ezekowitz - 2013-07-13 +-- +-- This mod supplies various steel pipes and plastic pneumatic tubes +-- and devices that they can connect to. +-- +-- License: WTFPL +-- + +pipeworks = {} + +local DEBUG = false + +pipeworks.worldpath = minetest.get_worldpath() +pipeworks.modpath = minetest.get_modpath("pipeworks") + +dofile(pipeworks.modpath.."/default_settings.txt") + +-- Read the external config file if it exists. +if io.open(pipeworks.worldpath.."/pipeworks_settings.txt","r") then + dofile(pipeworks.worldpath.."/pipeworks_settings.txt") + io.close() +end + +-- Random variables + +pipeworks.expect_infinite_stacks = true +if minetest.get_modpath("unified_inventory") or not minetest.setting_getbool("creative_mode") then + pipeworks.expect_infinite_stacks = false +end + +pipeworks.meseadjlist={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=0,y=1,z=0},{x=0,y=-1,z=0},{x=1,y=0,z=0},{x=-1,y=0,z=0}} + +pipeworks.rules_all = {{x=0, y=0, z=1},{x=0, y=0, z=-1},{x=1, y=0, z=0},{x=-1, y=0, z=0}, + {x=0, y=1, z=1},{x=0, y=1, z=-1},{x=1, y=1, z=0},{x=-1, y=1, z=0}, + {x=0, y=-1, z=1},{x=0, y=-1, z=-1},{x=1, y=-1, z=0},{x=-1, y=-1, z=0}, + {x=0, y=1, z=0}, {x=0, y=-1, z=0}} + +pipeworks.mesecons_rules={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=1,z=0},{x=0,y=-1,z=0}} + +pipeworks.liquid_texture = "default_water.png" + +-- Helper functions + +function pipeworks.fix_image_names(table, replacement) + local outtable={} + for i in ipairs(table) do + outtable[i]=string.gsub(table[i], "_XXXXX", replacement) + end + + return outtable +end + +function pipeworks.add_node_box(t, b) + for i in ipairs(b) + do table.insert(t, b[i]) + end +end + +function pipeworks.node_is_owned(pos, placer) + local ownername = false + if type(IsPlayerNodeOwner) == "function" then -- node_ownership mod + if HasOwner(pos, placer) then -- returns true if the node is owned + if not IsPlayerNodeOwner(pos, placer:get_player_name()) then + if type(getLastOwner) == "function" then -- ...is an old version + ownername = getLastOwner(pos) + elseif type(GetNodeOwnerName) == "function" then -- ...is a recent version + ownername = GetNodeOwnerName(pos) + else + ownername = S("someone") + end + end + end + + elseif type(isprotect)=="function" then -- glomie's protection mod + if not isprotect(5, pos, placer) then + ownername = S("someone") + end + elseif type(protector)=="table" and type(protector.can_dig)=="function" then -- Zeg9's protection mod + if not protector.can_dig(5, pos, placer) then + ownername = S("someone") + end + end + + if ownername ~= false then + minetest.chat_send_player( placer:get_player_name(), S("Sorry, %s owns that spot."):format(ownername) ) + return true + else + return false + end +end + +function pipeworks.replace_name(tbl,tr,name) + local ntbl={} + for key,i in pairs(tbl) do + if type(i)=="string" then + ntbl[key]=string.gsub(i,tr,name) + elseif type(i)=="table" then + ntbl[key]=pipeworks.replace_name(i,tr,name) + else + ntbl[key]=i + end + end + return ntbl +end + +------------------------------------------- +-- Load the various other parts of the mod + +dofile(pipeworks.modpath.."/common.lua") +dofile(pipeworks.modpath.."/models.lua") +dofile(pipeworks.modpath.."/autoplace_pipes.lua") +dofile(pipeworks.modpath.."/autoplace_tubes.lua") +dofile(pipeworks.modpath.."/luaentity.lua") +dofile(pipeworks.modpath.."/item_transport.lua") +dofile(pipeworks.modpath.."/flowing_logic.lua") +dofile(pipeworks.modpath.."/crafts.lua") +dofile(pipeworks.modpath.."/tubes.lua") +dofile(pipeworks.modpath.."/trashcan.lua") +dofile(pipeworks.modpath.."/wielder.lua") + +if pipeworks.enable_pipes then dofile(pipeworks.modpath.."/pipes.lua") end +if pipeworks.enable_teleport_tube then dofile(pipeworks.modpath.."/teleport_tube.lua") end +if pipeworks.enable_pipe_devices then dofile(pipeworks.modpath.."/devices.lua") end +if pipeworks.enable_redefines then dofile(pipeworks.modpath.."/compat.lua") end +if pipeworks.enable_autocrafter then dofile(pipeworks.modpath.."/autocrafter.lua") end + +minetest.register_alias("pipeworks:pipe", "pipeworks:pipe_110000_empty") + +print("Pipeworks loaded!") + diff --git a/mods/pipeworks/item_transport.lua b/mods/pipeworks/item_transport.lua new file mode 100644 index 00000000..8d5cc51b --- /dev/null +++ b/mods/pipeworks/item_transport.lua @@ -0,0 +1,487 @@ +local function delay(x) + return (function() return x end) +end + +function pipeworks.tube_item(pos, item) + error("obsolete pipeworks.tube_item() called; change caller to use pipeworks.tube_inject_item() instead") +end + +function pipeworks.tube_inject_item(pos, start_pos, velocity, item) + -- Take item in any format + local stack = ItemStack(item) + local obj = luaentity.add_entity(pos, "pipeworks:tubed_item") + obj:set_item(stack:to_string()) + obj.start_pos = vector.new(start_pos) + obj:setvelocity(velocity) + --obj:set_color("red") -- todo: this is test-only code + return obj +end + +-- adding two tube functions +-- can_remove(pos,node,stack,dir) returns the maximum number of items of that stack that can be removed +-- remove_items(pos,node,stack,dir,count) removes count items and returns them +-- both optional w/ sensible defaults and fallback to normal allow_* function +-- XXX: possibly change insert_object to insert_item + +local function set_filter_infotext(data, meta) + local infotext = data.wise_desc.." Filter-Injector" + if meta:get_int("slotseq_mode") == 2 then + infotext = infotext .. " (slot #"..meta:get_int("slotseq_index").." next)" + end + meta:set_string("infotext", infotext) +end + +local function set_filter_formspec(data, meta) + local itemname = data.wise_desc.." Filter-Injector" + local formspec = "size[8,8.5]".. + "item_image[0,0;1,1;pipeworks:"..data.name.."]".. + "label[1,0;"..minetest.formspec_escape(itemname).."]".. + "label[0,1;Prefer item types:]".. + "list[current_name;main;0,1.5;8,2;]".. + fs_helpers.cycling_button(meta, "button[0,3.5;4,1", "slotseq_mode", + {"Sequence slots by Priority", + "Sequence slots Randomly", + "Sequence slots by Rotation"}).. + "list[current_player;main;0,4.5;8,4;]" + meta:set_string("formspec", formspec) +end + +-- todo SOON: this function has *way too many* parameters +local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompos,fromnode,filtername,fromtube,fromdef,dir,fakePlayer,all) + local sposes = {} + for spos,stack in ipairs(frominv:get_list(frominvname)) do + local matches + if filtername == "" then + matches = stack:get_name() ~= "" + else + matches = stack:get_name() == filtername + end + if matches then table.insert(sposes, spos) end + end + if #sposes == 0 then return false end + if slotseq_mode == 1 then + for i = #sposes, 2, -1 do + local j = math.random(i) + local t = sposes[j] + sposes[j] = sposes[i] + sposes[i] = t + end + elseif slotseq_mode == 2 then + local headpos = filtmeta:get_int("slotseq_index") + table.sort(sposes, function (a, b) + if a >= headpos then + if b < headpos then return true end + else + if b >= headpos then return false end + end + return a < b + end) + end + for _, spos in ipairs(sposes) do + local stack = frominv:get_stack(frominvname, spos) + local doRemove = stack:get_count() + if fromtube.can_remove then + doRemove = fromtube.can_remove(frompos, fromnode, stack, dir) + elseif fromdef.allow_metadata_inventory_take then + doRemove = fromdef.allow_metadata_inventory_take(frompos, frominvname,spos, stack, fakePlayer) + end + -- stupid lack of continue statements grumble + if doRemove > 0 then + if slotseq_mode == 2 then + local nextpos = spos + 1 + if nextpos > frominv:get_size(frominvname) then + nextpos = 1 + end + filtmeta:set_int("slotseq_index", nextpos) + set_filter_infotext(data, filtmeta) + end + local item + local count + if all then + count = math.min(stack:get_count(), doRemove) + else + count = 1 + end + if fromtube.remove_items then + -- it could be the entire stack... + item = fromtube.remove_items(frompos, fromnode, stack, dir, count) + else + item = stack:take_item(count) + frominv:set_stack(frominvname, spos, stack) + if fromdef.on_metadata_inventory_take then + fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer) + end + end + local pos = vector.add(frompos, vector.multiply(dir, 1.4)) + local start_pos = vector.add(frompos, dir) + local item1 = pipeworks.tube_inject_item(pos, start_pos, dir, item) + return true-- only fire one item, please + end + end + return false +end + +local function punch_filter(data, filtpos, filtnode) + local filtmeta = minetest.get_meta(filtpos) + local filtinv = filtmeta:get_inventory() + local owner = filtmeta:get_string("owner") + local fakePlayer = { + get_player_name = delay(owner), + } -- TODO: use a mechanism as the wielder one + local dir = minetest.facedir_to_right_dir(filtnode.param2) + local frompos = vector.subtract(filtpos, dir) + local fromnode = minetest.get_node(frompos) + if not fromnode then return end + local fromdef = minetest.registered_nodes[fromnode.name] + if not fromdef then return end + local fromtube = fromdef.tube + if not (fromtube and fromtube.input_inventory) then return end + local filters = {} + for _, filterstack in ipairs(filtinv:get_list("main")) do + local filtername = filterstack:get_name() + if filtername ~= "" then table.insert(filters, filtername) end + end + if #filters == 0 then table.insert(filters, "") end + local slotseq_mode = filtmeta:get_int("slotseq_mode") + local frommeta = minetest.get_meta(frompos) + local frominv = frommeta:get_inventory() + if fromtube.before_filter then fromtube.before_filter(frompos) end + for _, frominvname in ipairs(type(fromtube.input_inventory) == "table" and fromtube.input_inventory or {fromtube.input_inventory}) do + local done = false + for _, filtername in ipairs(filters) do + if grabAndFire(data, slotseq_mode, filtmeta, frominv, frominvname, frompos, fromnode, filtername, fromtube, fromdef, dir, fakePlayer, data.stackwise) then + done = true + break + end + end + if done then break end + end + if fromtube.after_filter then fromtube.after_filter(frompos) end +end + +for _, data in ipairs({ + { + name = "filter", + wise_desc = "Itemwise", + stackwise = false, + }, + { + name = "mese_filter", + wise_desc = "Stackwise", + stackwise = true, + }, +}) do + minetest.register_node("pipeworks:"..data.name, { + description = data.wise_desc.." Filter-Injector", + tiles = { + "pipeworks_"..data.name.."_top.png", + "pipeworks_"..data.name.."_top.png", + "pipeworks_"..data.name.."_output.png", + "pipeworks_"..data.name.."_input.png", + "pipeworks_"..data.name.."_side.png", + "pipeworks_"..data.name.."_top.png", + }, + paramtype2 = "facedir", + groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, mesecon = 2}, + legacy_facedir_simple = true, + sounds = default.node_sound_wood_defaults(), + on_construct = function(pos) + local meta = minetest.get_meta(pos) + set_filter_formspec(data, meta) + set_filter_infotext(data, meta) + local inv = meta:get_inventory() + inv:set_size("main", 8*2) + end, + after_place_node = function (pos, placer) + minetest.get_meta(pos):set_string("owner", placer:get_player_name()) + end, + on_receive_fields = function(pos, formname, fields, sender) + fs_helpers.on_receive_fields(pos, fields) + local meta = minetest.get_meta(pos) + meta:set_int("slotseq_index", 1) + set_filter_formspec(data, meta) + set_filter_infotext(data, meta) + end, + can_dig = function(pos, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:is_empty("main") + end, + mesecons = { + effector = { + action_on = function(pos, node) + punch_filter(data, pos, node) + end, + }, + }, + tube = {connect_sides = {right = 1}}, + on_punch = function (pos, node, puncher) + punch_filter(data, pos, node) + end, + }) +end + +local adjlist={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=0,y=1,z=0},{x=0,y=-1,z=0},{x=1,y=0,z=0},{x=-1,y=0,z=0}} + +function pipeworks.notvel(tbl, vel) + local tbl2={} + for _,val in ipairs(tbl) do + if val.x ~= -vel.x or val.y ~= -vel.y or val.z ~= -vel.z then table.insert(tbl2, val) end + end + return tbl2 +end + +local function go_next(pos, velocity, stack) + local next_positions = {} + local max_priority = 0 + local cnode = minetest.get_node(pos) + local cmeta = minetest.get_meta(pos) + local can_go + local speed = math.abs(velocity.x + velocity.y + velocity.z) + if speed == 0 then + speed = 1 + end + local vel = {x = velocity.x/speed, y = velocity.y/speed, z = velocity.z/speed,speed=speed} + if speed >= 4.1 then + speed = 4 + elseif speed >= 1.1 then + speed = speed - 0.1 + else + speed = 1 + end + vel.speed = speed + if minetest.registered_nodes[cnode.name] and minetest.registered_nodes[cnode.name].tube and minetest.registered_nodes[cnode.name].tube.can_go then + can_go = minetest.registered_nodes[cnode.name].tube.can_go(pos, cnode, vel, stack) + else + can_go = pipeworks.notvel(adjlist, vel) + end + for _, vect in ipairs(can_go) do + local npos = vector.add(pos, vect) + local node = minetest.get_node(npos) + local reg_node = minetest.registered_nodes[node.name] + if reg_node then + local tube_def = reg_node.tube + local tubedevice = minetest.get_item_group(node.name, "tubedevice") + local tube_priority = (tube_def and tube_def.priority) or 100 + if tubedevice > 0 and tube_priority >= max_priority then + if not tube_def or not tube_def.can_insert or + tube_def.can_insert(npos, node, stack, vect) then + if tube_priority > max_priority then + max_priority = tube_priority + next_positions = {} + end + next_positions[#next_positions + 1] = {pos = npos, vect = vect} + end + end + end + end + + if not next_positions[1] then + return false, nil + end + + local n = (cmeta:get_int("tubedir") % (#next_positions)) + 1 + if pipeworks.enable_cyclic_mode then + cmeta:set_int("tubedir", n) + end + local new_velocity = vector.multiply(next_positions[n].vect, vel.speed) + return true, new_velocity +end + +minetest.register_entity("pipeworks:tubed_item", { + initial_properties = { + hp_max = 1, + physical = false, + collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1}, + visual = "wielditem", + visual_size = {x = 0.15, y = 0.15}, + textures = {""}, + spritediv = {x = 1, y = 1}, + initial_sprite_basepos = {x = 0, y = 0}, + is_visible = false, + }, + + physical_state = false, + + from_data = function(self, itemstring) + local stack = ItemStack(itemstring) + local itemtable = stack:to_table() + local itemname = nil + if itemtable then + itemname = stack:to_table().name + end + local item_texture = nil + local item_type = "" + if minetest.registered_items[itemname] then + item_texture = minetest.registered_items[itemname].inventory_image + item_type = minetest.registered_items[itemname].type + end + self.object:set_properties({ + is_visible = true, + textures = {stack:get_name()} + }) + local def = stack:get_definition() + self.object:setyaw((def and def.type == "node") and 0 or math.pi * 0.25) + end, + + get_staticdata = luaentity.get_staticdata, + on_activate = function(self, staticdata) -- Legacy code, should be replaced later by luaentity.on_activate + if staticdata == "" or staticdata == nil then + return + end + if staticdata == "toremove" then + self.object:remove() + return + end + local item = minetest.deserialize(staticdata) + pipeworks.tube_inject_item(self.object:getpos(), item.start_pos, item.velocity, item.itemstring) + self.object:remove() + end, +}) + +minetest.register_entity("pipeworks:color_entity", { + initial_properties = { + hp_max = 1, + physical = false, + collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1}, + visual = "cube", + visual_size = {x = 3.5, y = 3.5, z = 3.5}, -- todo: find correct size + textures = {""}, + is_visible = false, + }, + + physical_state = false, + + from_data = function(self, color) + local t = "pipeworks_color_"..color..".png" + local prop = { + is_visible = true, + visual = "cube", + textures = {t, t, t, t, t, t} -- todo: textures + } + self.object:set_properties(prop) + end, + + get_staticdata = luaentity.get_staticdata, + on_activate = luaentity.on_activate, +}) + +luaentity.register_entity("pipeworks:tubed_item", { + itemstring = '', + item_entity = nil, + color_entity = nil, + color = nil, + start_pos = nil, + + set_item = function(self, item) + local itemstring = ItemStack(item):to_string() -- Accept any input format + if self.itemstring == itemstring then + return + end + if self.item_entity then + self:remove_attached_entity(self.item_entity) + end + self.itemstring = itemstring + self.item_entity = self:add_attached_entity("pipeworks:tubed_item", itemstring) + end, + + set_color = function(self, color) + if self.color == color then + return + end + self.color = color + if self.color_entity then + self:remove_attached_entity(self.color_entity) + end + if color then + self.color_entity = self:add_attached_entity("pipeworks:color_entity", color) + else + self.color_entity = nil + end + end, + + on_step = function(self, dtime) + if self.start_pos == nil then + local pos = self:getpos() + self.start_pos = vector.round(pos) + self:setpos(pos) + end + + local pos = self:getpos() + local stack = ItemStack(self.itemstring) + local drop_pos + + local velocity = self:getvelocity() + + local moved = false + local speed = math.abs(velocity.x + velocity.y + velocity.z) + if speed == 0 then + speed = 1 + moved = true + end + local vel = {x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed} + + if vector.distance(pos, self.start_pos) >= 1 then + self.start_pos = vector.add(self.start_pos, vel) + moved = true + end + + minetest.load_position(self.start_pos) + local node = minetest.get_node(self.start_pos) + if moved and minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then + local leftover + if minetest.registered_nodes[node.name].tube and minetest.registered_nodes[node.name].tube.insert_object then + leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel) + else + leftover = stack + end + if leftover:is_empty() then + self:remove() + return + end + velocity = vector.multiply(velocity, -1) + self:setvelocity(velocity) + self:set_item(leftover:to_string()) + return + end + + if moved then + local found_next, new_velocity = go_next(self.start_pos, velocity, stack) -- todo: color + if not found_next then + drop_pos = minetest.find_node_near(vector.add(self.start_pos, velocity), 1, "air") + if drop_pos then + minetest.item_drop(stack, "", drop_pos) + self:remove() + return + end + end + + if new_velocity and not vector.equals(velocity, new_velocity) then + self:setpos(self.start_pos) + self:setvelocity(new_velocity) + end + end + end +}) + +if minetest.get_modpath("mesecons_mvps") then + mesecon.register_mvps_unmov("pipeworks:tubed_item") + mesecon.register_mvps_unmov("pipeworks:color_entity") + mesecon.register_on_mvps_move(function(moved_nodes) + local moved = {} + for _, n in ipairs(moved_nodes) do + moved[minetest.hash_node_position(n.oldpos)] = vector.subtract(n.pos, n.oldpos) + end + for id, entity in pairs(luaentity.entities) do + if entity.name == "pipeworks:tubed_item" then + local pos = entity:getpos() + local rpos = vector.round(pos) + local dir = moved[minetest.hash_node_position(rpos)] + if dir then + entity:setpos(vector.add(pos, dir)) + entity.start_pos = vector.add(entity.start_pos, dir) + end + end + end + end) +end diff --git a/mods/pipeworks/legacy.lua b/mods/pipeworks/legacy.lua new file mode 100644 index 00000000..84ae31d6 --- /dev/null +++ b/mods/pipeworks/legacy.lua @@ -0,0 +1,60 @@ + +if not minetest.get_modpath("auto_tree_tap") and + minetest.get_modpath("technic") then + + minetest.register_abm({ + nodenames = { "auto_tree_tap:off", "auto_tree_tap:on" }, + chance = 1, + interval = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local fdir = node.param2 + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + inv:set_size("pick", 1) + inv:set_size("ghost_pick", 1) + inv:set_size("main", 100) + minetest.set_node(pos, {name = "pipeworks:nodebreaker_off", param2 = fdir}) + minetest.registered_nodes["pipeworks:nodebreaker_off"].on_punch(pos, node) + inv:set_stack("pick", 1, ItemStack("technic:treetap")) + end + }) + + minetest.register_node(":auto_tree_tap:off", { + description = "Auto-Tap", + tiles = {"pipeworks_nodebreaker_top_off.png","pipeworks_nodebreaker_bottom_off.png","pipeworks_nodebreaker_side2_off.png","pipeworks_nodebreaker_side1_off.png", + "pipeworks_nodebreaker_back.png","pipeworks_nodebreaker_front_off.png"}, + is_ground_content = true, + paramtype2 = "facedir", + groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2, mesecon = 2,tubedevice=1, not_in_creative_inventory=1 }, + mesecons= {effector={rules=pipeworks.rules_all,action_on=node_breaker_on, action_off=node_breaker_off}}, + sounds = default.node_sound_stone_defaults(), + tube = {connect_sides={back=1}}, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + inv:set_size("pick", 1) + inv:set_stack("pick", 1, ItemStack("default:pick_mese")) + end, + after_place_node = function (pos, placer) + pipeworks.scan_for_tube_objects(pos, placer) + local placer_pos = placer:getpos() + + --correct for the player's height + if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end + + --correct for 6d facedir + if placer_pos then + local dir = { + x = pos.x - placer_pos.x, + y = pos.y - placer_pos.y, + z = pos.z - placer_pos.z + } + local node = minetest.get_node(pos) + node.param2 = minetest.dir_to_facedir(dir, true) + minetest.set_node(pos, node) + minetest.log("action", "real (6d) facedir: " .. node.param2) + end + end, + after_dig_node = pipeworks.scan_for_tube_objects, + }) +end diff --git a/mods/pipeworks/luaentity.lua b/mods/pipeworks/luaentity.lua new file mode 100644 index 00000000..241da144 --- /dev/null +++ b/mods/pipeworks/luaentity.lua @@ -0,0 +1,334 @@ +local max_entity_id = 1000000000000 -- If you need more, there's a problem with your code + +luaentity = {} + +luaentity.registered_entities = {} + +local filename = minetest.get_worldpath().."/luaentities" +local function read_file() + local f = io.open(filename, "r") + if f == nil then return {} end + local t = f:read("*all") + f:close() + if t == "" or t == nil then return {} end + return minetest.deserialize(t) +end + +local function write_file(tbl) + local f = io.open(filename, "w") + f:write(minetest.serialize(tbl)) + f:close() +end + +local function read_entities() + local t = read_file() + for _, entity in pairs(t) do + setmetatable(entity, luaentity.registered_entities[entity.name]) + end + return t +end + +local function write_entities() + for _, entity in pairs(luaentity.entities) do + setmetatable(entity, nil) + for _, attached in pairs(entity._attached_entities) do + if attached.entity then + attached.entity:remove() + attached.entity = nil + end + end + entity._attached_entities_master = nil + end + write_file(luaentity.entities) +end + +minetest.register_on_shutdown(write_entities) +luaentity.entities_index = 0 + +local function get_blockpos(pos) + return {x = math.floor(pos.x / 16), + y = math.floor(pos.y / 16), + z = math.floor(pos.z / 16)} +end + +local active_blocks = {} -- These only contain active blocks near players (i.e., not forceloaded ones) +local handle_active_blocks_step = 2 +local handle_active_blocks_timer = 0 +minetest.register_globalstep(function(dtime) + handle_active_blocks_timer = handle_active_blocks_timer + dtime + if handle_active_blocks_timer >= handle_active_blocks_step then + handle_active_blocks_timer = handle_active_blocks_timer - handle_active_blocks_step + local active_block_range = tonumber(minetest.setting_get("active_block_range")) or 2 + local new_active_blocks = {} + for _, player in ipairs(minetest.get_connected_players()) do + local blockpos = get_blockpos(player:getpos()) + local minp = vector.subtract(blockpos, active_block_range) + local maxp = vector.add(blockpos, active_block_range) + + for x = minp.x, maxp.x do + for y = minp.y, maxp.y do + for z = minp.z, maxp.z do + local pos = {x = x, y = y, z = z} + new_active_blocks[minetest.hash_node_position(pos)] = pos + end + end + end + end + active_blocks = new_active_blocks + -- todo: callbacks on block load/unload + end +end) + +local function is_active(pos) + return active_blocks[minetest.hash_node_position(get_blockpos(pos))] ~= nil +end + +local entitydef_default = { + _attach = function(self, attached, attach_to) + local attached_def = self._attached_entities[attached] + local attach_to_def = self._attached_entities[attach_to] + attached_def.entity:set_attach( + attach_to_def.entity, "", + vector.subtract(attached_def.offset, attach_to_def.offset), -- todo: Does not work because is object space + vector.new(0, 0, 0) + ) + end, + _set_master = function(self, index) + self._attached_entities_master = index + if not index then + return + end + local def = self._attached_entities[index] + if not def.entity then + return + end + def.entity:setpos(vector.add(self._pos, def.offset)) + def.entity:setvelocity(self._velocity) + def.entity:setacceleration(self._acceleration) + end, + _attach_all = function(self) + local master = self._attached_entities_master + if not master then + return + end + for id, entity in pairs(self._attached_entities) do + if id ~= master and entity.entity then + self:_attach(id, master) + end + end + end, + _detach_all = function(self) + local master = self._attached_entities_master + for id, entity in pairs(self._attached_entities) do + if id ~= master and entity.entity then + entity.entity:set_detach() + end + end + end, + _add_attached = function(self, index) + local entity = self._attached_entities[index] + if entity.entity then + return + end + local entity_pos = vector.add(self._pos, entity.offset) + if not is_active(entity_pos) then + return + end + local ent = minetest.add_entity(entity_pos, entity.name):get_luaentity() + ent:from_data(entity.data) + ent.parent_id = self._id + ent.attached_id = index + entity.entity = ent.object + local master = self._attached_entities_master + if master then + self:_attach(index, master) + else + self:_set_master(index) + end + end, + _remove_attached = function(self, index) + local master = self._attached_entities_master + local entity = self._attached_entities[index] + local ent = entity.entity + entity.entity = nil + if index == master then + self:_detach_all() + local newmaster + for id, attached in pairs(self._attached_entities) do + if id ~= master and attached.entity then + newmaster = id + break + end + end + self:_set_master(newmaster) + self:_attach_all() + elseif master and ent then + ent:set_detach() + end + if ent then + ent:remove() + end + end, + _add_loaded = function(self) + for id, _ in pairs(self._attached_entities) do + self:_add_attached(id) + end + end, + getid = function(self) + return self._id + end, + getpos = function(self) + return vector.new(self._pos) + end, + setpos = function(self, pos) + self._pos = vector.new(pos) + --for _, entity in pairs(self._attached_entities) do + -- if entity.entity then + -- entity.entity:setpos(vector.add(self._pos, entity.offset)) + -- end + --end + local master = self._attached_entities_master + if master then + local master_def = self._attached_entities[master] + master_def.entity:setpos(vector.add(self._pos, master_def.offset)) + end + end, + getvelocity = function(self) + return vector.new(self._velocity) + end, + setvelocity = function(self, velocity) + self._velocity = vector.new(velocity) + local master = self._attached_entities_master + if master then + self._attached_entities[master].entity:setvelocity(self._velocity) + end + end, + getacceleration = function(self) + return vector.new(self._acceleration) + end, + setacceleration = function(self, acceleration) + self._acceleration = vector.new(acceleration) + local master = self._attached_entities_master + if master then + self._attached_entities[master].entity:setacceleration(self._acceleration) + end + end, + remove = function(self) + self:_detach_all() + for _, entity in pairs(self._attached_entities) do + if entity.entity then + entity.entity:remove() + end + end + luaentity.entities[self._id] = nil + end, + add_attached_entity = function(self, name, data, offset) + local index = #self._attached_entities + 1 + self._attached_entities[index] = { + name = name, + data = data, + offset = vector.new(offset), + } + self:_add_attached(index) + return index + end, + remove_attached_entity = function(self, index) + self:_remove_attached(index) + self._attached_entities[index] = nil + end, +} + +function luaentity.register_entity(name, prototype) + -- name = check_modname_prefix(name) + prototype.name = name + setmetatable(prototype, {__index = entitydef_default}) + prototype.__index = prototype -- Make it possible to use it as metatable + luaentity.registered_entities[name] = prototype +end + +-- function luaentity.get_entity_definition(entity) +-- return luaentity.registered_entities[entity.name] +-- end + +function luaentity.add_entity(pos, name) + local index = luaentity.entities_index + while luaentity.entities[index] do + index = index + 1 + if index >= max_entity_id then + index = 0 + end + end + luaentity.entities_index = index + + local entity = { + name = name, + _id = index, + _pos = vector.new(pos), + _velocity = {x = 0, y = 0, z = 0}, + _acceleration = {x = 0, y = 0, z = 0}, + _attached_entities = {}, + } + + local prototype = luaentity.registered_entities[name] + setmetatable(entity, prototype) -- Default to prototype for other methods + luaentity.entities[index] = entity + + if entity.on_activate then + entity:on_activate() + end + return entity +end + +-- todo: check if remove in get_staticdata works +function luaentity.get_staticdata(self) + local parent = luaentity.entities[self.parent_id] + if parent and parent._remove_attached then + parent:_remove_attached(self.attached_id) + end + return "toremove" +end + +function luaentity.on_activate(self, staticdata) + if staticdata == "toremove" then + self.object:remove() + end +end + +function luaentity.get_objects_inside_radius(pos, radius) + local objects = {} + local index = 1 + for id, entity in pairs(luaentity.entities) do + if vector.distance(pos, entity:getpos()) <= radius then + objects[index] = entity + index = index + 1 + end + end +end + +minetest.register_globalstep(function(dtime) + if not luaentity.entities then + luaentity.entities = read_entities() + end + for id, entity in pairs(luaentity.entities) do + local master = entity._attached_entities_master + if master then + local master_def = entity._attached_entities[master] + local master_entity = master_def.entity + entity._pos = vector.subtract(master_entity:getpos(), master_def.offset) + entity._velocity = master_entity:getvelocity() + entity._acceleration = master_entity:getacceleration() + else + entity._pos = vector.add(vector.add( + entity._pos, + vector.multiply(entity._velocity, dtime)), + vector.multiply(entity._acceleration, 0.5 * dtime * dtime)) + entity._velocity = vector.add( + entity._velocity, + vector.multiply(entity._acceleration, dtime)) + end + entity:_add_loaded() + if entity.on_step then + entity:on_step(dtime) + end + end +end) diff --git a/mods/pipeworks/models.lua b/mods/pipeworks/models.lua new file mode 100644 index 00000000..6a841d3c --- /dev/null +++ b/mods/pipeworks/models.lua @@ -0,0 +1,202 @@ +--------------------- +-- The various models + +-- Pipe models + +pipeworks.pipe_leftstub = { + { -32/64, -2/64, -6/64, 1/64, 2/64, 6/64 }, -- pipe segment against -X face + { -32/64, -4/64, -5/64, 1/64, 4/64, 5/64 }, + { -32/64, -5/64, -4/64, 1/64, 5/64, 4/64 }, + { -32/64, -6/64, -2/64, 1/64, 6/64, 2/64 }, + + { -32/64, -3/64, -8/64, -30/64, 3/64, 8/64 }, -- (the flange for it) + { -32/64, -5/64, -7/64, -30/64, 5/64, 7/64 }, + { -32/64, -6/64, -6/64, -30/64, 6/64, 6/64 }, + { -32/64, -7/64, -5/64, -30/64, 7/64, 5/64 }, + { -32/64, -8/64, -3/64, -30/64, 8/64, 3/64 } +} + +pipeworks.pipe_rightstub = { + { -1/64, -2/64, -6/64, 32/64, 2/64, 6/64 }, -- pipe segment against +X face + { -1/64, -4/64, -5/64, 32/64, 4/64, 5/64 }, + { -1/64, -5/64, -4/64, 32/64, 5/64, 4/64 }, + { -1/64, -6/64, -2/64, 32/64, 6/64, 2/64 }, + + { 30/64, -3/64, -8/64, 32/64, 3/64, 8/64 }, -- (the flange for it) + { 30/64, -5/64, -7/64, 32/64, 5/64, 7/64 }, + { 30/64, -6/64, -6/64, 32/64, 6/64, 6/64 }, + { 30/64, -7/64, -5/64, 32/64, 7/64, 5/64 }, + { 30/64, -8/64, -3/64, 32/64, 8/64, 3/64 } +} + +pipeworks.pipe_bottomstub = { + { -2/64, -32/64, -6/64, 2/64, 1/64, 6/64 }, -- pipe segment against -Y face + { -4/64, -32/64, -5/64, 4/64, 1/64, 5/64 }, + { -5/64, -32/64, -4/64, 5/64, 1/64, 4/64 }, + { -6/64, -32/64, -2/64, 6/64, 1/64, 2/64 }, + + { -3/64, -32/64, -8/64, 3/64, -30/64, 8/64 }, -- (the flange for it) + { -5/64, -32/64, -7/64, 5/64, -30/64, 7/64 }, + { -6/64, -32/64, -6/64, 6/64, -30/64, 6/64 }, + { -7/64, -32/64, -5/64, 7/64, -30/64, 5/64 }, + { -8/64, -32/64, -3/64, 8/64, -30/64, 3/64 } +} + +pipeworks.pipe_topstub = { + { -2/64, -1/64, -6/64, 2/64, 32/64, 6/64 }, -- pipe segment against +Y face + { -4/64, -1/64, -5/64, 4/64, 32/64, 5/64 }, + { -5/64, -1/64, -4/64, 5/64, 32/64, 4/64 }, + { -6/64, -1/64, -2/64, 6/64, 32/64, 2/64 }, + + { -3/64, 30/64, -8/64, 3/64, 32/64, 8/64 }, -- (the flange for it) + { -5/64, 30/64, -7/64, 5/64, 32/64, 7/64 }, + { -6/64, 30/64, -6/64, 6/64, 32/64, 6/64 }, + { -7/64, 30/64, -5/64, 7/64, 32/64, 5/64 }, + { -8/64, 30/64, -3/64, 8/64, 32/64, 3/64 } +} + +pipeworks.pipe_frontstub = { + { -6/64, -2/64, -32/64, 6/64, 2/64, 1/64 }, -- pipe segment against -Z face + { -5/64, -4/64, -32/64, 5/64, 4/64, 1/64 }, + { -4/64, -5/64, -32/64, 4/64, 5/64, 1/64 }, + { -2/64, -6/64, -32/64, 2/64, 6/64, 1/64 }, + + { -8/64, -3/64, -32/64, 8/64, 3/64, -30/64 }, -- (the flange for it) + { -7/64, -5/64, -32/64, 7/64, 5/64, -30/64 }, + { -6/64, -6/64, -32/64, 6/64, 6/64, -30/64 }, + { -5/64, -7/64, -32/64, 5/64, 7/64, -30/64 }, + { -3/64, -8/64, -32/64, 3/64, 8/64, -30/64 } +} + +pipeworks.pipe_backstub = { + { -6/64, -2/64, -1/64, 6/64, 2/64, 32/64 }, -- pipe segment against -Z face + { -5/64, -4/64, -1/64, 5/64, 4/64, 32/64 }, + { -4/64, -5/64, -1/64, 4/64, 5/64, 32/64 }, + { -2/64, -6/64, -1/64, 2/64, 6/64, 32/64 }, + + { -8/64, -3/64, 30/64, 8/64, 3/64, 32/64 }, -- (the flange for it) + { -7/64, -5/64, 30/64, 7/64, 5/64, 32/64 }, + { -6/64, -6/64, 30/64, 6/64, 6/64, 32/64 }, + { -5/64, -7/64, 30/64, 5/64, 7/64, 32/64 }, + { -3/64, -8/64, 30/64, 3/64, 8/64, 32/64 } +} + +pipeworks.pipe_boxes = {pipeworks.pipe_leftstub, pipeworks.pipe_rightstub, pipeworks.pipe_bottomstub, pipeworks.pipe_topstub, pipeworks.pipe_frontstub, pipeworks.pipe_backstub} + +pipeworks.pipe_selectboxes = { + { -32/64, -8/64, -8/64, 8/64, 8/64, 8/64 }, + { -8/64 , -8/64, -8/64, 32/64, 8/64, 8/64 }, + { -8/64 , -32/64, -8/64, 8/64, 8/64, 8/64 }, + { -8/64 , -8/64, -8/64, 8/64, 32/64, 8/64 }, + { -8/64 , -8/64, -32/64, 8/64, 8/64, 8/64 }, + { -8/64 , -8/64, -8/64, 8/64, 8/64, 32/64 } +} + +pipeworks.pipe_bendsphere = { + { -4/64, -4/64, -4/64, 4/64, 4/64, 4/64 }, + { -5/64, -3/64, -3/64, 5/64, 3/64, 3/64 }, + { -3/64, -5/64, -3/64, 3/64, 5/64, 3/64 }, + { -3/64, -3/64, -5/64, 3/64, 3/64, 5/64 } +} + +-- Tube models + +pipeworks.tube_leftstub = { + { -32/64, -9/64, -9/64, 9/64, 9/64, 9/64 }, -- tube segment against -X face +} + +pipeworks.tube_rightstub = { + { -9/64, -9/64, -9/64, 32/64, 9/64, 9/64 }, -- tube segment against +X face +} + +pipeworks.tube_bottomstub = { + { -9/64, -32/64, -9/64, 9/64, 9/64, 9/64 }, -- tube segment against -Y face +} + +pipeworks.tube_topstub = { + { -9/64, -9/64, -9/64, 9/64, 32/64, 9/64 }, -- tube segment against +Y face +} + +pipeworks.tube_frontstub = { + { -9/64, -9/64, -32/64, 9/64, 9/64, 9/64 }, -- tube segment against -Z face +} + +pipeworks.tube_backstub = { + { -9/64, -9/64, -9/64, 9/64, 9/64, 32/64 }, -- tube segment against -Z face +} + +pipeworks.tube_boxes = {pipeworks.tube_leftstub, pipeworks.tube_rightstub, pipeworks.tube_bottomstub, pipeworks.tube_topstub, pipeworks.tube_frontstub, pipeworks.tube_backstub} + +pipeworks.tube_selectboxes = { + { -32/64, -10/64, -10/64, 10/64, 10/64, 10/64 }, + { -10/64 , -10/64, -10/64, 32/64, 10/64, 10/64 }, + { -10/64 , -32/64, -10/64, 10/64, 10/64, 10/64 }, + { -10/64 , -10/64, -10/64, 10/64, 32/64, 10/64 }, + { -10/64 , -10/64, -32/64, 10/64, 10/64, 10/64 }, + { -10/64 , -10/64, -10/64, 10/64, 10/64, 32/64 } +} + +-- Device models + +pipeworks.pipe_pumpbody = { + { -7/16, -6/16, -7/16, 7/16, 5/16, 7/16 }, + { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 } +} + +pipeworks.pipe_valvebody = { + { -4/16, -4/16, -4/16, 4/16, 4/16, 4/16 } +} + +pipeworks.pipe_valvehandle_on = { + { -5/16, 4/16, -1/16, 0, 5/16, 1/16 } +} + +pipeworks.pipe_valvehandle_off = { + { -1/16, 4/16, -5/16, 1/16, 5/16, 0 } +} + +pipeworks.pipe_sensorbody = { + { -3/16, -2/16, -2/16, 3/16, 2/16, 2/16 } +} + +pipeworks.spigot_bottomstub = { + { -2/64, -16/64, -6/64, 2/64, 1/64, 6/64 }, -- pipe segment against -Y face + { -4/64, -16/64, -5/64, 4/64, 1/64, 5/64 }, + { -5/64, -16/64, -4/64, 5/64, 1/64, 4/64 }, + { -6/64, -16/64, -2/64, 6/64, 1/64, 2/64 }, + + { -3/64, -16/64, -8/64, 3/64, -14/64, 8/64 }, -- (the flange for it) + { -5/64, -16/64, -7/64, 5/64, -14/64, 7/64 }, + { -6/64, -16/64, -6/64, 6/64, -14/64, 6/64 }, + { -7/64, -16/64, -5/64, 7/64, -14/64, 5/64 }, + { -8/64, -16/64, -3/64, 8/64, -14/64, 3/64 } +} + +pipeworks.spigot_stream = { + { -3/64, (-41/64)-0.01, -5/64, 3/64, -16/64, 5/64 }, + { -4/64, (-41/64)-0.01, -4/64, 4/64, -16/64, 4/64 }, + { -5/64, (-41/64)-0.01, -3/64, 5/64, -16/64, 3/64 } +} + +pipeworks.entry_panel = { + { -8/16, -8/16, -1/16, 8/16, 8/16, 1/16 } +} + +pipeworks.fountainhead_model = { + { -2/64, -32/64, -6/64, 2/64, 21/64, 6/64 }, -- main segment + { -4/64, -32/64, -5/64, 4/64, 21/64, 5/64 }, + { -5/64, -32/64, -4/64, 5/64, 21/64, 4/64 }, + { -6/64, -32/64, -2/64, 6/64, 21/64, 2/64 }, + + { -3/64, -32/64, -8/64, 3/64, -30/64, 8/64 }, -- bottom flange + { -5/64, -32/64, -7/64, 5/64, -30/64, 7/64 }, + { -6/64, -32/64, -6/64, 6/64, -30/64, 6/64 }, + { -7/64, -32/64, -5/64, 7/64, -30/64, 5/64 }, + { -8/64, -32/64, -3/64, 8/64, -30/64, 3/64 }, + + { -3/64, 20/64, -8/64, 3/64, 32/64, 8/64 }, -- top flange/outlet + { -5/64, 20/64, -7/64, 5/64, 32/64, 7/64 }, + { -6/64, 20/64, -6/64, 6/64, 32/64, 6/64 }, + { -7/64, 20/64, -5/64, 7/64, 32/64, 5/64 }, + { -8/64, 20/64, -3/64, 8/64, 32/64, 3/64 } +} diff --git a/mods/pipeworks/pipes.lua b/mods/pipeworks/pipes.lua new file mode 100644 index 00000000..ad79a3ed --- /dev/null +++ b/mods/pipeworks/pipes.lua @@ -0,0 +1,226 @@ +-- This file supplies the steel pipes + +local REGISTER_COMPATIBILITY = true + +local pipes_empty_nodenames = {} +local pipes_full_nodenames = {} + +local vti = {4, 3, 2, 1, 6, 5} +local cconnects = {{}, {1}, {1, 2}, {1, 3}, {1, 3, 5}, {1, 2, 3}, {1, 2, 3, 5}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5, 6}} +for index, connects in ipairs(cconnects) do + local outboxes = {} + local outsel = {} + local outimgs = {} + + for i = 1, 6 do + outimgs[vti[i]] = "pipeworks_plain.png" + end + + local jx = 0 + local jy = 0 + local jz = 0 + for _, v in ipairs(connects) do + if v == 1 or v == 2 then + jx = jx + 1 + elseif v == 3 or v == 4 then + jy = jy + 1 + else + jz = jz + 1 + end + pipeworks.add_node_box(outboxes, pipeworks.pipe_boxes[v]) + table.insert(outsel, pipeworks.pipe_selectboxes[v]) + outimgs[vti[v]] = "pipeworks_pipe_end.png" + end + + if #connects == 1 then + local v = connects[1] + v = v-1 + 2*(v%2) -- Opposite side + outimgs[vti[v]] = "^pipeworks_plain.png" + end + + if #connects >= 2 then + pipeworks.add_node_box(outboxes, pipeworks.pipe_bendsphere) + end + + if jx == 2 and jy ~= 2 and jz ~= 2 then + outimgs[5] = pipeworks.liquid_texture.."^pipeworks_windowed_XXXXX.png" + outimgs[6] = outimgs[5] + end + + local pgroups = {snappy = 3, pipe = 1, not_in_creative_inventory = 1} + local pipedesc = "Pipe segement".." "..dump(connects).."... You hacker, you." + local image = nil + + if #connects == 0 then + pgroups = {snappy = 3, tube = 1} + pipedesc = "Pipe segment" + image = "pipeworks_pipe_inv.png" + end + + --table.insert(pipeworks.tubenodes, name.."_"..tname) + + minetest.register_node("pipeworks:pipe_"..index.."_empty", { + description = pipedesc, + drawtype = "nodebox", + tiles = pipeworks.fix_image_names(outimgs, "_empty"), + sunlight_propagates = true, + inventory_image = image, + wield_image = image, + paramtype = "light", + paramtype2 = "facedir", + selection_box = { + type = "fixed", + fixed = outsel + }, + node_box = { + type = "fixed", + fixed = outboxes + }, + groups = pgroups, + sounds = default.node_sound_wood_defaults(), + walkable = true, + drop = "pipeworks:pipe_1_empty", + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end + }) + + local pgroups = {snappy = 3, pipe = 1, not_in_creative_inventory = 1} + + minetest.register_node("pipeworks:pipe_"..index.."_loaded", { + description = pipedesc, + drawtype = "nodebox", + tiles = pipeworks.fix_image_names(outimgs, "_loaded"), + sunlight_propagates = true, + paramtype = "light", + paramtype2 = "facedir", + selection_box = { + type = "fixed", + fixed = outsel + }, + node_box = { + type = "fixed", + fixed = outboxes + }, + groups = pgroups, + sounds = default.node_sound_wood_defaults(), + walkable = true, + drop = "pipeworks:pipe_1_empty", + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + after_dig_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end + }) + + table.insert(pipes_empty_nodenames, "pipeworks:pipe_"..index.."_empty") + table.insert(pipes_full_nodenames, "pipeworks:pipe_"..index.."_loaded") +end + + + +if REGISTER_COMPATIBILITY then + local cempty = "pipeworks:pipe_compatibility_empty" + local cloaded = "pipeworks:pipe_compatibility_loaded" + minetest.register_node(cempty, { + drawtype = "airlike", + sunlight_propagates = true, + paramtype = "light", + inventory_image = "pipeworks_pipe_inv.png", + wield_image = "pipeworks_pipe_inv.png", + description = "Pipe Segment (legacy)", + groups = {not_in_creative_inventory = 1, pipe_to_update = 1}, + drop = "pipeworks:pipe_1_empty", + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + }) + minetest.register_node(cloaded, { + drawtype = "airlike", + sunlight_propagates = true, + paramtype = "light", + inventory_image = "pipeworks_pipe_inv.png", + groups = {not_in_creative_inventory = 1, pipe_to_update = 1}, + drop = "pipeworks:pipe_1_empty", + after_place_node = function(pos) + pipeworks.scan_for_pipe_objects(pos) + end, + }) + for xm = 0, 1 do + for xp = 0, 1 do + for ym = 0, 1 do + for yp = 0, 1 do + for zm = 0, 1 do + for zp = 0, 1 do + local pname = xm..xp..ym..yp..zm..zp + minetest.register_alias("pipeworks:pipe_"..pname.."_empty", cempty) + minetest.register_alias("pipeworks:pipe_"..pname.."_loaded", cloaded) + end + end + end + end + end + end + minetest.register_abm({ + nodenames = {"group:pipe_to_update"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + local minp = {x = pos.x-1, y = pos.y-1, z = pos.z-1} + local maxp = {x = pos.x+1, y = pos.y+1, z = pos.z+1} + if table.getn(minetest.find_nodes_in_area(minp, maxp, "ignore")) == 0 then + pipeworks.scan_for_pipe_objects(pos) + end + end + }) +end + +table.insert(pipes_empty_nodenames,"pipeworks:valve_on_empty") +table.insert(pipes_empty_nodenames,"pipeworks:valve_off_empty") +table.insert(pipes_empty_nodenames,"pipeworks:entry_panel_empty") +table.insert(pipes_empty_nodenames,"pipeworks:flow_sensor_empty") + +table.insert(pipes_full_nodenames,"pipeworks:valve_on_loaded") +table.insert(pipes_full_nodenames,"pipeworks:entry_panel_loaded") +table.insert(pipes_full_nodenames,"pipeworks:flow_sensor_loaded") + +minetest.register_abm({ + nodenames = pipes_empty_nodenames, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + pipeworks.check_for_inflows(pos,node) + end +}) + +minetest.register_abm({ + nodenames = pipes_full_nodenames, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + pipeworks.check_sources(pos,node) + end +}) + +minetest.register_abm({ + nodenames = {"pipeworks:spigot","pipeworks:spigot_pouring"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + pipeworks.spigot_check(pos,node) + end +}) + +minetest.register_abm({ + nodenames = {"pipeworks:fountainhead","pipeworks:fountainhead_pouring"}, + interval = 1, + chance = 1, + action = function(pos, node, active_object_count, active_object_count_wider) + pipeworks.fountainhead_check(pos,node) + end +}) + diff --git a/mods/pipeworks/teleport_tube.lua b/mods/pipeworks/teleport_tube.lua new file mode 100644 index 00000000..99b71a1f --- /dev/null +++ b/mods/pipeworks/teleport_tube.lua @@ -0,0 +1,181 @@ + +local filename=minetest.get_worldpath() .. "/teleport_tubes" + +local function read_file() + local f = io.open(filename, "r") + if f == nil then return {} end + local t = f:read("*all") + f:close() + if t == "" or t == nil then return {} end + return minetest.deserialize(t) +end + +local function write_file(tbl) + local f = io.open(filename, "w") + f:write(minetest.serialize(tbl)) + f:close() +end + +local function update_pos_in_file(pos) + local tbl=read_file() + for _, val in ipairs(tbl) do + if val.x == pos.x and val.y == pos.y and val.z == pos.z then + local meta = minetest.get_meta(val) + val.channel = meta:get_string("channel") + val.cr = meta:get_int("can_receive") + end + end + write_file(tbl) +end + +local function add_tube_in_file(pos,channel, cr) + local tbl=read_file() + for _,val in ipairs(tbl) do + if val.x==pos.x and val.y==pos.y and val.z==pos.z then + return + end + end + table.insert(tbl,{x=pos.x,y=pos.y,z=pos.z,channel=channel,cr=cr}) + write_file(tbl) +end + +local function remove_tube_in_file(pos) + local tbl = read_file() + local newtbl = {} + for _, val in ipairs(tbl) do + if val.x ~= pos.x or val.y ~= pos.y or val.z ~= pos.z then + table.insert(newtbl, val) + end + end + write_file(newtbl) +end + +local function read_node_with_vm(pos) + local vm = VoxelManip() + local MinEdge, MaxEdge = vm:read_from_map(pos, pos) + local data = vm:get_data() + local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge}) + return minetest.get_name_from_content_id(data[area:index(pos.x, pos.y, pos.z)]) +end + +local function get_tubes_in_file(pos,channel) + local tbl = read_file() + local newtbl = {} + local changed = false + for _, val in ipairs(tbl) do + local meta = minetest.get_meta(val) + local name = read_node_with_vm(val) + local is_loaded = (minetest.get_node_or_nil(val) ~= nil) + local is_teleport_tube = minetest.registered_nodes[name] and minetest.registered_nodes[name].is_teleport_tube + if is_teleport_tube then + if is_loaded and (val.channel ~= meta:get_string("channel") or val.cr ~= meta:get_int("can_receive")) then + val.channel = meta:get_string("channel") + val.cr = meta:get_int("can_receive") + changed = true + end + if val.cr == 1 and val.channel == channel and (val.x ~= pos.x or val.y ~= pos.y or val.z ~= pos.z) then + table.insert(newtbl, val) + end + else + val.to_remove = true + changed = true + end + end + if changed then + local updated = {} + for _, val in ipairs(tbl) do + if not val.to_remove then + table.insert(updated, val) + end + end + write_file(updated) + end + return newtbl +end + +local teleport_noctr_textures={"pipeworks_teleport_tube_noctr.png","pipeworks_teleport_tube_noctr.png","pipeworks_teleport_tube_noctr.png", + "pipeworks_teleport_tube_noctr.png","pipeworks_teleport_tube_noctr.png","pipeworks_teleport_tube_noctr.png"} +local teleport_plain_textures={"pipeworks_teleport_tube_plain.png","pipeworks_teleport_tube_plain.png","pipeworks_teleport_tube_plain.png", + "pipeworks_teleport_tube_plain.png","pipeworks_teleport_tube_plain.png","pipeworks_teleport_tube_plain.png"} +local teleport_end_textures={"pipeworks_teleport_tube_end.png","pipeworks_teleport_tube_end.png","pipeworks_teleport_tube_end.png", + "pipeworks_teleport_tube_end.png","pipeworks_teleport_tube_end.png","pipeworks_teleport_tube_end.png"} +local teleport_short_texture="pipeworks_teleport_tube_short.png" +local teleport_inv_texture="pipeworks_teleport_tube_inv.png" + +local function set_teleport_tube_formspec(meta) + local cr = meta:get_int("can_receive") ~= 0 + meta:set_string("formspec","size[10.5,1;]".. + "field[0,0.5;7,1;channel;Channel:;${channel}]".. + "button[8,0;2.5,1;"..(cr and "cr0" or "cr1")..";".. + (cr and "Send and Receive" or "Send only").."]") +end + +pipeworks.register_tube("pipeworks:teleport_tube","Teleporting Pneumatic Tube Segment",teleport_plain_textures, + teleport_noctr_textures,teleport_end_textures,teleport_short_texture,teleport_inv_texture, { + is_teleport_tube = true, + tube = { + can_go = function(pos,node,velocity,stack) + velocity.x = 0 + velocity.y = 0 + velocity.z = 0 + local meta = minetest.get_meta(pos) + local channel = meta:get_string("channel") + local target = get_tubes_in_file(pos,channel) + if target[1] == nil then return {} end + local d = math.random(1,#target) + pos.x = target[d].x + pos.y = target[d].y + pos.z = target[d].z + return pipeworks.meseadjlist + end + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("channel","") + meta:set_int("can_receive",1) + add_tube_in_file(pos,"") + set_teleport_tube_formspec(meta) + end, + on_receive_fields = function(pos,formname,fields,sender) + local meta = minetest.get_meta(pos) + + --check for private channels + if fields.channel ~= nil then + local name, mode = fields.channel:match("^([^:;]+)([:;])") + if name and mode and name ~= sender:get_player_name() then + + --channels starting with '[name]:' can only be used by the named player + if mode == ":" then + minetest.chat_send_player(sender:get_player_name(), "Sorry, channel '"..fields.channel.."' is reserved for exclusive use by "..name) + return + + --channels starting with '[name];' can be used by other players, but cannot be received from + elseif mode == ";" and (fields.cr1 or (meta:get_int("can_receive") ~= 0 and not fields.cr0)) then + minetest.chat_send_player(sender:get_player_name(), "Sorry, receiving from channel '"..fields.channel.."' is reserved for "..name) + return + end + end + end + + if fields.channel==nil then fields.channel=meta:get_string("channel") end + meta:set_string("channel",fields.channel) + remove_tube_in_file(pos) + if fields.cr0 then meta:set_int("can_receive", 0) end + if fields.cr1 then meta:set_int("can_receive", 1) end + local cr = meta:get_int("can_receive") + add_tube_in_file(pos, fields.channel, meta:get_int("can_receive")) + set_teleport_tube_formspec(meta) + end, + on_destruct = function(pos) + remove_tube_in_file(pos) + end}) + +if minetest.get_modpath("mesecons_mvps") ~= nil then + mesecon.register_on_mvps_move(function(moved_nodes) + for _, n in ipairs(moved_nodes) do + if string.find(n.node.name, "pipeworks:teleport_tube") ~= nil then + update_pos_in_file(n.pos) + end + end + end) +end diff --git a/mods/pipeworks/textures/homedecor_oil_extract.png b/mods/pipeworks/textures/homedecor_oil_extract.png new file mode 100644 index 0000000000000000000000000000000000000000..ef0f89699fbe1dad0134d01778bd33118c532f47 GIT binary patch literal 383 zcmV-_0f7FAP)-!Tb;D&<9*4wX`alK_}m1AtOW zm%h?2V+W@&f1OL`qGN&}c(3|*yWMr3=TRKTd3Zwa%x_W^?4}P2XC3OQ8GiO?Uj8K>`pC6a&DBKoCe$-$aq4`ymkT6f}t7oa-N` z?}GpW>DnnUv$i&W2*a~+qtRFZ`1txvS0Zu=paljQ9K`Rv{A0UL>?BHS$!U<i30S!4Zu#9U2mBZNV~&oF9&pZ|8iw)2^SoA`=U%;D zw}{BpT1%zWvpmngMp3lf+uK|G1qgy*v(xDeecwl=QbDy^g<%+|*Xyut8vu~!Ii}O; zvM7pVwOW0-yu5tZ>-EkE0CskE-mkB(qup*J%Q9G&g|)Rc*tQMMIi!@3Qo^?F3K3Np zV=v0(^79}FdS&G)(}&`T6-z4gj3<>GAO~ z;y8ws5=oL^I2>X;9zzHLtu<=38p`D|7-Lv07MM&X;^yY&BRf1id}*5It9HBHbQ}jl z2q>i>guwRpHXO$R5kYGW!!V$=MifQ3y1F{+cDs*B2=Ru9%#Do=FvbvuA@1((P_0%W zgaGFpT5D*nQ4|GMs}&lJ2Aa+0BLJY=+uOkNybo!bVry#)oO8r+j5JM=rYT0F(fxEH zf>H`Zgi@)5!C(-VPESw2?e6XtN~x~vy4?4DIF19?brFUkE-o%GpU+|2HnJ?kY&O%g z*-VFFs2F2IIyg9>e!u^Ee}DfoW9-xQ_4Pw3WyLUzB#z@>qtVE0G#Zji>0000H*b`9>0M=R%5sWdz9sr04)>?e&QB+lx-Dz+-oib)F zoO2kBMo?9V2$&hnJdDvNfPB4P?`}lwA$>Iw8S?u$01!fWp=-cwHrqMp@+;AXE2%vP%|{%^Z%>T`0993G*4iS30Bh~t!(X%V a-^V9nq2`NC=e$M$0000MW+v&dA>AcP1 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_accelerator_tube_plain.png b/mods/pipeworks/textures/pipeworks_accelerator_tube_plain.png new file mode 100644 index 0000000000000000000000000000000000000000..0baa5414c1e4dbd29e01b49bed32f923869a7597 GIT binary patch literal 1240 zcmV;}1Sk86P)AZ>cPL%_|9sm$Z7(B-nd+mp}avC`(XzTB15=eXAC zywm5m$l;`}(|g$Jz{}&S)abgg)PK(8ue#ZeyV{Vl)q=Ixhql**4kAEV z&qtYo6lD-WC&{$o?gZKd5r~&$+FWL!Q2VebU^ef{;bV8JI}tm2qW!oTvc%OLJmlVQIprO6{Z}cGzBmk@(!RUl-q7Pw-r29-fEdp6%STX5s@5J|M z|22FN6;=zmy3S9|M>O72@)A* zf`QTpN*kz&Q2PKizv;mTSYxD8)uzkApp-evt^=i2!~iVzm_U$1N-g(RV_qqdYfu*U z{f%lH2~#PI(U=^yTN&vl10XZ^h|EN=}>X z!b{qw?YXUKZIP^Ku_K(*WBb-*yhfX5loy25uV;E~8q)NO&|>sK`@^y=yZS(CwXd?C z6S-IVqpa(85)!vw!Fa~R%SC#9MzF0;-T{E0fs&b)6gP*~CKeTj0tk?|osn zF!k#pmEZ4zB328yH=8Q<5Wn-&T5!&I>58Q)zu)-ghaOD7M@K(_Tzl^oX}9D}QTYLI ze-;%U=v-|T_hUnc0ps|@-so2NVVQ~K$^GQW%h@(ZJSZ@R)Jc6I ztG}EQ-ZUjmqa4@=Q`T6E`;Sd*O|KG`;pe8ax)K6W0?V}&0F~}lhrt2=6DHOe_oAiN z5UCd{tx>&lVJC!;Mxa%om05S%3Ik@_bAzp71K2B)0oe;(r)3ulCVTc@MfE|ISDV1T z01t{(>agA@fGlUUzU($(b0UjdUo0Dpg9v1P^`$E90=u&%zEl-=Mf%4P2ObEh2y-Ia zGz*R5!?+(ft=r|S+@GT~VKY)ExGx>`E)OGs))$}Fg!w?5&x=>MNgzQiv%|uRms@7T zUN{iR+?8AxkbzF@TGy>6nam6ZCenS_p87f8vanjf;^wvU6^6a?FyMawINLBm(a61S zeJdFY6qMR;VT-F|cR~k<| zT(a$Y$E9amFF)UY=JA@_uaDe(b@24#)t8^|IQeMBwU>L2-d}L;$@*P4`wrimd+6Sr z^G`PJzcc;%%Y8d;bYFR~YwzvJ2k*|>dwa_6TNC!(nF@45YjCYEkkTp%@(cb?EMPEN z@gatRfpMj$i(^Q{;kQ$7=G`_BaJ{ScQ7ihlUSLd{@#Fvh4_d5ytRc5kBS7Q@^Ycc9 zmWvmk?iJZ-^*?njlL7+>J&XgSiNY?OU|gFEAg zjN^^{J_62*_HGZn>d0*7xkt|SEjz=7l20y+|7Qp@%$~W;v@~j4YH;qIkl9A}m!*Y% zi<~UCET^dTWzBnR+u=7o=~5gO`^i)O{kp| zFffRViBeQl3=Ix+u(eK3OyDz-18K7Hba4#fxSm|l$i#O2Lc@iCYZnCA!W|boB!)T) ztF&zl+^})gM$YDDA&CtPqU^10tAd<2I&Lu34lq0;$uKojsX-XuWIcBvKTyF{an^LB{Ts5OQ93) literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_blue.png b/mods/pipeworks/textures/pipeworks_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..c063ae1ea908ac8f29634b188f079884156b155b GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx|ReoE6Tpmvs#}JO|$q5R)K%M~umdKI;Vst0G0$5xc~qF literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_conductor_tube_end.png b/mods/pipeworks/textures/pipeworks_conductor_tube_end.png new file mode 100644 index 0000000000000000000000000000000000000000..a0d6915ccbc5573ea5b66f7b8c4e5140655cdff5 GIT binary patch literal 2805 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_conductor_tube_noctr.png b/mods/pipeworks/textures/pipeworks_conductor_tube_noctr.png new file mode 100644 index 0000000000000000000000000000000000000000..cc03245e6b799d45b77e8ec8f1a1150178535ad8 GIT binary patch literal 2133 zcmV-b2&(sqP)-+;P&;~)!RZ#>%7hSsn z@+SmA7G4Gpke3rD@jLDV?LLO$$dN3I9L{_0?P4t1ib#s0Mc8vT1c!HK?tF9Zch33l zpIXox*<@|4GyDP5bhsDUptU9lg8BiFrYWD)O zBuSF`0U)KMC^dWWSGU{Ub*#~7umynU`Dm@{2|${bH1+`C*s)`~SYj*eg&|~FJW|AX z;s8jJgxQ%Ua*X_KX=zDZym-;Hra(xmo_T=ly7YSS_V=&8`f6Y4T%*w-?tv84GZQq% zpe#uo?>%;l^d7dgwKbYe5TeQ|YX^W*3Zpf>-UG(}=9_QKAinsiz542_;=lg`AtmeU z>-7UbYmHJ4b8|a+p`RT+dQ^P=`RBX9`PDBW%Zhr2LDzMO$)hVNYfN!3|i|dBUOr4t3?z=SeC`+<|dBg5Cj3@{rBH8rPg?! zOSc=*@GRma!?9hY)EEP{ZINXftxH_jzJHSh&+|yq97{>EEXA^Hv^IdIEK6Q{?e7QT zyB~b;mgz+)o@?C)T;0E)OO_?rwuO+AvM6wz24L9i^l)7ZCBd?6vMi-6B|+el7bQhr zpeze(b@lBBu{*Dn*dznbfsIYDB$c!+;Q0kGK&J~+t?HZ~R$+Dqgal(Cios}DUVi7m z+_cr6=AZw1gV`BS3ckAq&p!uA0rY-;g^ed!B9WM_8)k%h_ zQOx)KeU0BUv%Gxy^1k2bIOiOc?bl-gzW(~_;pcq%>8ECrZg|kP=K~Gkfq}j|Y(K6a z;#rnG)@3k^y!$CpVc!@yqJ8$+XSE8ISFT(+`1xMCbg5P#42o28ziVg9Ha9nG^)?4Z zHtD+VcvaK{OVn}K`Y?;4s6PNNzx=Yee*OBsQEd+De3-B;EiH+0BF@mwm2m)goEhNx z^XJF9?~NNbOy62y+z>WNxq6t*%*-6vG7x9aVgNSoL9+=z+=hjPhsh4QJ!rQej;nIA z+pC%v90%_F2xSS+{H&6(7mmQad$6?p4^Ex@(}57hg$wVRn>YVJUH}G^4c$()Z&(y? zuLDO8gKbqhq7v1-ngKK#5Ju3t-(#`90k(p6yPB_cG@ zB7z`5YmJnWEX%OYoH;X*cy{jGIpa43|M~Zuk3e>Rg}YMv9TW4H2zeO9VF z?C@c*ZMU8+GLGY*jo@Bq{P5ZBLYk%Z>=KKjh%_m-+4o@^^?`~K0>9C>k?M&DAP555 z?FRR^4tCf}FTFIdSz<@LpN2S2>e(cfrYUipP?qD@5@}u)G5(_v$>RdRwrz}2m`C95 zjl1ADHl0qVegMRAj4>%{z#SGB7ezm1>FU+1+s9nDDq?EcA<}3xuq=CMgG4_yxqN8N z7*hcdkJ4&3rcJE%qRJ?3?ha}2T3%irxziv$(h@w&b=K zUVtd-J(_^|xB&1xkA^QvQ@D8X;=bzlt!1#)O<&6fi8M_yTG4C{S7Z7S;nsM^g(NNO zNrJxbV@#F9zw*i}V$gf0+q;DXVv??}K9bv17-?FlAcn zvYv^M@B6fx7GZZQrVm!12W?hxZ264o53sB@W^?+WlhmH$hAdeLaHzn|9s%sgQ9j_j~D09ckqmTQ6$y| literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_conductor_tube_on_end.png b/mods/pipeworks/textures/pipeworks_conductor_tube_on_end.png new file mode 100644 index 0000000000000000000000000000000000000000..a70d988bb127e80ca9b3b18719d96b68b2d803b1 GIT binary patch literal 2778 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_conductor_tube_on_noctr.png b/mods/pipeworks/textures/pipeworks_conductor_tube_on_noctr.png new file mode 100644 index 0000000000000000000000000000000000000000..30edb603dc9f9e3d1a24063c4cabc8f8320264ed GIT binary patch literal 2113 zcmV-H2)_4;P)I45P>YJ)_zVme%=#x!N zP0{@ae#vnUfVWd z7`E>t2M`e)$H^W5VHjf9=Q%ui*1FBu*ciKc^X7Zo;QaaX1OQS3Qc46tkUao6=ZF)+ zjvejW)oQi(>TbVvy(vY=WylI;#awW_emHpj%o1berx5%ylb1OyK|iWu7tfFKC4 zbJ&8$y1#dHbd*g`Pt))hfK(!zJis(fc=c%Q^Tmr7yP|WsTn?2oVCcvu6C@(&8bhVB zdE185d)tIDh;D;MY|)!=P!J2!a^5@2=M|*4iVsqPvzs*`&fz6v4I> ze)iM#x%LdFdpF?K6*NuDCK2L7!)Kp% z*8a$mBkbI{a~u3Xu>cGdjBN4%A_BwaRJiRb>cDqw>lGlS#Pd?;_Z&QUaKlWadP<8k z2|$u0s0YBWe$hLNvn+xTqOVR+J9g|C*|rTS&7q9>XVtI)YFkj#av{ zh!{2g+* zK>C@Y_PW>GneY3}0ocEPKbxJM?Hbj5KL1ew7#$sDy+oY0FIRd2;A1ktsi~=+o_piQ z4QiST^cuqYDOb0%!NI|;+Xju)aejf3A2OPm-I!i3E;71to6+;qdOBHJX5_l*^@Hyj zeRnUtp1GNp3k#qh7XPtjtD{uafA<8$!|%VLI4a}u zei+l-Bk zwcQ})SAeEl**qo(0MC~set)RDdqze^SVL|*Z~#c+;KKyWj|G5bSs32Q;d#LH^mJEL zwy_Nw^UmY}i7*V|dmKYU?bVoOj+lwq2MU&{848SqnX{k4=9yv`p;F{RuABuqrB2t z>~E&^|N2XS5p7_HnE^o4H24AG(@#3*4ezfaAdE#ew?GgCh{6b-*Es`hsw?DJHve%_ r*L4gQE!_U@Lqru|wbDO55CHxU8}Vy_1yz@c00000NkvXXu0mjfByk0l literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_conductor_tube_on_plain.png b/mods/pipeworks/textures/pipeworks_conductor_tube_on_plain.png new file mode 100644 index 0000000000000000000000000000000000000000..1aaa15bc7ebb821e2679eca4652ba4ac4807dac0 GIT binary patch literal 2657 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 P00000NkvXXu0mjf3!DrG literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_conductor_tube_plain.png b/mods/pipeworks/textures/pipeworks_conductor_tube_plain.png new file mode 100644 index 0000000000000000000000000000000000000000..b432dc4294acc9820188a2582cdbce609ce7af2e GIT binary patch literal 2596 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 Zk3Uy;8_j-`C%XUu002ovPDHLkV1oVDTXFyZ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_crossing_tube_noctr.png b/mods/pipeworks/textures/pipeworks_crossing_tube_noctr.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a75c94e04e41809327f145d3fcdb0ac15e6029 GIT binary patch literal 1236 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_deployer_back.png b/mods/pipeworks/textures/pipeworks_deployer_back.png new file mode 100644 index 0000000000000000000000000000000000000000..2bac175f923672a3a706c7cba95d6d871098938f GIT binary patch literal 512 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU&&m0G|+7 z1qB5~MMY(0Wg8nCA0MBPkPuH#&#4#^}W2icQ02Q`um>cbPeB(s%ckc%+hkVgo^ts9N*-< zM#D@?%e`Clz{(ZW4SmV*24eTecsUCaL>&+$;H zSjEcg>U{4LpE$+too`<`ZA}XMteZN&_Z+>x+n$Hz%&$PUpSpg_S1p#9G41*L{}t7$ zi!>Te{3|-w+;8H2)VtZVprr8c&kdgZN!K-AIdpz2339)BCAvDxov)++t>5Jzk^WsJ z-P$~bYx^c%>oWCO^M~b#82@Gt$+|;H8t%Wiqnh=SX74$^2k2D>Pgg&ebxsLQ07@RG AZvX%Q literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_deployer_bottom.png b/mods/pipeworks/textures/pipeworks_deployer_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..763a7bd0c3ef0d94ed5ef4779b071fb136a22389 GIT binary patch literal 819 zcmV-31I+x1P)9 zOdQM6%i)|-($UhVN*vPC&rVH9(0@GE*w?J7tV2RQqeK|f)Y7i3r__f+M@B-UsH4?~ zLeR;{q^YD*QA}}gX|J!Z*^Nfd(9SI^Dadm*tE{RuG%!s}NOyH_aBpc@S5j+gV_RBO zVqjZ;eRt2#(|vq((}h8|yti#@W!H^H(b3PUsHv!?s@2!nC@3XeTvuFMRXRB}a&c=u zJvl-_Jv%!#Z*FK^TvjeEDN9O5VqsfpXkt`TPB1VmZ*FH_URgpxJYHQ_MnyqEKs;(` zV?RDRIyyBxJU3`(VN+5~P)|xXHZoIEOk-hOTUu3YYh_?xTDxH>=A&2Ll}pTdIhs2Z z$a6E8IupuyH@;^r&3ih+X)nTSFWZqxz-cW_Oh;p4T-=gMVPINtZfHb9K7)dLU|(4| zI5cc(WJ^g!ZER*kLOyYDYEe*2Sy)p^NJCy-SZr%#)`>)%JrvJSCSA!#HpbZP2DMIsOfi5#a@$KnuH=D4zAp|HG4 z9Yf+Y4cwTVj#dOqE5(}sNd;@m(dIC%lpshv+B9 z51+5Kvwvuu=fUOJv0J;FbZv=*aV9-63a2_OwQ553?0}hc≪-^542Gsp&zAoS(HU zEldIW<7MrbW7}qAy=UaZ6?}iX-m^FOc}8%OyifZBKm|UY)0Y_&g&o*DcVABMyk(yr xvt;UMcmEL2ys&_qUwyudJ-0rQJZ8~r>mLEfV%cu4d0GGf002ovPDHLkV1f|;Vut_# literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_deployer_front_off.png b/mods/pipeworks/textures/pipeworks_deployer_front_off.png new file mode 100644 index 0000000000000000000000000000000000000000..323cdaaa73ea01a3871c2e96bdbc85d1ff55758d GIT binary patch literal 685 zcmV;e0#f~nP)W7OTqloAAe>Ggfj1PmS|yG@7>-38j!7P#SSHwh zH=tQ3l}8-Ycr=((Be7B;ia;66aWRrmBD7W_vQ#0qStOoQBfVfK$!#yTSR|NIBfMWH zo>C%%LmY`m9h_4nk4qoATqf3gHpy%*&vY`@dN##rEZKiJwO1q1bTgVe6v}xw!f7v_ zKNj7UOPD$n)`>*oollYAv%>BFAbi z#b_+PVJOUSFwlQJ%zHV{b27qaE8CGt)Q3XOaxqCsNuxvU&9QB>xvgqfzy4MxndIjD zzM!jeKY}XDst$%G^&@DKq#0n_#mA?Y{GDrUab>A!+kjBvOzerR&VGG)uYeGQleyhS znH4#qOF!q5Vc>m(Z#2t!K6}tIDy_U8^?g)4Seh_AAAK!IF81)A{ zpqs(ra_OGoShl$lGRt00000NkvXXu0mjfH>)2M literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_deployer_front_on.png b/mods/pipeworks/textures/pipeworks_deployer_front_on.png new file mode 100644 index 0000000000000000000000000000000000000000..38caed6cbc3186af7cecae7bc577730676152e86 GIT binary patch literal 560 zcmV-00?+-4P)sPPDvU!LoK7E#KN$)E0E(S| zKpB-s9C$Ysqgp4RStk$$0g*=?o>L>9QX+vo7mrLJfj1O@Iv0O86r58en^Gf~QX`j8 zBA8Pnjzt`fNgjhk9FkBXk4qnkM;#Cb0S*HJFfcGkNJc_HLc(b;o*wDcSr0007)cL_t&-(>0ETZUiw5L|tZP=JuGGwhLKKvWflw-%|Ialb)Vr zjinigLw^Y?^!+e~Bnp|l3qXO`z6#QZ~{B7Ls);amu4jTdjq zT177IjXtP?X(BdL+eN@_uHK=^yR$3%$ z?Pep5Av5lyLgE~~W7lL*HOZ^zaIGf1N=y~{!|99u?<6aaro%o|%Hl>VPdeLDPDHuF y(@Q7UclWnj8-q0{@$@V$RyWr{yHvp&d90+1U30000=Ywk4L*=DVRDF%y~I;a%#L|D$|8PnmZKc zqgTp#H^OT#UtU$7KNfX#Yj194($deSrJiSIVRCV8YH4C)VqI`=Y;tjIa&c~ks ztV2RQPEANnO-w>SLawZ*W@TVVNJd9SLY9`2ad2rcFff>ymr_woFD@@3A|fa#C5()O zt*oPylZ>mZs##Z3VqjY>EGf>=&NVbJO-x94b#Jh*r)z3sTUu17N*vF9JEKGx)Q3WC zYh`b4XMcTn$a6J)e06GRV`5=j(}h8|ytip+V$sphU0hc>IW;aVDXOTc*NsNi*Vw40 zs!K{nK|nk^J2pN&IdXApZ*FK@TUA0qJzZQ@R8vk~T~{zLEJ8s%KR!A-IyF;LO)`>*BVJXmmJ(@Zb%zHV) zX)kbZY0}ct#&I*-kx9yRHOO-_&3igcOh;p4T-=gMVPINtZfH3;G=qYBL_?74F)=YoNlEAuZ5#jq0S-w-K~xyi70v@<15p$J zz*pP0ZM&&$+eU2L_WJKlo6ZRaVm|7ZppHF9hX?rl0!IbrFYnKbOJmvJ-dIs9=9KUh z|Mb{zBRiYZs1Nlb1n$SzciI`U4Y3JLEDP?3aNK5Ew002XS%t;Y61a)q-A6)(cBTx= z$<8Yh!Z{g@S)@cGld9$ml5#O{h74Q%omvee%S;pSGV(!tK}C%e-N2-9A)PN$LEtj7 zt0#K`^`%^1ve1u1@a$@j9yJGA>colyrC$Qqr^cXthSYbr)>hS2S5^QW^PQ}l93un& zF}AH4i0E6GT%8RM46gOzr8m!>Ai7@1CjiT(0FX2fV2 TO3e{I00000NkvXXu0mjf>G)pM literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_deployer_side1.png b/mods/pipeworks/textures/pipeworks_deployer_side1.png new file mode 100644 index 0000000000000000000000000000000000000000..f3ede41534e2f25376fdb0164c183d957587491a GIT binary patch literal 841 zcmV-P1GfB$P)=Ywk4L*=DVRDF%y~I;a%#L|D$|8PnmZKc zqgTp#H^OT#UtU$7KNfX#Yj194($deSrJiSIVRCV8YH4C)VqI`=Y;tjIa&c~ks ztV2RQPEANnO-w>SLawZ*W@TVVNJd9SLY9`2ad2rcFff>ymr_woFD@@3A|fa#C5()O zt*oPylZ>mZs##Z3VqjY>EGf>=&NVbJO-x94b#Jh*r)z3sTUu17N*vF9JEKGx)Q3WC zYh`b4XMcTn$a6J)e06GRV`5=j(}h8|ytip+V$sphU0hc>IW;aVDXOTc*NsNi*Vw40 zs!K{nK|nk^J2pN&IdXApZ*FK@TUA0qJzZQ@R8vk~T~{zLEJ8s%KR!A-IyF;LO)`>*BVJXmmJ(@Zb%zHV) zX)kbZY0}ct#&I*-kx9yRHOO-_&3igcOh;p4T-=gMVPINtZfH3;G=qYBL_?74F)=YoNlEAuZ5#jq0S-w-K~xyi70v@<15p$J zz*pP0ZM&&$+eU2L_WJKlo6ZRaVm|7ZppHF9hX?rl0!IbrFYnKbOJmvJ-dIs9=9KUh z|Mb{zBRiYZs1Nlb1n$SzciI`U4Y3JLEDP?3aNK5Ew002XS%t;Y61a)q-A6)(cBTx= z$<8Yh!Z{g@S)@cGld9$ml5#O{h74Q%omvee%S;pSGV(!tK}C%e-N2-9A)PN$LEtj7 zt0#K`^`%^1ve1u1@a$@j9yJGA>colyrC$Qqr^cXthSYbr)>hS2S5^QW^PQ}l93un& zF}AH4i0E6GT%8RM46gOzr8m!>Ai7@1CjiT(0FX2fV2 TO3e{I00000NkvXXu0mjf>G)pM literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_deployer_side2.png b/mods/pipeworks/textures/pipeworks_deployer_side2.png new file mode 100644 index 0000000000000000000000000000000000000000..0b31eecf8a2dcb8868cdfcee1193a2453d289db1 GIT binary patch literal 841 zcmV-P1GfB$P)=Y1I~3xbQs$#qyk#rdk4L*=Dav^_!fP*IUR9Vn6U=!zykjcU zg+QJ^7Ik!MZ*FDF(aX!o%X4ySa&c{PacpX7VsLM4($ddkVqK=Co@ZuZO-)R4ac-fY zl&q<&Lqa`5KtfJUNJvOVuB@kKWneEZFGof~mX?xnaA}yBmr_woAtE9$FffdagsrTj zEi5U{(9Wx@sx>q)O-x8xS5j+gW0RANcXe-KU|Xk39DjXxTUu1eb2WW@b+E6eC@3Y< zg+b4KJEKGx)Q3X1yti#@Wji}IK0P^dacggGXk1%WIyp5$K|NhuRxT|m(b3P<*VxyM zMyjZ(sHUo7VOwcvVpLO3OG-vCFf3hMS8r}-UtU>4K|Db~JVr%9UR_r|K00b?V>&uD zJUlmOXJJ!PO*b|&P)|xzQcPoETw7XIY-?p;Us~OjOV)`*yJ0ENe?7`~H<~&V($dnx zX)n!tI?8o5%zHU-Z)wPLGux3##&I)EOh;p4T-=gMVPINtZfHb9K7)dLIXE<6Us-Kz zW=ly$Y-(h2aB4$BK2cChSy)p^NJCy-SZr%#oIMmwOGZUSKtw}7YieX)URYdPR!T`k zL_|N%eLKQ!F=l07XJ%lAgne3BQ>?74F)=YoNlE^R^A+qH0J2s=P2;-!PIh-suLbA;N`0`3>2 za)p%*fgV!76WtDg#4pQK$?IDK#wmJ#cOwX;ukS%q%m0h*AG4ZH z?_4oDQSUT zWh=|k%hJ)(r%D{*oKn)#&!a>bPEAPAe>~RM*Q}|mLqa{&heAh2LZhgouB@kVaB0)j z(xj=RQc+CEb2V^pY1M~9(8Ku&z-cW_Oh;p4T-=gMVPINtZfJvodrL`0IXE;# zLq2S3WME%eSy)qTY-VwAYC}RkUR_v8NJDIEWKmE{)`>)%JrvJrRQl(9sG=AH4=i<9L zkhMMfd^e|VeIj+mCZ8P;_{5*?aT2{eIlIVa-dUjhA1~?KjETa|t%27s7yNvC-tfEZ zLFVu%b)EM5A^G5B?U-fMYGj>jqB@$~c@?CoyyU3|W_?!J);o(IA97{k<6GqsJay~E5516%XamN2cB zAV@qqG-WUVHz22@mBG>~u`)>HI2DA|Ij*8uC@ibd#E>{mLx-|KR3rlN|JG_^acHV9 xFDWRL{YF9|StKt=bCNJY&~hoKQYf@s><{ppV%b*)v)BLt002ovPDHLkV1gV$Yv%v} literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_detector_tube_end.png b/mods/pipeworks/textures/pipeworks_detector_tube_end.png new file mode 100644 index 0000000000000000000000000000000000000000..ef0d5feb222b949963950010479401c4a3af9863 GIT binary patch literal 1393 zcmbu9`#Tc~9L7h=Wse%&ofHaPP#%>_)V3zZ%xEr^in)|at8^@vSfn!NED`eLPRur! z&DdP#GUhfmHipeGmr$b92}R=QZ#eJsyzl3EfBb%bcnK(^ow}Nq8UO%Lhugzkw+Q}i zm2F#@&5HfJ1*JO>CkOyQPXey{Y~SkbCOibkG=g-W{6c!fB zSheoaly(9jTz z#S)9fot>Qn0|PxhJ$-$BOeV9etV}2r3Iu}E($e1EUMiJJqtU9Wswyffs;jFR3`Ti* zIh{_gtgPHRMWjAey9MZ1)5%b9FPLXbOf^v zn5vlys_{6&<|aAW)FJ_Xm}|MiCB3_(-c207OtP!7lz>}?XU!UVeN=JhY5F39T=mzu z7eqOAQVs*yO1tf{Snknb!@2g8IK zXCa>YLGv)3R5EvHzTbQn3S#M(B0%_C9jD)3J(h%2%9pX4LV`~~`;3VeHN?!cJ+C60 z2VUkOv>+VpHPpo9)QsfGBE}q|`&D9K|8zw2EIA|(iVaMCPm9goaM%?CDmnK$)Xe4u z0tkRAyiztuTRNkgp!GL!hXvr|;iLL3#OZuJ%@leYe07yCAMF{5jOo z=?p1xH__cIh+^8|;L@|JM`z}33g!Ut1pB9aIn0IsIB+$`E#_jkbHv2{*TrI!l0_;e zx5$6>CoA9B^Am7xdtNkqw^d1(})a%*m8esutl6 z*K&W@ilD*R2>tM1Mobj?MfgKq%ONu}*4^t_4fitCIhLn>QP$0Q-`FzaMJn5#S_!hs zHD+~hi_uhuru z>Itue3^_^xIeg`ym=of-ITcwpCrwB{q~RQM*;FJtzTYNP;LG2hih$c#o#dVqo+5&t zy{QfuIGz$<>hn+DWa~R$u)?YXS^`cxQjBeE9*#lTtJQ`D`U$@X5yl8#Lq)dW9v#sp zB>>{@+@J*5ncu@7as%la*Az;?`}(@JFwa-QU2c!rQzn2cUm*T zD4s8{N=B?SlOe1rYHd~MN`Tde1qP$AQ7%tP9p_eBAhrY7v9pTJ3q|t}Ixn#5cz)zj zsWk`7UlI2*_Tol>dL_me@Ojt@>kR%qh84sd;-bfp)s>&Y?MZD}>3$x1LvcMv`gA@( gRCQ?h{LeV~ej};qpuGaAb!!v=a9bp-9O@nSAH7=YP5=M^ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_detector_tube_inv.png b/mods/pipeworks/textures/pipeworks_detector_tube_inv.png new file mode 100644 index 0000000000000000000000000000000000000000..b6cadb933ae8b02340a51ffae5cc1081dedf4b51 GIT binary patch literal 853 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCikP2Ka=y z-o1PG|68^HAEW=j)xCZD_MJO-Zr;54|DDml557l_9=&((-i;eK4jede{rdIYyLbQl z5cvPS%l~&K|KB_P{}_4b(4l`Hy#K$m{P!XF#EBEvu3h{8&iem5vx5f@Ub%AR>eZ|N z-`gKMcI@!s!^e*wKXT;AzxSU1-`QTieEI)-$BP#)o;-Q-(xpph&z?PX>eT7er_Y~1 zf8oM~bLY;TIdcZ+x(fy0J%E&PNswRgf06-1;k>Hdq%EBbDb%Mz{_vJse&i)i;;7^eJAMjc`rt>`eylww)r&XApvuE@u z4gVt2$95#}&D*k%zbt#pC&t*?&i`+zaN$j|?dSZzaR-I1)Z1pAot2Q`QuFx660fPN zIVP7EsIo>TZvM2m>&HL7>Y$^hLJHdgBGG4)LItq(9v5l^1^^{~hRbynYqr@MEaaCK`9yD%?+*X`JAU*Vl`eA0$0h4R-I zZulIfQevpa$j`WE)vU8d54PxQFm7^RwPn_SEpCqr$J_c0S6{HWux@lH&ty3hJ;8t8 zeVaoo=1&UsdBC`E;uR~y3k|cmuS*%$Gjv?c;}=nFSa{I!_2P{Ay&D=nakO%=$eC;m zi8Qy(zylR~~+jNkG7`h1)4hO?g;`}p{dh~%g| Q046yGPgg&ebxsLQ0DqUliU0rr literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_detector_tube_noctr.png b/mods/pipeworks/textures/pipeworks_detector_tube_noctr.png new file mode 100644 index 0000000000000000000000000000000000000000..c415d770da80ce822becefab17d76b3e726a5fbb GIT binary patch literal 1169 zcmbu8`7_%I0L8yj8lq80w|2Wxp{;b)q@6J8=wvXWm^6r^j;LgN*^Z8@t6Q}uY`2bT zZOb}~HYsvA5`;KHh$E3hS?mCaqRGG&D3jJKNviKQ}iwFfcGWIyyKw*xcMaJUlEGi+McW$jC@nJa(PQji%O+xZEfx8>6x0E>hA7lGMUrU(;N<`tE-E}VzsxocXoEN+3b#vj<&Wo z<9v;}Ce8@-Ej%uA@Baws+fMfcfPG#ef&Njkf?qEdWKhpoFNY%4A+Q;)8J6=FuKH(h z==-WCaIo(sDLlsa<-_hbs}zUq0^cMiq(HG-7e5q#%{`j!WNW&9WVdxOj=5e91r^3c z@fs3-MtYe82-@NChu`v1*5tZsj*f%SflR~ay*RAYLlrOqg})ONTB>|aeh)JB^~ce~Rq|Ot=Q#=MK>c_Yx9G(i+y=VQTW3Y&acohhcuA0F&1*ZXZkd zJdZdN;3UGCrJ<@U@?S8Vp(IkdDZRMbYXW@x_+jU=3^aio#d6Dx>t@jj^{kAFzplVC z^s=i<8P1nc*F*t0PQba4YeXl4r0n`G;kd2)(NAeunYYZcwm2<5_nY*i2rO!~fwO>A zPP-ZYzQh3kM09{VJYNH-cat3Bnu@wUrr2Y|G?-q($gzgCIle+8vJ<7dD1O52B~HXF z;h=o+ml(~Uf>*m`AJmhK<^XF84r`Srp0078MIW;DB|lzn^zx4^|6*$gOb(e)m6k>2 z0;8D=ckQ!)dp-nhXaug^%5Nn_iZ9<_F3f0|4lNrANS6q^UOTd*K^`5G3uW<$`nTbk zEw0{L*~UlJ-p&2~x~Ymi1%RQKD%Ko*^Zs~q3hbSnirzKcQa+&E@{|*5eqTl%PA^PK zEeJYk>-Gw5)tq^$1BW}i8Rm505meNe<5DwVQ5G(IB3-APEDk*6R#7f4`#SG{f4V3* z-{s!8XIKhV=>GI^=8Mp*w;@+Cchj3lAoax z;Y76Vo~o9G;&NI6lg5RK-RGPk*q!MrYzW&`0xz_*Y|9`bm+ z$;n9|449st&dbZ2n3w>36R;F2lcWOiUD+ZQECm8_yiEEmH#ZlEBFD$a^Yily3JQSe z+WYtKWkRp9v9YG6COVxC_(&l7Qzl6POF=+{=W@CA_4Pn>1BesYY<62)TVY{gOG`^* zW1~!xCX+mFXlUr{>|`()Kt!mmtsNK`7#SIgs9^heM;$N=r+JhK6K|nEw8L*`iZ%adA~uRb^#mSy|b;ckh7UWJN^hDCOnl z>oo=()$v+K5Z=w%9sD1HOo^oG_4&*k(bgW`t)AZ#oo)~~vUJkL#vyjg`Vcy0!RX#KIL#S8V9)PO~oj@|qCoRd)4F~bYJ2gTm{)-&x5tn_o8_2CZIlo6bAUfMubHgRAmHU5Bd%VP<1(T& zw`$+-IF3?GNH~?;oRcfvgNgEh;mlFOjK(RQZ9iL1>~}jDrqX zWN7D0%*vPWdwc`u(BX&Ep0-gw7rl_`F|E9-p8jfLvVr5nD=!>^#dS~RV$PqDo?aw9 zu$H=6!Zl&j^B={d@=35I1NyIQ7K-GjZ$iOKR(%cPiyme6igv%Wy9ECkz8bwY>qF|D zQ2CG~X}ay0)mJa^JAlrlzilSR-jPiXtl{T%l~p(zF19(@uKv~9P|tkT@UGYo_#X!G zwSjh#PR6l!O;oIgTeZX^Pf5I5(?oI>RF$R}Z+5{#OD%lPr$MXc<{?_MMXrt%ix^R( z=$r8xN-!pChsRCMHhjGC?gigw@H|FcO3;`|nrUj_?%{9II86MRcmSh!%sqO}YVkFA zqE}z<9kLMT{AexJik4z{FZg%o_N~S?xYhCE;18%-GvbW$kjyDyf)uthpFGuGJ^4va zJum7Jf~AN^`gHm}I*J@LsSn?9SAoN#LK)*UNYfUJ+zxqgRotZuXQO$M(rNy5tge#eF6bY)935ta_;ERX2OFk&6yg2Z(h$3Hkf-P0+SyqQJ^S@tFq}KY!dvl=g0ordH eJ!w;VaGAXLjo8YKI&pFRwjf7aXEepeKk;9^5qlQ^ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_detector_tube_short.png b/mods/pipeworks/textures/pipeworks_detector_tube_short.png new file mode 100644 index 0000000000000000000000000000000000000000..ad5e034922c9a29dd64e18a72974fb4b9d357e4b GIT binary patch literal 760 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCil)2l#}z zK6vn8)v8tZ@87?9^X7&P8;%}5dhXo0+qZ8YKYskonKNtGu0473HPWg7cN{lb?VgV)2DCTxN-5~ z#bd{gUAc1Q;K74iwrttDb?fHMn=fC!eBi)={rmTyJ$v@jrAynkZQHwd@71eU_w3oT zZ{NP%yLa!{v19x8?YnmE+PQNl(2aYR%y! z2>oDZn6mTMYQOA2t_vsbNBw)NcyP&@4O2v$4uxs!1bW}gyrIa*apttoycF*Kgkr@@ z?aoYsOSb7&+*}#U#;_-rW9ccs@0lzUcIos*zF;X7I2-ONyXio*b&lANyeDt6x990R ztISK3eOCHGO7j-e@6Ge-@17K6nP7drRqdwyl=!5*$_=T7u_}vmYy+9<`S}DK%9&-( z$4^(#6Ln$vV0I?K_|!4~Hi01N(2om`&3-mz!nbx;#@yo9mh$Q4B_i*y*ZSu2{GQ+& zEk4nBo=U^zZ*>{U)(_-1oa1B&b3PirSHQYnJR*f9VBPZH^4S%P=S*dlBE-*F?EjS_ z|GmgM>+v)Rea-|8n`PF5Yj>M1H?g^HE!2?G`}n%=$3J^|_y6{<6E;cw9MZmenWaeF z=jM$~KMQ3xe0Xqdy|D3#rN{nm>{`Gy^TS!gOx0!jS2;s(sRq3$Tf8x9oBC{T)l$=s zwg>V8o3eJsHHk?oys|wW67IB6WSegA)RQ7wKUXw-h=?t O1B0ilpUXO@geCx!=8@|F literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_dispenser_back.png b/mods/pipeworks/textures/pipeworks_dispenser_back.png new file mode 100644 index 0000000000000000000000000000000000000000..f4fade2b62fc103cda8a29a682ef5fab9281bc47 GIT binary patch literal 2031 zcmY*Zc~H}b68!6cxn>KDAPmdN-nDM?uus#vFLc9`?BA}=Sn&Tn+5=K2moje z0PyCM3tf3J6aXfv004IYz_+E_C}$G^VD?N#Dh}1v)z#9{VltVGMx)c|tgfzZZf>rr zscCF%tgWrJ*=!bzMX%RuG@A1Aa;;WdRaMp2*5+_H}Sl{%e{$z&E67nhZliN#`(NW@~X^78UZOG~X*E0szuC@A1^xeNw_NF){&6-gwL z0tSQ0bU8Yo&ld;;xjET6xU6g(HlIdOs}y)VJ~bs7orp|KL}p<#1p;1rdU|qlaza8v zTwGjAN=kNic2-taPEHO6gTZ34Nl8g46e>5@)h3%$$SUHn6>_OssnBWE3Yk>M=ZQrE zjY_H4YGl$fnWT)%k*5DVxdqZ5b$}feq4!IR9j`WnvE1PDK<8iNWfc+y6yIw>Pm~n zY^rdn(P%ar^*XIeA=ha&a+!=qr84L=d|n=rKw!}6QBhG55fN}WJUTjh^XAPPH*Wm& z>66!Dc8_Z#v+`5W$oDY|+BL3V9uJcz1OU(fe70FYlhX$P+{TlT2wc=)=v9{J4h}Fq zs7&AyeoMj>-M+y#JjHKojuQLU4)cpnGaJR9IKlApzkM~^t zGjG#dZ&4_RFmg(zId-@>34Ji~;l!UIVidp1-w@t&esT5jcjJn?ZqJ%q&YY3%3TyH4 z2=n}Ul^v=5ic0l|olx>SPwqc{SV5h@c&u18)L3-I+JajUIF&p5OYqAFSAS7Uj%^$n zjfiT(c%QR=+;(RS1a(foJ3Ozazh+}Y|Fhse((;41cBBUyeoBTcn(|&Z!8kyCz4-Ly z*>5$+4sZpaCu&*jI9P$7=XbD+-E zkL=Rh1S=x$+E^+me9}m!eOJ13i@8K3*XdOs^fWNQE6W_S@o1bFjWuQ|!bYZWvug^JUig!=q0$6PJ za!_W}v*`^ir|kFJPn?Q-Z@6oZ^~88tYJV5^1CPq{ZY_lTQn~i$M?-^aPdyyi-~IFW z@YC)WmGz70#DpJCBRkH)Y;;cKi1hlUqwkLrN{_2}g)5h4`PzLwVQX$g5A@t$Cb=h` z@jLe9-n%);LBz-B_I}}w@#vr1#0;K^{qz2CbkFlP^NJ;FbAnjJBVM*c;<@g)gPY#| zF_wN&_hb6zSL;m^zBli;F0kFtfa4|yrq^Bhs5$ifrze!o98`*J$-OzIF`fr^|MuyJ zDPdQ1TgjwTLnc$#1+SFZ!@Z8ayU8zyO}9oJjg7Lux{i*@Bp(#|PDJsDPVGM&1FPHD zJ`?*luOGcMQvLqI-d(DXXLn$Fio24Yg0=bC=O-fyRIgq|j;d!qd>#97`maff`okp# zB%A9i4~sjnFK!P(e{ymr?dC*mhfHyOmt)^LkNp>BPr4t#kA-6LX5*yzh+of9(pKIS zo#D(H9!hB~VdgFi*B9(uMfaI{G&&#kV_SYsHoC*HFk@L|W2d`M1RDQCz?G8mi+Il) zD^W#OqF>e79{+>uyz6kBSh8@9{*LPnKt!lq5rZZwfYSv9E&yQA@b#h4$WT}~E_^*476FH?4~B-r sq0nzy<4*mHP+ZDjGiCoGtb=ceg2Tf9Pmm#}FS-ao5^4*wJD#fl2QuV#Y5)KL literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_dispenser_bottom.png b/mods/pipeworks/textures/pipeworks_dispenser_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..35416de2dc966f64de118ccdd6d211b6fc6a2dfb GIT binary patch literal 4508 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%0Dy?KRyv>0 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 FV1m~oj?e%A literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_dispenser_side2.png b/mods/pipeworks/textures/pipeworks_dispenser_side2.png new file mode 100644 index 0000000000000000000000000000000000000000..8f306b281707b44d5079d66e5b1a0168487e7fbc GIT binary patch literal 4518 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 Ef(t{3+W-In literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_dispenser_top.png b/mods/pipeworks/textures/pipeworks_dispenser_top.png new file mode 100644 index 0000000000000000000000000000000000000000..8d6f9d0e7bf56b7c262c0d383357967d9e87bbc7 GIT binary patch literal 4501 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_filter_input.png b/mods/pipeworks/textures/pipeworks_filter_input.png new file mode 100644 index 0000000000000000000000000000000000000000..e57a5ec7c8d10a411081e9b194792c7f7924d268 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF5o86~@%91=?978y+>-O&EJYc}X8p?A1 zk!cW%jf2ajU4n84HeQ=_wVEXZF0oCto!ltDB3sW)XjO()oI*x(C)78&qol`;+ E0BPh$qyPW_ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_filter_output.png b/mods/pipeworks/textures/pipeworks_filter_output.png new file mode 100644 index 0000000000000000000000000000000000000000..e0ae6220c9e85c33733dfadb2a9f716dca076f36 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF!oKm3LY@vV0I{tJTmVH zEAx*Mod(ahU0<7>Cu%JZ{;q!T?)%_1H@}K_Yj@Nh)%4o2cy+H@_A*gY5d<~hS|Q!udAQj_;_sbMrGT3kFuMS{ynRcF)#{WA}W3!Xdi>8tDnm{ Hr-UW|KTJzp literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_filter_top.png b/mods/pipeworks/textures/pipeworks_filter_top.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c130c061dc5f3f271284754ede86c65e1b87c6 GIT binary patch literal 212 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_grating_top.png b/mods/pipeworks/textures/pipeworks_grating_top.png new file mode 100644 index 0000000000000000000000000000000000000000..7219861bf9e61f225ca236b98ccf3750b5945019 GIT binary patch literal 4452 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_green.png b/mods/pipeworks/textures/pipeworks_green.png new file mode 100644 index 0000000000000000000000000000000000000000..2e4939d00302ea48a8e09a8235ac6e25d8d1243c GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx|bKKg|Rz^`#(ZSX_E+*>E?c+W`Wl5ecjv*Y^b$fSn9x&ix4P`n1 z$TWz>#=+&%E=(VN+86g{c^G#`ReP9ml}n>FVdQ&MBb@ E0A)!>hyVZp literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_filter_output.png b/mods/pipeworks/textures/pipeworks_mese_filter_output.png new file mode 100644 index 0000000000000000000000000000000000000000..35db0fefc7570f9f5ddaabf103840830010a2fac GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF*gY5d<~hS|Q!udAQj_;_sbMrGT3kFuMS{ynRcF)#{WA}W3!Xdi>8tDnm{ Hr-UW|_F7EA literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_filter_top.png b/mods/pipeworks/textures/pipeworks_mese_filter_top.png new file mode 100644 index 0000000000000000000000000000000000000000..7b8e2b1d2d083bc886c84743cf8b531a90dd58a1 GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFJ!Z~g0>bgTl>toXr(@r;DyC9Qsc^apieft-Sgw(jrGZZ_xR$j2K zmQoUTN>KAY5x?@yg~@%NRKBm7&i(yEr+8_7e=$>)$ioa+{2OG#g^sMuHMF%=hd^{$eQTbx9Qrv>DjvQ=F#fh zzvk4j=hwFD-NNM2tM1~<=-9dK;KuCU!`{c4?BB)T$(-fVtn1yt>f62G%AeuPqVMC( z;?1Mr%AM`u$l=SN;?AYx?Z08`Gn*#H0l0d!JMQvg8b*k%9#00Cl4M??UK1szBL z000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*q^5f}x{s{{=I00W;%L_t(o!WoGW2haNnl0#aI_&m{Bzf8Z?$O40KnT}vpj>?Ucl6SC~(sJc@sumBlnXbP#| z0Gb7G_J5~4Edqfp3&3MN-FJ&1IKu+K#f0-LD3DkHE!o?oUoNHgbw1;zCsJo0@r!hz8Dm1h+J0gu}{KbKyC;{g?(hi*>Weh56CrPU{ zDo>~}dn>=ct?WZBuDuLR(VUtPLL^lgO8F+k(APrz4gq~3LSI@N{+z;4*S3zshFiEa zPlk1BIF0i7j~IE;3U5-DO-7%j{zU7>MizNwbF55mm7Gs69<~5Dva*;@BEY7RqI@S5N?AD@wA!pay$tNd86RzF*CsS}|HKE^ zXNw+g^=jipiF&)~u*Aqq04-&9w<2VN9UF|}OMA;#$I?;sk(>jmk9!rS+xqM!z+#w( zI$KeS$W9ZbRmocM9EEo?J<14dN01>a#;BfJoZ-c0Lob39|JkN#M6hqN3AGdfT~k~R z_83kg4DWI%YGs<1vW|iSevr!z=8?4Y4l@1W$vYjH3)_*nB7oOmwA;1DlLOa9Z17#~03#zgh)}*Y z)aDc^>qoBETULJGGwT8j8(KHK+DKs6Jz9)~J+H}9d6SZ5jX6()YDj~mXqna7+mxzG z&Fj(-HUNQmPE`AP#Zmp(?lZe}zwVWz9@6o8q?Y=WI>M#m0YHT zauSD?7q6M{yblgUI~R?m3J}wYZL@IRjV6UdW+0`_cGh=_mkU^?CH$TF)uy0N>&MCS z2*qHZb`erBO<47blM2@GOz@v|D&QuQyMH$>YQPTw{{y@-YDxi_CU^h<002ovPDHLk FV1i@SHv0eo literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_sand_tube_inv.png b/mods/pipeworks/textures/pipeworks_mese_sand_tube_inv.png new file mode 100644 index 0000000000000000000000000000000000000000..8829422d46b2c9e0039e1d091971f1f1e4ce3c67 GIT binary patch literal 699 zcmV;s0!00ZP)P)t-sVE_Q- z(yZpxvFFvZ=hwFA*th7|x#`)u>Ds*N+r8@Czw6z=>)pca-oxzQ#qHq6?cvDo;>+*j z%4}v90004WQchCjo&Q+enDEK$+in%DdH9lbm+=aJURij3CPH!# zAWwG695QA=RU9^2xbwLpaE26!j^P+9{sbr zv_7;gr9?Q^Yvv$r8%qG16MmP9>}T&pYWkeg%cAZ#P)njBBnQC3uYD&ZRhhjn5x)zh6`y}9Y_(Kk9JAd*$6rw>oPFggHE z`%K4Y<{ZDPC4+ISG(6H2bW@_zP7iAQ`V@t41uX^bD%)D_kNB&ek`id1KfPh|lM-Nm ztz{rzL$lY)gPX$!Te|fFER*th4^v){;?>Ds*K*S723 z!sOAb=G3w5-ox$S#_r)pWK$C>Kez2VHF;L4ri&7L;#2d9Y_EG010qNS#tmY z3ljhU3ljkVnw%H_000McNliru-3JX301vNabxHsL0@z7JK~z}7l~>o6qc99*cS`z@ zPz*Q*S4sc>hf4@#afTH60gMj5s9uRASzLLuj|Cne;VefX797B_01ERt+-VY&*s=f& zR>OTg34+xu0Gv!HM!^<|1<;beZq%fKwk!bp8UfCuAaeyT3RsT2`f@oXq2-wXIvaPV zt05sr7JxPN{Bf6bvS9(Fg^!-kTi|J+LEQW|_%JX50K)_@IHB?Sz)K|EXX0@d$bh_J z(oKEK!k?iU9j_L0*NrDf6}&OLFv{$J^=lnP=*BXk{QN)mIs$OY>7uGKwS*r ziD!a^Iu_K1$%$~siNQYNgB2KS$+>3J=3tR1M`~Me{*IN2G!;f;-Z;uNI0HrhqH7Ye zjl&eJ%~8`@uZbL@UI;o#tx-}7)-?S|htd!_Og^&X(bpc@?EkafIlHZ5DP(JK@@Zs#gKUMIms_L*!a*!+O zj5P*})h0EzX9=^!;n3)wbtD|{i)^Yfb=tW#B<{~NEiE{k=6hJ002ovPDHLk FV1hPT+_eAz literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_sand_tube_plain.png b/mods/pipeworks/textures/pipeworks_mese_sand_tube_plain.png new file mode 100644 index 0000000000000000000000000000000000000000..ff0a10702572459fb413816fd8c92eb9a19cfbcc GIT binary patch literal 2464 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_tube_noctr_5.png b/mods/pipeworks/textures/pipeworks_mese_tube_noctr_5.png new file mode 100644 index 0000000000000000000000000000000000000000..2cc44d4815cfa4560e6c85bc834f40f6eea6249c GIT binary patch literal 1136 zcmb7^=~Gh&0K{Js5=jt68aXTiiWKpnTvEo25RO0sB!nXbs5nq8nOe$W9koNz2NN`k zNstNx21`{Sav3R_c+dvL;#HbbN`pFxLL}$Q%lWJUDgFuFncd&)xBaxIn2cms!Uh5W z0IoD@V&)3TAMA`-$#!Xteg#gPIC>laTo<}57GYPqh?$m6d26|2g`b#=O6XOV6@Fxx z&9s|GE!q=^c?f!)XV%m}uL~@?GZvk|tgc4PGMk~zs&BIDgcdE&IQNBBf8MMH^nBXeovbiH_FW_elqAW}K>SDzK^-K#!#sPh-lhLmxkH&1xvtBxc2 z$g)Rx1d0^M1cXbz=6NSxM;yv)OTx^U)5B;AitOI5=7YPa#E!E~jJ|Hd)@0P_^W>oB z0J*1c8NrR;s?iKCZl>3uw`zr8XBn3ZqAQxmrG<{a-)tw!?dW3R;~V!_WY+gn<%-Y* zG_e66%99Y(Yoyenmx-JxDq40wkv+`2cALAT$;7|NbEc3=1cBLSUj5eM;Gj-2oF~>2 zhrLddyix={#kmC~Z@=5kcjs(Px%r8IgUmygLQhTgp7>~e7|Q$j{3_$=%8Rns9A+TpVySXt%nBiQI!Og~Z-F=^QeUJbVBsCT{@nVNx9TBjOE9ym=59^aEZ)zj3 z^J%q!PH2o~<#TA+Q(t*po1>?N$CsgOyB{C;wTE}((X%aA8)JH&N(I%UV;5vtpF>Ai zMc~ML(s%xdiCLJoIY&e9{VJ4y01o`@Q(*iv@b}fT4Dj$wg2P900g-G(C70urv8$}K zZ`UQs?MMH-w}g{S#tJ+}!cQRYmb})o^IO1rua}rLow!n0xi+}47|3^pT|oy?vJ1FY z?1C$D+^zf9ou68b^+Mov{*fuXNO>4=p&PX4P@8BQHsq{(Cvjy>KjY(UEu}+m6 z_df@nuJp|uo6KVc(c1d^nJVM0LQxnz;~6zKoGPjE9oYNq4rAaj+&deE{hYZe=3L;u zmi>FJWjJ~UvC&h`y>!WN#y^U!Ai1+MgQu9&N=isv&&jT~Hc*N+-|86HMh%9hbH&4CJy0^&%D_vqvssi&cd=!=a!kgPN7um7+vk3J#gp4lrHk52@E*P!w^8r}h ztlR^FfU}#UDi<`9h6;YPzvrp6AWfEE7fV2LnN3GSH~awThak4C6#q^cD*A~j+cCk6 xZ(E=yY--Plr&R8gAfrQ(`l8ovtzga`U=g!^97!2FDE{y*0FA;(9EdNh{SQTNMS%bS literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_tube_noctr_6.png b/mods/pipeworks/textures/pipeworks_mese_tube_noctr_6.png new file mode 100644 index 0000000000000000000000000000000000000000..d93213d608f7985d6f57a68a682c39a050366d8e GIT binary patch literal 1136 zcmb7^`#0MM0L8ya#3QQ3QjbncJ%$$ZsyWRm@dybL@rYpbFeYc6dCgHfrv2)PHXcbZ zR6ROt>-|cNN*}gpbyPbuGo$TM8Y&M-zKJB?uA!!X!tOcue$M^v{&Xv-lyDQw5extT zCM05L>^|`yY>3*=wz0CUedsZQ$Uy*bn`^w2j^6LB)TnsE+wJ>m=&4e%BwveDLr-L@ zv0BySw&XIb8j-(FQi;ptuT!_B)!R~zN>mD~_!?QWdaFS# zLhB6WW-+w!wen3t&O$G%G=fAy=uz7$b?VaG3^2F_v1-#lgEdvxcM z;XMm)9|X>c3UGIisn+#a?Li1D$B>mNy=i{}0&m_XVuPoM*!J26N`Du|B^*(C74O{W zAh0}^gE3`a6N`s;?8#+F7YP^a$YC-;WM1R!SeowdHz%GV~t)W84_?=9H;o|wcna_48#?R;rt=& zxK$<2DuQE^k(iqG_Pf(;bB0UAolop)_!j&Ka%80S{6~kq5Y`vh4HT969_4wKny9??`;m z>rs~gDOcf7OJm0d-j3DPSnW zSU+9&p!{ERc4R5q3Wm(=d?Q%C0xzJY3)ChM`UY;gu`eX#+k_`+oY|zhFvoGUUjEU{ z7ogs){*?<0Ni=6t^S}UgLvc5))eBm&^b?Lp@=A^kraZq-87zYOR{hYQQ;!GKJDqLH zOi}0PlVh-TmICID8?tIUKl&WboF41CNL^kccm(xc>1=KW$Iz;~?Sm(XuJYx?Zb^N@ zb%X{9UvGM$baf9vne$=*Yl%gx5ih4En&CGx*VX`)SCu@Dp@aQ`il$G^+xQ=2x9%C% zz=Siv4(jkM95GeU{oz{x5`hvr7@T(LKVxr3rT_o{ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_tube_plain_1.png b/mods/pipeworks/textures/pipeworks_mese_tube_plain_1.png new file mode 100644 index 0000000000000000000000000000000000000000..517f5a4d9688f2f0ad7b9f4f83471535e28d9695 GIT binary patch literal 1314 zcmb7^`#aMM9LK+AiZ#yS98)e&3DI$Tq|B5yMK0Nyg;5kvWVuE**W)V1pi17iG>Kc4b+5`_ z$b`kBZ;{I7$IJ8iqHoc%h0^7@E8?j**+Q92czt=kNWMUkFIFq1t;*$2`65-Z^!xH$ zwnD^Ei0CWg2g`GLE0QLql(iymkT2X4Pn}Xq+vQ7lRwOOr=`#w^U8&%rR6vwWpOws{ zNM_Q+(+QH9BXbeR~m2x9UAen znmS+6>(K&`{RQz*bm|PyK6U@P8{;1)p2P0Pc~H4 zk~){n;%F{9(*;G}FhuUxF;46OApPj4G#~=v0<`u*u5N|t$UyGU$XJi~9rbY1^TO~5 z3aM&yZa46z@$Fi?GR*zM7P>DIbg`q{dXoz&bgXAf*=eUSqD}{TP99=O;6Mvmq76f< zxL-)caUiH&vd?)*l1(g9>i*APAhl8DCo_|Y6v+2n^cS&XUyo(=uMmF+PKwPupL?&O zH`6LnYG$u;#a0@z*K?T+t4Erp{msaS8KoO4PBkv93EuAa72GV~D6Et&+KyvbXOCd6cIo@CY zGs@RMge$!9_ukY2<7zt?2JT_p-W6C>fVYCwvscR8SI)QW)p8I^Y%RH&EnJ$iu*!)v(6sEj20F> z$`-$;*5nSZ3?uSAFMa07lFj*R--(0~@fw<_5rs>@ouj7d7t9mYp*C!48e_eT)NP*5 z?l3J!l5#*27WE+L@YLtu*v~1ph(d=t+8u8MF9oJLZgMkt9o%{)(QWu$%*H{tbAg?& zF%YsI&4POgjGD1}_~=JvyCoc+LY;I}l{7a8x?Ub=X1uKc*$fWoKd{enI$v_1Va*Ww zQWPgv07VP<>^7 zw$~3_arL#i)KReAV1F82pXfeP?&Eh|fO2rgKxRdYO5yjAu3bE(Yk+?gswGcHy&1w1 VQg6k)@z9nB5a5eB!t#kJ_!k75qSOEY literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_tube_plain_2.png b/mods/pipeworks/textures/pipeworks_mese_tube_plain_2.png new file mode 100644 index 0000000000000000000000000000000000000000..63234924b06a6b79562b6139c3d45791b6bf2743 GIT binary patch literal 1319 zcmb7^{Xf$S6vw|?>)H%W)GLc}>n0`Up;1U^VI!|zOyaUuH*u}5RZ0;ir99;6dYDbw zL>|VJ^rV-f@TxA^t$ST!ZK-99?Yr-uJgjzi|Ac#9ug`g(bAI`p*ZJY(9}EvRH^rI) z0ANlGAw(GI|DTX6jQQrHoH-*9i2(-!0N`E;T7PtmUp30|URI_;3zy$;P>Rm)1$bCo*fT^;mT zJy)%nXKCd1kTgRh=V%p;kThEhw&;|6t)fXSD^q-?sOM{R%1$lFQ+zqDk>65IpI1&_ z0KX)Hl2f20Me*eXD4{98o(cHqV_eN3!x#((V}aDLYK*|AMubNiC;vNuOAiFbqpX04 zgaGp4mzC8sXQsR{SD$!zITend1fLN*wHBqi?1yE}>vwEl z*Xt#OX3fa+IQ^v>k2$ynD+8vTRd9Z>vdx8xJ)1y#Xe}O#}b+0zQdlK!1I?sc@FlkV!z-Y!RUO@sFYv{6CUv< zWj!(7i{9J-)|$ln{y_3Gvz~f#1C>7aseA8@p%hNiXg8yDvC{tB*W#|Qi*E_>kAWT8 zY!gK+@%65e=mYgzT&n;Yc6j9xO#2!p&3fnUBGkiZczNx6LK0v7QD2&}mi*NgUg{3( zt2#!sF~KA|;kowBRmuCFAc&5ZaO9~ar=Zt4jz8G0?UXm?I09Ml}v|~6H)eFt;vVkTW>Vk{(SHaD#{@Z38y+?pWMA9@~ zZE)?)<+B01k>Ed%QeK`$#A!Wx`6l3y>7&gYmalaGS*xI4B?N9#7|6+2Wm#_T&GK8W zOpIpLwxQ68I=?$O)VJDs?rHd0s4IJV+_PJwQ@(2uX>viOuw9Iz^PI&}Pr*V(7SdsR7l2~Jzk;%flVmEoVqDrb9lJEQ@2d z>{G+OH@RalOzuE+dfyT2$a41UmFA5VMAHIVpQO{WfaL6z*B-SY#Qel2;_wiMhM>Vo zOs>J3e4l4k=QOf>`L}p~2fh3T`8MT{2qt`^*jgTdJ@%y!r*VECE_dS zJw9d7q{1?IFU(crQPxIs@-?%dbhuscYv&2zvu-6}OM5osyV&>~nDs>eDh`jgueqVl zB#xv7KRuNjuHmc1;~@j7<)d2HQ`bc? zj8u1e;xufb2f_%4S-t%+i{{p_k|1ovE2Praao}%a-{j42luS`*TEpT72h=@uk_N}f Z-qN!4`_Uw~HskvMi2K6{{6OmEe*x9=ryBqO literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_tube_plain_3.png b/mods/pipeworks/textures/pipeworks_mese_tube_plain_3.png new file mode 100644 index 0000000000000000000000000000000000000000..c7af0cf3de54733543be4df60c8a2d1e0cc79cf8 GIT binary patch literal 1320 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 WQC5Bd!Ei8?2jJ^PI>h%3&H5LMi=p@c literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_tube_plain_5.png b/mods/pipeworks/textures/pipeworks_mese_tube_plain_5.png new file mode 100644 index 0000000000000000000000000000000000000000..f78178784c2564c9746b93882c27af70697b1947 GIT binary patch literal 1314 zcmb7^{Xf$Q0LQc!B9lnn5v>PL zd+ksp4{fPluRHRP;?gyQ*=+2Yq2b)0aG%%f^Lf8MzkPoCu*jq%aOf5&0040Bqlf+1 zN%+r32J2bzJacv(kn==eA^<)Lf_3U=>X}UW1YIL5P)n{TCc`wcLX9*}J(HuAv9+_MI#q*C-Kw1}o1gn_Ud~ZV z(&pt=3yQ~T$<+mAtxm;TP*iJWw-l47b*d)q+`R>5y<+Ozy!^gOd|4%CD5uUVMX^dz zykaUsDT-E2ClW{9MD8YQG6XI{x;~Izc<|ObTrT;O0@nV&03Rwk8~_Yd-iL`4+UwG? znc_MpL{6u!PgFzP*HqXHc!3^w+j1( znHvU%*~WNWR7PV$@hX>p{sikc-Tq`@HWmy0mO=cYaKLn+O3y-%+Vf*EGeW_G;;tmC zNR@@%k`p;kyw6tBcwM&Y;>^$F1k1o4)6}ew_uK}ZMXqMaU%?IfSgZ6%8=J`kXZEu0 z2xwq#lnXMQ_$(-d=QmK`Y)h+xU|g$N1E*#L`l5Jq%JkM2>u_+E%unrlqzB5)x@PBy!#NDB0&`Nh{ps%NGkkcP_ctxKVygQ2bLg_;=S56C&4w|?*OX*$otUK zuP;JQWo-@_GhjsIw40E9t+bpM#@ojkDU4gXt2>*!lKFR|a^Fz8V$c6f8qUsnnx^yr66rkfK4kTv^MzxrHY8}H zVfj`;3WOlCdh+xKT@wn4j73g5tX`|DyRkd9r;hV(0*vYFF?wv5?szf(AqUNodZfeh z8*1K*`I{c{9QJH=H1%~iqWaq#xd)xJ=`A5chU>jp<^I4EZ?we_9vLA;Tw(GlafUIy z0~0=-TzBFhn9ZN!w1a)%T432$D1<}HMaK6kMRfk*sgKU|QRU*z{ zT#x-JltH=I);D!*IJ@=bvy?q{BRqkgR_J-Cv<{ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_tube_plain_6.png b/mods/pipeworks/textures/pipeworks_mese_tube_plain_6.png new file mode 100644 index 0000000000000000000000000000000000000000..efd85a51f46171c7ff21422a2cca6194e589bc7e GIT binary patch literal 1320 zcmbW1`#aMM9LK-AWpOZ|`gK=Ga)Q8E0~-buf-Nr(BweMlPpPa?&#@ zwVF;YwNROpWDg?iV(v;xa~YOhZA%(w=U+JQ=Xt+h&-=H}^ZDU@mK^A3Zfb7|0Dw7> zfTtLV{m*cSG0O$npN)Vra0hSzP*-I3jSe&Rn`9EzckUxeqj;s1zm?s{;rsaRZb?TrcU5Kc%frwmt}~_eOAUBqZJ{RMtG!90)vH#`v7mS+dh=y{7)2#^Ns{#_W|GiFnT z9s5~sD6NQHqA;X^BnQj1FLgC>m3G+kDbQnyn|;AiKvjLZ-TIb8^(ruQQ9Q%j+nco( z9yw}QhiSh7m_LWEAr0qB#)b&3DU$exV%Qf4WStxG*@$hLA*ba@K?$r>T_ zHf8U3%9CQm5;wA%&P8-5lElAS4jJO3vmm|?2VuFd9zd&hpR9-xB_n5BVMi85Fki&} z{vGMhezV@5T?eK0#kqdTiMub1;BnW+kZPN)FHKxW`Xt}cPZgYc$lWDHuuE3L8*Bqa zXf`>#Y9$Q!n7U5nMDRI_z{d3*cJsHuyN%T{1A?4OQX30pu5BUI@*1$6sn|JCP$^T^ zv9^x$fmP2N1FTR{-HqD=s8_M*$OsaZBOSgpxZQ&y+0(u>)d5UTy?b)Fq>}YkWx*Wi zH62V&^#r>XFaU8SXHE{_>9%vR>`^HCHPChv7j#CB0r?aCdeT?CaK?H)xV2mW+K@5| zoo4PkXQ8pb=r~q?6O{H7n-SXR02-LU?YMevC-@?#z%G6HE@f+k{(M<1f#meQK{p}kOOIJzuqnNK*WlIN&~v|~h=VlnH|FXUNw6Sxcp}J8klhjF+ncd~e5Zgn zHh~1;37{&-3ui#Vdh58;ou4TfS)}FcFI9Jy&7A3bzoOXNqi4832pB0qLLAJeK05OL z&JCATAi{-RpzD4BRZias__ z|A)_Df3;_U!K*jMx(*J}7MlM6xHYNtgdd%!;*SPL>O)!U2WdGB$5nmALnCdEHfJ$F zya;;D?%E$yz{ffis1 Y^iBTtGS4wO&bS`{(Kis!_c@aDFN>b15C8xG literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_mese_tube_short.png b/mods/pipeworks/textures/pipeworks_mese_tube_short.png new file mode 100644 index 0000000000000000000000000000000000000000..fae64c43450fa60ae92c485fa14a65cedd4a833b GIT binary patch literal 690 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCil;0(?ST ze||ag{&CXJFNeOqTlC}8&M$AKe}3KfrybuvZTa$c=C=c~+2>aspI^0o zeYfEI#|@ueHhz3o^zFmyPcN!Jy=?vTqW0tSicc@FMGa5^?zL)SG#?4Fp{8s(sXo{;d}n(`Nkm|Nny)>mF;!?bHYmdBOa=QK9AH z#ix5kc3S;UUCX4v074Js87An;o-qD>k$JJ@#GittH+s3;!#G-wv?v=%pWool_#xwX zW517pbJCvefma=w%{=!=+P-CHFev%tviN_7FvIMZ+pd;IZA%T#y%X}<=>D>*&~K5G z<(B0XwVwNYMl{rPYOONkivKxh_uspszEWYYZ$wGGcD3yCy$oya=3Y9xtJ1OQr$o>M zwK}FppWmzgSl#5t;8)JSDAL@{aN#t=NxzqU+`KAPyi1+o-=<8x8LSJ^C6j9<+n&CV z`lvF!;qkkRTOwsXaNLMuY&aYHaqT^qIq^()6&N0uRsKD_(C?Cq#=04m`>pI%Q{t9w z5I%UiwnF^gskt3T4;xK?_3y5Y7{fKax9ZR1;>+Kj|F^V!>FT?uL-OaWj;Z@Oee31g z+tYTf+q5nI!vUkmiebDO56-z1y7zqZm7Tce{S9N+o-E(vM+^*Cw|-{$o5`YdI6J|f zK}nt`Ds0|_+DS2fdm42$`XtY=O1x`j;AjA%|AHU*w(O{Ta7!^E02tK_p00i_>zopr E01KaUga7~l literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_nodebreaker_back.png b/mods/pipeworks/textures/pipeworks_nodebreaker_back.png new file mode 100644 index 0000000000000000000000000000000000000000..6337d40e0e4367160f7dda8a02abaad7351a77a4 GIT binary patch literal 651 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{)&V{t zuCcK(QBe^A0e zzTV!RBErIcem)Z7;=DXOo}M0of&Pw;_U`Vk78Yi9b~avKp7!>(E-p@7TwFpzLjL}K zUS1wHHrDR$Zr0Y8q9P)$uFjGY63)&}-rioq!ov3UcD%g278d5dzCI2P_8uPYE-ub) zZmuFCBI4rWety0J{QTzTK$C6F%uI!agv3Ne#l^&2U0rN#ZTR{5g#>}_1qCZV9|#!F z*jEnZ{PuKl43W4jd&0Hsuz?7}f%vqvG!En99Q8sO6JxKb@9LYrl}=;kcG6gQ<%r0xH0Io*{+ATjakcY za4wmsD{a2%*5-JQGg-kq+b8OW{OGgFcQx?7+8cDz+W)y$jX;!O#;ygw@138|%`ceM z^z8nxd-Zc(<+&J~>B?!m{^d@jk#fPeOD#t>#0Z$$&$T%fV|JU5RYv0Lriz*kyEm5` z@y&Jb&|Vbygl~J&#?mlOT_%s2e(j9gIkUBM%J%gz#P&Cz+_q#{m}_OSy*#6vp3@B< hgLS8mc$R+TzG~#Q&w>BCH82<$JYD@<);T3K0RWs3$z%Wk literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_nodebreaker_bottom_off.png b/mods/pipeworks/textures/pipeworks_nodebreaker_bottom_off.png new file mode 100644 index 0000000000000000000000000000000000000000..133be48d591c2076f97b9bd1a463738dd9c5eaf8 GIT binary patch literal 657 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{E&)Cv zuCcK(K0e-VZmtdv_V)I+@$qqvj`j`?b_oe_9v<#dQ4v;FmO(**DJe;Mdb;}hdRA6e zrlzK;smZCSDY?1Xad9z;i3t%AVR?DEnVIR1jt=JLW-&35axyZ>$%$@mE`fmofr0)Z zAwfAgSqk#g?y|>+S93?(XL8 z?P+6UZDC>V?Cc~iE-on{!N<$X#l_|1-9vBw|XKQQY>gwX+;%sJS zDk35xEG!JP%-7e)-{05H&Q@GZOhQ~-NJxm6msb=lEx^w&C?FsvDk>l#AS5U#EF{Da z1biUiefmNeFnoV_x;TbNT;@F+Jo#{fgu}z~+}W|WSLH7C?OL+Y?*ISaXWts9KWjL> z^MMn~49~Fy1<+tCOn44tO5KN7o3$n ze_4aqlATvkDk*7ej(!&l^V`#I`}*I_x6kQk5nORL?6T9hn`aMOD_!IZd42U%++4Y@ z>*ViiJeH6OJ!&wC-Fokp*m$$o^Ao~8wdH-;UfuqDyTATprYmhrPw%-G@BQ{&ya@Ya znI-O3E49|^9eZ4TDx+Xh!@(6X>v*2(oYB=bTp8Ekv)v*`=ZufP>er=@&#sl}$zGPS l%y{$NcYC%>x)Jf8T}IhQ+(K*X6kr%Ic)I$ztaD0e0sx4<)F=P| literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_nodebreaker_bottom_on.png b/mods/pipeworks/textures/pipeworks_nodebreaker_bottom_on.png new file mode 100644 index 0000000000000000000000000000000000000000..b21c261b45c013168a611532b3dcb5252194eaee GIT binary patch literal 660 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{E&)Cv zuJ-n}K0e+K4)*c!aj~&6j*j*T32_b%b{-z?R#uj&smYm{=@AiOK|z5rF_C$Bxv8ls z$;pYix!EZxN&5PFrlzJ=R#tj?x}l*ViHQj*Daq1OQgLxWa~#ag%>n}h+}vCO1N~)X zWRj8++}&Np#l&Q!rK6)GLqmh@>})(d+{DGjEiEm?#Kf$uECdAwd3kuafq;uEGczL~ zz%MT^Cn_q!#Kbr!C(FjhDm^_lBqYes&&Sx<$lKe~)z#V5)WqH0&CSi#+uO_8*~!Af z+{VUQQbIyRM1+r*my3%lKR?&W$-jD2FeKv@&f@M z2<-J1+zt%i-<~dxArhB)&mNuB93aAQ(fZxHS%u$s>=qJIaNDrJ|9`!Gj(=(B;U2?t z7T*P*)|kC5X$Y2T^5;lW{PUMdNo9dZJ(HpH!H{q(!{ z1cJWn=YP8{kj3hJIcfH8r$2l2Z+_+9aN5%M`mfiA&fR-?`1KAJ-r|zkmw&T={JYsB zQ1ZE=?FDz%%xp`ky(Vm@N` mqPcQT+jpz1Q|0&n$Eg0zTac+$;T4NvOiuRNa&pFxtet$n`StjD~QWbl~i^4 z5W?IWSTLid@{UX;^CFRwi%$g-Tz|u-|cczQCF7J!hJ# z*6!z<)w;USjnRnxZU9>3_E m>BU=YbpOn`G-pNTFMhe@F21tza|MBZXYh3Ob6Mw<&;$Uo+riBM literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_nodebreaker_front_on.png b/mods/pipeworks/textures/pipeworks_nodebreaker_front_on.png new file mode 100644 index 0000000000000000000000000000000000000000..82ebd3aed6487b76f55cca183af3890dcc1e7f88 GIT binary patch literal 563 zcmV-30?hr1P)3knLs!NDRSA;!kW$;rta8yg-R92*-O6%`e&t*x)Guf@g1%gf6a78VT*4D<8z z@bK{K>+9p=7Zw&26B7>)4-gO#5)ly(4h{|u z4(Bi0djJ3cT5w~C| zrk_LA@4gPkUvr5Pa@7_}nZ^2J%(W~Kyfuapz8H-bhRUJr!^u1;l6wWcg~%71=lJ*%eGo>u?>002ovPDHLkV1lnS B^sfK_ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_nodebreaker_side1_off.png b/mods/pipeworks/textures/pipeworks_nodebreaker_side1_off.png new file mode 100644 index 0000000000000000000000000000000000000000..ec0a00f04fa768cfb13e868a31af8185c570d38b GIT binary patch literal 598 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{f&o4u zuJQ44QBe^A0e&7H?v9T3j*bp-aWM`KcKZ5yR#sMSZZ4*#rh0n1fq?;TZm!nWmhSGZ zc6K&Oii&}O{)+PQ{{Fra5)z`KqT-^W(o#}lVq$VKGIDZql9H0#TwL7T+`K$I{{DU@ zCdN)qj@H&zHa0+0Ed>PyeSLkrygba!&6E@ryuH0-WMnKX%q=Y~oSmKg{CwTr-Q;9t zy}dpC{CxO$c@^a4xwyFO?d=>K>}_prTwI)ujg4Ggo$c&wU0q#lY^-IZr6naKgoTB9 zxVg>DOofDmczJon#l=lcO%xRrWMyOofPkN0Tue+zP*6lfL{LCLL|9lt-`*hQ@i#zx1)Ge5m zBvW{u_2Gh`olb4XPcc28qg8O@o;6?k=7Zu|XXg~iXZ;rV@~-*n@;DG{dqYVb5_hXIxV5SNLBSp``Zeu z_!L#|E}Opct_9!J`Tg}fj~kQ~c_r?Cxm~^cdOEY=w52W0VUtr!t^D_V|9?Gp!|NdD i+kKnQm~0dd{LX*C$G#_x+le3OcLq;aKbLh*2~7ZLth*5a literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_nodebreaker_side1_on.png b/mods/pipeworks/textures/pipeworks_nodebreaker_side1_on.png new file mode 100644 index 0000000000000000000000000000000000000000..9dace63be403ef14d1e9b760d5cefbc2b52ad5ff GIT binary patch literal 608 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{;sHJ( zu9=w`0RetdQ4t;MSE8V{UF{YHH%`?PXzM?(FPjV`J^^?j|QIYiViW z?d|F3=i~41s~|7W$IHvb#bs}A=kM=lYir}+U~g@0<>KP(<>le(>LMd8?dRt!DIp;& zEDW^I*Vo6+&eqJ#R8c`eRz^l#OiWx{Ttq~KmzP&aNJsz(`1wUeM1+9u5D<_6N&&SA z3Gwsui;0Tz^MSzh{d3%bLH5Pd#W6(UvS?pu(P0M>miQSnEe(wq^GrH=CQA42f0>Q- z%XjT!UzfesX{~9@@fL%Bzs=h>&-S~#$?E-_VzC$Y#Ts+CPd{Dk88Ig{W!dWh%Y6c` zzYF;V_b7|8D9GrDZ7*NtK3OKcr`W>io4+1=^D%R;Ejh1SAKg=&BLC*)@*bg>-dO^d z+G4lOf4g$ATIIe~4yNv#9-laOyIqfpl=zcdpsXm>qYW*@X?``hbx o6V^^&I`3xfM^oN*LH>V?x9lADK9XY;0s5c8)78&qol`;+0DnTg4gdfE literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_nodebreaker_side2_off.png b/mods/pipeworks/textures/pipeworks_nodebreaker_side2_off.png new file mode 100644 index 0000000000000000000000000000000000000000..8320646e61e9f5592148e6dab58ae9dfdc0d1e9d GIT binary patch literal 601 zcmV-f0;c_mP)2K9UL4G4-XI!5Em8}6ciK^5fKp( z5EK&=6%-U07Z(!}5)Tg#78Ml^4h|0v4g}CNi~s-t^GQTOR2b70&P9TQKokJcKkn{6 zad!nG1cF;b(|Z4d%w$`eS1|wi6_T+i9tG=4u)cu#x8+G8gzVUMw{v+4mNjEp7D*P} zYMOFZ0nd{$rD;m>%}PB#YQS2^jN+WTCb=q?4-^O_%eFarZ}1x|=4=iSaS@ zuj@YS7onlwoYXM&>*-8_CqXX$_a53lGOA91cHfKj5$Xr zuPskXJ0*%TobVitCxhVvgvcC9xtlyc-St{a1td!m=fr$_8TYEK)nXU^KVRKsGFYl= naRZ)+9lG5jG+b;-TEYGULSa9QOu~KD00000NkvXXu0mjfywu6A}dit_S-f&Nxj7Gh#zZf>p;5)zVgp^gC}?bKWMgA(YHH%`?PXzME+;GN?CfN2ZszXp=I!n2 z=jUT-Y2okhs~|7W$IHvb#bs}AXKiie;^OS@@8{*^VQXvS>gwX)U@s#r?dRt!DIp;& zEDW^I&d%1?*GEx7!OYB5Rz^k~2*kuhL_~Obd4+_81o-&{1O!AyM1+7Y5D<_M7Z(9) z6B6R*=NA(d<>v!|sX+|ifkF1o)5S4F;<9Mp)3Rm<3D*6)c4yz(v739sga>@P*X;dY zJmufs^mAugZ@%w;Fr}?KaC2PFwe^Y9F4yR_RAfent*98UE8Kw@O$4eN6DnBB{=g&x(`oO?^F1UZyn2EK;;J9r6{HxQ9*!_h24foW>^M)=Cz52iX&GXfZ`F@=$ qnwj6Azo_9&*}drSe32)uU)fXp9QKN3XyyY$fWgz%&t;ucLK6Vl-N2Oq literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_nodebreaker_top_off.png b/mods/pipeworks/textures/pipeworks_nodebreaker_top_off.png new file mode 100644 index 0000000000000000000000000000000000000000..8e5a1cd9d4f5f2cd4cb0cf54a438fa8c299ba860 GIT binary patch literal 656 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{E&)Cv zuCcK(K0e-VZmtdv_V)I+@$qqvj`j`?b_oe_K|z5jDM_iR$x%@esi`Tsx!G}XF&-Z7 zR#ujYi3t%AVR?DEnVIR1jt+r={xLC;Zf-8g$%%o10eX76`uciSR#v8_rXe9g=H_N{ zGBPQc?d|36?q+Okgw$5 z>||Bh;;_vTgYir};;%sJS zDk35xEG!JP%-7e)-{05H&Q@GZOhQ~-NJxm6msb=lEx^w&C?FsvDk>l#AS5U#EF{Da z1biSM8zor@4BzjbE{-7*mwC?wPd^+W;cziOXSVF^Rk=%jyOwNR_y7OzC#CbZ^7TkB zOL_Kb^WJ-VwoJ9NZmn6rC`3GM*>a&@&;C`eVL2SQFd*cK$eFc#eM_o%i&JUj2RgXr$$rQg3aa)>i##G8Gp{qo^cX0?g{k4Z~LN9WZ| zw)5Kr1Nbj4I4gVpvIegu`|mdKI;Vst0F&R>gw$5?BwR=YHVy|YHDI( zVQyn%Eh!-(A|k@a%ge>Zm7kv*9v&JT9B6NE=j7z*<>e6^9OUQcYin!c;^J&=ZDnR= zDj_Z|EG!JP*x%pR*Vo72-_O<6MMy}9mzUSh&Q?rRR1|2Ou&@9>zkq;%pn!moprEjj z5I+#`fj}CIYCAA|e|fq%hDcoIJ#%!@VFLk%i;-z*XN-zx%=Go->71GB`M*9sK0e&^ zgzW6i+Cm@x2$cuz@M$=5z311vnqIKjV!fW{=z8T?YGShK z%sbbQp3G&mI`%_jwW0OPw_gw6a>;9oJ+o@oDII=u{&Vl*pNd^My=&F7Yunmh7Q1b@ zJ^zA4f5f&e+l|iL-Mi;@ywI0>yOv(mn0)@}{LLE zFE*~;5hrp?V5i@c@0~AqUDn{@WW4-(rk$$Bxx@xtE=DKCV~sCslbwETmR}%oxuP$? qVTI}M->lseBv!~LNF7f2z<;OMTTnZaX$LSA7(8A5T-G@yGywqDKH5tF literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_one_way_tube_input.png b/mods/pipeworks/textures/pipeworks_one_way_tube_input.png new file mode 100644 index 0000000000000000000000000000000000000000..3968c0d76564353708ce7b18b572506637574fa7 GIT binary patch literal 839 zcmV-N1GxN&P)q->H@&DM)ICe~szzsc*fPjWe&CBut6i9%Opr@dwq5ugyj;}LwilbPE zy~8H^NS3y>*RM-#`Lgt_H6w!%LI@#*5JCtcgb+fAzlR#?!k3qq&N+wg`xs;R`1l}6 z5+;)g0A1HHola@n7T@<#O5u4P)>^u*BMd{Fb13!iBVJrw4DzhrPz5l?kfv$>Vo8z^ z$1y<=pp+ttBD$`__kEhCL2C`r7sOhNF@~ZjaLx^ufMBp_DMglL?ChbaM+qYT`!XXndSOF%J3C=l^Bw2rB@B3SqWl7g{AqJP+UZ$2SCxF+@?sY&QGyoU^kt zwQhL+_Zr5SjfdtRm4MgRSMofkC<*}X?(Q}k<%frd>iYWH0aR5*UDs<@l0QBHv)SxZ z#DCQaKZ@fRfcbn*k|g6yz-lA2dhyfKQ}yuhuu%$*j*b*SUDqh31}(r~37F64bY1sp z75JSLtXjYr!|v|x_zIBcIlk|+v$NCx_tld4tCb`O0`fc`Zwr)V+5bK{Ir*(EUE8)8 zW5&4*uJ-Vr=W%s)<@WaW&{|`RVYyrqMG?+9!Z4(&Dy+4XWl0>zXsxNL3g;YkUH9J# zMpXcS?d@%zo}T(|13?fFMG$+T^TK;&~oQDHe-Gp9ZZpP16k80zwEOgb+dqA%qY@2qFF^{{U3ITox;z R-0J`U002ovPDHLkV1mj9kgfm# literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_one_way_tube_output.png b/mods/pipeworks/textures/pipeworks_one_way_tube_output.png new file mode 100644 index 0000000000000000000000000000000000000000..7dc5910a3e2bedecdee09bad59aa7811dc6fee6b GIT binary patch literal 839 zcmV-N1GxN&P)q->H@&DM)ICe~szzsc*fPjWe&CBut6i9%Opr@dwq5ugyj;}LwilbPE zy~8H^NS3y>*RM-#`Lgt_H6w!%LI@#*5JCtcgb+fAzlR#?!k3qq&N+wg`xs;R`1l}6 z5+;)g0A1HHola@n7T@<#O5u4P)>^u*BMd{Fb13!iBVJrw4DzhrPz5l?kfv$>Vo8z^ z$1y<=pp+ttBD$`__kEhCL2C`r7sOhNF@~ZjaLx^ufMBp_DMglL?ChbaM+qYT`!XXndSOF%J3C=l^Bw2rB@B3SqWl7g{AqJP+UZ$2SCxF+@?sY&QGyoU^kt zwQhL+_Zr5SjfdtRm4MgRSMofkC<*}X?(Q}k<%frd>iYWH0aR5*UDs<@l0QBHv)SxZ z#DCQaKZ@fRfcbn*k|g6yz-lA2dhyfKQ}yuhuu%$*j*b*SUDqh31}(r~37F64bY1sp z75JSLtXjYr!|v|x_zIBcIlk|+v$NCx_tld4tCb`O0`fc`Zwr)V+5bK{Ir*(EUE8)8 zW5&4*uJ-Vr=W%s)<@WaW&{|`RVYyrqMG?+9!Z4(&Dy+4XWl0>zXsxNL3g;YkUH9J# zMpXcS?d@%zo}T(|13?fFMG$+T^TK;&~oQDHe-Gp9ZZpP16k80zwEOgb+dqA%qY@2qFF^{{U3ITox;z R-0J`U002ovPDHLkV1i^PkTn1R literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_one_way_tube_side.png b/mods/pipeworks/textures/pipeworks_one_way_tube_side.png new file mode 100644 index 0000000000000000000000000000000000000000..044e4f4453257346591fa7b3f5dd8637373bf5b9 GIT binary patch literal 1665 zcmV-{27dX8P)1L)XElze^oA*=k&mk6|7))7f*l~5`qwW7WWTDf@BvYW`RINLSlukgkS|i zO}f+Vv0Sctizk=5lWvpFTi*J1F5Bf(XZ8Us7K_DVu~;k?i^XEGSS%Kc#q#fgJbwIG zbIzfZ0;LpLmLUv7WLXBSH8wUjAcR0!mSBv5QVK!{JkLW}mT(*gRaGGf0yIqn$8k{C zH5|u5S(X?K2AEE#pp>F%8UO(29G>T)sw(qc$8k^;1zgufQ4~0T{yg$Lhm;bI<3K3| ztu?gP;GCQNT-SwC${c7mn<0*4^K8>J&{~5r1|bBZC_kzK=9b!5Bjv#{ht;s*ofJlu{ssplKRJQG}*x%)UVofKqA%Q%afV9mj#= zH~@f+jST>R>$(_?M#!=Z=gyr2r4&+1XstmA0U-pGQUE}fWyrD&)9DnG$pjZKUNmyG zhR|A@_s8QgwAM(H1YsD0eEIT4S5;-S2>@kTB8nnNDN$7wE?l^Pq9~xX#^K>1;y4Cl z3{pxk#&C3Wgd|BoDMe8fV2t7W_wNuw;Of<@AcVm8eF!0t=ebdc@B65#3WN|8MS(C3 z;W!S25cu)q2R1i1@$K6;5JGVI@?|tl140N~*EN>aTBFzNp)5;CDIuja$^ih+^U&+{ z@bl+S5JJEhLtWQUNC|O&y-BY*y zU%!5x92^|zr3yG}7%;{bTuf^X&+|-<=(7C$`m0y3{uiHfrLzmI&*lJCRe>$Lu{1lL zf}1yQl6eKpW;0{GJkL+>mUCIWX&O_OSJCVB&Lr>F))t|w;_9r~wWTNuc%BE}_c8AG z^?&~U8~^O@qs#K``rW&CN!y1cNrKJI&CYM#zI~fKfBsybIS0IW@#4hGU9Q)x=x>gLe*}bblVT>&Z+j_!ri?_Mq_y4D(w<1A$KuIjNY4-JPy0638Yx(>98Rh7+1w=56* zsquOF@}=(5xDaBg3or8o&iRS;qA1J{+5gMV&JOwb@uOa;fEzb%tlj=~^$YF4_-PuM zHVl^~FCoNI<7{tluPyJgxN;7(P)GyioiKHgO0CX zzoM!tT)A?^$fLD3-W3FaDV0)6(>Mh|fOgPRRTUUx@H`JkM@OcT3rfI+!Gs6}sCGtE+nx@9mqtVEW*Rm`Fr4+8~n#qt5!W^(HOL(4#G)*xc zkKy}1q?E=`?PzQ|okA&Pyuo6zSS%Kc#bU8oEEbE!VzF2({}%oWtJ<6xNzErd00000 LNkvXXu0mjfGPDf@ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_one_way_tube_top.png b/mods/pipeworks/textures/pipeworks_one_way_tube_top.png new file mode 100644 index 0000000000000000000000000000000000000000..bb54e45f25da7bd06905aa1647a6db0a76a3c64d GIT binary patch literal 1704 zcmV;Z23PrsP)?Af<$D+W-K@7>c3*00cpRgM$MQLeT5=kmorp%K{+;mSq6|D5a>X3YKMI zI-P$>{?2qB=9qG=k`bq&XHpp*h31OQM~6*%YM zoMSv5!?tZuO7-6)N#HmREXzV!mQYHeX&PNJ+ECXWuLV!|=D2kA# zDHvnO^ISW>y+A?;7-JZXMi4>(0DRvE00<#KK7IP6#^bSm*zI;vmZiQ0N-2a8$n#u# zm@x(^B|OhVp6B`iv$y#1<3~7-gU!uN9U(#pq-l!baEL6+0055TAdX{nIvs>zh%Cz> zgn*P1oO68n@&#pC;@r7&NRkA$ZKEg(P)gD1bo4=d-^XY)g6q1-vJ62G=;&;kW-jb4 z%R*IEsHzHVb90l-K79N3tvY}HJo(++x_9rMnog&fPN(?uufG5Q{mEo*-*K;}7Ol6u zfB#+;MFHEkarW%lg}=Ff|Gv6;^X4zxOAjy9b-nf`PoF+jhu7LPa$Wbx@1H$;rjE0( zWm&pDEQ2w&w!N=jy;4gZaPi_r^7!#%^}7+^I1U(N@H`Lw$%OPL6Eg1g)VSAEZMq#^ zKfFhqT9neI@40&QDtY+u;ac`4NwPcwe#NVc43ts=07j$Hk!RPgT_Z1FzWk}tZ6RD0 z0RVI@I4)IHt#-gFk1yi#<;ix+bTvTYkmDP4>X-}oQ9y9?K6BO%Xo)OD>}=Q7H& zT+7~Dw{DR(4HuqtYio-faiHybgWZ6XZMg&9&zp>u3Wi7R&|p_b!cS-tm69h>tt_l zZ)M2s@9!gyW29*c0C@7`iJI;I<6cj-kubad$L=oP{__v|lL;w`0%cjk^Ss~cNS7{M zB8yrz0MK=FrzMJ_mCt?OpY!~pRQOp{55o{a5X?ouak|GkosG?g+*)5znI-*0;8Fbti<(Ip9}>8UQW5k3_(Q3m3@i*RR+1>TG*kL>Pu}UH6v_27sa{Af?2K z6DQ_s)4IY30F+Y4lfuVkdwY9nUI9QH#}GnbFc|2Ze|P5&4(I%$S}@y57-NXz_=scH z<;IO07S**tUlP;*;(tOrK&1ODUVd~e!u^pr2*O7+f$4&JzS{k z8cHdgJb4mP6wRrurfI+!17i%X>mrIG5JL2Dq^c@CfcX6RGn7&|bLI^8_xEw?)G2Vz zA*Do?W$-)?N+~#wgQ6(VG!61RN2k-#-}6c-eE9GIoO7H$eHwLL!}B~eO@la&(d~9o z*EJYpsOuU@l3*|x=y}7BA3yXrNt&iw+q5$W$8kXJ-o2|@$yrquY}!?tbRuiHtC>$(WT5MRH31tCO-v*&qQi?;=mF@~}%QB@T-Ha1X} zrIym|`+eWn1CLh8#c>SA7>2_kqA0?6JjP%!fRqwNQRw+aI|*v1Q*Dh(k_0r%GQ@EV zLJ0c(zMh~ELiCud?G)d?e@Cy^Ll}neeP4^5cJ$Pauoz=#ng$042k?C#!{JaLdODrX zi5#UAD5ap3>S_upP!$Ih=`t@o{Nf#m6Vj(+S-eYi;9Yh{QUf;rlq*Jxc~qE$;rw4`}>NE zi|FeAG{E?ZNoa*jM<=FRH@VTjTi3HClPR=UU?9HJkej zev&mJ=jF7o6ko|&Kv=WMU_7g|af!g)Z}Q>Dxqx(iJ4ShN2ko0Zat8Xx_B*FA?lpOu ifd2dW40x*3a`*-qQzx$lCL{;|0000NEi-(7Yi;Ietl$F}r z+S%FJ^Yin+zrUTGo$KrCuCA`);^M%-z=no~udlC+jEu<0$kEZ!o}QkSm6f-*x2C41 zZ;wE20001yNkl(yNmdk$^2d? zD$?VI$^z`_*}hC?57vjlKH)FFQiI-G>&s0T^!d_yFN_9z6Q-%Z5+~gvad|nN7bMoY zRZy-kSj@u4SXYQ#e;SnR8rtpc=;H@?-|n$<@Sm>VS;BfUC>k#Te@uO)G6)l?bD`Cn>Tk}cURZcDN}CVy4BqcWOhxM zFk#M|IWuO=`19w_vSmwm?AY=D|NoOGPyYV>y9=nI8>o2dty{Nl-n{ww^XL8h_s^X> z_x0=7>(;G%^ytxn0|$C~dfM9B)~{cG@#4i3Cr-?pH*f0HsoS@2U$$%+&_&9gw|@dD z{gNQRV4$%i0EVcg7T<=I6Wz|2O_UXWAp495?;L i|Gzaybp&Qu{ANh*Qd)I>Zf^?EWelFKelF{r5}E)Hz~{yQ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_pipe_inv.png b/mods/pipeworks/textures/pipeworks_pipe_inv.png new file mode 100644 index 0000000000000000000000000000000000000000..567b77137e933faf4cf20d31139ba42430f5d007 GIT binary patch literal 1610 zcmV-Q2DSN#P)czOIieMVj)~cIURVx*vgGspD7jaRPxLu;+kS~D{+IOEgG!}BBoe_ejMg=VVX$l0 z_r;17aPHiQ9viz&D%DL#hfOpZ#q&JM@hDWyaR!Ja)oT-GAwqKyd%c6bc1Gp)gu& zCMPFx90$j7s8*|-IrA6&@yCB%mLe8?2x_gdZJT1TfN2^8gF%#1%+1YVnkJP>g^rF6 z%H=Wufj|JQ=QHPn4^C?-CC@!~K(y@{0Pz0%f70pn7}2OrJRV1Dg>A>l=kH-z7WI0a zKp+4>u~@{mZJIrU5CSPBhG8%~d{DHd0DyPj{e!-D?;fF02-~(%N)ZZ$@H~%dwTfj~ zRI62@(I}4NP_NgC#bRi!@5`naUN|J$QouJkb?SH8^E^Dy!?tbm`FtyQ+qMxxkk9Ao z?d?Tt-71@|s{qZRLq8R5Edb!eiQj0Y6iO+g(I~ZA4cB$)>gr-@D$mA^n<$maOikt4 zv}qHrtB_KlwMHogz`=t*5p64=$+2T^Y0py_hDj=w;`Z%Z^!E=iJ3Gs&Rb7NaVJ0Rf zNG6j+qmfo8*~}mz1kXOZ|AB~*|BHtnKKzpKJdNWxoH%iu{{DXM+?k-!XrMKWkB_r? z^JWagAf3(-4u_G_AQTE=Sr)-ykaOooblYY?lcPs}sYgd|QYg&u|IRLWcBLR3$KDe2#x2>fA;NrT(qTtCQm)JU+>(x3n>i-2L~A) zy-6(ANl#A?xm=c^p@%7zO5}1m1_lNYLbO`yX8H6ykG*^Mh_(~}@aCJp(uQH+d5VF7 z^%#ahCX->ymMvtnS-QKsiO1t)vsql%rN6%)*L7Png;EO7^LXsB9|(X?KmEJbTCsEI z(uS@Fdg2~C_Lepb11TkzWwBwy2EP3AIz2tBiN#_}PfxRc{d$yAq|<5EtXYF)S*-@D z`E8nJYv2k50))dM9(w3|V%ZC5^7h*&wP~8TuFK%yAmwtId_K?Cty{@tGNe)|5{U%4 zT#jnB%EpZw5JI*p#Qabu2m}ILzI++ibxEbVdFGkLSC0Q%7k2XGDQy@Mts#*}(AU?; zwQJYt>sw1C5~WxyvTofvgb>`ibqgsay}iAJ!(o(CxUS2^ix*K!(P%WN*X!)wy_+YV z_>pJ}0rTDCZ?%*LhGC$TVrXcHyLazWDwWu_Z5v}_W2{=0q^m1VFc@TF;toOx=H}+O zdi5%xTW146Fc{*MS6*%(0Zra{=l8mq+P%HK*tX4$8#n0d>%+1v3WWl(Sd3sWh?J5` zmoDKr4xZ}xAGv9O(z ztr2_Kw8Beac=(`@Qev7WrfCuig~(+7MKBnoSS;RG1?Ge2zQ(C-s=$Ba^yxoq&(ow* z-3TE_r_)SMPJUyb;4Pd3nj=RJixnjR;G>Vu>Soh3Iy%}KnHR!ea`4}3C-^`&wok literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_plain.png b/mods/pipeworks/textures/pipeworks_plain.png new file mode 100644 index 0000000000000000000000000000000000000000..48af08f5dffc23826b4fcf0d22da914481ce9d06 GIT binary patch literal 330 zcmV-Q0k!^#P)o}He_$;tcs`-+Q;m6Vl>i;CLX+Vk`C+1c5@zrXA2>#nY@;^N|+ot?nI zz@DC-udlDs(b34r$c&7PhK7c>x3{LIrj?bI{qjFEwmwQji1(MX%t@mTu2?3d6;!mbo>7E7=LzKZyq|Dxf(Q7Xdka_}Vi!H!e?Q-` cOBoxNAD9^(e)53fyZ`_I07*qoM6N<$f`CY(XaE2J literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_plastic_sheeting.png b/mods/pipeworks/textures/pipeworks_plastic_sheeting.png new file mode 100644 index 0000000000000000000000000000000000000000..1386b1902cbc80f021b248a8fc0b63c907e50544 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!93?!50ihlx9Ea{HEjtmSN`?>!lvI6;>0X`wF zCr+HWdi5%hcVywm2SAFsB*-uL|9^(-r+9&C8EiaV978y+Cr7Zd@OT{I(p9+lVry4o zYsLkwwqqA2gz|7ZJ8zW;YiX-8TqDF=niO$WYSGaRSqp`I47(T^VlOM1Oq(Na2sDSm M)78&qol`;+0E|R5(f|Me literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_pump_bottom.png b/mods/pipeworks/textures/pipeworks_pump_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..615965bab2481b57598fb0b1ead8bd7690a746e9 GIT binary patch literal 4498 zcmd^?_ct5f|HosL)~I^hN_EkpMrl#1MU57vD2lhzH>IsvqgL%1d<pioIhCiCufd z3_?;Vu{SXy`Q-a|eD68;zJ9ppp7VS@UgMk#e5a?y&LYSH007wEyjC})MV0^Cml^18ZOa2EI%^w;9TA{d+v z%Y(Hdk^6i5**V!TSYB#sYDPu|k+_1x;bLRsVq;@AHa5ma$3{m+L200>%BrQMrIr@N z!NEasaY=nceQHWdbyan5U*FW!i@W@DELE+T&bYW3pQc_}h zMfv39#L>~wz`y{7LMbXN8b^=M&dwrRk!Un}Vq$`3s-vSLE-r3(XgEK=AU!P|3V~86 z7p<+WU0q$p#YJQ?`S9RiZEbyEU@$o;`TYF6q_pIB&+qm1_3iELt8)@%Hxiv9Ym|k`e?0QD0wQP*6};R~Hr*Mgt3hKxjE_ zY;2@42@em?%F3#&tc1hirKP3S)zvh5R4TQqswyWZ2ZchxV6b8uwW6Zrnds}dCuw~l8p(OCf}!lp@nhTcF7TM5j{0! z+Bffg@AFJ{&UwXg!eL(QTw)NwE62KZbmh1yFX6FmF|t}y`5}o zXe8-$Ph$`3zTHe(7#)*v`(#=47@>Qw1hS33vktQ~FEsOwO#2ddmphMpYl8PmwMKVx zV)UWd#p8-`I`@rZpP724%3CwLQ#wVF#=S~R_n5S{g~4kd(d!6L7NA_+z1c>xt+TclOLY)@m_Ot$L9nY(U$q&)D zdV;0$c^A4Dt^cjGn29*Ew2`mOx1DGkbQlW{R9&+`?goWNg}7 zLD6tJNY(b`$IF3DHWX$-!w2Ig26A6{z^Cxd)J)#kB=r%Tbzk@Mw+V$GDbE54tq!ZD8`CaQal(+*=YD*2M;~G;x5?8`-#Hp>ble&EXSEk503eKaSiD;MJqn9W+MxX-(lvRWAfs<6ht=m z7393!(FWMM?h&+*$0(Y?)wumgNF?{U4PMzNB*jt3h;Uj54l~g+WzCH_kZz25`=%8(rm8=!@8j zr2cpK^luwrQf{oaz3R`$KDJo@NuMp?2)v|ZxuoCo0xN}T$s=2KKm(~m3G^phH@Jd(I5`}fZLA|Fw$BwN-xDw9ma zXg^N!HoH4atSYa(VH>)vS&_kJCzBgJItuWk!=As^av_ugDF0027|w+Rf()1^ScG=P zMgs)DI|fnP2w$1%1wJ!LdL8TLjE@doc>h&1OK55d;=?Rmh%?LZ4Jd~!-1mdXKE_fTq(J68QRlNz>=wh zHaJS8WP&V#V@ALsj;om%24*f%v&k} z1igzDxT)kHY}VFB*;vf<@))4LCzCG0-K6fyZg2kl-23%_nZDnAj;m61-1ut%%+mR_ zDF=)3Cj@_8w2Y|S2*L{M;|x~aLEG$vAlZ-!gFyiCt6_?HeSnH9MB@&B!5QAxo1N|= zD4S3nH(jE+R_{Qx`b5Q8tDt!*dCZXln*S4pA*0zWWIl&fHL|?@di=+rzBRhVL_%1% zS7)ubzpj3HsM%{p;AH28)dd*y>@dg$@3rug&o#&|XD86u1H#MwW!%r3H&TXY*XyR$ zvqCQqA1^&As`O!&MxOV8%+3!CjMIxO{kxFR;bCAd&In$Hh3jYgR#KX>0$OYD zthvZ{>vIN|`HQQd`ZhbS7+3@5uWSkTy&$&Tt-&!;-u^3pZScCc;nJ+TBphnvB6|mx z#cJN%Exse8?G~RnyWMbt`)oFC{wC5P+{CBe=e_d7svDpJVAwsYs!16EIl=jO43^&S z;i1cJa0um+VpPXVW~$PkU@N*oW}akgoZ3+wjMWvHF{sTguD5fWg%#zHFRb~C8fR-H zFh}y0!0GpA)7y*gA9W><8gUjt%6Y=C69`-45?`NPXDggA*|74_4f*mO&!OOSJejL2 zVIoU@0M(>?w&rPHsrK*t!A~yRrS?*EpbV~{uYd+&|J#?^`Vt!@SEios5gfE*)K|R4 z8n$+8Q3z!M&~Lmx@4dN$vSVHC#FX6&oFmUhW>>Kkex3!x=xi|}Ck4T!`MqKjYD!pV zMW?s-b8NM-#|xa@@MaAjKElcE#$X`rI5YJJ1V6j05b?V1N4_n8-8}CTtNR~?a0Gmc z_8%r(;Y$IMShk+~2Kw0`-rY~@>Qt98+V5qf^BdrOGfP6IjpfzoH0RlPlfKUf-(Ot1 zm&o>Q#|s~S%CKQ(tH!92Otx(gQI@X=+kGk6WZF?Is#kTM*^7dQ9!TL&>?^4?K((?l z=eTr{Jf{6&U)iq}_cYL7O72!`U^U%eSG!yRN({`3UMRJQIPCI8-K4ioD_42A>n}3F z{5&!I%<$}yVloE~e@J>IE=$qs*OKn}>-NKa`!N{Jy$hl@(7&k8Su0`A=B5mU~! zRWy$l7|Y*^NS)xHGt1@+Y|5M3JU$vxWw`UfNtJr{3BFWn)NAoh0P`sjdeuV&SF|~{ z7=@}>R$9HUH*w>)lf2gLh{g|c5;bBmougEl4-$>0rnSsiGN-NyCb?J8D-9cpY=j9xM(Bp#-&$4eVV04~DvTZKu zT3BNXYa`*Ho?D-RW=;BOo#0hi1Rpvv-3Z^+GW!Jhr5_0>c^|oXo9VM z4jW&a_EX%JcqBbWy0&V9=fNXo>R!?Z-0&3|9}U_e5N(~ccSG9vPXq(v1Fs)oWpZqn z?3IrYPd{Fn;hJhaTrps{XDw@xNRfQ>pZMOFCoA%&SfyhP`%;U-NkRE~9poL@T+$+L zyAo%$3VHXqeFY(9y7L(?cXH#sispFKgCHKYG{)UFL4(bXP*;%)J~!#$S-YTkS&D)~ zoPF}Rx{>!yCtP-#ooRTux4@XcEbeq}fv6(!R4{mTQiZ_ud4F zupP;+9*LegKiLET1YMSt+1%(c&l6&6 z%$nL`@Mw2bM6(obpkl4Xo#)(G8W@i+gn_0D^>;tAIjxJriabiSHU@=raG7T--TiPb zHV;V^x(7RyN82@r31eYK5oIrA5mf?@9o1sq+Nx-HJw{jFiN4+*s4kze^hw$BOWHh^ zEagNj>#>*BaKP}zXwi$bo?LKjYPR^#iyMV?v-IdT+P!}%PfA)x*L>ThPTz}&bb)w7 zevP)fW67Re+b*}W1gRf8k=L8ocCLk9I^`pf)1YSvPF3bTmVWDEU}$br6?7qZJj997_&4#@P;ar;@(G3K`vBGM8>_B^WW^Q z$MNa~efyQh#;5aLPSC!QQD5mcr@OXT5)fowU|3sI_WY?#W7&1HlOh}a?9D*wpW~kA zONoO$&<$5IYZI>zwU&H(p5A({KrJx{XR#g~=ORCP%FKL~{z3+saCt;pKcEro9VNic z_2sr%*@ul)RZ52Pl6<5aXO$PaWkx)uYAtt0f8_Au&*VO9ySUb~S?PL`|NhzGH^$tN$|26G8{S9R5JA z-5HtO*jvX>1fMwIlEQ7zW#DsVpjA`3r^wPHJ~88s1m5_U3O{^YPkgCyvR?mI#xzFo z2hgYPPm!DgD1<@?(VJZK&d=PHxOj(q?1JZJ*(x}yU88FZFUZF*pyZBe)AkX4 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_pump_off.png b/mods/pipeworks/textures/pipeworks_pump_off.png new file mode 100644 index 0000000000000000000000000000000000000000..0b640c92462def2cc52c38880f19cb6bda77f3b9 GIT binary patch literal 3621 zcmd^Bi96Ka_kY_-C_9ntA~6-ok_^v>-9SKxv>T?Ev8GnmjD1@($Us11lLD@Cp{Ht zvzx<$yq|7rh0n1PoKgiC7;O2 z$%%*<+`W5WR`w1vGgMq$hlNG!(IWw7=37ESDx#u_($d0obTAc_`?R!=6cry|xk4t9 zBf=wMVq-JXGeSZ_a&vNacggy?x(1@6x>{Or78aFDqYNTaAm0D=aKLKR-7zGSUSA1Og#KORGUap`xO~ zM@=nANx4Vfb#!!80sv_M*d_0cjEvxCW>%J0kjNA?1``$*78x1Y-Q8VPRdsrLYDh_` zrlzJ309q6j;>^q<%*^}%u(Pux3jjzIia;PVG&Fqs_U-ui_~__J7y$5iJc&fy+TKb_ zOA4FVL6)fk@-+Xo_ zCnv!>EiEmnscASIZgzHdZf*{ZMz^-Mwzaik(3s`r<&TYxSy@>pCnpXL4rKDq*!UO< zi7YKG%`eDrZ*QNUpI=*BTUuKBva~ccHIIB<4$wzsz@l1L~dDm4`} z$iBY*>FMdOU$+Ja2dk>87Zw)I&dzp7q!c7_czAemaS??|ZES2TD=V9snUVTiJGr;F zx2LCPV`F1|eZ9K6y1&0aJ3CubQ&SxZotT)|+ub7)iS_mM7z{=f07ygARcYm;}#T3T9{BEXX>M+=r>B>emS$#V zW?^ArYHA9H!wn1!jE#-;_4Q#en2CuAs3k)~Lva9*09yh8OmAe;0{{i!X9zO_^Zfrj z0HdFDAk7T@IvQ%m=6&xl494tQyl+2`uVi)ZD{YHqwV284h(cnwy845(!+8t03<&=@ z*eD-}u_jAgFVnCV<<%_Ie$<+Cl?r)-<$#+X5yca*?&@mu3a@AD-x0ppt)@gi#7eqI z1iV@OW2Wc-TNBw*z^@cYoQWlDXR3O;x~Z%#&juckHXVP+>~jB8u&0YKd-aT*7Mkn# zRpvI~Zq0@z>!q4&q1L0N3^eoO-NoyE(0~0;_4V(Ivx}^GuwA-+_!)D^gE{d9-N~U| z-cU8l3uDlPX#d?g{WS}6G$li`~JI|ad(v^>a{D^uLFwUlN$m24=594 z6uz&N6o9>=$M1YS7lnuCP(^+337Mkap`wTh&F>27dH!MkXDJY_M-EmC#=VZQo#VQ0 z^YsCL7#7=gE(5z^pbGrj{T1?NiY-EU;Fo7t9%0s#j>*a1>F)4**`$m}5_T|#lx}50 zkbLoJnK#USp7R%R_Jz>(rGYF+diAMJRgSuJciRX2% zP)rs~KBW2c=B9T6NAjTDmTN_l-{>Hh}@vEuMD^@5?Itfzso^ye> zO$SWP@~5$K&_p1gTAQW$vqSs``-YrLisxF`$%+kNSlx5GpUiCS%(u{Lv15C+E{lR2 z^)c>>@C5bxI*6pl%Pa37uO!sh{^Pa<2!WhX`GF?3#&Jp|4Gt&T?$he5P-UMr@BQ;x z=^DOE6&lR>0TNLUe0h=s5@Z%S-9u{hbZZ*yAt$#S(#;b>30wJn0^ATn4eol@DOtci zdx*x^CBfHA(~VGU^ZcAvMIAJWTrEocfJhe`RDA|oT4tO$>c;A&%=!vm> zims~&I|fXAEXbK`Um68@!eOnp#PHx7OB6Fd#Mjo%%}rn5P2YQPk=!i17&cyiWB8q*8b$3Sl@{8$vU@DfY78fG+ zV!Ogcg0Y!LC6)r|hXMNf-rlR2pQh7FtV-I0@IJ!?-T~&<2{HkQ(^TsUch4d|NCA$I z(9UvMmvl&zQ&{R?#TqvLb}u|8zt`sf;A`c+Hs)h)F5Y*kTg9P&%qDsNcPLK%{y&(} zq;ggIN&_OKYi-#2i>e=evz~+Rmd~$Fo>zP1)`X}Jac<3|Cb29|eD9$_KJFxZzA5yC zLB=P&WN1A`Wwg_Ga4biPMy0bD&jU#r_CZryPB^}yNMNyZe;P?fkMezQ#u=_r5j#IY z4C8nYY9a9tXqFt`s9lKDNiwP*${Ow2CvDU=BfhmuQW5cXrLy6E&wV#Q3g7-?B4}nG zR4a>uJPABor2Nvu8>WTj;SK^_htMydOdRNht?r*D-sG5PO)%z=?1N((rwvU&0Mn$n zI<9?8bTrIN{=;$nA7qM_+eHKwcYl=>L@EpZD?xEGzrN=(YO=J{g)MO zx5Kyn)35c%2yRCw>sAsi&*C$bUq^(e!wBrcB1*UA!BE)q{c<*Wyg#bK-sU~c*B;Gx zs{GcArEhU%h@~>6m^coN=XCJp?BdTzFebM^vz26)B;W7%MI_0EUezF{BZa)6r=`DN zw3+l>*&ej3i7Z^Y9Z9(ZD#O3U`jY~~HDehcCVX++Rg;gkFMl4v3$>CnFHm_>DBf9F zC=C77Z#GiW6?_5~&MsPA*a?bpLi6>~QrTHagok6#v!dB!qr-ic+N>NG(jI8tdBM&J z3e%_K<-oQ)wmC)t?&KRlTn{Ah?L>>faY&((IO%>Sh4(i_A+)O8ASdo-=beJfmwIEj zBn>nncM>I{dWk+qZTNpUR7G4>#n=i>ykz5 z8$`(yp<9e=FBebYrMOp~A^-RuZ;c1P@pmMkrNNJ)Z_>-3&6AHHZb$^sMeX&mE05Z% zdD8D8fx(7aoe+P8e?z@;#=5QxC38e*)ML~Qjqv+fD++jYhN)q_pQfh=qVG&RE*dMbg0eN~cwz7S z4Q2Fweye7DwedJ2wl$D$o{p2NdZl)~n#l;0Se^9@gT-3?RIRF|+?rcsv-Fg(I#KL;6BYOiUIQ7Sic-xEI_OVM}BZ1F{294^hq@&JPkF#O}t1al<0G z5ivV4v;x|*XU|$%S`rfz*Vfj!TrScN39U2;aG#{_rz3C(*FaZv657Gv0hNRb&I^v*jST07(@JS0 zBO|l3vsqbLRyI~p7}W2P9}Eq1LO7wxXx~&{FcgdkM4%s`UEN&0N#4jHWI%oZVS_;A z5FF8ciAlyF z@QB5g#W~L0(#jI8i1zl~+nt>qh!X_j0&(?o#iikpF-UWuxksdjqo1P--Ua3WBW@9w zmzT-A zdDuBRI=Z;HkakH+OG_Oc9o5y<4Gj%tWn~{ed`L)0fcwGC%*=dKeC_S+Q@AO$wY5*5 zJ_Uh5I6BVC%8IkHvb?ffQc{wAkd2B)Im4YNCnt-Gi)s6`jEoF07<^bQ)1RhcE-;&a zY{GZLDHKXuTN~qm!Q=6wcB0tJ>|}0od3iYu2FuOOrR-BIEG)=mGW~!a7Z>+s$N!x}aBjL8!l%P-a?N837rvCS&4T)%Q+!ei>8iD7XT@qu zt?Q;uC$nEvywF=;{*bL-ed*6X*C0pg{=NLo{QjPpQKrsrVEx0NoaTU~w?k^ffE!-J zZ$Ao!rR%CN+l-!7CP`y;Y+Bn7I1$Y2p<7P-BYPb~3|~GSEeC6niF~T~?N?vFl4qeq5^D_)JTYuIeiUGdjY*3gRm zdt}pNt|^dq@@A|Y@O$->x8mm-bIM<7(|})B2RwfaE4)g2b)oeY&|)8UcSrMS=+kx1 z_!o@2y2B+69hX6wbL5jGg>Qs=?-TS+&fk#yqHA;x+md3^zF_K&0i{)AL6)oQC>}RZ z;uBQGcU<)L;Nr1687H)uHvxnHYq1eV9y6&*>H}LQR73@cH>#kCk){i|A2#xsW@m z7xRQuW)}wxo4*MZ+&!)mX((O|F<+M{|B-%`oka;3gxAHSH~DI;M63NtIa{=XpL?_nMZCo!xb6Mcx{@71eR&nA%vf{_zwJcbO z$z2Am-Y$>qChc6BI`!Kch`-328E@D;WpzlBpaDO!d9)?#QTguf?lW;68F6EYyh^kT z75ECKqUzu&{D00^pCpZimwqBj6ulp=_7rTr&L6>iw)U<_S!r`qCT1?(5Ou1H^^0If z+W#q_$G+Qb6AdW^!F%2hAGbE}^tG)o8qHL3Y!s8x<>MI$s6A>uigIS0Nv?NLrjxF2 zYSe>u4<+Lm5I3K_zn@uiRlCERj#WojS}@jcxoOYm84{z9$Jrcv%x`b5f8h3dkt2f< z`0ak9NNQ_o#f1*F53qcx1@PT7kwTHYMOox6jj2nHEnnl^G0T4`?^)@DsUy^kw?0hD zoY`?|Y?}b2Fp-@tnlA$1xeBG6sMh`o)e)1Ud;E1}>RX2Vsm_t|POab7XrKq|c}~6w zI?%pMzU$A#g1@sUGs;$?fp+i8+(w95ZJ$JbAG7i=cnj`zT$GlP8nBayjw<0v1xm;n zRJ-&|4C)&(eX~pJdABDQ)17&~h1JK)ev1^Z;?seER z^6qCnpKwl+1G*x>)A?Yx(^8 zeZpE|y`h_OZp^iIe5reV#l0!*(cJBaKbh6Q0L6h(p{f|6VMT&3!%;CgBRKj?p@C2I zY={H(ss5lP-tc6T?X)0y)uiX}?esqFmXSMcN@gSKeR$Z4GQ2tnkC) za*dwo%|>ncSL+XW8G(DhL?U)|=|=n??wNge6Tx-m-0D-AIj`wpbeF zLY!1H#_Guw@r<8vyW}jqBuL*2W9K!NNi{fcluj>QN|FQ~3Ln_ggDVC%T|Jk&q}??W z%*XovqnNQ#<=2?#-P`y=pEWupj;wdsQ?)=a8bVeBpajLkyl&)(YNy(;?-%t2-lH!p z*fmbbg`J|R)9EyQ)*=IKr1#u=aa$Ezva+1Tx}y7vUs{_w8+zUOQIk)*UHwGieZ4glAq&)FdLS;hVaT<4r z31>+zW}W}O`|n#-ttT~a&f3Iz^q=HxY0yae0@Sh25iyI-$wL*C>N#sYv~OXzH8v@1 z+IF|Rd0~K}AiT0t*DO#@SNA*eLE?G}@YlU^nhK$@OX&pS(E9X!&5#Dt3&in0@MWpX zgxB#uWApoQ(!zGp{rAuy%h&6JS?qFx3O?&Hq&uu29h@Ks)Y>lm#b`-JTlnKD-WYU( zT=b$rE^6y3pj-yae4g4%y%D=K0<)^NnnEU&H8t6okNqBKH=}nFv>nI(ZGJI*1z(BD zgjPTwws*ULTgGRMpa|)#-uFXwln=s7uPCR}CndD0`M<{cv0z%ib*vOvJ*sl6eq`vF zuz!Y^sRS#}Y{*(7*mZ-jOXOIU*Whb_#l4eI_22U>#mXt;mS%jPpkOGLvxD2)%H!?p zK0F}qZ7Khn+797vPHwNB%)Y12x8N@O7izmtP)kWR?6GuzLBcnAZYxgs(My4g4nThq zP@|N*apxI$(O4+I`PnVbc!2xbG&V{pV)V%G@^qI~y=bGw*Q6@iK794GkldYio@&fj@?%m`kpOKn7kqQ?a`wKk=SqC*00psl+<49d%QrNv*Rp)^i zq;R6m#&LVAOa0s4C7M>)>6JA-MWut!)2zPp)qO4;W#4flLh;i4ufP8m8_a1msI!I} z5H}_^M=omWDH(p7kbCg+Rv(jr-(=3ePA0@6g^ZrqjUSD5-WW={> XLJ13s`DAnWu?Lvn0hw0ac8&fo1*jn; literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_pump_sides.png b/mods/pipeworks/textures/pipeworks_pump_sides.png new file mode 100644 index 0000000000000000000000000000000000000000..11b6c64db428807f4caf3472ca23e43bdb607214 GIT binary patch literal 3742 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_red.png b/mods/pipeworks/textures/pipeworks_red.png new file mode 100644 index 0000000000000000000000000000000000000000..05ccc05d31c532180a46ef689740ca0920db9421 GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx|FVdQ&MBb@06b3^9-^iNi z*thB0yy@Ax@aEC#+`s13vFF#e>)pcS(W~y_%jnp-?cm1j-oxIF404j7+PE-H?|NsC0 z|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|Ns90GN|xe000B1NklR~F07et8iy%j00kmWun?7owEen7?7J&OADAbh~ z1#Fg`nEu>G-||cVT`arX!w_F03&1+Dem#$a>{tMYt4ZGPIq)>lP(S@Q`_MB10DT0Q zozNM5g-npIIV>9UQ=zx=KG?&wvklVO|y#t!&6%GLQhkEZ zKYcK+eG_!c65%mcU*|TF@tW495l#Ktr1Dddl2TS42PHT0yS%K0=!}oHNDykX|G@_j zvdqqD0>$<&H%=6&(g4KEvf?#>5@LMn;K#vC1IGD-=^!XMbt@@GgeDlDh7VKO1lS-Ms(nz3Hn^@_AN*{FKUB=kWTuKR6p$!b!aC zTcx~3vJ)?zO*z<-gd8kvetnk3opd3=F z%3Ef4b|$5&Lh+_Fgbjcvo)hK1T5(iAjr+`L-K}Tkpog%$8L6c{r4D~9c>qwSiESO5#DgXqi_AnyhwZWNB(D~*7?XDX z&irbV(5L<5;&_CjSM7aPK}eDs*L z*tzT7!tdkE?BB)e+`sMM#_Zn1>f62T;mGUVzyJUM9E`G00000ObW%=J|NsC0|NsC0 z|NsC0|NsC0|NsC0|Ns90%@Z!_0005>NklB;}`I=un^5nu;Hh7j~Yz?|+^bqH{?>47{R0Zi-1YU#ZHIsjOg zHzI)!>>!(n=tM7IsvmBhfWh6DmC@St0YcR6Y7gn_cNf6aLWuGg4nS0aSg)}sl|d-` zAruPK?k=J002KdKm^3gQ#YANtXs@b_U;u*CL=ctGAspCI&dXj$xa2z2Iix&*p(c@4 zN#tJBv0Ibbd;VX+)S9bDKwQB=OT2%H_asX_`BQrx(V zf=F&xP91a1HEg1aS0*5C^rjzmV?qFkc`lUlrCm>cCj*`Us9I-u+(zEXU`}Y^6$>D9>>vKeetPAc&hFE1^+*3a01ZIz<}&$b3D5#Y zG=OABB}p#lKNWr8!WuBpEt^iV$xwgyCO+~e6xyCeREqHu@I8mN9a!icWEp1WjAV;; zt77(x9c_OB*vbP;Nlff14L2QCzVyF!p_->+Cni2XG)=8+O)S89r>q(FMIKbU1z-u# zXaL0=1-Tn>0ebKzMZ(Q%F4@juTenkTFF?|gv=pV&%gKVh<34^aM$T!ppvIH>dcX3# b0X^3byUu7PgjbS100000NkvXXu0mjf?WkBz literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_sand_tube_noctr.png b/mods/pipeworks/textures/pipeworks_sand_tube_noctr.png new file mode 100644 index 0000000000000000000000000000000000000000..cbb3a0937e7f2ec97271e85ebbf808052da31177 GIT binary patch literal 1004 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_spigot_bottom2.png b/mods/pipeworks/textures/pipeworks_spigot_bottom2.png new file mode 100644 index 0000000000000000000000000000000000000000..86b96961069d608744c289f31b657d6dc4c4779f GIT binary patch literal 2444 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 KMNUMnLSTZz(8dD* literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_spigot_sides.png b/mods/pipeworks/textures/pipeworks_spigot_sides.png new file mode 100644 index 0000000000000000000000000000000000000000..f9898e6d1d26d958c31c724cebc23c0ec0871174 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6)_A%&hG?9Ro#4oKSb>LS`Bdhz zfB&x~G%fm;z@#FsBJsXz`uVTBEehu}1;?d3>uKF%XF7A+)5%Y3YEyAQA=lP^GoiLA z3s)Rg{Lq%@A!{xBKF&N$#Io%$&vgM2XTub`-_E%yQ+j;%?muH{G^LT-FIifnZJOA{ z>P7D!oL;|_FS)+QE3!)alwaJmH-bhV{EnU28&{E`Z+*VRVdmu}mC+AQ?ANpSeDMG4vU*XjsfU`Iz3Qul-l!NA20Z_^)2zwo z9q;wBxgVX>Hc!0KVWl?byqvmFr;pmH9`32fj27P$xxT$s{k6M^+Lg+^$E*(3)#djZ z>D`Rj@Am$&zK-n+NB*h{&2nEBu;XXetv3IC$VYeWthK9wj%M(5^>bP0l+XkKQvF<+ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_storage_tank_back.png b/mods/pipeworks/textures/pipeworks_storage_tank_back.png new file mode 100644 index 0000000000000000000000000000000000000000..cf7f245173af4f45eec2a68ebb1b0ab43d4a7636 GIT binary patch literal 558 zcmV+}0@3}6P)U3s;o;ZU z*U8Dr%F4>Xz`)DP%c-fUqobprpP#d{v$V9djEsz=q@=dCw#3B5ot>T2)6=!JwSInn zlarICrlydPke;5Nt*x!Eudj%Rh?tm|eSLkryu5*dfxW%G!^6Xok&&UHp_G)Anwpx4 ziHW$lxTvV8i;IhwmzSBDnWv|xe}8|3goJ{Ef}o(Fu&}U$gM*5SijtC&(kvcg0002# zNkl{DJq%!53im#gQ$?H#{d8T07*qoM6N<$flqg z&CS)-)#Kyi#l^+X&(Ful$JyE0)YR0>%*?yHyNryCqobpIe0;vXzTMs3+uPgT-rmsA z(8$QhuCA_+kB^m=m4}CikdTm{pPzkweSv|2si~=+o}P$^h<<*4!otGX*x0wXx5mcC z$;rv#;o;ZU*UHMuz`(%E%geO1w6n9bwzjsSqN1v*s?pKWq@<*ilar>Vro_a=)6>(L znVE@+iM6%0t*xzugoKool)SvWot>SLk&&93ny;^~i;IiH!^4V-ihqB9mzS54l9H&X zsJ*?tf`Wp$xVV^@n4zJegM)*or>CHxps=v8U|-Zk0002-NklJAiBHQH69wsUB)3>JVCA?%zSA7(5`^-U3g_!>7GoMgv! zhR6Ci1Byvp6OcKoXS2Vs{#HerC@aR2}S07*qoM6N<$f-L?!X#fBK literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_storage_tank_front_0.png b/mods/pipeworks/textures/pipeworks_storage_tank_front_0.png new file mode 100644 index 0000000000000000000000000000000000000000..c91466f1e7fea50e7641c67f6b1c3f3be86c796b GIT binary patch literal 3791 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 BsGI-* literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_storage_tank_front_10.png b/mods/pipeworks/textures/pipeworks_storage_tank_front_10.png new file mode 100644 index 0000000000000000000000000000000000000000..6456afeb299884030cc3f6663d4b62105860d3c9 GIT binary patch literal 669 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU&&s0G|-o zUAuOzUcLI!qep#xeb1jiKY#vwdwcui$B%dK-u>*^vj-0zR904&mzU3;J^RX)D`(D} z*}i@I%9Shk?b~eS}Vn@^lLQBzZMgb6)8JzKYKJ#ys8v17;P&Ye4N-n?bYmhITFWAfz5wY9YqCr(_raN(3G zQ}*oHvwr>h<;$0Mc6K&4HqM$gYwzB@-QC?C9UVz33v){5PI1jv*44MbCsLH3x_= zT#PO+@2qZe7HZo4x#WMf=HL028#HIAn|*zM@V?!h@9Xpx@;DbiwL7x9WaHfUxlV0S zlP;!&KX%UY`Ds|OCL_>g^07Csr>E~>pDM06+hDa+$=Mm+55mNLm(SU>^7n!E1g@p0 z(h3j0n454ahEc{$wf7P4N!g8-k2Gx_ZT;=G*zep5jSqrLiau;vpV5}HWF_bN#M!TQ z{F zk6-u@Zc*Z`o}Zuo!L)w*v99&(U-O=49Qnr_H_b|eWl~}s(BBN6u6{1-oD!MgsCGpFdYoQF-v-!TIy&H*MPV>C-0-4UI*M7VX-#OH@?!_3PJ~nwpOvKVGwD zO? zFW$X-ck0xs_wL=haN)wkhYxSxzJ1`pfm5eWoj7q~^XAQpii+y$>aDG<<>lr3_U*fV z{rbt1C)cf8w{qpm88c=yG&CGKbZFbQZKqG4zI^%emMvSBELk#P!h|D7jvPLGc=6)J z$BrG_x^?T09XpmSTQ+y@+{u$C&zm=|r>Cc`u5Q+>S+%vb6DLmGvuDqgDO1+3U*Fl; z+1S|F-QC^M(Xnvh!sW}CH#Ifw-Me?ef(0{Y&Rnr##q{aZTUuJ`>+3gc*wEbE+||`J zY0@NMxOJrZfPycvB*-uLKaByyx`up1pk<#tT^vIsE{mRJZaN$w;&9P?Tkh(4vof#T z_;=F%`~I$zIuGV?XSuBPoAj6K*`Igc{(KR*(-hDqrugpo-tNs6@_Y6u$X#B-!~OA3 zMn1QWl<3aGTU_=$dc0v1*UG0)tQHnk&3_oXZWEuQ*5&%+4oiEk%~B}JaN3>ca#MA> z;SB~EwGPX5UNwt1KVG}#0b_r&__HZRKUalH3-rJFrj#1D?m1WRcJoBJ&lcX7I{ix) zUE#lF@WPa3cZtrd`&ax{G4il)J})SC`jmR>E}ORF%dcJev+;PNn)b!7m)f8AZ(qOi w=JCV^p8YGzAO78H`DfnDJ##%LEfo06&%e+)D5NA$ALx4qPgg&ebxsLQ02#HaYybcN literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_storage_tank_front_3.png b/mods/pipeworks/textures/pipeworks_storage_tank_front_3.png new file mode 100644 index 0000000000000000000000000000000000000000..d237dd5a85e8277b047b3dd4bac502825dff7aff GIT binary patch literal 716 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{vH?CJ zuIlP)K%l9q+1lEwuC9Lm{CO1>l|_pdJ$Ufo`Sa(WK7H!z>)W+!m#C=d>({T_+uI*M ze!OPQnn#ZwUA=ns=FOYOj~}nBtSm1tpFMl_+O=!1T)A@Q%$fP~=WpM>edWrPH*Vax zc=6)hyLYEfoqF%yy$csEJbd`@_U+pT4jedj>ePu7ClnPGYiert?b~<#`t_41Pj244 zdEL5oGiJ zJGOP})*U-`EL*m0?%cVPCr_R?Z{Ea-6BjOAxM$CvDO0AbU%$Syv$L_Wan`I^wY9Y! z9UaS;FK=pU+PimecX#)K1q)`*oVjAfis{p**Vor?*s!6crKP#KxvQ&d(xgei5M$ha z4HSOyB|(0{|7i*sCeMo30b2Fm)5S4F;IWMM)9ytB{_xCF@i!NwS0-Er!Sc)c$b=ye89S3j3^P6VMGqc4c>er(Utiy+PoLV`+js5SB`PZV`t|F_ zj~}mDv*zm6tB)Q%s;sOmFE77&^XBp6$7j!;y>{)|D_5?ZIdf+F_U$WIuDo&M#=d>~ z?%ut7@#4j)Q>R|IaN*v)dk-HzynXxjfddClojP^m#EH$DH!CVC&YwTOrl#il_3I~3 zo?N$X-HaJC8X6i79Xhma+qToEPhY-#dCQh9OO`A-a^%S2!-pqKm{3<&w|Md5o}Qj# z$Bu2?x^>5n9m|$2n>%;zym|9#Yik!ST)1b?o+(qNtY5#rv$M0Yv2oU{S(7JEo;Y!0 zM@Pr<<;$Czn!3BY_wL=hV8Mc!GiRGk#XEiEk@Hf-qX>S}Ioo-}C^FvPAp z^{N7?_>v&M;QurQ43lTY>j16#=;`7ZB5_&tENfD;g9yXL`0{e!yGgy;2b*^5W#9QP zv6Ov=xk3Mmo1UNJZwkE6(?8#LP*dV*hUBEWOS`Rn`xK6`cJEyM%*F4>Bfpn&A3pe{*k#Hpu84~|gTe~DWM4fCljQe literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_storage_tank_front_5.png b/mods/pipeworks/textures/pipeworks_storage_tank_front_5.png new file mode 100644 index 0000000000000000000000000000000000000000..f51d113e5cfd98fc7969d29630057452304f5059 GIT binary patch literal 704 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{A^|=j zu4-y(=g*(l(9l@4XpxGF%7X_F`uh5wKY#w|)2H_Kc2QB$UAuO@e*OCKZ3=GDl03?%gblao_+J?&Ev<9uU)(L%9Sf;&Yao4ef!FlEBEc&cjLy5ix)56y?b}+ z)Ty^`-+uV;;k|qJE?l^9;J|^CCr_R@aY9j1asK@I*RNkcb?Q`2P0i-bo7b&d*U-># z=+L2U+qRuPefsj{%UiZ=S+Zowkt0VAA3j`HS2ttEjKzx=_w@8km@whkv141eZr!nC z$K1Jd=gph9Y}vBOlPA~K)=r!_apA&+d-m*^GG)s8_3IlO8)wa$)zQ(>-QC^U*|~iA z@}{Pyy?ggASg>H`%$d`tPp_}9U$J6EOH0d!4I7%9o4dNYCQX_I45-$;)h0kHrX#KlcJnZwp?{(oHO)y^Av&D(Tbu6-9ewtia2VYUet+7(Z9GZMI>FQ&1} zow$kOW*elF{r5}E*s7pC3- literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_storage_tank_front_6.png b/mods/pipeworks/textures/pipeworks_storage_tank_front_6.png new file mode 100644 index 0000000000000000000000000000000000000000..c21115e9d333226e58efbeb4b4121bc8c338b5d1 GIT binary patch literal 691 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{+yOoz zt_lhYDk>@u9z1yd{CQtr-=|NX+S}VjMMZb*+V%SN>&K5DuUWI^>eZ`{9zCk8tSm1t zpFMl_&6_umA3uKO%9ZWgx365e^2UuD`}Xa-c=6)hyLYEfoqFNIh1<7p-@AA3;lqaq z4jedn^5m&gr%s$Wp{S_1cJ10TXU@!@KmYpm>zg-kuBoY6w{BfSL&Kp%hqi6ocKY<` z%a<>2*|KHHk|jru965aWa9v&9gb5RRdU}o>JGOP})*U-`EL*m0?%cWa=FOWiW5(je ziziQ>Tw7Z^apJ^<3m5L$vuDbbDeKp-@9gYsY;2r0YgTu6cSlFZ^5x5$nwnom#ta5Yl zC2Zd zZ`rbC$&w{UjvP6B_;6ia-QvZIXUv#!=+L1F6DIWZ^c*{OY{!lrbLY;TH*en7ty`BZ zTQ+&}udi=uY1y!0LvwTUq)C&yy1IbjW4!!G3y_K|3Gxg6Pb0wK-^$1j zwB((qi(`nyWzjROiH8jY7!K$g8!r>dn!#)6d}fmFo%%_;nC~3a5&gI5$o^T&@7<4` zKljkGq^9Sud%j)#^h`$9(ML<{v&Zoe=T|2m^8HX+>v3Z7r9Gwr+jjG|$_vfrT%D0r zwPE{Jw(T2^{D1u9>ztEfGd|a-R?QCiuzF|a3Dpa0&Q$K0x$#Kk6a_(>3mbnQJ6zTG zGfB_7!R_GVT@MU5c5doYVH1@UnSN9&(X3ndX3N1(p4_jFi!br+OJzBH@Jq4F*(lXD zuTIrg)cu`RF*o6j+q6k>Cs^X_qV5Z?_ct~#pY&=I``howKBT{rWV}}Dp7>2Z>4jbN U+aI^y0)5Wl>FVdQ&MBb@04YhBhyVZp literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_storage_tank_front_8.png b/mods/pipeworks/textures/pipeworks_storage_tank_front_8.png new file mode 100644 index 0000000000000000000000000000000000000000..5598e596072c8440aa07c1f6cb51d9be40371c03 GIT binary patch literal 692 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBi{+yOoz zuB%tCe(~bP?%lgTefp%Nq_ltk{=U9GQBl#QOP9WW{kpxq{qf_+Yu2oJ^ypD#Wo3DJ z`Rv)VZ{ECl{P^)JSFW5nb7uSY?JHNVym8~kzJ2>HUc7ks?%k(@`7JbB>2ffFZAtXsG4>eZ`j*RGvEfBvacr#5fiTvJoi(9m$`(4lSHww*qG z`ts$=OO`A-a^y%|UESivi)YN3v1QAa!-o$~m@uKIr{~zQV_UawojZ5#ym|AMEnBu@ z$BxO9C)d{2PMkP#;lhP`_UxH5Wy<>X>z6NI-r3pN*w{F0)~xRC?v9R*rlzLp)2Gjz zIdkvcy(?C%Sg>G0eSLjPOUs508=9M&Crz5v)zt+IpL^X!RX{4TB*-uLKaBu`e=8$D z(31C_E{-7*mqpLGHZ?nlFkG~M_ikMw|0EWtg6V8g@9QTeehcM)Ci(rzsy}yktiC;a z^=9FYtW%Nu_)c)}u8)4fAry1DXp4dY!@3)z4*}Q$iB}4Zf58 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_storage_tank_front_9.png b/mods/pipeworks/textures/pipeworks_storage_tank_front_9.png new file mode 100644 index 0000000000000000000000000000000000000000..b0f750d13f91f8106226030f785a31d2fff51540 GIT binary patch literal 670 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU&&s0G|-o z)vH&3{`|SGuTN4^^7ZT2?d|Q4A3uKd=+V`ySIf)GD=RB!&z^nr=FKZtuADh@X8ZQ- z`}Xa-apT6tix=2iOrAWswzhWS#EAswk{ zHf-3?+}u2A(xk4gE?@vy?KJ)lq(Vx9{DS{eA20-eFS-ac|E;HsV~E6M(KA<*njJ(K zE=GS}wyrQ-f$QL0)@fJ&|DS&8`%LE5J{4Me_5JU@e0=!tmC&Lt&Ux}oR?d?jnp(BD zgy=l{xNnKOiOk%&4eFb^T5OKFWnaIN%Fd;)A|{-6aoy~FR}O0We0+byQZL%~Cad#F z^CX$nru&+0YS$f@=X^GZ+IS_*(1V3{SHZoCh|`?mqBohB{9NpOP&jGgTeWGbJ{S9@ z?YObzOj4)jZG-tXvVU)VWRaY}E!k`rU!Q$t#ri3s%#~c{_3gd4Ki8jg<4)Rkqt@%^ z*T1_o_u_$*Z@27{Jbb*`{r&p8bK~EA|28eMK19k&+^bRk7trGjp00i_>zopr0HHmH A8vp>Qu>#~`RtuyJUHrZUdol|S4NyKCaxlU*;W|+acmnO^@_gh7im}Mkn zNyEBKO*3W?B?=XCi;yC8GiJWuxyF9h`76%r@p!$SzrG&t$NTZREVjUs-ATLI6>9d4n!w_@;(q@ zA?jJlc@LoM0IM!QDFCadWfeJ+3tnGeK3SU@f)ag!>Y;>!S3bHYyO9B<5mh}r)l(sW zX+Xh|*A=Q>JOavlvg&*w&6d|PAeujrUIMZbS!EuOW`b3B*{#a}P6A?Y0L9D7v*ZmW zveFa)(^b8#QYKBosZe$_0$Gu=y+OuGlh+g|n#uq~0rFaTJrl@pNdKTi^Z>Bx3BTWfw=)%>}YTAY(u&K|q=d#Akr~7Esgy`JVuaRdzNj z?p4X}6ahuEf?Ey5XMv&tDA)js2J)LyMm&Jd$s1Wf#*$u70P;!&|2CW(0bhzz@M@Go zHk?UP3hIE^A4rHm5(J<~AP$fgoReOo07)2>9s(r40|^;OLg33Wa85X!AGdM;thfQe z29hp#xp{;ClMuD|%NxI-nT2z-$NP0NeK#e%voTzxiulK)@0GaBz&u>q9uqT{Wv5)i zd=8B-h1^?-oIaX)XD&u%XetR`ym3w)Lp4Zv`Qx>%>?gi^|DAht7O6Wua`^j)w3VMk zvwCW$EQ66Gt}p@oN7JGy8%rQHJm453+ED3OkI%-*Ax0}*M>#q*mFNfJSOj;$y4`!I zvkV_VECwLA5L*?nR^ z&D$x+$=RZoQmWlqejy#R1C5^D=SLGvl8`BZqb64BLfOF^Ye#0(cD+-k?e!!~-xlBX zBzVqE)15b`R3%O9AuUCj3CxA4;nyR1B+m<0OL_rSuQl@6s4;I^7L(q0wm;6vCzm(3 z3cJ)^Gz;2`hx~k;HAZ%P``2e-N7J~81EL@0dg_O5 z=*lq@YjO0a`HL~_)KPK_YQa8Y)F^_Up%^F0fLnAE8(WSp9!vZ}p|5 z(*7Q5T>3ae<;TrRk`F2u`u2O*ec1PH=LdJnp*Krbcrw!b>btzHg7%p#i^Btb|1Foog6p-Wo3{)%1)eK6Hq`mXFEC#Hw?LP>Vrfn((mAG7`1gY0JNQyt1dQG;L1( zmO(x4)SXN}%I8cj`b%NX)2RpUE$gMRN!eM)2Gq`foCs+BaF$tXbexfPyt1HvU+H%>Utxk88WpKu6Ye~TyGd^kiAj$vY z_=haW*mvG_lf}eNwsXXDrqL`idNQE%u1%lu^lAR{ORT{PR-_DmaT;T{E1SJ zYwvfw5A5!4`OWb%e1b-v8eD8Mw7F)3G5u>S1f@0B*i5+iiIv!_FF$ltOs%ONwWHKi z4?o`hs;d9a%hRqH(^re{{2k5E`vXgScB=*s9eALvFA7HLbJfFlo=JPv1=({5VOwZZr{s2Wf{dZ#&5jd=yW7A1O#y>Z5;qm|g literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_teleport_tube_inv.png b/mods/pipeworks/textures/pipeworks_teleport_tube_inv.png new file mode 100644 index 0000000000000000000000000000000000000000..653afbbf35fb2a069c4485def712716ccac16c59 GIT binary patch literal 903 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCilq1^9%x z{yKN)|Igk3zqbDWQvd(w&i_C6{yM$y*U3Hqzc&9ou<`%b_WxhI|Nq$deeKL|3%maR z-2DH?`d`O({Quhd|J%gxOL~9qU;qEd%5O6p{{LA1|Hs;&hc^HJzVzFop6@Fr|Nq+i zef9M3%O`$cHTD1Z+5dm6{{MaP|8JB3f9wCbckRzzE59%8|FLo2|8LWOY+v^O+ti+~A_3kv)_8TsxO^Lq6M-aY!S;~M%sBvf;LF+2+u|1gd5&Uc0- zdwz1?)2)2HvFZHWK*NSi=4aN)k>B6XYS=DO%Rb>jPCS1={nslGV*?`<4=ff_$k*BZ zD(Szhn`JD+jNq}bo<&MoNSsqo;gx743^ z?{1RZ!`pWc|6I-(KgsrK^~`IP1}fQ)oHosUwO7o1O^?>9w1&kG7wCsc@Nmz{s2#O;_MJ6>Ve4_XbAFwwwzUgGo=3#`URt$c$wJwN4;ebU zB~G&(So>C7S^e%h;b|KV=%~s{OyZMpJfnQ?z<1RT$I7afWmJeCuwCPtB&sd-;9}Fp z6*u!3W}ZC0`|yc(3`>H}$|rx(@B8u1M8RvStc21k$)8iwWHesAdh_q9=$pCA13JB} z9)#BRS=n8*$oOZs$gAb2ZiD7(SrK)UEtlDuU&^GKWx24n1fOtsnz}}7n$p?B+m_qO zJFeo4u-r3iYDBZMfqC1z!urpzA71X;e8I2#`P=QYf1i$@$L;X^7q{??sv8~&-_HZn OBZH@_pUXO@geCy&5c}Ey literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_teleport_tube_noctr.png b/mods/pipeworks/textures/pipeworks_teleport_tube_noctr.png new file mode 100644 index 0000000000000000000000000000000000000000..3d10b411432e4c229df00a582849d95d8dba29f7 GIT binary patch literal 1487 zcmchX`9IWo0LCX*%F8ibLPEVlLaJSAL!*q`SH?KQ5XupTbuDW~7`Z}|#(fXjF*DI9 zSB@2%94|>yNUAN(#>{u-`<-$0S^H1y^Ljnc`?u$Z=Z7cT+3~XcZq?l=6iVL4+R}BK znExy*xt$dqB+1?EcR&DbD5Vvj4O#%@cO2C8le(^vXKh6yXVOknob6a>X1@NvwDZb)9 zHW22)<+s3^i@3W5X(<7M6v3@v_AxL2Rs~<>IaZ2QAeZr zDN}eS4!|^oK?6t~fTDq@1@HrqreXly6c)vcIQ8PrW5t0msFE3+sX9Kk3NI?Fl89792Db^+n6uUDCyE9bI@uY#4SUA7YAv} zYMGXWrTn<@lO$Q&E`y-Wz=!HG=!5@!V1RIq;Ik^9C8ayY4?&L?4I*;nG$pWH?1zlD zq^@DAF$MFk$z#T8xR)Dmb6w6-sqlwFuma(@?HNspih}t$xXKx0=07B0^vtY!nT9L> zY5hIYXg*o{yf!86o6n+rDuTzz8firB-`6B_&cm2H~L4s{Wy-{nrdDKcht_G%w*V6_?#5^fB6G{@UJps#D> zEnzP$cU`lPj}!!#s!r4gU3qqR_@qM2E1iu*zP<}>B6Xs%%`J0ab+6RbJ2Z^GN<$?b z&x9WN82F9q;Fmdyw`V|y?*$#>?vb$s^5TNUzM3WLt!CKYoVE332RYE`9#b)c@6?ytm_l4q?R(EP;iRY8 z1=6c=Im?Oq`Dx1lO#l7+sT1bU2hAhYn+Y;fr#=?*qGv6wbQJpgN6vOFP97{{?P^sE zYE0rAdc8Q{1QRFpu-)!jyp^rL7=*y{#JO6pX;1!E*|Xn%DrDl|MS_E|KsV^L-lZ^R z<@mi&vj$pjRc2d`l~Y_ofW^i;oL#2zF_oex0|DAr@uBnFX3qrX0waF9b>Kc(Oa7Xa zc|)6*Q(-J;a938D72W4SmTX>Vff6oT-Src5ltm=%&vbV_MP}*cjn=H(^>8G~ii#M; zZ@e{`cQH~KBVyn2IqJ$`ZV(~8YLc5v%VBxZa^_Zv%J)~Nj5PFLo2u^rGSnmS$Bbgn zqnMlOICb}<)UI7_^tEMeihuD~tu1~!z}!giRfA&N?&d*tKjL`6^lCZF+DaOI>r*`y zXnDNr_8N6XfW H{^WlF%0pLr literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_teleport_tube_plain.png b/mods/pipeworks/textures/pipeworks_teleport_tube_plain.png new file mode 100644 index 0000000000000000000000000000000000000000..23a793d47a287bff49545be572a5e96a50d6de00 GIT binary patch literal 1716 zcmc(f`#0Nn9LA&KUNzdT*7S0!JJZhE+Gx93wbcd5Mi^1|qNp^kK}M=BUzZ?7s)V`) zbz7=PiUzH=F4ay|&4^m3RU4+#Me_Y7-y|-d*TMi%P|B=!JFg|B!6 zRWDfi0jRpcinD^tl*PNPjz3-deGE?Y1nNE+ovf%x2S@@?b;4;u>SsOb=MMpr1e5~x zXutZ&J)mk=+{#0n3RRBP6<%*D}mHQ*K&yeW8Nku#&qZiU8Bmk~B@alwRgX4HBjxNkfYvJS)dQF&zmcHo;UU>n zBsT)d2mw-GAPWMr03h`TaJW35CcjPxvM?A52C~aQ77Ap+2rCL;4zJK(1VWDoNo$-TY$%V_l1Z?MrZSi2?6ZS!4ud5c)fY|}< zx?8HVqur&ojCaw#*A}!*polAFi8$`*S8-pl@qt{SKN?9%l?iVoGV%Ol8@P3=;fCOn z@60SaVlV1MpF8kgBl7(A)n{*QcKhrYSzkad^{v`2|4zUkh$n)e_4uFO`#xPYtd% zwS@cGb$W=i)gOY|yGoX}m!AB9DC7P1x*M_vD&q3hZ(=2lG~1L(bI~DNkVz4j{P1+b zWpeWV2LBte(Q3owmDvo@uIQh*y%`Wgl_sDd`pEnpL25T?Y%$#`|MK0axkFdA zAJ?#GOV+%)z~eh-w5Z|KY-~2h^i`vYD0cinHq*r0V|Kdk=Iq|Yqix&#-CUlAZJjDl zHc23^OfP?3c>3{Ttm99(v4d}43XHC1RkdDliZSF%lwr6DjcNu})N$isj0Rct){3`w zqRgnc6eDJs9iduDo8R~v(2z&O$(bp4<+llu#OfCu*G>WYk!b=OY9b`n1h{zMa`a{y zceX*_{>s^z@b1-}xx?xQ`-JtP?c5BTnSkr^% z^V&%}i02I+oDewZyHtB|-&6XT8%=*re6h}>R?D%mE#hOsNW-y4 z>qfm%$_4+n9oKa`d}@k*^HR+3HtC}Ps!w}gefha%CnWHb+azJ-p>faA;SpL)FAM4z zyrl{Z)uj}Bmg#&o*TK~Z3zh7#*Nk+yO*qLX%^&@YfUQ7G&-au-3!2Zp5;b}Fr*;+N z)W7<)XP-ubo0f2m=e(1_(w)hr|$@rfYrA&*WRfYzu0Crn<5#&)cQ~YB5gD@JrT`G a-G5I`P=L9Jhz`8 z@9P!lg%I*hOo&Z!lKby^Fr2q_pyDql+=RSj9zr^)_j=X~2)S(EzfTZHe&4iap0JCv zfNUkZ!7jjSfa)T(3hew> zU_T1BBV;+&ibUy9n{NSIR$Sg|XAAtXNP~owq7^jzw#8{r- z;P^8cnXlw-oq9N|3~o*Pg}>+V@ar%BJ(kz!GgnZ&0Z{v1<|V0$Cmz0i$rCN8SuIoQU2dU@Pkm6%gOZI??wNnt}iVO$wcV2n!$`vr&qZ-)ZC3$}BYVu?t z5{IsKMBu;WFBtFS1&w@&`Sh-EUMo(L&kJ>nqQ+2j?vd!2<(!qd`_(KD)6~uAdgo?KJ6)Pnl6q@+sEUN7gFlEatuYZjmIdK618V`e@Y- vwmja?u=m2f_#j5^V1L`X|9`^D-PX4VYbTS~Yn%;d=}=-EKep$i%rpN06h=!K literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_testobject.png b/mods/pipeworks/textures/pipeworks_testobject.png new file mode 100644 index 0000000000000000000000000000000000000000..2c675618a006008f78158fd99b22e2725dc7cb4b GIT binary patch literal 4083 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_trashcan_bottom.png b/mods/pipeworks/textures/pipeworks_trashcan_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..a50c7892d6e61aeeb8c33a178fca308893483a33 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jh-%!Ar`&Kb4+VL)w5|_xN6>F zD5)23bH0J6;H05p07n3i!*)?=hw#HoR_AwIf4Rft@E1cxZUyEPJ3Gr`kB|5LNngOQ z;Q@DU4udieho*vx``wI`gahwcbBaXRmE4@1zNstPbuqpWdLdPKa-vA@u3v2hXANd? i#xg24tZRFe!NTyi%-j6pTSbs#7(8A5T-G@yGywoJ0zhd1 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_trashcan_side.png b/mods/pipeworks/textures/pipeworks_trashcan_side.png new file mode 100644 index 0000000000000000000000000000000000000000..7b081bfa2e05fa8408aa666cfae54fdf1ba21b59 GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`+MX_sAr`&Kb4+VL)w5|_xN6>F xD5)23bH0J6;H05p0EZi|glWQ+hJ#5A3}1e7JbuOKG8d?g!PC{xWt~$(69B@B9IgNW literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_tube_connection_metallic.png b/mods/pipeworks/textures/pipeworks_tube_connection_metallic.png new file mode 100644 index 0000000000000000000000000000000000000000..86a74c6ce5c663661247e23f3675800908c84d77 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`*`6+rAr`0KPT0uXV8Fv7f21N( zA=d0<-%RG;vJwnj838>kP9-}(rR=@OUt(umv1!UC-PcTu8&%Hmtm>LmTx?&-xHYUr zKu>S!6Eg{0O|8Dm&l$BI?fB{1uqjueuKDG=R*A=k3Y_zl%j%NY<9y5)e%#f+5NIuf Mr>mdKI;Vst08zg=-2eap literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_tube_connection_stony.png b/mods/pipeworks/textures/pipeworks_tube_connection_stony.png new file mode 100644 index 0000000000000000000000000000000000000000..1e72d81cfa549913957e8f5c3bd91ca3eae6998d GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EuJopAr_~T6C_wgnB8)kq{H=p z{{MYmo{cfCt}T3hym3KMk%57MkpWBFaYLchS64iR{~H?^EO;P!dD*|?%cgP8e(+pB z-r&f-1i{0Z4BFhgTe~DWM4f#%4+X literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_tube_connection_wooden.png b/mods/pipeworks/textures/pipeworks_tube_connection_wooden.png new file mode 100644 index 0000000000000000000000000000000000000000..c20cd7d553a59319f78f010930f8902d11e92b0f GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`)t)YnAr_~T6C_wgnB8)kE^|Bm zH#RgdsQLMGdgIiY6CWO*|DWg0nI4{>!Pk>kq#sN>@W1}QVKa-aQNJr55M)957)Q- eU+mcz#=xMcBj+0yzfl3`3_)V3zZ%xEr^in)|at8^@vSfn!NED`eLPRur! z&DdP#GUhfmHipeGmr$b92}R=QZ#eJsyzl3EfBb%bcnK(^ow}Nq8UO%Lhugzkw+Q}i zm2F#@&5HfJ1*JO>CkOyQPXey{Y~SkbCOibkG=g-W{6c!fB zSheoaly(9jTz z#S)9fot>Qn0|PxhJ$-$BOeV9etV}2r3Iu}E($e1EUMiJJqtU9Wswyffs;jFR3`Ti* zIh{_gtgPHRMWjAey9MZ1)5%b9FPLXbOf^v zn5vlys_{6&<|aAW)FJ_Xm}|MiCB3_(-c207OtP!7lz>}?XU!UVeN=JhY5F39T=mzu z7eqOAQVs*yO1tf{Snknb!@2g8IK zXCa>YLGv)3R5EvHzTbQn3S#M(B0%_C9jD)3J(h%2%9pX4LV`~~`;3VeHN?!cJ+C60 z2VUkOv>+VpHPpo9)QsfGBE}q|`&D9K|8zw2EIA|(iVaMCPm9goaM%?CDmnK$)Xe4u z0tkRAyiztuTRNkgp!GL!hXvr|;iLL3#OZuJ%@leYe07yCAMF{5jOo z=?p1xH__cIh+^8|;L@|JM`z}33g!Ut1pB9aIn0IsIB+$`E#_jkbHv2{*TrI!l0_;e zx5$6>CoA9B^Am7xdtNkqw^d1(})a%*m8esutl6 z*K&W@ilD*R2>tM1Mobj?MfgKq%ONu}*4^t_4fitCIhLn>QP$0Q-`FzaMJn5#S_!hs zHD+~hi_uhuru z>Itue3^_^xIeg`ym=of-ITcwpCrwB{q~RQM*;FJtzTYNP;LG2hih$c#o#dVqo+5&t zy{QfuIGz$<>hn+DWa~R$u)?YXS^`cxQjBeE9*#lTtJQ`D`U$@X5yl8#Lq)dW9v#sp zB>>{@+@J*5ncu@7as%la*Az;?`}(@JFwa-QU2c!rQzn2cUm*T zD4s8{N=B?SlOe1rYHd~MN`Tde1qP$AQ7%tP9p_eBAhrY7v9pTJ3q|t}Ixn#5cz)zj zsWk`7UlI2*_Tol>dL_me@Ojt@>kR%qh84sd;-bfp)s>&Y?MZD}>3$x1LvcMv`gA@( gRCQ?h{LeV~ej};qpuGaAb!!v=a9bp-9O@nSAH7=YP5=M^ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_tube_inv.png b/mods/pipeworks/textures/pipeworks_tube_inv.png new file mode 100644 index 0000000000000000000000000000000000000000..d24d61cccd4481f5238f44cb7a18fd3b4e1b70a2 GIT binary patch literal 752 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 E7e4RPr~m)} literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_tube_short.png b/mods/pipeworks/textures/pipeworks_tube_short.png new file mode 100644 index 0000000000000000000000000000000000000000..ad5e034922c9a29dd64e18a72974fb4b9d357e4b GIT binary patch literal 760 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCil)2l#}z zK6vn8)v8tZ@87?9^X7&P8;%}5dhXo0+qZ8YKYskonKNtGu0473HPWg7cN{lb?VgV)2DCTxN-5~ z#bd{gUAc1Q;K74iwrttDb?fHMn=fC!eBi)={rmTyJ$v@jrAynkZQHwd@71eU_w3oT zZ{NP%yLa!{v19x8?YnmE+PQNl(2aYR%y! z2>oDZn6mTMYQOA2t_vsbNBw)NcyP&@4O2v$4uxs!1bW}gyrIa*apttoycF*Kgkr@@ z?aoYsOSb7&+*}#U#;_-rW9ccs@0lzUcIos*zF;X7I2-ONyXio*b&lANyeDt6x990R ztISK3eOCHGO7j-e@6Ge-@17K6nP7drRqdwyl=!5*$_=T7u_}vmYy+9<`S}DK%9&-( z$4^(#6Ln$vV0I?K_|!4~Hi01N(2om`&3-mz!nbx;#@yo9mh$Q4B_i*y*ZSu2{GQ+& zEk4nBo=U^zZ*>{U)(_-1oa1B&b3PirSHQYnJR*f9VBPZH^4S%P=S*dlBE-*F?EjS_ z|GmgM>+v)Rea-|8n`PF5Yj>M1H?g^HE!2?G`}n%=$3J^|_y6{<6E;cw9MZmenWaeF z=jM$~KMQ3xe0Xqdy|D3#rN{nm>{`Gy^TS!gOx0!jS2;s(sRq3$Tf8x9oBC{T)l$=s zwg>V8o3eJsHHk?oys|wW67IB6WSegA)RQ7wKUXw-h=?t O1B0ilpUXO@geCx!=8@|F literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_tube_transparent.png b/mods/pipeworks/textures/pipeworks_tube_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..10e890784f3c64acd8af64de40f249fa45fb178f GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFt3?wJp^Voto>5jgR3=A9lx&I`x0{P4VJ|V6^ zdU=)YEg;2M666=m;PC858j!>7>Eal|aXmSq0m$KCVANN*YY1d9c)I$ztaD0e0svkK B7S8|x literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_valvebody_bottom.png b/mods/pipeworks/textures/pipeworks_valvebody_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..43d30d58af4fb2d50fc74eed9a5e3d9336aadb55 GIT binary patch literal 2914 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 M07*qoM6N<$g7gf;$^ZZW literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_valvebody_ends.png b/mods/pipeworks/textures/pipeworks_valvebody_ends.png new file mode 100644 index 0000000000000000000000000000000000000000..69a615f8d5d69eee1d938513934715b895019590 GIT binary patch literal 3562 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 literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_valvebody_sides.png b/mods/pipeworks/textures/pipeworks_valvebody_sides.png new file mode 100644 index 0000000000000000000000000000000000000000..47e80ea3ea3e5550fcad3b4c4b94ce7f548c2f53 GIT binary patch literal 3756 zcmV;d4pZ@oP)Z9^Yik@ z$H<|fp^1u$h=+*v_4JC0i?Xw_n3$LR{r&j)`LwmQp`oJM+S$|6(x9K9OG``Y>guJX zrOV37=jZ2^mzL4c(dg*uFDO>=j-b0l9Q6?>FM6x-kzPF z#>dCGxw*r{!@$45!NI|^v$KbXhsMUmwYIgTrKFjfnW?F$m6nzF_x5pdaddQacXxNx z)z!wv$Kc=Klai9Cr>N!R<>KMu*4Eb8*x1+D*yiWwt*xz(j*ivT)zHz=k&%$m(a^`o z#@yW8>FDXs&d<-!&zhN;uCK4Rx3`&@nv0B!!ok9Cdk;^OJ)>E-3*;^E@v=H``@mEhpt$;rvp)YYo0s@mDw*45U~(9prc!RhJfo12@l zv9Z(B)32_s&CSfn$jQ6AyQik7wzajoxw*5lvP?`&VPRpz!^GFu*yQBp=jZ0i%FE^D z<>KPv($mt*%gf;4;H|8zxw^WmtE>9@`j?lN-{0S?tgPYT;ndXB!otC@v9bOA{gacE zN=i!7($d4j!`0Q*_xJbt`T0&xPTASn+S=M*Utjh0_5S|;l$4ao$;qasrt|aj|NsA8 zU0v(z>+$jNU|?XKot>ztsHv%`wzjr;d3jAuP1xAjpP!${$H(pM?eFjJxVX5jt*yPi zy_S}i(b3U(czB?opqQALo}Qk*zP`f3!d_lp-rnA%q@>Eq%EZLP+uPfFdwa&l#<{t< zTU%Ss&d#y1v3h!XrKP2-tE;uOwUCgIqN1X*va+wQua%XR&CSi3nVG!2yiZS0oSdA% zz`$HwTzq_dkB^T~P*8n+eUXuol9G~AQc_u2S$=+gj*gCujEqrHQB+h^fPjFFjg5+m zidI%ue}8|1f`Wm8fm2gcgoK2NiHVDgi-UuMg@uJ$T3U#Rh*(%yhK7b$S65Y4RfmU% zFX$rH000YDNkla(Q&rYgS+z|K^dKp0V_~<}0NOh9bvN+Gh3*9^Sy0t@Ism9QYpcpmvTQKW zO4(oxe#c5JRLMf7?Qz4%##ygwDK&=gMOEp+cxtQzs6i*ibkFyLHzn1eQmXdU2$HUy zw6w}VE-QctY@-@iNzv08)G+oFSiSPqV78}Kl7Viez>lxzx>Xj~g`H)pNCKU~a&|RP zDnEy5lOVGToaCsx0dn z)ixbus`CA;QTb4mhU|1pcYA&^7iefvG8JUtPG?0hNak9_tZLZfxq(V59l#n!p^~72 z1z~Yr>9N|{$`WYez}8iubyiiaD$&07gG~E2MCE5mQK>1YQCCpYRwK}3NVLc_v<{H0 zp?p|zI_T;mP-<&eRSVD(Jy5Dq^#=BIw@7U0Z{Y*q%5=kMG}Kg44H9rrY^!`2rJ@Ql zFl8&KUE4+01$XvB&`mP%RTOoLVBQAZ>TOkbu4@#nN_DHCQo7Nzvt&>VvT*`Ms5%H3 zz_G8if@F(sGTR+YRpX*t>4n6HatruW7|_zfhCqB6W*AmI)&(TmE3&GaRY|W`^a_== zVBIR2hHh``s=Csumy9#5?YAi-fiFHx`(SolgH-_inANRTFM;)8`o}t%1%It+RrH`; zP=ZPlm{aH~Oh(Z##`YisFTSd(qLB^i;&&Gb%={pMjZwg~&-sZBbL2zJ88kFoc#~~c zQ`#>AztGc$>cP(Fslo>l@~po(laWDb9XEMS?erK^TgQ)%e2@4r)J7^hL4z#L_>u-GE z!JS8rKe~PIrkhWmKDMRoV?t8W4u$kk8n<1K64wJe(2?+ zj~Q$HCqBOEoj-p1>swC9ND2{gR62qaQZAapwM@ZSc|NB!7Bj%R!;dZ<`1~sWgmK@` z)chr1dGEoK!2iX)ahhYki<)7Wj(Ehw5tl^f*eRQi(+Mq7^DFv)0Q^s1ca!npL%$FF z-c9d3dHP)7zsE$UX^8`&5V9O~Ql6KwDVZm!6?@3yG4Q|ptE-;dB?-X3jgVvKe6X~Z@lnY+haru zYLT`G=dCo3(>9Ajj&o7wq$G4S$^YHMA2J@@{*_hz6Zh8qW{JF}5Y&|pElbH5GO@$y zJhDj4+5!WA3*JBC~_SbVwd&T#9x7SJnDgY&LGc z`E!u}Gb{Y&{ij~x*D&sR=8Q*aia2hkaVVF|k%t)WgzkmT8UDL9|Fiq=HV$46^K;pr zHT_p^3qxwTbi@UfdCBHwWTJF5OwD=@Eg8j={8O9ne$Kf3PME)!{%D2&saI}$br%tN zM68t2645lZaM~v`&Pb+lRC0L@naJ;{&9A-iLF3MI@A|-=n*Z1Re**lc&Wz=glb1S(KvO%waUn<_G+9AH2mlw&epW{rlGbf2sLzqg>*WlqE&HLmBK%k;*c< zI+7fEDzCj}!vAZ}y>ZJ+#+z6B2l~HK^G|xE#Yxz4!+bszi-L;KLz1P$feCjxvd;Od zo32{tUwr9=abnMlEBUYLKl#`$RK_yKCH9br+Gz(nn0d^@xf^4Q^F`?29TWUr#!D}* z=$~5S&v8mGjvSW9F{TkM(@q${{>1UM(h+V<@Pz-GKW41yf9>H_{)@|bOe4WXj2tQQ zTt>O%WlpihCFd6RCiy>pX3L$%s{T6vbl9F}s3}T}NKO~8rhTvUWN3P&6ivj3;Uxd& zV|Si3UbuVn{-@6HFF*Z!XnA1=MUv(`GOxyDSuj)*$0fs%xFb#`{6F*c)0f|D++EM# zS^jme-wxf6=_UjnojV?PJiy^+l|d<^Q-w~IFLKJM>$92!mt@T zt`o~X>Nu$!Qp%}0sekg|?R$+Yeq)7y;+|FhFu{?GqmG58=UhlF%#lRG!cl}G3FLgX2L|H~;KEip-V$$ax2_+G1MwA{#XZe!{|MQ~lj~E|X z@qf>U*Z5H>P~RL%Gs5Yj6>;f_8N|H&0AGyZR5IBF|Bb)-#G}WJiTbYu{!%#h1Zv7f z=0u$xA#7&Up>Qsi9Gfh5nrxE4-?|&<7n7NgpX1$hOG<3kjHJAM=9ro zyNio5#UwrJANb?vJ!Gu&%ZF<|Y7Vhv!jq=8NWxrr+>;2lxOBXj;&KOF=l5Rn$nhf& zJ!stY#n7}D6t@4U}=;<^t{@+FMRh%m;j zG9EUibenJhR(;gRf@C9_Jn8b*AE%5<2f zBBn9!!%Qn=h$*@33@QHsI~1k6(8wn^0I zVV>NmwqJc>xOdH(!r{x$#L#rI$T z{%4It8}w0W_G8o>@l;64T{$1hQpBmZ3)X?lE_LHG`9b~nfA)W${h{&vt)HLJFBvzl zwfeCv7lk?RFfX+7a8bI>4uR4Okd>o#{(<}71^oXRw_dq{&pQ^fOb;$W2a{dwX+d)Y zH#^)`DQcP|_1?Nx{|)cEzUKeOSl-CHQJ!7{R_mQ71Tk~i%fzIiBO=-t9hY6S{Woj< z8{YTT75=}C9h3auyF&rT2gep1g@+NGuW_5lB4s%>=@6A+JG`Xkzx3|+tnvS4Y}6l) za>ulIXI@HvxC}cE%2QmTaLB^fBVLwn2>$7A&sa!go(=y({heLSac{6b;Q{hMk)vnIp zI=|0Y;k{^uzxDY;Z{beZj|io#W18(4T3})dXIh_LP3i|g(&AoSW_K?bq1Y@bK{5+}zyU+_|~A!^Fe#^6|jG z!1(z0v$M1H_4NGx{o>-|h=+)Zii*a@#fplHrKO~&rl+Z?sQ35wOiWC5b#+}`T~JU^ z)YaAM>gu1LpxWBn*Vxz5(9y=m$JN%>?e6Z$$;syD=dG=+-{9Zb+1k+2(cRwN@$vDm zuCD0m=+Dp3kB*M+?(MFxud1u7`1tsYjElFox3#vmlai9GtgVNJhnkt0adB~XcX!s- z)~2VY;o{N)V=fT3k(9qDav9adn=Euj!&CSg9_4LTd$-BF| z`}_O4xw*ErwX?FaR8&+>PEJ@@SWiz+)YQ|Glaj;3#M9H%=jZ0-<>l$<>DJZOb=S(#p!q=;-Oo%ggKP>+bIE^YikptgN}Zx}Ke$`uh5to14PH!j+blc6N55qM}?} zT-Vpw>FMc}l$ETktm*0L!otC;tE%$y^8Eb#u(7e1mzUz<;^5%m)zsCIkdf%<=`IMBDSy@@h z$;qasruX;w{r&w_RaL2}skXMZ^Yin^$H%CssGXgi;^N}#>+86lq=?d`t4zQV%7(b3WG@9)IK#LCLb zo}QkdprE9rr1A0b{{H^P#>Tn1xv{aa|NsA%mX@WZrK_u}&d$!YwY7VDdzhG*S65fE zva+wQuX=iV+uPgC&CQ~sqP)Dk-rnB8z`&4@keQj8oSdAMm6d&ceSCa;kB^U%l9G{; zk$!%Dj*gCujEsPQfQ^lfe}8|9ii&}Ofr5g9goK2NiHU=QgN22Ki;IhfhK7iUh=+%V z-g*H<000VoNklRa8HP{HVitEI#v(DIIZ=Z<(GqbtF>0cMrDz0!0u$L3 zQHY8dAt8X4sDvmCj2eYurii1Kg5}Jxbn^q*3#x_!o0bNI9_HTLeeXT@)Y+Gu+dVUM z^QZqk{eIj1zW0F6&d%MPyFYqj)u4@^-nO;>S|5@qiy4b84Mo=d$gH}^|W<=>n=Xy6-;zh*%!xK1e5zOqFVOCgyLmkV1U7~+Ij-EZeB z=e~cSyYzOHT=HY9HR$1g==ks5@Y8qJDHc#Ghg*)b6k!+?q2^E$;`>Z%$l_~v9Pe^` zIY^YT+FDTISKYnwjoW^9!;*K_P4jUZ78DC1q{>ENNQX)8bE~QK<1&@Gdfq@#;eVO( zzhCmgx@l`L_q1OOn3c%savM+`isphL6e@_2uIG6S()jP*ILpOf;Wxxs+c4RiVCfT? z3(DMJDip##pLs`xKXgTcBxA~l!cfKt=ZTTRV;&_UgjVBvzFY#U{x@*eFZ%Qk z4K8a>Ql6zbrl_`abJk=s)(BtQvI%^ced_Hxz8efm^|Ad5M_&D8S`cY#mebN%bn ze{d=mvGKwnCZ<5R45Bzt7A3y&xy(k4?5*SX{%8)kZEM>985gJgBhO74LBkLgMUq6) zv&>CD7P3f@hcD*xG-l)4%u!DZgUMh(}%W%VVjv^kpbxB^7KAC3JJ- zF-i%Fd-&g_`~$~#tOxy<^z?7=rWI4R>_2SEp};Cc-33eK={RVMTsq4`VQipnjKg02 zKUMVC9|3C@^zkblzuiY(sF-BK?SX8pI1CjO+I^FP2wOx@*Tui{$S$y8bWimv6f+V<(g-Q3s9fA~emzs}vfcyce2Qkzl{3uU0Md90ZSW9zxejLJ{F+QXmy=Y_9< z#kU?BeBO$cx9mTB&bU*Sjyxt5(Tr2=SxjLYg3UP0`6%LH$>&;>tjqt^hkN+X_6@xq z96dkPACcDYl&41?+nl&MlQL08dzw>0ltd&HDw0w~A=9R(e--`@FW>$asPMO>{GO$+ zAKUzGA?8F&=8=L#Z61aY7kGjMRnjP82rHf7_q}}ATNi@C^Pj8g?|C}q2e@g;Ny#D| zGGjF7)_3cjwONlqUXZj@tAFtEZ@vceADmL7Ki~`K)R9Bo=rV?kZNpSCq6neH+K9z{ z`7a!Lm*ejRE2fS}>%Zsc|ETa^dwefs-G&SkVSr0IVO(3kXb~=x&$-aDFaG;d{d)(1 zsiPh}{NlJVz5F*~E*Ej^H^+=&D`){jq`OQhwwxAGG(7C(UrYJ#elZ?wxzo+hDN9rS z?~Z>QA?8J_{A?Rp(f{K&j~~nusS@I0 z&WvRkdlUzxIV@=m6C?CoQd7TA27J5u0xk^B zf)!7&Rlahg(bK;w|K$ZEL0|vA_-o4Vvr1D#+y$|s$hiA9CDtanB5|9MbG>|SP5j?} zd2Hl1aB8)GJ^K4Tb{kO;RE&^nLoy?oM6uNzlh93gB&_G=e`p{7)wVrg&(g1I^gmvm zbq7;JYG`cbvdIlsPH3Fa67!g<2vSN_CY}EpejM2LRjvN&vqKZZB;*Q0%9gcGYPhm} zSyM4b;c^|y2ohQof68wMJ^D|+RppO#DaaD%E1(T^Q%6UBSx3IrC`LWE*n}tITK?B# zhKvPO{XYI$RA}QiCk?ekwNAXebzaA$4vqZSXqmI3jB5E)w~yTqHjl5>U%vx+F)G?b zyR(*Db@_z$Gn!iRhJ+C*BNCMasfmBg^M~&o1;(fIcY;422L%+FC@Ih|$>&`G+S^;H zg@{QE31qm2-+uVfQB%Qy6ZK2^F1L`2DrQ1hGQ53qOXIx8mV97~A=YKa1oLb4_ivfH z0^IwP3jdqSs{8>$6AhE1M|B)t-r6{!HJ{H*k0yytY{(?7)!*{L%K6~yC#(FfD&Jj< zrIf}bq%ENxEiEnW^IAIy(nRuRX<}+m@cXy??dtg-f(xthU;3{qUoz4Lep&ko#hJ!s zt@)0ov+_JvdqoDit>p7s{y*mpJ_Ks>PyLTud(!4~hKEVb8=Eg%jA5=vIgM}W0c8gObM>xH{E>b*2Unyg>`(A zD^ty7tbH#-+B=#$T08Q2_lfH;hK!m;tdC!@>BB=u7q0;)@rv%n&0ZlBKqb(`rZYS8 zjg#65Ehrl~`)zq#&u^FxKD+GFTHd&EDLHc|JOj&<^Z9v`+uJ8-s+@0eH#?@hxBidZ zeCX&+8>Wv2t9SKVU*~@VW4LGBX()-aTJsHOHZ(Lr25I0{ouM!ob53vmM{oM~v~}-* zUHvNlyU)Ku?OeI#rs$eBFW-=FKdq_N>Le3<44~y6CBxD@4tmCaDtrM zZzKLyEvMxhS|;X$oNR`rgyeF=+N$~~zh>I#1vC4Dopt)w_yM%JlE6|kF)u%{JwK_b z1;<$oGw#^o2=>JwJ9wFr*~Q*Gs0XyX@{-VVm;_jz8$hf5zwqDgPHqg4P|K(O3vvOCf;_{Bp$glw;+*2;PTpFtJUw^4NiJL?4$t|-KP71dvC)g(&EpP;O*t>oq9;^E=d)zs0@ z(e3T+*45SU@bKK++}zyU!^Fe#^6|jG!1(z0v$M1H_4NGx{o>-|h=+*A#>JYNnu>~x zrlzN-rl+Z?sQ35wbaZraadBN;U0hsT>gwvXwzkyN)YH_{#>U6(?(XL2=gG;*-{9Zf z-re!>@tK;L=;`Rs&(DvJj_&U5`1tsYjElFox08~RtgNkvhKHr4q;++5US3|-*4E+T z;+B_}*x1+3&d;Z(sMXZf+S%Hws;a@l!NVTU$*{O?P*9)YaA3*x2Rd<<`~Kxw^XI;o_2$lEcHq)6>-F=jQ3?>E-3*(a_M+ z)6&Yy%joFo%gf8_>g(?A?(_5Vo}HentE>9@`oh7&m6nxuc6OnmqSx2h>FMc}l$ETk ztm*0L!otDw^75~*udS@Co12^b{QR)7v6`8hPEJl)Sy@z6RMFAV;NalY)YOrXk>}>; z=;-L{>*~Y9!%SyxVYlt;_K_{$H&LLy}eac zRe5=N=jZ32pP%93;q~?P*x1l?|?Y_Rg!otFMczDs#(eLl?#Kgo`S6ABF+RDnx ztE;P?o}QqfproXv@$vEg{{C24Sf!<oh|NsA%mX@`(wX(9Z&d$!5 zn3#KedwP0$+uPgC&CR^LyrQC_-rnB8z`&4@keQj8oSdAMm6d&ceUg%re0+S5kB^a& zk$!%Dj*gCujEsPQfQpKWe}8|Cjg5hUfr5g9goK2NiHU=QgN22Ki;Ihhh=_)UhKGlT z7rDXG000VpNklRa6~}KD60@&rq9zzCF``M-AZke>NHkHS0k~x&i{hW&dxoZd)~cg<tTZHQ^oPB@2-#j@T1sEVLRA;}QQh?G+4_9TwkFeO6aEOQ~OFjZ*e4F)y-=T-g> zi=SM#c?}VP4NDPs3VB`OB4%URS~QeljS;dZepk;62&(a4yK$P2zs7HX#JV`$pAr>P zRfsCW5GFMuArpFrF}&;Wzw3CNfb(CR-lOmH_xxwvm4r-XA&ONu;|5EWVH8@zDP*DQ zP8;-fQUdo(zjnwp&riL&#vd7-BE`85u{4ZxDnx3O40yn(jIpz%k*}1&%Kr_S_OpKd zBik!BP)xM50@uvC83kvuS!ZNuUByHpZhz$E2EH2%t?EC$xR1Zz1<)|cgu#|^EwM&L zX$;P?f)-TuBB2T52vSp|LPZITv_omAL!sIePWLzP`@cIEjM`c~|H&6r`CA_xK83|GD#Ik6&?x=XZoCh&5Myk~`cEwZO5)()v3osdOcTZA1LKj_n4s2lew)JU_xjj8a02 zNLlCzE+&xEBvD2x#gxGH@mKk`!JxkSfAPnMjy^GBpG~b&sdOe*l2VfmRT6|s2s2D_ zj#X=2{8fGxxZ{F>{GS-{n@2IxOt$k7AyW2t0+pquRi6YG#~$C3 z`a07J)y4)^FiEvSG?qG1N+&V5W*~ph|L2sKz&U;AH)7wC=Z|msv^Z-Ek5>7;zFP`P@x;d57%PMe{dngY7f>vUiZ$|| z96SJK-88&TfA4DS)saVi>vE2a%MhkH)s!;oT*Bckjr{dsMK%AYM(q3PzdZlY>H~q; zk9oJDK*kX%+ms9I!jeOzLO&4Fs(${48ow9#`*ZZEyT{e|y{iu#lrw~cFl>dK6DL`b zU}U>Y89KpAD47)Z@y}KHuYP4bSa^-^pK(ii^$&i65DyYw_T6u_5gD6?j+84TtoC7G zQ(Vu#_qFjKf@|*d{j+Usjc;mdIdx21bIXLbrA_&ce6FLZX(=NSZH>#8;M7PvgVyE$ z-ri5QoC`c(?Vl~5{%!SvT&^vj8toS)Y} zczW}^j(kggX-8YzrI)p}%xi0&*xaEIbXE`=`wmZ}3w-~d(a(RhZ6DaTcz; z93S~*V{-ZVx%mt73tDo`6XrEt%3>yIWEKZ&E1)!8OhY?o(Zx?)SQLCGO{P7oSEgkpI_nm&lar#x4(5!J+Ik* z(i#-A5!MoAR0X=&Aj*o`CEkAfYBcg2?f|R$>)+$we7lsrxs!pxm4dZN!OvsMwD&E3 zXG13X;=k4NBRAYJ2)w}t?=CXBEvlqFG?%fx1oH3}2h?!V)g z9Z9g~e^ljPJL}BH9$!0nE7&==!T$>xE(;=TO;&}OSU?nLl(k8`Tsd-y3$*L4|HuuS zAA8dCqd@KbQsA31k3CB>ynD{<3qB*kHW*wK#YqL zDR;pU0hOeV_x?+yIF{0+v7ZFq z<|PdI@1-J*6J&`%*4KaXEB*TaJs;HbRsV&B#QqwKET@KP;woAQMwWSb=cG_*F@3V*In4?-z9Xq%bQwtLdGeKy*YTa;JEGD5bE38K zPlO~(oqx8Nlo=u%iIHVU6$5_ex_bT2J>aDG!!8yv*=@QH`}a0pE-Mvp@L($@mZ;bY zpY1^XYkVi@d4Hxg{tG*I&6F{UQp&j~g<%o}=N?E|tHJYD@<);T3K0RYUy7XbhO literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_windowed_empty.png b/mods/pipeworks/textures/pipeworks_windowed_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..3b64478865430fa10593f02ef07ca16dcd8f7af7 GIT binary patch literal 388 zcmV-~0ek+5P)_upP!$Ih=`t@o{Nf#m6Vj(+S-eYi;9Yh{QUf;rlq*Jxc~qE$;rw4`}>NE zi|FeAG{E?ZNoa*jM<=FRH@VTjTi3HClPR=UU?9HJkej zev&mJ=jF7o6ko|&Kv=WMU_7g|af!g)Z}Q>Dxqx(iJ4ShN2ko0Zat8Xx_B*FA?lpOu ifd2dW40x*3a`*-qQzx$lCL{;|0000C>k#Te@uO)G6)l?bD`Cn>Tk}cURZcDN}CVy4BqcWOhxM zFk#M|IWuO=`19w_vSmwm?AY=D|NoOGPyYV>y9=nI8>o2dty{Nl-n{ww^XL8h_s^X> z_x0=7>(;G%^ytxn0|$C~dfM9B)~{cG@#4i3Cr-?pH*f0HsoS@2U$$%+&_&9gw|@dD z{gNQRV4$%i0EVcg7T<=I6Wz|2O_UXWAp495?;L i|Gzaybp&Qu{ANh*Qd)I>Zf^?EWelFKelF{r5}E)Hz~{yQ literal 0 HcmV?d00001 diff --git a/mods/pipeworks/textures/pipeworks_yellow.png b/mods/pipeworks/textures/pipeworks_yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..44ea445ab34af3f4cb3715985464e8182f22eda6 GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx| 0 then + yaw = math.pi + pitch = 0 + elseif dir.x < 0 then + yaw = 3*math.pi/2 + pitch = 0 + elseif dir.x > 0 then + yaw = math.pi/2 + pitch = 0 + elseif dir.y > 0 then + yaw = 0 + pitch = -math.pi/2 + else + yaw = 0 + pitch = math.pi/2 + end + local virtplayer = { + get_inventory_formspec = delay(wielder_meta:get_string("formspec")), + get_look_dir = delay(vector.multiply(dir, -1)), + get_look_pitch = delay(pitch), + get_look_yaw = delay(yaw), + get_player_control = delay({ jump=false, right=false, left=false, LMB=false, RMB=false, sneak=data.sneak, aux1=false, down=false, up=false }), + get_player_control_bits = delay(data.sneak and 64 or 0), + get_player_name = delay(data.masquerade_as_owner and wielder_meta:get_string("owner") or ":pipeworks:"..minetest.pos_to_string(wielder_pos)), + is_player = delay(true), + is_fake_player = true, + set_inventory_formspec = delay(), + getpos = delay(vector.subtract(wielder_pos, assumed_eye_pos)), + get_hp = delay(20), + get_inventory = delay(inv), + get_wielded_item = delay(wieldstack), + get_wield_index = delay(wieldindex), + get_wield_list = delay(wield_inv_name), + moveto = delay(), + punch = delay(), + remove = delay(), + right_click = delay(), + setpos = delay(), + set_hp = delay(), + set_properties = delay(), + set_wielded_item = function(self, item) inv:set_stack(wield_inv_name, wieldindex, item) end, + set_animation = delay(), + set_attach = delay(), + set_detach = delay(), + set_bone_position = delay(), + } + local pointed_thing = { type="node", under=under_pos, above=above_pos } + data.act(virtplayer, pointed_thing) + if data.eject_drops then + for i, stack in ipairs(inv:get_list("main")) do + if not stack:is_empty() then + pipeworks.tube_inject_item(wielder_pos, wielder_pos, dir, stack) + inv:set_stack("main", i, ItemStack("")) + end + end + end +end + +local function wielder_off(data, pos, node) + if node.name == data.name_base.."_on" then + node.name = data.name_base.."_off" + minetest.swap_node(pos, node) + nodeupdate(pos) + end +end + +local function register_wielder(data) + data.fixup_node = data.fixup_node or function (pos, node) end + data.fixup_oldmetadata = data.fixup_oldmetadata or function (m) return m end + for _, state in ipairs({ "off", "on" }) do + local groups = { snappy=2, choppy=2, oddly_breakable_by_hand=2, mesecon=2, tubedevice=1, tubedevice_receiver=1 } + if state == "on" then groups.not_in_creative_inventory = 1 end + local tile_images = {} + for _, face in ipairs({ "top", "bottom", "side2", "side1", "back", "front" }) do + table.insert(tile_images, data.texture_base.."_"..face..(data.texture_stateful[face] and "_"..state or "")..".png") + end + minetest.register_node(data.name_base.."_"..state, { + description = data.description, + tile_images = tile_images, + mesecons = { + effector = { + rules = pipeworks.rules_all, + action_on = function (pos, node) + wielder_on(data, pos, node) + end, + action_off = function (pos, node) + wielder_off(data, pos, node) + end, + }, + }, + tube = { + can_insert = function(pos, node, stack, tubedir) + if not data.tube_permit_anteroposterior_insert then + local nodedir = minetest.facedir_to_dir(node.param2) + if vector.equals(tubedir, nodedir) or vector.equals(tubedir, vector.multiply(nodedir, -1)) then + return false + end + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:room_for_item(data.wield_inv_name, stack) + end, + insert_object = function(pos, node, stack, tubedir) + if not data.tube_permit_anteroposterior_insert then + local nodedir = minetest.facedir_to_dir(node.param2) + if vector.equals(tubedir, nodedir) or vector.equals(tubedir, vector.multiply(nodedir, -1)) then + return stack + end + end + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:add_item(data.wield_inv_name, stack) + end, + input_inventory = data.wield_inv_name, + connect_sides = data.tube_connect_sides, + can_remove = function(pos, node, stack, tubedir) + return stack:get_count() + end, + }, + is_ground_content = true, + paramtype2 = "facedir", + tubelike = 1, + groups = groups, + sounds = default.node_sound_stone_defaults(), + drop = data.name_base.."_off", + on_construct = function(pos) + local meta = minetest.get_meta(pos) + set_wielder_formspec(data, meta) + local inv = meta:get_inventory() + inv:set_size(data.wield_inv_name, data.wield_inv_width*data.wield_inv_height) + if data.ghost_inv_name then + inv:set_size(data.ghost_inv_name, 1) + end + if data.eject_drops then + inv:set_size("main", 100) + end + end, + after_place_node = function (pos, placer) + pipeworks.scan_for_tube_objects(pos) + local placer_pos = placer:getpos() + if placer_pos and placer:is_player() then placer_pos = vector.add(placer_pos, assumed_eye_pos) end + if placer_pos then + local dir = vector.subtract(pos, placer_pos) + local node = minetest.get_node(pos) + node.param2 = minetest.dir_to_facedir(dir, true) + minetest.set_node(pos, node) + minetest.log("action", "real (6d) facedir: " .. node.param2) + end + minetest.get_meta(pos):set_string("owner", placer:get_player_name()) + end, + can_dig = (data.can_dig_nonempty_wield_inv and delay(true) or function(pos, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + return inv:is_empty(data.wield_inv_name) + end), + after_dig_node = function(pos, oldnode, oldmetadata, digger) + -- The legacy-node fixup is done here in a + -- different form from the standard fixup, + -- rather than relying on a standard fixup + -- in an on_dig callback, because some + -- non-standard diggers (such as technic's + -- mining drill) don't respect on_dig. + oldmetadata = data.fixup_oldmetadata(oldmetadata) + for _, stack in ipairs(oldmetadata.inventory[data.wield_inv_name] or {}) do + if not stack:is_empty() then + minetest.add_item(pos, stack) + end + end + pipeworks.scan_for_tube_objects(pos) + end, + on_punch = data.fixup_node, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local meta = minetest.get_meta(pos) + if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then + return 0 + end + return count + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local meta = minetest.get_meta(pos) + if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then + return 0 + end + return stack:get_count() + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local meta = minetest.get_meta(pos) + if player:get_player_name() ~= meta:get_string("owner") and meta:get_string("owner") ~= "" then + return 0 + end + return stack:get_count() + end, + }) + end +end + +if pipeworks.enable_node_breaker then + local data + data = { + name_base = "pipeworks:nodebreaker", + description = "Node Breaker", + texture_base = "pipeworks_nodebreaker", + texture_stateful = { top = true, bottom = true, side2 = true, side1 = true, front = true }, + tube_connect_sides = { top=1, bottom=1, left=1, right=1, back=1 }, + tube_permit_anteroposterior_insert = false, + wield_inv_name = "pick", + wield_inv_width = 1, + wield_inv_height = 1, + can_dig_nonempty_wield_inv = true, + ghost_inv_name = "ghost_pick", + ghost_tool = "default:pick_mese", + fixup_node = function (pos, node) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + -- Node breakers predating the visible pick slot + -- may have been partially updated. This code + -- fully updates them. Some have been observed + -- to have no pick slot at all; first add one. + if inv:get_size("pick") ~= 1 then + inv:set_size("pick", 1) + end + -- Originally, they had a ghost pick in a "pick" + -- inventory, no other inventory, and no form. + -- The partial update of early with-form node + -- breaker code gives them "ghost_pick" and "main" + -- inventories, but leaves the old ghost pick in + -- the "pick" inventory, and doesn't add a form. + -- First perform that partial update. + if inv:get_size("ghost_pick") ~= 1 then + inv:set_size("ghost_pick", 1) + inv:set_size("main", 100) + end + -- If the node breaker predates the visible pick + -- slot, which we can detect by it not having a + -- form, then the pick slot needs to be cleared + -- of the old ghost pick. + if (meta:get_string("formspec") or "") == "" then + inv:set_stack("pick", 1, ItemStack("")) + end + -- Finally, unconditionally set the formspec + -- and infotext. This not only makes the + -- pick slot visible for node breakers where + -- it wasn't before; it also updates the form + -- for node breakers that had an older version + -- of the form, and sets infotext where it was + -- missing for early with-form node breakers. + set_wielder_formspec(data, meta) + end, + fixup_oldmetadata = function (oldmetadata) + -- Node breakers predating the visible pick slot, + -- with node form, kept their ghost pick in an + -- inventory named "pick", the same name as the + -- later visible pick slot. The pick must be + -- removed to avoid spilling it. + if not oldmetadata.fields.formspec then + return { inventory = { pick = {} }, fields = oldmetadata.fields } + else + return oldmetadata + end + end, + masquerade_as_owner = true, + sneak = false, + act = function(virtplayer, pointed_thing) + local wieldstack = virtplayer:get_wielded_item() + local oldwieldstack = ItemStack(wieldstack) + local on_use = (minetest.registered_items[wieldstack:get_name()] or {}).on_use + if on_use then + virtplayer:set_wielded_item(on_use(wieldstack, virtplayer, pointed_thing) or wieldstack) + else + local under_node = minetest.get_node(pointed_thing.under) + local on_dig = (minetest.registered_nodes[under_node.name] or {on_dig=minetest.node_dig}).on_dig + on_dig(pointed_thing.under, under_node, virtplayer) + end + wieldstack = virtplayer:get_wielded_item() + local wieldname = wieldstack:get_name() + if wieldname == oldwieldstack:get_name() then + -- don't mechanically wear out tool + if wieldstack:get_count() == oldwieldstack:get_count() and + wieldstack:get_metadata() == oldwieldstack:get_metadata() and + ((minetest.registered_items[wieldstack:get_name()] or {}).wear_represents or "mechanical_wear") == "mechanical_wear" then + virtplayer:set_wielded_item(oldwieldstack) + end + elseif wieldname ~= "" then + -- tool got replaced by something else: + -- treat it as a drop + virtplayer:get_inventory():add_item("main", wieldstack) + virtplayer:set_wielded_item(ItemStack("")) + end + end, + eject_drops = true, + } + register_wielder(data) + minetest.register_craft({ + output = "pipeworks:nodebreaker_off", + recipe = { + { "group:wood", "default:pick_mese", "group:wood" }, + { "default:stone", "mesecons:piston", "default:stone" }, + { "default:stone", "mesecons:mesecon", "default:stone" }, + } + }) + -- aliases for when someone had technic installed, but then uninstalled it but not pipeworks + minetest.register_alias("technic:nodebreaker_off", "pipeworks:nodebreaker_off") + minetest.register_alias("technic:nodebreaker_on", "pipeworks:nodebreaker_on") + minetest.register_alias("technic:node_breaker_off", "pipeworks:nodebreaker_off") + minetest.register_alias("technic:node_breaker_on", "pipeworks:nodebreaker_on") + -- turn legacy auto-tree-taps into node breakers + dofile(pipeworks.modpath.."/legacy.lua") +end + +if pipeworks.enable_deployer then + register_wielder({ + name_base = "pipeworks:deployer", + description = "Deployer", + texture_base = "pipeworks_deployer", + texture_stateful = { front = true }, + tube_connect_sides = { back=1 }, + tube_permit_anteroposterior_insert = true, + wield_inv_name = "main", + wield_inv_width = 3, + wield_inv_height = 3, + can_dig_nonempty_wield_inv = false, + masquerade_as_owner = true, + sneak = false, + act = function(virtplayer, pointed_thing) + local wieldstack = virtplayer:get_wielded_item() + virtplayer:set_wielded_item((minetest.registered_items[wieldstack:get_name()] or {on_place=minetest.item_place}).on_place(wieldstack, virtplayer, pointed_thing) or wieldstack) + end, + eject_drops = false, + }) + minetest.register_craft({ + output = "pipeworks:deployer_off", + recipe = { + { "group:wood", "default:chest", "group:wood" }, + { "default:stone", "mesecons:piston", "default:stone" }, + { "default:stone", "mesecons:mesecon", "default:stone" }, + } + }) + -- aliases for when someone had technic installed, but then uninstalled it but not pipeworks + minetest.register_alias("technic:deployer_off", "pipeworks:deployer_off") + minetest.register_alias("technic:deployer_on", "pipeworks:deployer_on") +end + +if pipeworks.enable_dispenser then + register_wielder({ + name_base = "pipeworks:dispenser", + description = "Dispenser", + texture_base = "pipeworks_dispenser", + texture_stateful = { front = true }, + tube_connect_sides = { back=1 }, + tube_permit_anteroposterior_insert = true, + wield_inv_name = "main", + wield_inv_width = 3, + wield_inv_height = 3, + can_dig_nonempty_wield_inv = false, + masquerade_as_owner = false, + sneak = true, + act = function(virtplayer, pointed_thing) + local wieldstack = virtplayer:get_wielded_item() + virtplayer:set_wielded_item((minetest.registered_items[wieldstack:get_name()] or {on_drop=minetest.item_drop}).on_drop(wieldstack, virtplayer, virtplayer:getpos()) or wieldstack) + end, + eject_drops = false, + }) + minetest.register_craft({ + output = "pipeworks:dispenser_off", + recipe = { + { "default:desert_sand", "default:chest", "default:desert_sand" }, + { "default:stone", "mesecons:piston", "default:stone" }, + { "default:stone", "mesecons:mesecon", "default:stone" }, + } + }) +end diff --git a/mods/plantlife_modpack/mushroom/crafting.lua b/mods/plantlife_modpack/mushroom/crafting.lua index b05762b4..6b65cda3 100644 --- a/mods/plantlife_modpack/mushroom/crafting.lua +++ b/mods/plantlife_modpack/mushroom/crafting.lua @@ -22,7 +22,7 @@ minetest.register_craftitem("mushroom:brown_essence",{ description = "Healthy Brown Mushroom Essence", inventory_image = "mushroom_essence.png", wield_image = "mushroom_essence.png", - on_use = minetest.item_eat(10), + on_use = minetest.item_eat(5), }) minetest.register_craftitem("mushroom:poison",{ diff --git a/mods/sprint/README.md b/mods/sprint/README.md index 755b75db..6e73c21f 100644 --- a/mods/sprint/README.md +++ b/mods/sprint/README.md @@ -1,9 +1,10 @@ Sprint Mod For Minetest by GunshipPenguin -Allows the player to sprint by double tapping w. By default, -sprinting will make the player travel 80% faster and allow him/her -to jump 10% higher. Also adds a stamina bar that goes down when the -player sprints and goes up when he/she isn't sprinting. +Allows the player to sprint by either double tapping w or pressing e. +By default, sprinting will make the player travel 80% faster and +allow him/her to jump 10% higher. Also adds a stamina bar that goes +down when the player sprints and goes up when he/she isn't +sprinting. Licence: CC0 (see COPYING file) @@ -12,6 +13,13 @@ Licence: CC0 (see COPYING file) This mod can be configured by changing the variables declared in the start of init.lua. The following is a brief explanation of each one. + +SPRINT_METHOD (default 1) + +What a player has to do to start sprinting. 0 = double tap w, 1 = press e. +Note that if you have the fast privlige, and have the fast +speed turned on, you will run very, very fast. You can toggle this +by pressing j. SPRINT_SPEED (default 1.5) @@ -39,6 +47,7 @@ you want unlimited sprinting. SPRINT_TIMEOUT (default 0.5) +Only used if SPRINT_METHOD = 0. How much time the player has after releasing w, to press w again and start sprinting. Setting this too high will result in unwanted sprinting and setting it too low will result in it being diff --git a/mods/sprint/esprint.lua b/mods/sprint/esprint.lua new file mode 100644 index 00000000..c9cfc862 --- /dev/null +++ b/mods/sprint/esprint.lua @@ -0,0 +1,123 @@ +--[[ +Sprint mod for Minetest by GunshipPenguin + +To the extent possible under law, the author(s) +have dedicated all copyright and related and neighboring rights +to this software to the public domain worldwide. This software is +distributed without any warranty. +]] + +local players = {} +local staminaHud = {} + +minetest.register_on_joinplayer(function(player) + playerName = player:get_player_name() + players[playerName] = { + sprinting = false, + timeOut = 0, + stamina = SPRINT_STAMINA, + epressed = false, + hud = player:hud_add({ + hud_elem_type = "statbar", + position = {x=0.5,y=1}, + size = {x=24, y=24}, + text = "stamina.png", + number = 20, + alignment = {x=0,y=1}, + offset = {x=-320, y=-186}, + } + ), + } +end) +minetest.register_on_leaveplayer(function(player) + playerName = player:get_player_name() + players[playerName] = nil +end) +minetest.register_globalstep(function(dtime) + --Get the gametime + local gameTime = minetest.get_gametime() + + --Loop through all connected players + for playerName,playerInfo in pairs(players) do + local player = minetest.get_player_by_name(playerName) + if player ~= nil then + --Check if they are pressing the e key + players[playerName]["epressed"] = player:get_player_control()["aux1"] + + --Stop sprinting if the player is pressing the LMB or RMB + if player:get_player_control()["LMB"] or player:get_player_control()["RMB"] then + setSprinting(playerName, false) + playerInfo["timeOut"] = 3 + end + + --If the player is sprinting, create particles behind him/her + if playerInfo["sprinting"] == true and gameTime % 0.1 == 0 then + local numParticles = math.random(1, 2) + local playerPos = player:getpos() + local playerNode = minetest.get_node({x=playerPos["x"], y=playerPos["y"]-1, z=playerPos["z"]}) + if playerNode["name"] ~= "air" then + for i=1, numParticles, 1 do + minetest.add_particle({ + pos = {x=playerPos["x"]+math.random(-1,1)*math.random()/2,y=playerPos["y"]+0.1,z=playerPos["z"]+math.random(-1,1)*math.random()/2}, + vel = {x=0, y=5, z=0}, + acc = {x=0, y=-13, z=0}, + expirationtime = math.random(), + size = math.random()+0.5, + collisiondetection = true, + vertical = false, + texture = "default_dirt.png", + }) + end + end + end + + --Adjust player states + if players[playerName]["epressed"] == true and playerInfo["timeOut"] == 0 then --Stopped + setSprinting(playerName, true) + elseif players[playerName]["epressed"] == false then + setSprinting(playerName, false) + end + + if playerInfo["timeOut"] > 0 then + playerInfo["timeOut"] = playerInfo["timeOut"] - dtime + if playerInfo["timeOut"] < 0 then + playerInfo["timeOut"] = 0 + end + else + --Lower the player's stamina by dtime if he/she is sprinting and set his/her state to 0 if stamina is zero + if playerInfo["sprinting"] == true then + playerInfo["stamina"] = playerInfo["stamina"] - dtime + if playerInfo["stamina"] <= 0 then + playerInfo["stamina"] = 0 + setSprinting(playerName, false) + minetest.chat_send_player(playerName, "Votre sprint s'arrete, plus d'endurance ! Your sprint stamina has run out !") + playerInfo["timeOut"] = 1 + end + end + end + + --Increase player's stamina if he/she is not sprinting and his/her stamina is less than SPRINT_STAMINA + if playerInfo["sprinting"] == false and playerInfo["stamina"] < SPRINT_STAMINA then + playerInfo["stamina"] = playerInfo["stamina"] + dtime + end + + --Update the players's hud sprint stamina bar + local numBars = (playerInfo["stamina"]/SPRINT_STAMINA)*20 + player:hud_change(playerInfo["hud"], "number", numBars) + end + end +end) + +function setSprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting) + local player = minetest.get_player_by_name(playerName) + if players[playerName] then + players[playerName]["sprinting"] = sprinting + if sprinting == true then + player:set_physics_override({speed=SPRINT_SPEED,jump=SPRINT_JUMP}) + elseif sprinting == false then + player:set_physics_override({speed=1.0,jump=1.0}) + end + return true + end + return false +end diff --git a/mods/sprint/esprint.lua~ b/mods/sprint/esprint.lua~ new file mode 100644 index 00000000..ef3f24b8 --- /dev/null +++ b/mods/sprint/esprint.lua~ @@ -0,0 +1,123 @@ +--[[ +Sprint mod for Minetest by GunshipPenguin + +To the extent possible under law, the author(s) +have dedicated all copyright and related and neighboring rights +to this software to the public domain worldwide. This software is +distributed without any warranty. +]] + +local players = {} +local staminaHud = {} + +minetest.register_on_joinplayer(function(player) + playerName = player:get_player_name() + players[playerName] = { + sprinting = false, + timeOut = 0, + stamina = SPRINT_STAMINA, + epressed = false, + hud = player:hud_add({ + hud_elem_type = "statbar", + position = {x=0.5,y=1}, + size = {x=24, y=24}, + text = "stamina.png", + number = 20, + alignment = {x=0,y=1}, + offset = {x=-320, y=-186}, + } + ), + } +end) +minetest.register_on_leaveplayer(function(player) + playerName = player:get_player_name() + players[playerName] = nil +end) +minetest.register_globalstep(function(dtime) + --Get the gametime + local gameTime = minetest.get_gametime() + + --Loop through all connected players + for playerName,playerInfo in pairs(players) do + local player = minetest.get_player_by_name(playerName) + if player ~= nil then + --Check if they are pressing the e key + players[playerName]["epressed"] = player:get_player_control()["aux1"] + + --Stop sprinting if the player is pressing the LMB or RMB + if player:get_player_control()["LMB"] or player:get_player_control()["RMB"] then + setSprinting(playerName, false) + playerInfo["timeOut"] = 3 + end + + --If the player is sprinting, create particles behind him/her + if playerInfo["sprinting"] == true and gameTime % 0.1 == 0 then + local numParticles = math.random(1, 2) + local playerPos = player:getpos() + local playerNode = minetest.get_node({x=playerPos["x"], y=playerPos["y"]-1, z=playerPos["z"]}) + if playerNode["name"] ~= "air" then + for i=1, numParticles, 1 do + minetest.add_particle({ + pos = {x=playerPos["x"]+math.random(-1,1)*math.random()/2,y=playerPos["y"]+0.1,z=playerPos["z"]+math.random(-1,1)*math.random()/2}, + vel = {x=0, y=5, z=0}, + acc = {x=0, y=-13, z=0}, + expirationtime = math.random(), + size = math.random()+0.5, + collisiondetection = true, + vertical = false, + texture = "default_dirt.png", + }) + end + end + end + + --Adjust player states + if players[playerName]["epressed"] == true and playerInfo["timeOut"] == 0 then --Stopped + setSprinting(playerName, true) + elseif players[playerName]["epressed"] == false then + setSprinting(playerName, false) + end + + if playerInfo["timeOut"] > 0 then + playerInfo["timeOut"] = playerInfo["timeOut"] - dtime + if playerInfo["timeOut"] < 0 then + playerInfo["timeOut"] = 0 + end + else + --Lower the player's stamina by dtime if he/she is sprinting and set his/her state to 0 if stamina is zero + if playerInfo["sprinting"] == true then + playerInfo["stamina"] = playerInfo["stamina"] - dtime + if playerInfo["stamina"] <= 0 then + playerInfo["stamina"] = 0 + setSprinting(playerName, false) + minetest.chat_send_player(playerName, "Your sprint stamina has run out") + playerInfo["timeOut"] = 1 + end + end + end + + --Increase player's stamina if he/she is not sprinting and his/her stamina is less than SPRINT_STAMINA + if playerInfo["sprinting"] == false and playerInfo["stamina"] < SPRINT_STAMINA then + playerInfo["stamina"] = playerInfo["stamina"] + dtime + end + + --Update the players's hud sprint stamina bar + local numBars = (playerInfo["stamina"]/SPRINT_STAMINA)*20 + player:hud_change(playerInfo["hud"], "number", numBars) + end + end +end) + +function setSprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting) + local player = minetest.get_player_by_name(playerName) + if players[playerName] then + players[playerName]["sprinting"] = sprinting + if sprinting == true then + player:set_physics_override({speed=SPRINT_SPEED,jump=SPRINT_JUMP}) + elseif sprinting == false then + player:set_physics_override({speed=1.0,jump=1.0}) + end + return true + end + return false +end diff --git a/mods/sprint/init.lua b/mods/sprint/init.lua index e6fc11e4..325adb7a 100644 --- a/mods/sprint/init.lua +++ b/mods/sprint/init.lua @@ -8,129 +8,17 @@ distributed without any warranty. ]] --Configuration variables, these are all explained in README.md -local SPRINT_SPEED = 1.35 -local SPRINT_JUMP = 1.1 -local SPRINT_STAMINA = 10 -local SPRINT_TIMEOUT = 0.5 -local SPRINT_WARN = true -STOP_ON_CLICK = true --If true, sprinting will stop when either the left mouse button or the right mouse button is pressed +SPRINT_METHOD = 1 +SPRINT_SPEED = 1.35 +SPRINT_JUMP = 1.1 +SPRINT_STAMINA = 10 +SPRINT_TIMEOUT = 0.5 --Only used if SPRINT_METHOD = 0 -local players = {} -local staminaHud = {} - -minetest.register_on_joinplayer(function(player) - playerName = player:get_player_name() - players[playerName] = { - state = 0, - timeOut = 0, - stamina = SPRINT_STAMINA, - moving = false, - hud = player:hud_add({ - hud_elem_type = "statbar", - position = {x=0.5,y=1}, - size = {x=24, y=24}, - text = "stamina.png", - number = 20, - alignment = {x=0,y=1}, - offset = {x=-320, y=-186}, - } - ), - } -end) -minetest.register_on_leaveplayer(function(player) - playerName = player:get_player_name() - players[playerName] = nil -end) -minetest.register_globalstep(function(dtime) - --Get the gametime - local gameTime = minetest.get_gametime() - - --Loop through all connected players - for playerName,playerInfo in pairs(players) do - local player = minetest.get_player_by_name(playerName) - if player ~= nil then - --Check if they are moving or not - players[playerName]["moving"] = player:get_player_control()["up"] - -- s'arrete si le joueur fait un clique gauche ou droit - if player:get_player_control()["RMB"] or player:get_player_control()["LMB"] and STOP_ON_CLICK == true then - players[playerName]["state"] = 0 - player:set_physics_override({speed=1.0, jump=1.0}) - end - --If the player has tapped w longer than SPRINT_TIMEOUT ago, set his/her state to 0 - if playerInfo["state"] == 2 then - if playerInfo["timeOut"] + SPRINT_TIMEOUT < gameTime then - players[playerName]["timeOut"] = nil - setState(playerName, 0) - end - - --If the player is sprinting, create particles behind him/her - elseif playerInfo["state"] == 3 and gameTime % 0.1 == 0 then - local numParticles = math.random(1, 2) - local playerPos = player:getpos() - local playerNode = minetest.get_node({x=playerPos["x"], y=playerPos["y"]-1, z=playerPos["z"]}) - if playerNode["name"] ~= "air" then - for i=1, numParticles, 1 do - minetest.add_particle({ - pos = {x=playerPos["x"]+math.random(-1,1)*math.random()/2,y=playerPos["y"]+0.1,z=playerPos["z"]+math.random(-1,1)*math.random()/2}, - vel = {x=0, y=5, z=0}, - acc = {x=0, y=-13, z=0}, - expirationtime = math.random(), - size = math.random()+0.5, - collisiondetection = true, - vertical = false, - texture = "default_dirt.png", - }) - end - end - end - - --Adjust player states - if players[playerName]["moving"] == false and playerInfo["state"] == 3 then --Stopped - setState(playerName, 0) - elseif players[playerName]["moving"] == true and playerInfo["state"] == 0 then --Moving - setState(playerName, 1) - elseif players[playerName]["moving"] == false and playerInfo["state"] == 1 then --Primed - setState(playerName, 2) - elseif players[playerName]["moving"] == true and playerInfo["state"] == 2 then --Sprinting - setState(playerName, 3) - end - - --Lower the player's stamina by dtime if he/she is sprinting and set his/her state to 0 if stamina is zero - if playerInfo["state"] == 3 then - playerInfo["stamina"] = playerInfo["stamina"] - dtime - if playerInfo["stamina"] <= 0 then - playerInfo["stamina"] = 0 - setState(playerName, 0) - if SPRINT_WARN then - minetest.chat_send_player(playerName, "Votre sprint s'arrete, plus d'endurance ! Your sprint stamina has run out !") - end - end - - --Increase player's stamina if he/she is not sprinting and his/her stamina is less than SPRINT_STAMINA - elseif playerInfo["state"] ~= 3 and playerInfo["stamina"] < SPRINT_STAMINA then - playerInfo["stamina"] = playerInfo["stamina"] + dtime - end - - --Update the players's hud sprint stamina bar - local numBars = (playerInfo["stamina"]/SPRINT_STAMINA)*20 - player:hud_change(playerInfo["hud"], "number", numBars) - end - end -end) - -function setState(playerName, state) --Sets the state of a player (0=stopped, 1=moving, 2=primed, 3=sprinting) - local player = minetest.get_player_by_name(playerName) - local gameTime = minetest.get_gametime() - if players[playerName] then - players[playerName]["state"] = state - if state == 0 then--Stopped - player:set_physics_override({speed=1.0,jump=1.0}) - elseif state == 2 then --Primed - players[playerName]["timeOut"] = gameTime - elseif state == 3 then --Sprinting - player:set_physics_override({speed=SPRINT_SPEED,jump=SPRINT_JUMP}) - end - return true - end - return false +if SPRINT_METHOD == 0 then + dofile(minetest.get_modpath("sprint") .. "/wsprint.lua") +elseif SPRINT_METHOD == 1 then + dofile(minetest.get_modpath("sprint") .. "/esprint.lua") +else + minetest.log("error", "Sprint Mod - SPRINT_METHOD is not set properly, using e to sprint") + dofile(minetest.get_modpath("sprint") .. "/esprint.lua") end diff --git a/mods/sprint/wsprint.lua b/mods/sprint/wsprint.lua new file mode 100644 index 00000000..17192354 --- /dev/null +++ b/mods/sprint/wsprint.lua @@ -0,0 +1,121 @@ +--[[ +Sprint mod for Minetest by GunshipPenguin + +To the extent possible under law, the author(s) +have dedicated all copyright and related and neighboring rights +to this software to the public domain worldwide. This software is +distributed without any warranty. +]] + +local players = {} +local staminaHud = {} + +minetest.register_on_joinplayer(function(player) + playerName = player:get_player_name() + players[playerName] = { + state = 0, + timeOut = 0, + stamina = SPRINT_STAMINA, + moving = false, + hud = player:hud_add({ + hud_elem_type = "statbar", + position = {x=0.5,y=1}, + size = {x=24, y=24}, + text = "stamina.png", + number = 20, + alignment = {x=0,y=1}, + offset = {x=-320, y=-186}, + } + ), + } +end) +minetest.register_on_leaveplayer(function(player) + playerName = player:get_player_name() + players[playerName] = nil +end) +minetest.register_globalstep(function(dtime) + --Get the gametime + local gameTime = minetest.get_gametime() + + --Loop through all connected players + for playerName,playerInfo in pairs(players) do + local player = minetest.get_player_by_name(playerName) + if player ~= nil then + --Check if they are moving or not + players[playerName]["moving"] = player:get_player_control()["up"] + + --If the player has tapped w longer than SPRINT_TIMEOUT ago, set his/her state to 0 + if playerInfo["state"] == 2 then + if playerInfo["timeOut"] + SPRINT_TIMEOUT < gameTime then + players[playerName]["timeOut"] = nil + setState(playerName, 0) + end + + --If the player is sprinting, create particles behind him/her + elseif playerInfo["state"] == 3 and gameTime % 0.1 == 0 then + local numParticles = math.random(1, 2) + local playerPos = player:getpos() + local playerNode = minetest.get_node({x=playerPos["x"], y=playerPos["y"]-1, z=playerPos["z"]}) + if playerNode["name"] ~= "air" then + for i=1, numParticles, 1 do + minetest.add_particle({ + pos = {x=playerPos["x"]+math.random(-1,1)*math.random()/2,y=playerPos["y"]+0.1,z=playerPos["z"]+math.random(-1,1)*math.random()/2}, + vel = {x=0, y=5, z=0}, + acc = {x=0, y=-13, z=0}, + expirationtime = math.random(), + size = math.random()+0.5, + collisiondetection = true, + vertical = false, + texture = "default_dirt.png", + }) + end + end + end + + --Adjust player states + if players[playerName]["moving"] == false and playerInfo["state"] == 3 then --Stopped + setState(playerName, 0) + elseif players[playerName]["moving"] == true and playerInfo["state"] == 0 then --Moving + setState(playerName, 1) + elseif players[playerName]["moving"] == false and playerInfo["state"] == 1 then --Primed + setState(playerName, 2) + elseif players[playerName]["moving"] == true and playerInfo["state"] == 2 then --Sprinting + setState(playerName, 3) + end + + --Lower the player's stamina by dtime if he/she is sprinting and set his/her state to 0 if stamina is zero + if playerInfo["state"] == 3 then + playerInfo["stamina"] = playerInfo["stamina"] - dtime + if playerInfo["stamina"] <= 0 then + playerInfo["stamina"] = 0 + setState(playerName, 0) + end + + --Increase player's stamina if he/she is not sprinting and his/her stamina is less than SPRINT_STAMINA + elseif playerInfo["state"] ~= 3 and playerInfo["stamina"] < SPRINT_STAMINA then + playerInfo["stamina"] = playerInfo["stamina"] + dtime + end + + --Update the players's hud sprint stamina bar + local numBars = (playerInfo["stamina"]/SPRINT_STAMINA)*20 + player:hud_change(playerInfo["hud"], "number", numBars) + end + end +end) + +function setState(playerName, state) --Sets the state of a player (0=stopped, 1=moving, 2=primed, 3=sprinting) + local player = minetest.get_player_by_name(playerName) + local gameTime = minetest.get_gametime() + if players[playerName] then + players[playerName]["state"] = state + if state == 0 then--Stopped + player:set_physics_override({speed=1.0,jump=1.0}) + elseif state == 2 then --Primed + players[playerName]["timeOut"] = gameTime + elseif state == 3 then --Sprinting + player:set_physics_override({speed=SPRINT_SPEED,jump=SPRINT_JUMP}) + end + return true + end + return false +end diff --git a/mods/u_skins/u_skins/init.lua b/mods/u_skins/u_skins/init.lua index a0be27db..16739546 100644 --- a/mods/u_skins/u_skins/init.lua +++ b/mods/u_skins/u_skins/init.lua @@ -109,8 +109,9 @@ u_skins.generate_pages = function(texture) if i > 1 and x == 0 then y = 1.8 end - formspec = (formspec.."image_button["..x..","..y..";1,2;" - ..skin[2].."_preview.png;u_skins_set$"..skin[1]..";]") + formspec = (formspec.."image_button["..x..","..y..";1,2;".. + skin[2].."_preview.png;u_skins_set$"..skin[1]..";]".. + "tooltip[u_skins_set$"..skin[1]..";"..u_skins.meta[skin[2]].name.."]") end local page_prev = page - 2 local page_next = page