diff --git a/mods/mesecons/.github/workflows/check.yml b/mods/mesecons/.github/workflows/check.yml new file mode 100644 index 00000000..a447b04b --- /dev/null +++ b/mods/mesecons/.github/workflows/check.yml @@ -0,0 +1,45 @@ +on: [push, pull_request] +name: "Check" + +jobs: + lint: + runs-on: ubuntu-latest + name: "Luacheck" + steps: + - uses: actions/checkout@main + - name: apt + run: sudo apt-get install -y luarocks + - name: install luacheck + run: luarocks install --local luacheck + - name: run luacheck + run: $HOME/.luarocks/bin/luacheck ./ + + mineunit: + runs-on: ubuntu-latest + name: "Mineunit tests" + steps: + - uses: actions/checkout@main + - name: run mesecons tests + uses: mt-mods/mineunit-actions@master + with: + coverage: false + mineunit-args: -q + working-directory: ./mesecons + - name: run mesecons_mvps tests + uses: mt-mods/mineunit-actions@master + with: + coverage: false + mineunit-args: -q + working-directory: ./mesecons_mvps + - name: run mesecons_fpga tests + uses: mt-mods/mineunit-actions@master + with: + coverage: false + mineunit-args: -q + working-directory: ./mesecons_fpga + - name: run mesecons_luacontroller tests + uses: mt-mods/mineunit-actions@master + with: + coverage: false + mineunit-args: -q + working-directory: ./mesecons_luacontroller diff --git a/mods/mesecons/.github/workflows/test.yml b/mods/mesecons/.github/workflows/test.yml new file mode 100644 index 00000000..99f4817e --- /dev/null +++ b/mods/mesecons/.github/workflows/test.yml @@ -0,0 +1,28 @@ +on: [push, pull_request] +name: "Test" + +jobs: + test: + name: "Smoke Test ${{ matrix.cfg.image }}" + runs-on: ubuntu-latest + timeout-minutes: 5 + strategy: + matrix: + cfg: + - { image: 'registry.gitlab.com/minetest/minetest/server:5.0.1', mtg: false } + - { image: 'ghcr.io/minetest/minetest:5.9.0', mtg: true } + - { image: 'ghcr.io/luanti-org/luanti:5.11.0', mtg: true } + steps: + - uses: actions/checkout@main + + - name: Download Minetest Game + uses: actions/checkout@main + with: + repository: 'minetest/minetest_game' + path: ./.test/minetest_game + if: ${{ matrix.cfg.mtg }} + + - name: Run tests + run: ./.test/run.sh + env: + DOCKER_IMAGE: "${{ matrix.cfg.image }}" diff --git a/mods/mesecons/.gitignore b/mods/mesecons/.gitignore new file mode 100644 index 00000000..41756b55 --- /dev/null +++ b/mods/mesecons/.gitignore @@ -0,0 +1,3 @@ +*~ +*.patch +*.diff diff --git a/mods/mesecons/.luacheckrc b/mods/mesecons/.luacheckrc new file mode 100644 index 00000000..ca030532 --- /dev/null +++ b/mods/mesecons/.luacheckrc @@ -0,0 +1,63 @@ +std = "lua51c" + +ignore = { + "21/_+", -- Unused variable, except "_", "__", etc. + "213", -- Unused loop variable + "421", -- Shadowing a local variable + "422", -- Shadowing an argument + "423", -- Shadowing a loop variable + "431", -- Shadowing an upvalue + "432", -- Shadowing an upvalue argument + "433", -- Shadowing an upvalue loop variable + "542", -- Empty if branch +} + +max_line_length = 200 + +read_globals = { + "core", + "default", + "digiline", + "doors", + "dump", + "jit", + "minetest", + "screwdriver", + "string.split", + "table.copy", + "table.insert_all", + "vector", + "VoxelArea", + "mcl_dyes", + "mcl_sounds", + "hades_sounds", +} + +globals = {"mesecon"} + +files["mesecons/actionqueue.lua"] = { + globals = {"minetest.registered_globalsteps"}, +} + +-- Test-specific stuff follows. + +local test_conf = { + read_globals = { + "assert", + "fixture", + "mineunit", + "Player", + "sourcefile", + "world", + }, +} +files["*/spec/*.lua"] = test_conf +files[".test_fixtures/*.lua"] = test_conf + +files[".test_fixtures/screwdriver.lua"] = { + globals = {"screwdriver"}, +} + +files[".test_fixtures/mesecons_fpga.lua"] = { + globals = {"minetest.register_on_player_receive_fields"}, +} diff --git a/mods/mesecons/.test/minetest.conf b/mods/mesecons/.test/minetest.conf new file mode 100644 index 00000000..7e7b767f --- /dev/null +++ b/mods/mesecons/.test/minetest.conf @@ -0,0 +1,3 @@ +mg_name = singlenode +mesecon.internal_test = true +random_mod_load_order = true diff --git a/mods/mesecons/.test/run.sh b/mods/mesecons/.test/run.sh new file mode 100644 index 00000000..eb8c1987 --- /dev/null +++ b/mods/mesecons/.test/run.sh @@ -0,0 +1,31 @@ +#!/bin/bash +tempdir=$(mktemp -d) +confpath=$tempdir/minetest.conf +worldpath=$tempdir/world +trap 'rm -rf "$tempdir" || :' EXIT + +[ -f mesecons/mod.conf ] || { echo "Must be run in modpack root folder." >&2; exit 1; } + +command -v docker >/dev/null || { echo "Docker is not installed." >&2; exit 1; } +mtg=.test/minetest_game +[ -d $mtg ] || echo "A source checkout of minetest_game was not found. This can fail if your docker image does not ship a game." >&2 + +mkdir "$worldpath" +cp -v .test/minetest.conf "$confpath" +chmod -R 777 "$tempdir" + +args=( + -v "$confpath":/etc/minetest/minetest.conf + -v "$tempdir":/var/lib/minetest/.minetest + -v "$PWD":/var/lib/minetest/.minetest/world/worldmods/mesecons +) +[ -d $mtg ] && args+=( + -v "$(realpath $mtg)":/var/lib/minetest/.minetest/games/minetest_game +) +args+=("$DOCKER_IMAGE") +[ -d $mtg ] && args+=(--gameid minetest) +docker run --rm -i "${args[@]}" + +ls -la "$worldpath" +test -f "$worldpath/mesecon_actionqueue" || exit 1 +exit 0 diff --git a/mods/mesecons/.test_fixtures/mesecons.lua b/mods/mesecons/.test_fixtures/mesecons.lua new file mode 100644 index 00000000..a4d63b64 --- /dev/null +++ b/mods/mesecons/.test_fixtures/mesecons.lua @@ -0,0 +1,157 @@ +mineunit("core") +mineunit("server") +mineunit("voxelmanip") + +mineunit:set_current_modname("mesecons") +mineunit:set_modpath("mesecons", "../mesecons") +sourcefile("../mesecons/init") + +-- Utility node: this conductor is used to test the connectivity and state of adjacent wires. +do + local off_spec = {conductor = { + state = mesecon.state.off, + rules = mesecon.rules.alldirs, + onstate = "mesecons:test_conductor_on", + }} + local on_spec = {conductor = { + state = mesecon.state.on, + rules = mesecon.rules.alldirs, + offstate = "mesecons:test_conductor_off", + }} + mesecon.register_node("mesecons:test_conductor", { + description = "Test Conductor", + }, {mesecons = off_spec}, {mesecons = on_spec}) +end + +-- Utility node: this receptor is used to test power sources. +do + local off_spec = {receptor = { + state = mesecon.state.off, + rules = mesecon.rules.alldirs, + }} + local on_spec = {receptor = { + state = mesecon.state.on, + rules = mesecon.rules.alldirs, + }} + mesecon.register_node("mesecons:test_receptor", { + description = "Test Receptor", + }, {mesecons = off_spec}, {mesecons = on_spec}) +end + +-- Utility node: this effector is used to test circuit outputs. +do + -- This is a list of actions in the form {, }, + -- where is "on", "off", or "overheat". + mesecon._test_effector_events = {} + local function action_on(pos, node) + table.insert(mesecon._test_effector_events, {"on", pos}) + node.param2 = node.param2 % 64 + 128 -- Turn on bit 7 + minetest.swap_node(pos, node) + end + local function action_off(pos, node) + table.insert(mesecon._test_effector_events, {"off", pos}) + node.param2 = node.param2 % 64 -- Turn off bit 7 + minetest.swap_node(pos, node) + end + local function action_change(pos, node, rule_name, new_state) + if mesecon.do_overheat(pos) then + table.insert(mesecon._test_effector_events, {"overheat", pos}) + minetest.remove_node(pos) + return + end + -- Set the value of a bit in param2 according to the rule name and new state. + local bit = tonumber(rule_name.name, 2) + local bits_above = node.param2 - node.param2 % (bit * 2) + local bits_below = node.param2 % bit + local bits_flipped = new_state == mesecon.state.on and bit or 0 + node.param2 = bits_above + bits_flipped + bits_below + minetest.swap_node(pos, node) + end + minetest.register_node("mesecons:test_effector", { + description = "Test Effector", + mesecons = {effector = { + action_on = action_on, + action_off = action_off, + action_change = action_change, + rules = { + {x = 1, y = 0, z = 0, name = "000001"}, + {x = -1, y = 0, z = 0, name = "000010"}, + {x = 0, y = 1, z = 0, name = "000100"}, + {x = 0, y = -1, z = 0, name = "001000"}, + {x = 0, y = 0, z = 1, name = "010000"}, + {x = 0, y = 0, z = -1, name = "100000"}, + } + }}, + }) +end + +-- Utility node: this conductor is used to test rotation. +do + local get_rules = mesecon.horiz_rules_getter({{x = 1, y = 0, z = 0}, {x = -1, y = 0, z = 0}}) + local off_spec = {conductor = { + state = mesecon.state.off, + rules = get_rules, + onstate = "mesecons:test_conductor_rot_on", + }} + local on_spec = {conductor = { + state = mesecon.state.on, + rules = get_rules, + offstate = "mesecons:test_conductor_rot_off", + }} + mesecon.register_node("mesecons:test_conductor_rot", { + paramtype2 = "4dir", + description = "Rotatable Test Conductor", + on_rotate = mesecon.on_rotate, + }, {mesecons = off_spec}, {mesecons = on_spec}) +end + +-- Utility node: this is used to test multiple conductors within a single node. +do + local mesecons_spec = {conductor = { + rules = { + {{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}, {x = -1, y = 0, z = 0}}, + }, + states = { + "mesecons:test_multiconductor_off", "mesecons:test_multiconductor_001", + "mesecons:test_multiconductor_010", "mesecons:test_multiconductor_011", + "mesecons:test_multiconductor_100", "mesecons:test_multiconductor_101", + "mesecons:test_multiconductor_110", "mesecons:test_multiconductor_on", + }, + }} + for _, state in ipairs(mesecons_spec.conductor.states) do + minetest.register_node(state, { + description = "Test Multiconductor", + mesecons = mesecons_spec, + }) + end +end + +mesecon._test_autoconnects = {} +mesecon.register_autoconnect_hook("test", function(pos, node) + table.insert(mesecon._test_autoconnects, {pos, node}) +end) + +function mesecon._test_dig(pos) + local node = minetest.get_node(pos) + minetest.remove_node(pos) + mesecon.on_dignode(pos, node) +end + +function mesecon._test_place(pos, node) + world.set_node(pos, node) + mesecon.on_placenode(pos, minetest.get_node(pos)) +end + +function mesecon._test_reset() + -- First let circuits settle by simulating many globalsteps. + for i = 1, 10 do + mineunit:execute_globalstep(60) + end + mesecon.queue.actions = {} + mesecon._test_effector_events = {} + mesecon._test_autoconnects = {} +end + +mineunit:execute_globalstep(mesecon.setting("resumetime", 4) + 1) diff --git a/mods/mesecons/.test_fixtures/mesecons_fpga.lua b/mods/mesecons/.test_fixtures/mesecons_fpga.lua new file mode 100644 index 00000000..ba4440a3 --- /dev/null +++ b/mods/mesecons/.test_fixtures/mesecons_fpga.lua @@ -0,0 +1,59 @@ +mineunit("player") + +fixture("mesecons") +fixture("mesecons_gamecompat") + +local registered_on_player_receive_fields = {} +local old_register_on_player_receive_fields = minetest.register_on_player_receive_fields +function minetest.register_on_player_receive_fields(func) + old_register_on_player_receive_fields(func) + table.insert(registered_on_player_receive_fields, func) +end + +mineunit:set_current_modname("mesecons_fpga") +mineunit:set_modpath("mesecons_fpga", "../mesecons_fpga") +sourcefile("../mesecons_fpga/init") + +local fpga_user = Player("mesecons_fpga_user") + +function mesecon._test_program_fpga(pos, program) + local node = minetest.get_node(pos) + assert.equal("mesecons_fpga:fpga", node.name:sub(1, 18)) + + local fields = {program = true} + for i, instr in ipairs(program) do + -- Translate the instruction into formspec fields. + local op1, act, op2, dst + if #instr == 3 then + act, op2, dst = unpack(instr) + else + assert.equal(4, #instr) + op1, act, op2, dst = unpack(instr) + end + fields[i .. "op1"] = op1 + fields[i .. "act"] = (" "):rep(4 - #act) .. act + fields[i .. "op2"] = op2 + fields[i .. "dst"] = dst + end + + minetest.registered_nodes[node.name].on_rightclick(pos, node, fpga_user) + + for _, func in ipairs(registered_on_player_receive_fields) do + if func(fpga_user, "mesecons:fpga", fields) then + break + end + end +end + +function mesecon._test_copy_fpga_program(pos) + fpga_user:get_inventory():set_stack("main", 1, "mesecons_fpga:programmer") + local pt = {type = "node", under = vector.new(pos), above = vector.offset(pos, 0, 1, 0)} + fpga_user:do_place(pt) + return fpga_user:get_wielded_item() +end + +function mesecon._test_paste_fpga_program(pos, tool) + fpga_user:get_inventory():set_stack("main", 1, tool) + local pt = {type = "node", under = vector.new(pos), above = vector.offset(pos, 0, 1, 0)} + fpga_user:do_use(pt) +end diff --git a/mods/mesecons/.test_fixtures/mesecons_gamecompat.lua b/mods/mesecons/.test_fixtures/mesecons_gamecompat.lua new file mode 100644 index 00000000..07bffd00 --- /dev/null +++ b/mods/mesecons/.test_fixtures/mesecons_gamecompat.lua @@ -0,0 +1,5 @@ +fixture("mesecons") + +mineunit:set_current_modname("mesecons_gamecompat") +mineunit:set_modpath("mesecons_gamecompat", "../mesecons_gamecompat") +sourcefile("../mesecons_gamecompat/init") diff --git a/mods/mesecons/.test_fixtures/mesecons_luacontroller.lua b/mods/mesecons/.test_fixtures/mesecons_luacontroller.lua new file mode 100644 index 00000000..9090b477 --- /dev/null +++ b/mods/mesecons/.test_fixtures/mesecons_luacontroller.lua @@ -0,0 +1,12 @@ +fixture("mesecons") +fixture("mesecons_gamecompat") + +mineunit:set_current_modname("mesecons_luacontroller") +mineunit:set_modpath("mesecons_luacontroller", "../mesecons_luacontroller") +sourcefile("../mesecons_luacontroller/init") + +function mesecon._test_program_luac(pos, code) + local node = minetest.get_node(pos) + assert.equal("mesecons_luacontroller:luacontroller", node.name:sub(1, 36)) + return minetest.registered_nodes[node.name].mesecons.luacontroller.set_program(pos, code) +end diff --git a/mods/mesecons/.test_fixtures/mesecons_mvps.lua b/mods/mesecons/.test_fixtures/mesecons_mvps.lua new file mode 100644 index 00000000..b15774c1 --- /dev/null +++ b/mods/mesecons/.test_fixtures/mesecons_mvps.lua @@ -0,0 +1,45 @@ +mineunit("protection") + +fixture("mesecons") + +mineunit:set_current_modname("mesecons_mvps") +mineunit:set_modpath("mesecons_mvps", "../mesecons_mvps") +sourcefile("../mesecons_mvps/init") + +minetest.register_node("mesecons_mvps:test_stopper", { + description = "Test Stopper", +}) +mesecon.register_mvps_stopper("mesecons_mvps:test_stopper") + +minetest.register_node("mesecons_mvps:test_stopper_cond", { + description = "Test Stopper (Conditional)", +}) +mesecon.register_mvps_stopper("mesecons_mvps:test_stopper_cond", function(node) + return node.param2 == 0 +end) + +minetest.register_node("mesecons_mvps:test_sticky", { + description = "Test Sticky", + mvps_sticky = function(pos) + local connected = {} + for i, rule in ipairs(mesecon.rules.alldirs) do + connected[i] = vector.add(pos, rule) + end + return connected + end, +}) + +mesecon._test_moves = {} +minetest.register_node("mesecons_mvps:test_on_move", { + description = "Test Moveable", + mesecon = { + on_mvps_move = function(pos, node, oldpos, meta) + table.insert(mesecon._test_moves, {pos, node, oldpos, meta}) + end + }, +}) +local old_reset = mesecon._test_reset +function mesecon._test_reset() + mesecon._test_moves = {} + old_reset() +end diff --git a/mods/mesecons/.test_fixtures/screwdriver.lua b/mods/mesecons/.test_fixtures/screwdriver.lua new file mode 100644 index 00000000..1a98de06 --- /dev/null +++ b/mods/mesecons/.test_fixtures/screwdriver.lua @@ -0,0 +1,6 @@ +mineunit:set_current_modname("screwdriver") + +screwdriver = {} + +screwdriver.ROTATE_FACE = 1 +screwdriver.ROTATE_AXIS = 2 diff --git a/mods/mesecons/COPYING.txt b/mods/mesecons/COPYING.txt new file mode 100644 index 00000000..61bf7e2a --- /dev/null +++ b/mods/mesecons/COPYING.txt @@ -0,0 +1,30 @@ +The Mesecons Mod for Minetest is + Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors + +See the version control system log for information about other authors. + +License of source code +---------------------- +Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors + +This program is free software; you can redistribute the Mesecons Mod and/or +modify it under the terms of the GNU Lesser General Public License version 3 +published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + +License of media (textures, sounds and documentation) +----------------------------------------------------- +Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors + +All textures, sounds and documentation files are licensed under the +Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) +http://creativecommons.org/licenses/by-sa/3.0/ diff --git a/mods/mesecons/LICENSE.txt b/mods/mesecons/LICENSE.txt new file mode 100644 index 00000000..5df6546b --- /dev/null +++ b/mods/mesecons/LICENSE.txt @@ -0,0 +1,538 @@ +The LGPLv3 applies to all code in this project. +The CC-BY-SA-3.0 license applies to textures and any other content in this project which is not source code. + +The file mesecons_detector/textures/mesecons_detector_side.png is an unmodified copy of +"default_steel_block.png" by Jean-Patrick Guerrero , which can be found at +. +"default_steel_block.png" is licensed under a CC BY-SA 3.0 license. This license can be found later in this document, and can also be found at +. The artwork is reportedly copyright (C) 2010-2018 kilbith. + +================================================================= + +GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + +================================================================= + +Creative Commons Legal Code + +Attribution-ShareAlike 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined below) for the purposes of this + License. + c. "Creative Commons Compatible License" means a license that is listed + at http://creativecommons.org/compatiblelicenses that has been + approved by Creative Commons as being essentially equivalent to this + License, including, at a minimum, because that license: (i) contains + terms that have the same purpose, meaning and effect as the License + Elements of this License; and, (ii) explicitly permits the relicensing + of adaptations of works made available under that license under this + License or a Creative Commons jurisdiction license with the same + License Elements as this License. + d. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + e. "License Elements" means the following high-level license attributes + as selected by Licensor and indicated in the title of this License: + Attribution, ShareAlike. + f. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + g. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + h. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + i. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + j. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + k. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(c), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(c), as requested. + b. You may Distribute or Publicly Perform an Adaptation only under the + terms of: (i) this License; (ii) a later version of this License with + the same License Elements as this License; (iii) a Creative Commons + jurisdiction license (either this or a later license version) that + contains the same License Elements as this License (e.g., + Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible + License. If you license the Adaptation under one of the licenses + mentioned in (iv), you must comply with the terms of that license. If + you license the Adaptation under the terms of any of the licenses + mentioned in (i), (ii) or (iii) (the "Applicable License"), you must + comply with the terms of the Applicable License generally and the + following provisions: (I) You must include a copy of, or the URI for, + the Applicable License with every copy of each Adaptation You + Distribute or Publicly Perform; (II) You may not offer or impose any + terms on the Adaptation that restrict the terms of the Applicable + License or the ability of the recipient of the Adaptation to exercise + the rights granted to that recipient under the terms of the Applicable + License; (III) You must keep intact all notices that refer to the + Applicable License and to the disclaimer of warranties with every copy + of the Work as included in the Adaptation You Distribute or Publicly + Perform; (IV) when You Distribute or Publicly Perform the Adaptation, + You may not impose any effective technological measures on the + Adaptation that restrict the ability of a recipient of the Adaptation + from You to exercise the rights granted to that recipient under the + terms of the Applicable License. This Section 4(b) applies to the + Adaptation as incorporated in a Collection, but this does not require + the Collection apart from the Adaptation itself to be made subject to + the terms of the Applicable License. + c. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Ssection 3(b), in the case of an + Adaptation, a credit identifying the use of the Work in the Adaptation + (e.g., "French translation of the Work by Original Author," or + "Screenplay based on original Work by Original Author"). The credit + required by this Section 4(c) may be implemented in any reasonable + manner; provided, however, that in the case of a Adaptation or + Collection, at a minimum such credit will appear, if a credit for all + contributing authors of the Adaptation or Collection appears, then as + part of these credits and in a manner at least as prominent as the + credits for the other contributing authors. For the avoidance of + doubt, You may only use the credit required by this Section for the + purpose of attribution in the manner set out above and, by exercising + Your rights under this License, You may not implicitly or explicitly + assert or imply any connection with, sponsorship or endorsement by the + Original Author, Licensor and/or Attribution Parties, as appropriate, + of You or Your use of the Work, without the separate, express prior + written permission of the Original Author, Licensor and/or Attribution + Parties. + d. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of the License. + + Creative Commons may be contacted at http://creativecommons.org/. diff --git a/mods/mesecons/README.md b/mods/mesecons/README.md new file mode 100644 index 00000000..e8cbcba9 --- /dev/null +++ b/mods/mesecons/README.md @@ -0,0 +1,91 @@ + ######################################################################## + ## __ __ _____ _____ _____ _____ _____ _ _ _____ ## + ## | \ / | | ___| | ___| | ___| | ___| | _ | | \ | | | ___| ## + ## | \/ | | |___ | |___ | |___ | | | | | | | \| | | |___ ## + ## | |\__/| | | ___| |___ | | ___| | | | | | | | | |___ | ## + ## | | | | | |___ ___| | | |___ | |___ | |_| | | |\ | ___| | ## + ## |_| |_| |_____| |_____| |_____| |_____| |_____| |_| \_| |_____| ## + ## ## + ######################################################################## + +MESECONS by Jeija and contributors + +Mezzee-what? +------------ + +[Mesecons](https://mesecons.net/)! They're yellow, they're conductive, and they'll add a whole new dimension to Luanti's gameplay. + +Mesecons is a mod for [Luanti](https://www.luanti.org/) that implements a ton of items related to digital circuitry, such as wires, buttons, lights, and even programmable controllers. +Among other things, there are also pistons, solar panels, pressure plates, and note blocks. + +Mesecons has a similar goal to Redstone in Minecraft, but works in its own way, with different rules and mechanics. + +OK, I want in. +-------------- + +Go get it! + +[![ContentDB](https://content.luanti.org/packages/Jeija/mesecons/shields/downloads/)](https://content.luanti.org/packages/Jeija/mesecons/) + +Install it directly from your client by searching it in the Online Content tab. + +**Or** if you've downloaded a ZIP file check out [this page](https://docs.luanti.org/for-players/mods/) over at the official Luanti Wiki. For your convenience, here's a quick summary: + +1. If Mesecons is still in a ZIP file, extract the folder inside to somewhere on the computer. +2. Make sure that when you open the folder, you can directly find `README.md` in the listing. If you just see another folder, move that folder up one level and delete the old one. +3. Open up the Luanti mods folder - called `mods`. +4. Copy the Mesecons folder into the mods folder. + +Don't like some parts of Mesecons? Open up the Mesecons folder and delete the subfolder containing the mod you don't want. If you didn't want movestones, for example, all you have to do is delete the `mesecons_movestones` folder and they will no longer be available. + +There are no dependencies - it will work right after installing! + +How do I use this thing? +------------------------ + +How about a [quick overview video](https://www.youtube.com/watch?v=6kmeQj6iW5k)? + +Or maybe a [comprehensive reference](https://mesecons.net/items.html) is your style? + +An overview for the very newest of new beginners? How does [this one](https://uberi.mesecons.net/projects/MeseconsBasics/index.html) look? + +Want to get more into building? Why not check out the [Mesecons Laboratory](https://uberi.mesecons.net/), a website dedicated to advanced Mesecons builders? + +Want to contribute to Mesecons itself? Check out the [source code](https://github.com/minetest-mods/mesecons)! + +Who wrote it anyways? +--------------------- + +These awesome people made Mesecons possible! (as of 2016) + +| Contributor | Contribution | +| --------------- | -------------------------------- | +| Hawk777 | Code for VoxelManip caching | +| Jat15 | Various tweaks. | +| Jeija | **Main developer! Everything.** | +| Jordach | Noteblock sounds. | +| khonkhortistan | Code, recipes, textures. | +| Kotolegokot | Nodeboxes for items. | +| minerd247 | Textures. | +| Nore/Novatux | Code. | +| RealBadAngel | Fixes, improvements. | +| sfan5 | Code, recipes, textures. | +| suzenako | Piston sounds. | +| Uberi/Temperest | Code, textures, documentation. | +| VanessaE | Code, recipes, textures, design. | +| Whiskers75 | Logic gates implementation. | + +There are also a whole bunch of other people helping with everything from code to testing and feedback. Mesecons would also not be possible without their help! + +Check out the [entire contributor list](https://github.com/minetest-mods/mesecons/graphs/contributors) on GitHub. + +Alright, how can I use it? +-------------------------- + +All textures in this project are licensed under the CC-BY-SA 3.0 (Creative Commons Attribution-ShareAlike 3.0 Generic). +That means you can distribute and remix them as much as you want to, under the condition that you give credit to the authors and the project, and that if you remix and release them, they must be under the same or similar license to this one. + +All code in this project is licensed under the LGPL version 3. +That means you have unlimited freedom to distribute and modify the work however you see fit, provided that if you decide to distribute it or any modified versions of it, you must also use the same license. The LGPL also grants the additional freedom to write extensions for the software and distribute them without the extensions being subject to the terms of the LGPL, although the software itself retains its license. + +No warranty is provided, express or implied, for any part of the project. diff --git a/mods/mesecons/bower.json b/mods/mesecons/bower.json new file mode 100644 index 00000000..8c850f57 --- /dev/null +++ b/mods/mesecons/bower.json @@ -0,0 +1,12 @@ +{ + "name": "mesecons", + "description": "Mesecons is a mod for Minetest that implements items related to digital circuitry: wires, buttons, lights, and programmable controllers.", + "homepage": "https://mesecons.net", + "authors": ["Jeija"], + "license": "LGPL-3.0", + "keywords": [ + "mesecons", + "minetest", + "mod" + ] +} diff --git a/mods/mesecons/documentation.json b/mods/mesecons/documentation.json new file mode 100644 index 00000000..b12dc6d2 --- /dev/null +++ b/mods/mesecons/documentation.json @@ -0,0 +1,65 @@ +{ + "Conductors" : { + "Mesecon" : "mesecons_wires/doc/mesecon", + "Insulated Wire" : "mesecons_insulated/doc/insulated", + "T-Junction" : "mesecons_extrawires/doc/tjunction", + "Crossing" : "mesecons_extrawires/doc/crossing", + "Corner" : "mesecons_extrawires/doc/corner", + "Vertical Wire" : "mesecons_extrawires/doc/vertical", + "Mese" : "mesecons_extrawires/doc/mese" + }, + "Receptors" : { + "Power Plant" : "mesecons_powerplant/doc/powerplant", + "Blinky Plant" : "mesecons_blinkyplant/doc/blinkyplant", + "Switch" : "mesecons_switch/doc/switch", + "Object Detector" : "mesecons_detector/doc/objectdetector", + "Node Detector" : "mesecons_detector/doc/nodedetector", + "Wall Lever" : "mesecons_walllever/doc/walllever", + "Pressure Plate" : "mesecons_pressureplates/doc/pressureplate_wood", + "Pressure Plate" : "mesecons_pressureplates/doc/pressureplate_stone", + "Water Turbine" : "mesecons_hydroturbine/doc/waterturbine", + "Solar Panel" : "mesecons_solarpanel/doc/solarpanel", + "Wall Button" : "mesecons_button/doc/button" + }, + "Effectors" : { + "Noteblock" : "mesecons_noteblock/doc/noteblock", + "Lamp" : "mesecons_lamp/doc/lamp", + "Piston" : "mesecons_pistons/doc/piston", + "Sticky Piston" : "mesecons_pistons/doc/piston_sticky", + "Movestone" : "mesecons_movestones/doc/movestone", + "Sticky Movestone" : "mesecons_movestones/doc/movestone_sticky", + "Removestone" : "mesecons_random/doc/removestone", + "Ghoststone" : "mesecons_random/doc/ghoststone", + "Command Block" : "mesecons_commandblock/doc/commandblock", + "Lightstones" : { + "Dark Grey" : "mesecons_lightstone/doc/lightstone_darkgrey", + "Light Grey" : "mesecons_lightstone/doc/lightstone_lightgrey", + "Green" : "mesecons_lightstone/doc/lightstone_green", + "Red" : "mesecons_lightstone/doc/lightstone_red", + "Blue" : "mesecons_lightstone/doc/lightstone_blue", + "Yellow" : "mesecons_lightstone/doc/lightstone_yellow" + } + }, + "Logic" : { + "Luacontroller" : "mesecons_luacontroller/doc/luacontroller", + "Microcontroller" : "mesecons_microcontroller/doc/microcontroler", + "FPGA" : "mesecons_fpga/doc/fpga", + "FPGA Programmer" : "mesecons_fpga/doc/programmer", + "Torch" : "mesecons_torch/doc/torch", + "Delayer" : "mesecons_delayer/doc/delayer", + "Gates" : { + "Diode" : "mesecons_gates/doc/diode", + "NOT Gate" : "mesecons_gates/doc/not", + "AND Gate" : "mesecons_gates/doc/and", + "NAND Gate" : "mesecons_gates/doc/nand", + "OR Gate" : "mesecons_gates/doc/or", + "NOR Gate" : "mesecons_gates/doc/nor", + "XOR Gate" : "mesecons_gates/doc/xor" + } + }, + "Crafts" : { + "Silicon" : "mesecons_materials/doc/silicon", + "Glue" : "mesecons_materials/doc/glue", + "Fiber" : "mesecons_materials/doc/fiber" + } +} diff --git a/mods/mesecons/mesecons/actionqueue.lua b/mods/mesecons/mesecons/actionqueue.lua new file mode 100644 index 00000000..b3118f06 --- /dev/null +++ b/mods/mesecons/mesecons/actionqueue.lua @@ -0,0 +1,143 @@ +--[[ +Mesecons uses something it calls an ActionQueue. + +The ActionQueue holds functions and actions. +Functions are added on load time with a specified name. +Actions are preserved over server restarts. + +Each action consists of a position, the name of an added function to be called, +the params that should be used in this function call (additionally to the pos), +the time after which it should be executed, an optional overwritecheck and a +priority. + +If time = 0, the action will be executed in the next globalstep, otherwise the +earliest globalstep when it will be executed is the after next globalstep. + +It is guaranteed, that for two actions ac1, ac2 where ac1 ~= ac2, +ac1.time == ac2.time, ac1.priority == ac2.priority and ac1 was added earlier +than ac2, ac1 will be executed before ac2 (but in the same globalstep). + +Note: Do not pass references in params, as they can not be preserved. + +Also note: Some of the guarantees here might be dropped at some time. +]] + + +-- localize for speed +local queue = mesecon.queue + +queue.actions = {} -- contains all ActionQueue actions + +function queue:add_function(name, func) + self.funcs[name] = func +end + +-- If add_action with twice the same overwritecheck and same position are called, the first one is overwritten +-- use overwritecheck nil to never overwrite, but just add the event to the queue +-- priority specifies the order actions are executed within one globalstep, highest first +-- should be between 0 and 1 +function queue:add_action(pos, func, params, time, overwritecheck, priority) + -- 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), + func = func, + params = mesecon.tablecopy(params or {}), + time = time, + owcheck = (overwritecheck and mesecon.tablecopy(overwritecheck)) or nil, + priority = priority + } + + -- check if old action has to be overwritten / removed: + if overwritecheck then + for i, ac in ipairs(self.actions) do + if vector.equals(pos, ac.pos) + and mesecon.cmpAny(overwritecheck, ac.owcheck) then + -- remove the old action + table.remove(self.actions, i) + break + end + end + end + + table.insert(self.actions, action) +end + +-- execute the stored functions on a globalstep +-- if however, the pos of a function is not loaded (get_node_or_nil == nil), do NOT execute the function +-- this makes sure that resuming mesecons circuits when restarting minetest works fine (hm, where do we do this?) +-- However, even that does not work in some cases, that's why we delay the time the globalsteps +-- start to be execute by 4 seconds + +local m_time = 0 +local resumetime = mesecon.setting("resumetime", 4) + +local function globalstep_func(dtime) + -- 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 + m_time = m_time + dtime + return + end + + local actions = queue.actions + -- split into two categories: + -- actions_now: actions to execute now + -- queue.actions: actions to execute later + local actions_now = {} + queue.actions = {} + + for _, ac in ipairs(actions) do + if ac.time > 0 then + -- action ac is to be executed later + -- ~> insert into queue.actions + ac.time = ac.time - dtime + table.insert(queue.actions, ac) + else + -- action ac is to be executed now + -- ~> insert into actions_now + table.insert(actions_now, ac) + end + end + + -- stable-sort the executed actions after their priority + -- some constructions might depend on the execution order, hence we first + -- execute the actions that had a lower index in actions_now + local old_action_order = {} + for i, ac in ipairs(actions_now) do + old_action_order[ac] = i + end + table.sort(actions_now, function(ac1, ac2) + if ac1.priority ~= ac2.priority then + return ac1.priority > ac2.priority + else + return old_action_order[ac1] < old_action_order[ac2] + end + end) + + -- execute highest priorities first, until all are executed + for _, ac in ipairs(actions_now) do + queue:execute(ac) + end +end + +minetest.register_globalstep(globalstep_func) + +function queue:execute(action) + -- ignore if action queue function name doesn't exist, + -- (e.g. in case the action queue savegame was written by an old mesecons version) + if self.funcs[action.func] then + self.funcs[action.func](action.pos, unpack(action.params)) + end +end + + +-- Store and read the ActionQueue to / from a file +-- so that upcoming actions are remembered when the game +-- is restarted +queue.actions = mesecon.file2table("mesecon_actionqueue") + +minetest.register_on_shutdown(function() + mesecon.table2file("mesecon_actionqueue", queue.actions) +end) diff --git a/mods/mesecons/mesecons/fifo_queue.lua b/mods/mesecons/mesecons/fifo_queue.lua new file mode 100644 index 00000000..a71c71bc --- /dev/null +++ b/mods/mesecons/mesecons/fifo_queue.lua @@ -0,0 +1,62 @@ + +-- a simple first-in-first-out queue +-- very similar to the one in https://github.com/minetest/minetest/pull/7683 + +local fifo_queue = {} + +local metatable = {__index = fifo_queue} + +-- creates a new empty queue +function fifo_queue.new() + local q = {n_in = 0, n_out = 0, i_out = 1, buf_in = {}, buf_out = {}} + setmetatable(q, metatable) + return q +end + +-- adds an element to the queue +function fifo_queue.add(self, v) + local n = self.n_in + 1 + self.n_in = n + self.buf_in[n] = v +end + +-- removes and returns the next element, or nil of empty +function fifo_queue.take(self) + local i_out = self.i_out + if i_out <= self.n_out then + local v = self.buf_out[i_out] + self.i_out = i_out + 1 + self.buf_out[i_out] = true + return v + end + + -- buf_out is empty, try to swap + self.i_out = 1 + self.n_out = 0 + if self.n_in == 0 then + return nil -- empty + end + + -- swap + self.n_out = self.n_in + self.n_in = 0 + self.buf_out, self.buf_in = self.buf_in, self.buf_out + + local v = self.buf_out[1] + self.i_out = 2 + self.buf_out[1] = true + return v +end + +-- returns whether the queue is empty +function fifo_queue.is_empty(self) + return self.n_out == self.i_out + 1 and self.n_in == 0 +end + +-- returns stuff for iteration in a for loop, like pairs +-- adding new elements while iterating is no problem +function fifo_queue.iter(self) + return fifo_queue.take, self, nil +end + +return fifo_queue diff --git a/mods/mesecons/mesecons/init.lua b/mods/mesecons/mesecons/init.lua new file mode 100644 index 00000000..9a45a407 --- /dev/null +++ b/mods/mesecons/mesecons/init.lua @@ -0,0 +1,133 @@ +-- |\ /| ____ ____ ____ _____ ____ _____ +-- | \ / | | | | | | | |\ | | +-- | \/ | |___ ____ |___ | | | | \ | |____ +-- | | | | | | | | | \ | | +-- | | |___ ____| |___ |____ |____| | \| ____| +-- by Jeija, Uberi (Temperest), sfan5, VanessaE, Hawk777 and contributors +-- +-- +-- +-- This mod adds mesecons[=minecraft redstone] and different receptors/effectors to minetest. +-- See the documentation on the forum for additional information, especially about crafting +-- +-- +-- For basic development resources, see http://mesecons.net/developers.html +-- +-- +-- +--Quick draft for the mesecons array in the node's definition +--mesecons = +--{ +-- receptor = +-- { +-- state = mesecon.state.on/off +-- rules = rules/get_rules +-- }, +-- effector = +-- { +-- action_on = function +-- action_off = function +-- action_change = function +-- rules = rules/get_rules +-- }, +-- conductor = +-- { +-- state = mesecon.state.on/off +-- offstate = opposite state (for state = on only) +-- onstate = opposite state (for state = off only) +-- rules = rules/get_rules +-- } +--} + +-- PUBLIC VARIABLES +mesecon={} -- contains all functions and all global variables +mesecon.queue={} -- contains the ActionQueue +mesecon.queue.funcs={} -- contains all ActionQueue functions + +-- Settings +dofile(minetest.get_modpath("mesecons").."/settings.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"); + +-- Internal stuff +-- This is the most important file +-- it handles signal transmission and basically everything else +-- It is also responsible for managing the nodedef things, +-- like calling action_on/off/change +dofile(minetest.get_modpath("mesecons").."/internal.lua"); + +-- API +-- these are the only functions you need to remember + +mesecon.queue:add_function("receptor_on", function (pos, rules) + mesecon.vm_begin() + + rules = rules or mesecon.rules.default + + -- Call turnon on all linking positions + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = vector.add(pos, rule) + local rulenames = mesecon.rules_link_rule_all(pos, rule) + for _, rulename in ipairs(rulenames) do + mesecon.turnon(np, rulename) + end + end + + mesecon.vm_commit() +end) + +function mesecon.receptor_on(pos, rules) + mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules) +end + +mesecon.queue:add_function("receptor_off", function (pos, rules) + rules = rules or mesecon.rules.default + + -- Call turnoff on all linking positions + for _, rule in ipairs(mesecon.flattenrules(rules)) do + local np = vector.add(pos, rule) + local rulenames = mesecon.rules_link_rule_all(pos, rule) + for _, rulename in ipairs(rulenames) do + mesecon.vm_begin() + + -- Turnoff returns true if turnoff process was successful, no onstate receptor + -- was found along the way. Commit changes that were made in voxelmanip. If turnoff + -- returns true, an onstate receptor was found, abort voxelmanip transaction. + if (mesecon.turnoff(np, rulename)) then + mesecon.vm_commit() + else + mesecon.vm_abort() + end + end + end +end) + +function mesecon.receptor_off(pos, rules) + mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) +end + + +-- Deprecated stuff +-- To be removed in future releases +dofile(minetest.get_modpath("mesecons").."/legacy.lua"); + +--Services like turnoff receptor on dignode and so on +dofile(minetest.get_modpath("mesecons").."/services.lua"); + +-- Automated test run +if mesecon.setting("internal_test", false) then + -- currently does nothing, we only fail if some error happens right on startup + minetest.after(5, function() + minetest.request_shutdown() + end) +end diff --git a/mods/mesecons/mesecons/internal.lua b/mods/mesecons/mesecons/internal.lua new file mode 100644 index 00000000..49690d96 --- /dev/null +++ b/mods/mesecons/mesecons/internal.lua @@ -0,0 +1,624 @@ +-- Internal.lua - The core of mesecons +-- +-- 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 + +-- 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) + +-- 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) + +-- SIGNALS +-- 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) + +-- 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.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor + +-- 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 + +-- See fifo_queue.lua for documentation. +mesecon.fifo_queue = dofile(minetest.get_modpath("mesecons").."/fifo_queue.lua") + +-- General +function mesecon.get_effector(nodename) + local def = minetest.registered_nodes[nodename] + return def and def.mesecons and def.mesecons.effector +end + +function mesecon.get_receptor(nodename) + local def = minetest.registered_nodes[nodename] + return def and def.mesecons and def.mesecons.receptor +end + +function mesecon.get_conductor(nodename) + local def = minetest.registered_nodes[nodename] + return def and def.mesecons and def.mesecons.conductor +end + +function mesecon.get_any_outputrules(node) + if not node then return nil end + + 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 +end + +function mesecon.get_any_inputrules(node) + if not node then return nil end + + 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 +end + +function mesecon.get_any_rules(node) + return mesecon.merge_rule_sets(mesecon.get_any_inputrules(node), + mesecon.get_any_outputrules(node)) +end + +-- Receptors +-- Nodes that can power mesecons +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) + 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) + if receptor then + return true + end + return false +end + +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 + return rules(node) + elseif rules then + return rules + end + end + + return mesecon.rules.default +end + +-- Effectors +-- Nodes that can be powered by mesecons +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) + if effector and effector.action_on then + return true + end + return false +end + +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) + if effector then + local rules = effector.rules + if type(rules) == 'function' then + return rules(node) + elseif rules then + return rules + end + end + return mesecon.rules.default +end + +-- ####################### +-- # Signals (effectors) # +-- ####################### + +-- Activation: +mesecon.queue:add_function("activate", function (pos, rulename) + local node = mesecon.get_node_force(pos) + if not node then return end + + 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, depth) + if rulename == nil then + 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 / depth) +end + + +-- Deactivation +mesecon.queue:add_function("deactivate", function (pos, rulename) + local node = mesecon.get_node_force(pos) + if not node then return end + + 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, depth) + if rulename == nil then + 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 / depth) +end + + +-- Change +mesecon.queue:add_function("change", function (pos, rulename, changetype) + local node = mesecon.get_node_force(pos) + if not node then return end + + 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, depth) + if rulename == nil then + for _,rule in ipairs(mesecon.effector_get_rules(node)) do + mesecon.changesignal(pos, node, rule, newstate, depth + 1) + end + return + end + + -- Include "change" in overwritecheck so that it cannot be overwritten + -- by "active" / "deactivate" that will be called upon the node at the same time. + local overwritecheck = {"change", rulename} + mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, overwritecheck, 1 / depth) +end + +-- Conductors + +function mesecon.is_conductor_on(node, rulename) + if not node then return false end + + 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 + 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) + end + end + + return false +end + +function mesecon.is_conductor_off(node, rulename) + if not node then return false end + + 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 + 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) + end + end + + return false +end + +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) + 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") + return conductor.states[tonumber(binstate,2)+1] + end + end + return nil +end + +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") + return conductor.states[tonumber(binstate,2)+1] + end + end + return nil +end + +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 + return rules(node) + elseif rules then + return rules + end + end + return mesecon.rules.default +end + +-- some more general high-level stuff + +function mesecon.is_power_on(pos, rulename) + local node = mesecon.get_node_force(pos) + if node and (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) + local node = mesecon.get_node_force(pos) + if node and (mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name)) then + return true + end + return false +end + +-- The set of conductor states which require light updates when they change. +local light_update_conductors + +-- Calculate the contents of the above set if they have not been calculated. +local function find_light_update_conductors() + -- The expensive calculation is only done the first time. + if light_update_conductors then return end + + light_update_conductors = {} + + -- Find conductors whose lighting characteristics change depending on their state. + local checked = {} + for name, def in pairs(minetest.registered_nodes) do + local conductor = mesecon.get_conductor(name) + if conductor and not checked[name] then + -- Find the other states of the conductor besides the current one. + local other_states + if conductor.onstate then + other_states = {conductor.onstate} + elseif conductor.offstate then + other_states = {conductor.offstate} + else + other_states = conductor.states + end + + -- Check the conductor. Other states are marked as checked. + for _, other_state in ipairs(other_states) do + local other_def = minetest.registered_nodes[other_state] + if (def.paramtype == "light") ~= (other_def.paramtype == "light") + or def.sunlight_propagates ~= other_def.sunlight_propagates + or def.light_source ~= other_def.light_source then + -- The light characteristics change depending on the state. + -- The states are added to the set. + light_update_conductors[name] = true + for _, other_state in ipairs(other_states) do + light_update_conductors[other_state] = true + checked[other_state] = true + end + break + end + checked[other_state] = true + end + end + end +end + +-- Turn off an equipotential section starting at `pos`, which outputs in the direction of `link`. +-- Breadth-first search. Map is abstracted away in a voxelmanip. +-- Follow all all conductor paths replacing conductors that were already +-- looked at, activating / changing all effectors along the way. +function mesecon.turnon(pos, link) + find_light_update_conductors() + + local frontiers = mesecon.fifo_queue.new() + frontiers:add({pos = pos, link = link}) + local pos_can_be_skipped = {} + + local depth = 1 + for f in frontiers:iter() do + local node = mesecon.get_node_force(f.pos) + + if not node then + -- Area does not exist; do nothing + pos_can_be_skipped[minetest.hash_node_position(f.pos)] = true + elseif mesecon.is_conductor(node.name) then + local rules = mesecon.conductor_get_rules(node) + + if mesecon.is_conductor_off(node, f.link) then + -- Call turnon on neighbors + for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + local np = vector.add(f.pos, r) + if not pos_can_be_skipped[minetest.hash_node_position(np)] then + for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do + frontiers:add({pos = np, link = l}) + end + end + end + + mesecon.swap_node_force(f.pos, mesecon.get_conductor_on(node, f.link), light_update_conductors[node.name] ~= nil) + end + + -- Only conductors with flat rules can be reliably skipped later + if not rules[1] or rules[1].x then + pos_can_be_skipped[minetest.hash_node_position(f.pos)] = true + 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 + else + pos_can_be_skipped[minetest.hash_node_position(f.pos)] = true + end + depth = depth + 1 + end +end + +-- Turn on an equipotential section starting at `pos`, which outputs in the direction of `link`. +-- Breadth-first search. Map is abstracted away in a voxelmanip. +-- Follow all all conductor paths replacing conductors that were already +-- looked at, deactivating / changing all effectors along the way. +-- In case an onstate receptor is discovered, abort the process by returning false, which will +-- cause `receptor_off` to discard all changes made in the voxelmanip. +-- Contrary to turnon, turnoff has to cache all change and deactivate signals so that they will only +-- be called in the very end when we can be sure that no conductor was found along the path. +-- +-- Signal table entry structure: +-- { +-- pos = position of effector, +-- node = node descriptor (name, param1 and param2), +-- link = link the effector is connected to, +-- depth = indicates order in which signals wire fired, higher is later +-- } +function mesecon.turnoff(pos, link) + find_light_update_conductors() + + local frontiers = mesecon.fifo_queue.new() + frontiers:add({pos = pos, link = link}) + local signals = {} + local pos_can_be_skipped = {} + + local depth = 1 + for f in frontiers:iter() do + local node = mesecon.get_node_force(f.pos) + + if not node then + -- Area does not exist; do nothing + pos_can_be_skipped[minetest.hash_node_position(f.pos)] = true + elseif mesecon.is_conductor(node.name) then + local rules = mesecon.conductor_get_rules(node) + + if mesecon.is_conductor_on(node, f.link) then + for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do + local np = vector.add(f.pos, r) + + if not pos_can_be_skipped[minetest.hash_node_position(np)] then + -- Check if an onstate receptor is connected. If that is the case, + -- abort this turnoff process by returning false. `receptor_off` will + -- discard all the changes that we made in the voxelmanip: + if mesecon.rules_link_rule_all_inverted(f.pos, r)[1] then + if mesecon.is_receptor_on(mesecon.get_node_force(np).name) then + return false + end + end + + -- Call turnoff on neighbors + for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do + frontiers:add({pos = np, link = l}) + end + end + end + + mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link), light_update_conductors[node.name] ~= nil) + end + + -- Only conductors with flat rules can be reliably skipped later + if not rules[1] or rules[1].x then + pos_can_be_skipped[minetest.hash_node_position(f.pos)] = true + end + elseif mesecon.is_effector(node.name) then + table.insert(signals, { + pos = f.pos, + node = node, + link = f.link, + depth = depth + }) + else + pos_can_be_skipped[minetest.hash_node_position(f.pos)] = true + end + depth = depth + 1 + end + + for _, sig in ipairs(signals) do + -- If sig.depth is 1, it has not yet been checked that the power source is actually off. + if sig.depth > 1 or not mesecon.is_powered(sig.pos, sig.link) then + mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth) + if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then + mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth) + end + end + end + + return true +end + +-- Get all linking inputrules of inputnode (effector or conductor) that is connected to +-- outputnode (receptor or conductor) at position `output` and has an output in direction `rule` +function mesecon.rules_link_rule_all(output, rule) + local input = vector.add(output, rule) + local inputnode = mesecon.get_node_force(input) + local inputrules = mesecon.get_any_inputrules(inputnode) + if not inputrules then + return {} + end + local rules = {} + + for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do + -- Check if input accepts from output + if vector.equals(vector.add(input, inputrule), output) then + table.insert(rules, inputrule) + end + end + + return rules +end + +-- Get all linking outputnodes of outputnode (receptor or conductor) that is connected to +-- inputnode (effector or conductor) at position `input` and has an input in direction `rule` +function mesecon.rules_link_rule_all_inverted(input, rule) + local output = vector.add(input, rule) + local outputnode = mesecon.get_node_force(output) + local outputrules = mesecon.get_any_outputrules(outputnode) + if not outputrules then + return {} + end + local rules = {} + + for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do + if vector.equals(vector.add(output, outputrule), input) then + table.insert(rules, mesecon.invertRule(outputrule)) + end + end + return rules +end + +function mesecon.is_powered(pos, rule) + local node = mesecon.get_node_force(pos) + 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 _, rname in ipairs(rulenames) do + local np = vector.add(pos, rname) + local nn = mesecon.get_node_force(np) + + 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) + for _, rname in ipairs(rulenames) do + local np = vector.add(pos, rname) + local nn = mesecon.get_node_force(np) + if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname)) + or mesecon.is_receptor_on (nn.name)) then + table.insert(sourcepos, np) + end + end + end + + -- Return FALSE if not powered, return list of sources if is powered + if (#sourcepos == 0) then return false + else return sourcepos end +end diff --git a/mods/mesecons/mesecons/legacy.lua b/mods/mesecons/mesecons/legacy.lua new file mode 100644 index 00000000..2a8eae64 --- /dev/null +++ b/mods/mesecons/mesecons/legacy.lua @@ -0,0 +1,14 @@ +-- Un-forceload any forceloaded mapblocks from older versions of Mesecons which +-- used forceloading instead of VoxelManipulators. +local BLOCKSIZE = 16 + +-- convert block hash --> node position +local function unhash_blockpos(hash) + return vector.multiply(minetest.get_position_from_hash(hash), BLOCKSIZE) +end + +local old_forceloaded_blocks = mesecon.file2table("mesecon_forceloaded") +for hash, _ in pairs(old_forceloaded_blocks) do + minetest.forceload_free_block(unhash_blockpos(hash)) +end +os.remove(minetest.get_worldpath().."/mesecon_forceloaded") diff --git a/mods/mesecons/mesecons/locale/mesecons.de.tr b/mods/mesecons/mesecons/locale/mesecons.de.tr new file mode 100644 index 00000000..520c5aeb --- /dev/null +++ b/mods/mesecons/mesecons/locale/mesecons.de.tr @@ -0,0 +1,3 @@ +# textdomain: mesecons + +Mesecons=Mesecons diff --git a/mods/mesecons/mesecons/locale/mesecons.eo.tr b/mods/mesecons/mesecons/locale/mesecons.eo.tr new file mode 100644 index 00000000..76961f0e --- /dev/null +++ b/mods/mesecons/mesecons/locale/mesecons.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons + +### oldwires.lua ### +Mesecons=Mesekonduktilo diff --git a/mods/mesecons/mesecons/locale/mesecons.fr.tr b/mods/mesecons/mesecons/locale/mesecons.fr.tr new file mode 100644 index 00000000..2b51d695 --- /dev/null +++ b/mods/mesecons/mesecons/locale/mesecons.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons + +### oldwires.lua ### +Mesecons=Mesecons diff --git a/mods/mesecons/mesecons/locale/mesecons.ru.tr b/mods/mesecons/mesecons/locale/mesecons.ru.tr new file mode 100644 index 00000000..787f7d8d --- /dev/null +++ b/mods/mesecons/mesecons/locale/mesecons.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons + +### oldwires.lua ### +Mesecons=Мезеконы diff --git a/mods/mesecons/mesecons/locale/mesecons.uk.tr b/mods/mesecons/mesecons/locale/mesecons.uk.tr new file mode 100644 index 00000000..8d49577b --- /dev/null +++ b/mods/mesecons/mesecons/locale/mesecons.uk.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons + +### oldwires.lua ### +Mesecons=Месекони +Mod that implements a ton of items related to digital circuitry.=Мод, який реалізує масу елементів, пов’язаних із цифровою схемою. diff --git a/mods/mesecons/mesecons/locale/template.txt b/mods/mesecons/mesecons/locale/template.txt new file mode 100644 index 00000000..ca5f5d18 --- /dev/null +++ b/mods/mesecons/mesecons/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons + +### oldwires.lua ### +Mesecons= diff --git a/mods/mesecons/mesecons/mod.conf b/mods/mesecons/mesecons/mod.conf new file mode 100644 index 00000000..b49e9a83 --- /dev/null +++ b/mods/mesecons/mesecons/mod.conf @@ -0,0 +1,4 @@ +name = mesecons +# default is an optional dependency as some mods may expect it as a transitory +# dependency when they depend on mesecons. +optional_depends = default diff --git a/mods/mesecons/mesecons/oldwires.lua b/mods/mesecons/mesecons/oldwires.lua new file mode 100644 index 00000000..dfbe0677 --- /dev/null +++ b/mods/mesecons/mesecons/oldwires.lua @@ -0,0 +1,40 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +minetest.register_node("mesecons:mesecon_off", { + drawtype = "raillike", + tiles = {"jeija_mesecon_off.png", "jeija_mesecon_curved_off.png", "jeija_mesecon_t_junction_off.png", "jeija_mesecon_crossing_off.png"}, + inventory_image = "jeija_mesecon_off.png", + wield_image = "jeija_mesecon_off.png", + paramtype = "light", + is_ground_content = false, + walkable = false, + selection_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}, + }, + groups = {dig_immediate=3, mesecon=1, mesecon_conductor_craftable=1}, + description= S("Mesecons"), + mesecons = {conductor={ + state = mesecon.state.off, + onstate = "mesecons:mesecon_on" + }} +}) + +minetest.register_node("mesecons:mesecon_on", { + drawtype = "raillike", + tiles = {"jeija_mesecon_on.png", "jeija_mesecon_curved_on.png", "jeija_mesecon_t_junction_on.png", "jeija_mesecon_crossing_on.png"}, + paramtype = "light", + is_ground_content = false, + walkable = false, + selection_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}, + }, + groups = {dig_immediate=3, not_in_creaive_inventory=1, mesecon=1}, + drop = "mesecons:mesecon_off 1", + light_source = minetest.LIGHT_MAX-11, + mesecons = {conductor={ + state = mesecon.state.on, + offstate = "mesecons:mesecon_off" + }} +}) diff --git a/mods/mesecons/mesecons/presets.lua b/mods/mesecons/mesecons/presets.lua new file mode 100644 index 00000000..bf16d993 --- /dev/null +++ b/mods/mesecons/mesecons/presets.lua @@ -0,0 +1,88 @@ +mesecon.rules = {} +mesecon.state = {} + +mesecon.rules.default = { + {x = 0, y = 0, z = -1}, + {x = 1, y = 0, z = 0}, + {x = -1, y = 0, z = 0}, + {x = 0, y = 0, z = 1}, + {x = 1, y = 1, z = 0}, + {x = 1, y = -1, z = 0}, + {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 = 0, y = 1, z = -1}, + {x = 0, y = -1, z = -1}, +} + +mesecon.rules.floor = mesecon.merge_rule_sets(mesecon.rules.default, {{x = 0, y = -1, z = 0}}) + +mesecon.rules.pplate = mesecon.merge_rule_sets(mesecon.rules.floor, {{x = 0, y = -2, z = 0}}) + +mesecon.rules.buttonlike = { + {x = 1, y = 0, z = 0}, + {x = 1, y = 1, z = 0}, + {x = 1, y = -1, z = 0}, + {x = 1, y = -1, z = 1}, + {x = 1, y = -1, z = -1}, + {x = 2, y = 0, z = 0}, +} + +mesecon.rules.flat = { + {x = 1, y = 0, z = 0}, + {x = -1, y = 0, z = 0}, + {x = 0, y = 0, z = 1}, + {x = 0, y = 0, z = -1}, +} + +mesecon.rules.alldirs = { + {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}, +} + +local rules_wallmounted = { + xp = mesecon.rotate_rules_down(mesecon.rules.floor), + xn = mesecon.rotate_rules_up(mesecon.rules.floor), + yp = mesecon.rotate_rules_up(mesecon.rotate_rules_up(mesecon.rules.floor)), + yn = mesecon.rules.floor, + zp = mesecon.rotate_rules_left(mesecon.rotate_rules_up(mesecon.rules.floor)), + zn = mesecon.rotate_rules_right(mesecon.rotate_rules_up(mesecon.rules.floor)), +} + +local rules_buttonlike = { + xp = mesecon.rules.buttonlike, + xn = mesecon.rotate_rules_right(mesecon.rotate_rules_right(mesecon.rules.buttonlike)), + yp = mesecon.rotate_rules_down(mesecon.rules.buttonlike), + yn = mesecon.rotate_rules_up(mesecon.rules.buttonlike), + zp = mesecon.rotate_rules_right(mesecon.rules.buttonlike), + zn = mesecon.rotate_rules_left(mesecon.rules.buttonlike), +} + +local function rules_from_dir(ruleset, dir) + if not dir then return {} end + + if dir.x == 1 then return ruleset.xp end + if dir.y == 1 then return ruleset.yp end + if dir.z == 1 then return ruleset.zp end + if dir.x == -1 then return ruleset.xn end + if dir.y == -1 then return ruleset.yn end + if dir.z == -1 then return ruleset.zn end +end + +mesecon.rules.wallmounted_get = function(node) + local dir = minetest.wallmounted_to_dir(node.param2) + return rules_from_dir(rules_wallmounted, dir) +end + +mesecon.rules.buttonlike_get = function(node) + local dir = minetest.facedir_to_dir(node.param2) + return rules_from_dir(rules_buttonlike, dir) +end + +mesecon.state.on = "on" +mesecon.state.off = "off" diff --git a/mods/mesecons/mesecons/services.lua b/mods/mesecons/mesecons/services.lua new file mode 100644 index 00000000..f33aee42 --- /dev/null +++ b/mods/mesecons/mesecons/services.lua @@ -0,0 +1,139 @@ +-- Dig and place services + +mesecon.on_placenode = function(pos, node) + mesecon.execute_autoconnect_hooks_now(pos, node) + node = minetest.get_node(pos) -- Update the node in case it was just changed. + + -- Receptors: Send on signal when active + 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 + local conductor = mesecon.get_conductor(node.name) + if conductor.state ~= mesecon.state.off then + -- Turn the conductor off. + node.name = conductor.offstate or conductor.states[1] + minetest.swap_node(pos, node) + end + local sources = mesecon.is_powered(pos) + if sources then + mesecon.vm_begin() + for _, s in ipairs(sources) do + local rule = vector.subtract(s, pos) + mesecon.turnon(pos, rule) + end + mesecon.vm_commit() + end + end + + -- Effectors: Send changesignal and activate or deactivate + if mesecon.is_effector(node.name) then + local powered_rules = {} + local unpowered_rules = {} + + -- for each input rule, check if powered + for _, r in ipairs(mesecon.effector_get_rules(node)) do + local powered = mesecon.is_powered(pos, r) + if powered then table.insert(powered_rules, r) + else table.insert(unpowered_rules, r) end + + local state = powered and mesecon.state.on or mesecon.state.off + mesecon.changesignal(pos, node, r, state, 1) + end + + if (#powered_rules > 0) then + for _, r in ipairs(powered_rules) do + mesecon.activate(pos, node, r, 1) + end + else + for _, r in ipairs(unpowered_rules) do + mesecon.deactivate(pos, node, r, 1) + end + 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)) + end + + mesecon.execute_autoconnect_hooks_queue(pos, node) +end + +function mesecon.on_blastnode(pos) + local node = minetest.get_node(pos) + minetest.remove_node(pos) + mesecon.on_dignode(pos, node) + return minetest.get_node_drops(node.name, "") +end + +minetest.register_on_placenode(mesecon.on_placenode) +minetest.register_on_dignode(mesecon.on_dignode) + +-- Overheating service for fast circuits +local OVERHEAT_MAX = mesecon.setting("overheat_max", 20) +local COOLDOWN_TIME = mesecon.setting("cooldown_time", 2.0) +local COOLDOWN_STEP = mesecon.setting("cooldown_granularity", 0.5) +local COOLDOWN_MULTIPLIER = OVERHEAT_MAX / COOLDOWN_TIME +local cooldown_timer = 0.0 +local object_heat = {} + +-- returns true if heat is too high +function mesecon.do_overheat(pos) + local id = minetest.hash_node_position(pos) + local heat = (object_heat[id] or 0) + 1 + object_heat[id] = heat + if heat >= OVERHEAT_MAX then + minetest.log("action", "Node overheats at " .. minetest.pos_to_string(pos)) + object_heat[id] = nil + return true + end + return false +end + +function mesecon.do_cooldown(pos) + local id = minetest.hash_node_position(pos) + object_heat[id] = nil +end + +function mesecon.get_heat(pos) + local id = minetest.hash_node_position(pos) + return object_heat[id] or 0 +end + +function mesecon.move_hot_nodes(moved_nodes) + local new_heat = {} + for _, n in ipairs(moved_nodes) do + local old_id = minetest.hash_node_position(n.oldpos) + local new_id = minetest.hash_node_position(n.pos) + new_heat[new_id] = object_heat[old_id] + object_heat[old_id] = nil + end + for id, heat in pairs(new_heat) do + object_heat[id] = heat + end +end + +local function global_cooldown(dtime) + cooldown_timer = cooldown_timer + dtime + if cooldown_timer < COOLDOWN_STEP then + return -- don't overload the CPU + end + local cooldown = COOLDOWN_MULTIPLIER * cooldown_timer + cooldown_timer = 0 + for id, heat in pairs(object_heat) do + heat = heat - cooldown + if heat <= 0 then + object_heat[id] = nil -- free some RAM + else + object_heat[id] = heat + end + end +end +minetest.register_globalstep(global_cooldown) diff --git a/mods/mesecons/mesecons/settings.lua b/mods/mesecons/mesecons/settings.lua new file mode 100644 index 00000000..02207073 --- /dev/null +++ b/mods/mesecons/mesecons/settings.lua @@ -0,0 +1,15 @@ +-- SETTINGS +function mesecon.setting(setting, default) + if type(default) == "boolean" then + local read = minetest.settings:get_bool("mesecon."..setting) + if read == nil then + return default + else + return read + end + elseif type(default) == "string" then + return minetest.settings:get("mesecon."..setting) or default + elseif type(default) == "number" then + return tonumber(minetest.settings:get("mesecon."..setting) or default) + end +end diff --git a/mods/mesecons/mesecons/spec/action_spec.lua b/mods/mesecons/mesecons/spec/action_spec.lua new file mode 100644 index 00000000..55f75d8c --- /dev/null +++ b/mods/mesecons/mesecons/spec/action_spec.lua @@ -0,0 +1,62 @@ +require("mineunit") + +fixture("mesecons") + +describe("action queue", function() + local layout = { + {{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"}, + {{x = 0, y = 0, z = 0}, "mesecons:test_conductor_off"}, + {{x = -1, y = 0, z = 0}, "mesecons:test_conductor_off"}, + {{x = 0, y = 1, z = 0}, "mesecons:test_effector"}, + {{x = -1, y = 1, z = 0}, "mesecons:test_effector"}, + } + + before_each(function() + world.layout(layout) + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("executes in order", function() + world.set_node(layout[1][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal(2, #mesecon._test_effector_events) + assert.same({"on", layout[4][1]}, mesecon._test_effector_events[1]) + assert.same({"on", layout[5][1]}, mesecon._test_effector_events[2]) + + world.set_node(layout[1][1], "mesecons:test_receptor_off") + mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_off action + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal(4, #mesecon._test_effector_events) + assert.same({"off", layout[4][1]}, mesecon._test_effector_events[3]) + assert.same({"off", layout[5][1]}, mesecon._test_effector_events[4]) + end) + + it("discards outdated/overwritten node events", function() + world.set_node(layout[1][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) + world.set_node(layout[1][1], "mesecons:test_receptor_off") + mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_off action + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal(0, #mesecon._test_effector_events) + end) + + it("delays actions", function() + world.set_node(layout[1][1], "mesecons:test_receptor_on") + mesecon.queue:add_action(layout[1][1], "receptor_on", {mesecon.rules.alldirs}, 1, nil) + mineunit:execute_globalstep(0.1) + mineunit:execute_globalstep(1) + assert.equal(0, #mesecon._test_effector_events) + mineunit:execute_globalstep() -- Execute receptor_on action + assert.equal(0, #mesecon._test_effector_events) + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal(2, #mesecon._test_effector_events) + end) +end) diff --git a/mods/mesecons/mesecons/spec/mineunit.conf b/mods/mesecons/mesecons/spec/mineunit.conf new file mode 100644 index 00000000..81bd36ce --- /dev/null +++ b/mods/mesecons/mesecons/spec/mineunit.conf @@ -0,0 +1 @@ +fixture_paths = {"../.test_fixtures"} diff --git a/mods/mesecons/mesecons/spec/service_spec.lua b/mods/mesecons/mesecons/spec/service_spec.lua new file mode 100644 index 00000000..7b6fa0ab --- /dev/null +++ b/mods/mesecons/mesecons/spec/service_spec.lua @@ -0,0 +1,192 @@ +require("mineunit") + +fixture("mesecons") +fixture("screwdriver") + +describe("placement/digging service", function() + local layout = { + {{x = 1, y = 0, z = 0}, "mesecons:test_receptor_on"}, + {{x = 0, y = 0, z = 0}, "mesecons:test_conductor_on"}, + {{x = -1, y = 0, z = 0}, "mesecons:test_conductor_on"}, + {{x = 0, y = 1, z = 0}, "mesecons:test_effector"}, + {{x = -2, y = 0, z = 0}, "mesecons:test_effector"}, + {{x = 2, y = 0, z = 0}, "mesecons:test_effector"}, + } + + before_each(function() + world.layout(layout) + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("updates components when a receptor changes", function() + -- Dig then replace a receptor and check that the connected effectors changed. + + mesecon._test_dig(layout[1][1]) + mineunit:execute_globalstep() -- Execute receptor_off action + assert.equal("mesecons:test_conductor_off", world.get_node(layout[2][1]).name) + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal(3, #mesecon._test_effector_events) + + mesecon._test_place(layout[1][1], "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on action + assert.equal("mesecons:test_conductor_on", world.get_node(layout[2][1]).name) + mineunit:execute_globalstep() -- Execute activate/change action + assert.equal(6, #mesecon._test_effector_events) + end) + + it("updates components when a conductor changes", function() + -- Dig then replace a powered conductor and check that the connected effectors changed. + + mesecon._test_dig(layout[2][1]) + mineunit:execute_globalstep() -- Execute receptor_off action + assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name) + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal(2, #mesecon._test_effector_events) + + mesecon._test_place(layout[2][1], "mesecons:test_conductor_off") + assert.equal("mesecons:test_conductor_on", world.get_node(layout[2][1]).name) + assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal(4, #mesecon._test_effector_events) + end) + + it("updates effectors on placement", function() + local pos = {x = 0, y = 0, z = 1} + mesecon._test_place(pos, "mesecons:test_effector") + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal(tonumber("10100000", 2), world.get_node(pos).param2) + end) + + it("updates multiconductors on placement", function() + local pos = {x = 0, y = 0, z = 1} + mesecon._test_place(pos, "mesecons:test_multiconductor_off") + assert.equal("mesecons:test_multiconductor_010", world.get_node(pos).name) + end) + + it("turns off conductors on placement", function() + local pos = {x = 3, y = 0, z = 0} + mesecon._test_place(pos, "mesecons:test_conductor_on") + assert.equal("mesecons:test_conductor_off", world.get_node(pos).name) + end) + + it("turns off multiconductors on placement", function() + local pos = {x = 3, y = 0, z = 0} + mesecon._test_place(pos, "mesecons:test_multiconductor_on") + assert.equal("mesecons:test_multiconductor_off", world.get_node(pos).name) + end) + + it("triggers autoconnect hooks", function() + mesecon._test_dig(layout[2][1]) + mineunit:execute_globalstep() -- Execute delayed hook + assert.equal(1, #mesecon._test_autoconnects) + + mesecon._test_place(layout[2][1], layout[2][2]) + assert.equal(2, #mesecon._test_autoconnects) + end) +end) + +describe("overheating service", function() + local layout = { + {{x = 0, y = 0, z = 0}, "mesecons:test_receptor_off"}, + {{x = 1, y = 0, z = 0}, "mesecons:test_effector"}, + {{x = 2, y = 0, z = 0}, "mesecons:test_receptor_on"}, + } + + before_each(function() + world.layout(layout) + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("tracks heat", function() + mesecon.do_overheat(layout[2][1]) + assert.equal(1, mesecon.get_heat(layout[2][1])) + mesecon.do_cooldown(layout[2][1]) + assert.equal(0, mesecon.get_heat(layout[2][1])) + end) + + it("cools over time", function() + mesecon.do_overheat(layout[2][1]) + assert.equal(1, mesecon.get_heat(layout[2][1])) + mineunit:execute_globalstep(60) + mineunit:execute_globalstep(60) + mineunit:execute_globalstep(60) + assert.equal(0, mesecon.get_heat(layout[2][1])) + end) + + it("tracks movement", function() + local oldpos = layout[2][1] + local pos = vector.offset(oldpos, 0, 1, 0) + mesecon.do_overheat(oldpos) + mesecon.move_hot_nodes({{pos = pos, oldpos = oldpos}}) + assert.equal(0, mesecon.get_heat(oldpos)) + assert.equal(1, mesecon.get_heat(pos)) + end) + + it("causes overheating", function() + -- Switch the first receptor on and off until it overheats/breaks a receptor. + repeat + if mesecon.flipstate(layout[1][1], minetest.get_node(layout[1][1])) == "on" then + mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) + else + mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs) + end + mineunit:execute_globalstep(0) -- Execute receptor_on/receptor_off/activate/deactivate/change actions + until minetest.get_node(layout[2][1]).name ~= "mesecons:test_effector" + assert.same({"overheat", layout[2][1]}, mesecon._test_effector_events[#mesecon._test_effector_events]) + assert.equal(0, mesecon.get_heat(layout[2][1])) + end) +end) + +describe("screwdriver service", function() + local layout = { + {{x = 0, y = 0, z = 0}, "mesecons:test_conductor_rot_on"}, + {{x = 1, y = 0, z = 0}, "mesecons:test_receptor_on"}, + {{x = -1, y = 0, z = 0}, "mesecons:test_conductor_on"}, + {{x = 0, y = 0, z = 1}, "mesecons:test_receptor_on"}, + {{x = 0, y = 0, z = -1}, "mesecons:test_conductor_off"}, + } + + local function rotate(new_param2) + local pos = layout[1][1] + local node = world.get_node(pos) + local on_rotate = minetest.registered_nodes[node.name].on_rotate + on_rotate(pos, node, nil, screwdriver.ROTATE_FACE, new_param2) + end + + before_each(function() + world.layout(layout) + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("updates conductors", function() + -- Rotate a conductor and see that the circuit state changes. + rotate(1) + mineunit:execute_globalstep() -- Execute receptor_off action + assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name) + assert.equal("mesecons:test_conductor_on", world.get_node(layout[5][1]).name) + rotate(2) + mineunit:execute_globalstep() -- Execute receptor_off action + assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) + assert.equal("mesecons:test_conductor_off", world.get_node(layout[5][1]).name) + rotate(3) + mineunit:execute_globalstep() -- Execute receptor_off action + assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name) + assert.equal("mesecons:test_conductor_on", world.get_node(layout[5][1]).name) + rotate(0) + mineunit:execute_globalstep() -- Execute receptor_off action + assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) + assert.equal("mesecons:test_conductor_off", world.get_node(layout[5][1]).name) + end) +end) diff --git a/mods/mesecons/mesecons/spec/state_spec.lua b/mods/mesecons/mesecons/spec/state_spec.lua new file mode 100644 index 00000000..c66871bb --- /dev/null +++ b/mods/mesecons/mesecons/spec/state_spec.lua @@ -0,0 +1,147 @@ +require("mineunit") + +fixture("mesecons") + +describe("state", function() + local layout = { + {{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"}, + {{x = 0, y = 1, z = 0}, "mesecons:test_receptor_off"}, + {{x = 0, y = 0, z = 0}, "mesecons:test_conductor_off"}, + {{x = -1, y = 0, z = 0}, "mesecons:test_effector"}, + {{x = 2, y = 0, z = 0}, "mesecons:test_effector"}, + {{x = 0, y = -1, z = 0}, "mesecons:test_effector"}, + } + + before_each(function() + world.layout(layout) + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("turns on", function() + world.set_node(layout[1][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) + assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2) + assert.equal(tonumber("10000010", 2), world.get_node(layout[5][1]).param2) + assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2) + + world.set_node(layout[2][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) + assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2) + assert.equal(tonumber("10000010", 2), world.get_node(layout[5][1]).param2) + assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2) + end) + + it("turns off", function() + world.set_node(layout[1][1], "mesecons:test_receptor_on") + world.set_node(layout[2][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) + mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on actions + + world.set_node(layout[1][1], "mesecons:test_receptor_off") + mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_off and activate/change actions + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name) + assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2) + assert.equal(tonumber("00000000", 2), world.get_node(layout[5][1]).param2) + assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2) + + world.set_node(layout[2][1], "mesecons:test_receptor_off") + mesecon.receptor_off(layout[2][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_off action + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name) + assert.equal(tonumber("00000000", 2), world.get_node(layout[4][1]).param2) + assert.equal(tonumber("00000000", 2), world.get_node(layout[5][1]).param2) + assert.equal(tonumber("00000000", 2), world.get_node(layout[6][1]).param2) + end) +end) + +describe("rotation", function() + local layout = { + {{x = 0, y = 0, z = 0}, "mesecons:test_receptor_off"}, + {{x = 1, y = 0, z = 0}, {name = "mesecons:test_conductor_rot_off", param2 = 0}}, + {{x = 0, y = 0, z = 1}, {name = "mesecons:test_conductor_rot_off", param2 = 1}}, + {{x = -1, y = 0, z = 0}, {name = "mesecons:test_conductor_rot_off", param2 = 2}}, + {{x = 0, y = 0, z = -1}, {name = "mesecons:test_conductor_rot_off", param2 = 3}}, + } + + before_each(function() + for _, entry in ipairs(layout) do + world.set_node(entry[1], entry[2]) + end + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("works", function() + world.set_node(layout[1][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on action + assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[2][1]).name) + assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[3][1]).name) + assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[4][1]).name) + assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[5][1]).name) + end) +end) + +describe("multiconductor", function() + local layout = { + {{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"}, + {{x = 0, y = 1, z = 0}, "mesecons:test_receptor_off"}, + {{x = 0, y = 0, z = 1}, "mesecons:test_receptor_off"}, + {{x = 0, y = 0, z = 0}, "mesecons:test_multiconductor_off"}, + } + + before_each(function() + world.layout(layout) + end) + + after_each(function() + world.clear() + mesecon._test_reset() + end) + + it("separates its subparts", function() + world.set_node(layout[1][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on action + assert.equal("mesecons:test_multiconductor_001", world.get_node(layout[4][1]).name) + + world.set_node(layout[2][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on action + assert.equal("mesecons:test_multiconductor_011", world.get_node(layout[4][1]).name) + + world.set_node(layout[3][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[3][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on action + assert.equal("mesecons:test_multiconductor_on", world.get_node(layout[4][1]).name) + end) + + it("loops through itself", function() + -- Make a loop. + world.set_node({x = 0, y = -1, z = 0}, "mesecons:test_conductor_off") + world.set_node({x = -1, y = -1, z = 0}, "mesecons:test_conductor_off") + world.set_node({x = -1, y = 0, z = 0}, "mesecons:test_conductor_off") + + world.set_node(layout[1][1], "mesecons:test_receptor_on") + mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs) + mineunit:execute_globalstep() -- Execute receptor_on action + assert.equal("mesecons:test_multiconductor_101", world.get_node(layout[4][1]).name) + end) +end) diff --git a/mods/mesecons/mesecons/textures/jeija_close_window.png b/mods/mesecons/mesecons/textures/jeija_close_window.png new file mode 100644 index 00000000..8ab7783e Binary files /dev/null and b/mods/mesecons/mesecons/textures/jeija_close_window.png differ diff --git a/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_A.png b/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_A.png new file mode 100644 index 00000000..6f8f056f Binary files /dev/null and b/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_A.png differ diff --git a/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_B.png b/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_B.png new file mode 100644 index 00000000..7cc58eaf Binary files /dev/null and b/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_B.png differ diff --git a/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_C.png b/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_C.png new file mode 100644 index 00000000..3046d24c Binary files /dev/null and b/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_C.png differ diff --git a/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_D.png b/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_D.png new file mode 100644 index 00000000..ed46d974 Binary files /dev/null and b/mods/mesecons/mesecons/textures/jeija_luacontroller_LED_D.png differ diff --git a/mods/mesecons/mesecons/textures/jeija_microcontroller_bottom.png b/mods/mesecons/mesecons/textures/jeija_microcontroller_bottom.png new file mode 100644 index 00000000..7ae955c1 Binary files /dev/null and b/mods/mesecons/mesecons/textures/jeija_microcontroller_bottom.png differ diff --git a/mods/mesecons/mesecons/textures/jeija_microcontroller_sides.png b/mods/mesecons/mesecons/textures/jeija_microcontroller_sides.png new file mode 100644 index 00000000..40f4b60c Binary files /dev/null and b/mods/mesecons/mesecons/textures/jeija_microcontroller_sides.png differ diff --git a/mods/mesecons/mesecons/textures/mesecons_wire_inv.png b/mods/mesecons/mesecons/textures/mesecons_wire_inv.png new file mode 100644 index 00000000..db2676c2 Binary files /dev/null and b/mods/mesecons/mesecons/textures/mesecons_wire_inv.png differ diff --git a/mods/mesecons/mesecons/textures/mesecons_wire_off.png b/mods/mesecons/mesecons/textures/mesecons_wire_off.png new file mode 100644 index 00000000..d41f6263 Binary files /dev/null and b/mods/mesecons/mesecons/textures/mesecons_wire_off.png differ diff --git a/mods/mesecons/mesecons/textures/mesecons_wire_on.png b/mods/mesecons/mesecons/textures/mesecons_wire_on.png new file mode 100644 index 00000000..239356a0 Binary files /dev/null and b/mods/mesecons/mesecons/textures/mesecons_wire_on.png differ diff --git a/mods/mesecons/mesecons/util.lua b/mods/mesecons/mesecons/util.lua new file mode 100644 index 00000000..d779d600 --- /dev/null +++ b/mods/mesecons/mesecons/util.lua @@ -0,0 +1,524 @@ +function mesecon.move_node(pos, newpos) + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos):to_table() + minetest.remove_node(pos) + minetest.set_node(newpos, node) + minetest.get_meta(pos):from_table(meta) +end + +-- An on_rotate callback for mesecons components. +function mesecon.on_rotate(pos, node, _, _, new_param2) + local new_node = {name = node.name, param1 = node.param1, param2 = new_param2} + minetest.swap_node(pos, new_node) + mesecon.on_dignode(pos, node) + mesecon.on_placenode(pos, new_node) + minetest.check_for_falling(pos) + return true +end + +-- An on_rotate callback for components which stay horizontal. +-- Deprecated. Use paramtype2 = "4dir" instead. +function mesecon.on_rotate_horiz(pos, node, user, mode, new_param2) + if not minetest.global_exists("screwdriver") or mode ~= screwdriver.ROTATE_FACE then + return false + end + return mesecon.on_rotate(pos, node, user, mode, new_param2) +end + +-- Rules rotation Functions: +function mesecon.rotate_rules_right(rules) + local nr = {} + for i, rule in ipairs(rules) do + table.insert(nr, { + x = -rule.z, + y = rule.y, + z = rule.x, + name = rule.name}) + end + return nr +end + +function mesecon.rotate_rules_left(rules) + local nr = {} + for i, rule in ipairs(rules) do + table.insert(nr, { + x = rule.z, + y = rule.y, + z = -rule.x, + name = rule.name}) + end + return nr +end + +function mesecon.rotate_rules_down(rules) + local nr = {} + for i, rule in ipairs(rules) do + table.insert(nr, { + x = -rule.y, + y = rule.x, + z = rule.z, + name = rule.name}) + end + return nr +end + +function mesecon.rotate_rules_up(rules) + local nr = {} + for i, rule in ipairs(rules) do + table.insert(nr, { + x = rule.y, + y = -rule.x, + z = rule.z, + name = rule.name}) + end + return nr +end + +-- Returns a rules getter function that returns different rules depending on the node's horizontal rotation. +-- If param2 % 4 == 0, then the rules returned by the getter are a copy of base_rules. +function mesecon.horiz_rules_getter(base_rules) + local rotations = {mesecon.tablecopy(base_rules)} + for i = 2, 4 do + local right_rules = rotations[i - 1] + if not right_rules[1] or right_rules[1].x then + -- flat rules + rotations[i] = mesecon.rotate_rules_left(right_rules) + else + -- not flat + rotations[i] = {} + for j, rules in ipairs(right_rules) do + rotations[i][j] = mesecon.rotate_rules_left(rules) + end + end + end + return function(node) + return rotations[node.param2 % 4 + 1] + end +end + +function mesecon.flattenrules(allrules) +--[[ + { + { + {xyz}, + {xyz}, + }, + { + {xyz}, + {xyz}, + }, + } +--]] + if allrules[1] and + allrules[1].x then + return allrules + end + + local shallowrules = {} + for _, metarule in ipairs( allrules) do + for _, rule in ipairs(metarule ) do + table.insert(shallowrules, rule) + end + end + return shallowrules +--[[ + { + {xyz}, + {xyz}, + {xyz}, + {xyz}, + } +--]] +end + +function mesecon.rule2bit(findrule, allrules) + --get the bit of the metarule the rule is in, or bit 1 + if (allrules[1] and + allrules[1].x) or + not findrule then + return 1 + end + for m,metarule in ipairs( allrules) do + for _, rule in ipairs(metarule ) do + if vector.equals(findrule, rule) then + return m + end + end + end +end + +function mesecon.rule2metaindex(findrule, allrules) + --get the metarule the rule is in, or allrules + if allrules[1].x then + return nil + end + + if not(findrule) then + return mesecon.flattenrules(allrules) + end + + for m, metarule in ipairs( allrules) do + for _, rule in ipairs(metarule ) do + if vector.equals(findrule, rule) then + return m + end + end + end +end + +function mesecon.rule2meta(findrule, allrules) + if #allrules == 0 then return {} end + + local index = mesecon.rule2metaindex(findrule, allrules) + if index == nil then + if allrules[1].x then + return allrules + else + return {} + end + end + return allrules[index] +end + +function mesecon.dec2bin(n) + local x, y = math.floor(n / 2), n % 2 + if (n > 1) then + return mesecon.dec2bin(x)..y + else + return ""..y + end +end + +function mesecon.getstate(nodename, states) + for state, name in ipairs(states) do + if name == nodename then + return state + end + end + error(nodename.." doesn't mention itself in "..dump(states)) +end + +function mesecon.getbinstate(nodename, states) + return mesecon.dec2bin(mesecon.getstate(nodename, states)-1) +end + +function mesecon.get_bit(binary,bit) + bit = bit or 1 + local len = binary:len() + if bit > len then return false end + local c = len-(bit-1) + return binary:sub(c,c) == "1" +end + +function mesecon.set_bit(binary,bit,value) + if value == "1" then + if not mesecon.get_bit(binary,bit) then + return mesecon.dec2bin(tonumber(binary,2)+math.pow(2,bit-1)) + end + elseif value == "0" then + if mesecon.get_bit(binary,bit) then + return mesecon.dec2bin(tonumber(binary,2)-math.pow(2,bit-1)) + end + end + return binary + +end + +function mesecon.invertRule(r) + return vector.multiply(r, -1) +end + +function mesecon.tablecopy(obj) -- deep copy + if type(obj) == "table" then + return table.copy(obj) + end + return obj +end + +-- Returns whether two values are equal. +-- In tables, keys are compared for identity but values are compared recursively. +-- There is no protection from infinite recursion. +function mesecon.cmpAny(t1, t2) + if type(t1) ~= type(t2) then return false end + if type(t1) ~= "table" then return t1 == t2 end + + -- Check that for each key of `t1` both tables have the same value + for i, e in pairs(t1) do + if not mesecon.cmpAny(e, t2[i]) then return false end + end + + -- Check that all keys of `t2` are also keys of `t1` so were checked in the previous loop + for i, _ in pairs(t2) do + if t1[i] == nil then return false end + end + + return true +end + +-- Deprecated. Use `merge_tables` or `merge_rule_sets` as appropriate. +function mesecon.mergetable(source, dest) + minetest.log("warning", debug.traceback("Deprecated call to mesecon.mergetable")) + local rval = mesecon.tablecopy(dest) + + for k, v in pairs(source) do + rval[k] = dest[k] or mesecon.tablecopy(v) + end + for i, v in ipairs(source) do + table.insert(rval, mesecon.tablecopy(v)) + end + + return rval +end + +-- Merges several rule sets in one. Order may not be preserved. Nil arguments +-- are ignored. +-- The rule sets must be of the same kind (either all single-level or all two-level). +-- The function may be changed to normalize the resulting set in some way. +function mesecon.merge_rule_sets(...) + local rval = {} + for _, t in pairs({...}) do -- ignores nils automatically + table.insert_all(rval, mesecon.tablecopy(t)) + end + return rval +end + +-- Merges two tables, with entries from `replacements` taking precedence over +-- those from `base`. Returns the new table. +-- Values are deep-copied from either table, keys are referenced. +-- Numerical indices aren’t handled specially. +function mesecon.merge_tables(base, replacements) + local ret = mesecon.tablecopy(replacements) -- these are never overriden so have to be copied in any case + for k, v in pairs(base) do + if ret[k] == nil then -- it could be `false` + ret[k] = mesecon.tablecopy(v) + end + end + return ret +end + +function mesecon.register_node(name, spec_common, spec_off, spec_on) + spec_common.drop = spec_common.drop or name .. "_off" + spec_common.on_blast = spec_common.on_blast or mesecon.on_blastnode + spec_common.__mesecon_basename = name + spec_on.__mesecon_state = "on" + spec_off.__mesecon_state = "off" + + spec_on = mesecon.merge_tables(spec_common, spec_on); + spec_off = mesecon.merge_tables(spec_common, spec_off); + + minetest.register_node(name .. "_on", spec_on) + minetest.register_node(name .. "_off", spec_off) +end + +-- swap onstate and offstate nodes, returns new state +function mesecon.flipstate(pos, node) + local nodedef = minetest.registered_nodes[node.name] + local newstate + if (nodedef.__mesecon_state == "on") then newstate = "off" end + if (nodedef.__mesecon_state == "off") then newstate = "on" end + + minetest.swap_node(pos, {name = nodedef.__mesecon_basename .. "_" .. newstate, + param2 = node.param2}) + + return newstate +end + +-- File writing / reading utilities +local wpath = minetest.get_worldpath() +function mesecon.file2table(filename) + local f = io.open(wpath.."/"..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 + +function mesecon.table2file(filename, table) + local f = io.open(wpath.."/"..filename, "w") + f:write(minetest.serialize(table)) + f:close() +end + +-- Block position "hashing" (convert to integer) functions for voxelmanip cache +local BLOCKSIZE = 16 + +-- convert node position --> block hash +local function hash_blockpos(pos) + return minetest.hash_node_position({ + x = math.floor(pos.x/BLOCKSIZE), + y = math.floor(pos.y/BLOCKSIZE), + z = math.floor(pos.z/BLOCKSIZE) + }) +end + +-- Maps from a hashed mapblock position (as returned by hash_blockpos) to a +-- table. +-- +-- Contents of the table are: +-- “vm” → the VoxelManipulator +-- “dirty” → true if data has been modified +-- +-- Nil if no VM-based transaction is in progress. +local vm_cache = nil + +-- Cache from node position hashes to nodes (represented as tables). +local vm_node_cache = nil + +-- Whether the current transaction will need a light update afterward. +local vm_update_light = false + +-- Starts a VoxelManipulator-based transaction. +-- +-- During a VM transaction, calls to vm_get_node and vm_swap_node operate on a +-- cached copy of the world loaded via VoxelManipulators. That cache can later +-- be committed to the real map by means of vm_commit or discarded by means of +-- vm_abort. +function mesecon.vm_begin() + vm_cache = {} + vm_node_cache = {} + vm_update_light = false +end + +-- Finishes a VoxelManipulator-based transaction, freeing the VMs and map data +-- and writing back any modified areas. +function mesecon.vm_commit() + for hash, tbl in pairs(vm_cache) do + if tbl.dirty then + local vm = tbl.vm + vm:write_to_map(vm_update_light) + vm:update_map() + end + end + vm_cache = nil + vm_node_cache = nil +end + +-- Finishes a VoxelManipulator-based transaction, freeing the VMs and throwing +-- away any modified areas. +function mesecon.vm_abort() + vm_cache = nil + vm_node_cache = nil +end + +-- Gets the cache entry covering a position, populating it if necessary. +local function vm_get_or_create_entry(pos) + local hash = hash_blockpos(pos) + local tbl = vm_cache[hash] + if not tbl then + tbl = {vm = minetest.get_voxel_manip(pos, pos), dirty = false} + vm_cache[hash] = tbl + end + return tbl +end + +-- Gets the node at a given position during a VoxelManipulator-based +-- transaction. +function mesecon.vm_get_node(pos) + local hash = minetest.hash_node_position(pos) + local node = vm_node_cache[hash] + if not node then + node = vm_get_or_create_entry(pos).vm:get_node_at(pos) + vm_node_cache[hash] = node + end + return node.name ~= "ignore" and {name = node.name, param1 = node.param1, param2 = node.param2} or nil +end + +-- Sets a node’s name during a VoxelManipulator-based transaction. +-- +-- Existing param1, param2, and metadata are left alone. +-- +-- The swap will necessitate a light update unless update_light equals false. +function mesecon.vm_swap_node(pos, name, update_light) + -- If one node needs a light update, all VMs should use light updates to + -- prevent newly calculated light from being overwritten by other VMs. + vm_update_light = vm_update_light or update_light ~= false + + local tbl = vm_get_or_create_entry(pos) + local hash = minetest.hash_node_position(pos) + local node = vm_node_cache[hash] + if not node then + node = tbl.vm:get_node_at(pos) + vm_node_cache[hash] = node + end + node.name = name + tbl.vm:set_node_at(pos, node) + tbl.dirty = true +end + +-- Gets the node at a given position, regardless of whether it is loaded or +-- not, respecting a transaction if one is in progress. +-- +-- Outside a VM transaction, if the mapblock is not loaded, it is pulled into +-- the server’s main map data cache and then accessed from there. +-- +-- Inside a VM transaction, the transaction’s VM cache is used. +function mesecon.get_node_force(pos) + if vm_cache then + return mesecon.vm_get_node(pos) + else + local node = minetest.get_node_or_nil(pos) + if node == nil then + -- Node is not currently loaded; use a VoxelManipulator to prime + -- the mapblock cache and try again. + minetest.get_voxel_manip(pos, pos) + node = minetest.get_node_or_nil(pos) + end + return node + end +end + +-- Swaps the node at a given position, regardless of whether it is loaded or +-- not, respecting a transaction if one is in progress. +-- +-- Outside a VM transaction, if the mapblock is not loaded, it is pulled into +-- the server’s main map data cache and then accessed from there. +-- +-- Inside a VM transaction, the transaction’s VM cache is used. +-- +-- This function can only be used to change the node’s name, not its parameters +-- or metadata. +-- +-- The swap will necessitate a light update unless update_light equals false. +function mesecon.swap_node_force(pos, name, update_light) + if vm_cache then + return mesecon.vm_swap_node(pos, name, update_light) + else + -- This serves to both ensure the mapblock is loaded and also hand us + -- the old node table so we can preserve param2. + local node = mesecon.get_node_force(pos) + node.name = name + minetest.swap_node(pos, node) + end +end + +-- Autoconnect Hooks +-- Nodes like conductors may change their appearance and their connection rules +-- right after being placed or after being dug, e.g. the default wires use this +-- to automatically connect to linking nodes after placement. +-- After placement, the update function will be executed immediately so that the +-- possibly changed rules can be taken into account when recalculating the circuit. +-- After digging, the update function will be queued and executed after +-- recalculating the circuit. The update function must take care of updating the +-- node at the given position itself, but also all of the other nodes the given +-- position may have (had) a linking connection to. +mesecon.autoconnect_hooks = {} + +-- name: A unique name for the hook, e.g. "foowire". Used to name the actionqueue function. +-- fct: The update function with parameters function(pos, node) +function mesecon.register_autoconnect_hook(name, fct) + mesecon.autoconnect_hooks[name] = fct + mesecon.queue:add_function("autoconnect_hook_"..name, fct) +end + +function mesecon.execute_autoconnect_hooks_now(pos, node) + for _, fct in pairs(mesecon.autoconnect_hooks) do + fct(pos, node) + end +end + +function mesecon.execute_autoconnect_hooks_queue(pos, node) + for name in pairs(mesecon.autoconnect_hooks) do + mesecon.queue:add_action(pos, "autoconnect_hook_"..name, {node}) + end +end diff --git a/mods/mesecons/mesecons_alias/init.lua b/mods/mesecons/mesecons_alias/init.lua new file mode 100644 index 00000000..395c3682 --- /dev/null +++ b/mods/mesecons/mesecons_alias/init.lua @@ -0,0 +1,38 @@ +-- This file registers aliases for the /give /giveme commands. + +minetest.register_alias("mesecons:removestone", "mesecons_random:removestone") +minetest.register_alias("mesecons:power_plant", "mesecons_powerplant:power_plant") +minetest.register_alias("mesecons:powerplant", "mesecons_powerplant:power_plant") +minetest.register_alias("mesecons:meselamp", "mesecons_lamp:lamp_off") +minetest.register_alias("mesecons:mesecon", "mesecons:wire_00000000_off") +minetest.register_alias("mesecons:object_detector", "mesecons_detector:object_detector_off") +minetest.register_alias("mesecons:wireless_inverter", "mesecons_wireless:wireless_inverter_on") +minetest.register_alias("mesecons:wireless_receiver", "mesecons_wireless:wireless_receiver_off") +minetest.register_alias("mesecons:wireless_transmitter", "mesecons_wireless:wireless_transmitter_off") +minetest.register_alias("mesecons:switch", "mesecons_switch:mesecon_switch_off") +minetest.register_alias("mesecons:button", "mesecons_button:button_off") +minetest.register_alias("mesecons:piston", "mesecons_pistons:piston_normal_off") +minetest.register_alias("mesecons:blinky_plant", "mesecons_blinkyplant:blinky_plant_off") +minetest.register_alias("mesecons:mesecon_torch", "mesecons_torch:mesecon_torch_on") +minetest.register_alias("mesecons:torch", "mesecons_torch:mesecon_torch_on") +minetest.register_alias("mesecons:hydro_turbine", "mesecons_hydroturbine:hydro_turbine_off") +minetest.register_alias("mesecons:pressure_plate_stone", "mesecons_pressureplates:pressure_plate_stone_off") +minetest.register_alias("mesecons:pressure_plate_wood", "mesecons_pressureplates:pressure_plate_wood_off") +minetest.register_alias("mesecons:mesecon_socket", "mesecons_temperest:mesecon_socket_off") +minetest.register_alias("mesecons:mesecon_inverter", "mesecons_temperest:mesecon_inverter_on") +minetest.register_alias("mesecons:movestone", "mesecons_movestones:movestone") +minetest.register_alias("mesecons:sticky_movestone", "mesecons_movestones:sticky_movestone") +minetest.register_alias("mesecons:noteblock", "mesecons_noteblock:noteblock") +minetest.register_alias("mesecons:microcontroller", "mesecons_microcontroller:microcontroller0000") +minetest.register_alias("mesecons:delayer", "mesecons_delayer:delayer_off_1") +minetest.register_alias("mesecons:solarpanel", "mesecons_solarpanel:solar_panel_off") + + +--Backwards compatibility +minetest.register_alias("mesecons:mesecon_off", "mesecons:wire_00000000_off") +minetest.register_alias("mesecons_pistons:piston_sticky", "mesecons_pistons:piston_sticky_on") +minetest.register_alias("mesecons_pistons:piston_normal", "mesecons_pistons:piston_normal_on") +minetest.register_alias("mesecons_pistons:piston_up_normal", "mesecons_pistons:piston_up_normal_on") +minetest.register_alias("mesecons_pistons:piston_down_normal", "mesecons_pistons:piston_down_normal_on") +minetest.register_alias("mesecons_pistons:piston_up_sticky", "mesecons_pistons:piston_up_sticky_on") +minetest.register_alias("mesecons_pistons:piston_down_sticky", "mesecons_pistons:piston_down_sticky_on") diff --git a/mods/mesecons/mesecons_alias/mod.conf b/mods/mesecons/mesecons_alias/mod.conf new file mode 100644 index 00000000..533d54c8 --- /dev/null +++ b/mods/mesecons/mesecons_alias/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_alias +depends = mesecons diff --git a/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/description.html b/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/description.html new file mode 100644 index 00000000..0d987a56 --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/description.html @@ -0,0 +1,2 @@ +The blinky plants toggles between on and off state every three seconds. Can be used to make clocks. Also works after having restarted the game. +It stops blinking in an inactive block, then starts again when the block becomes active. diff --git a/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/preview.png b/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/preview.png new file mode 100644 index 00000000..4c93b5ff Binary files /dev/null and b/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/preview.png differ diff --git a/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/recipe.png b/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/recipe.png new file mode 100644 index 00000000..afd572a4 Binary files /dev/null and b/mods/mesecons/mesecons_blinkyplant/doc/blinkyplant/recipe.png differ diff --git a/mods/mesecons/mesecons_blinkyplant/init.lua b/mods/mesecons/mesecons_blinkyplant/init.lua new file mode 100644 index 00000000..44dd3ffd --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/init.lua @@ -0,0 +1,60 @@ +-- The BLINKY_PLANT + +local S = minetest.get_translator(minetest.get_current_modname()) + +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= S("Blinky Plant"), + drawtype = "plantlike", + inventory_image = "jeija_blinky_plant_off.png", + paramtype = "light", + is_ground_content = false, + walkable = false, + sounds = mesecon.node_sound.leaves, + 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 = function(pos, _, clicker) + if minetest.is_protected(pos, clicker and clicker:get_player_name() or "") then + return + end + + toggle_timer(pos) + end, + 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",""}, + {"group:sapling","group:sapling","group:sapling"}} +}) diff --git a/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.de.tr b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.de.tr new file mode 100644 index 00000000..1f1e3eb0 --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_blinkyplant +Blinky Plant=Blinkpflanze diff --git a/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.eo.tr b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.eo.tr new file mode 100644 index 00000000..db628ba5 --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_blinkyplant + +### init.lua ### +Blinky Plant=Palpebruma Planto diff --git a/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.fr.tr b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.fr.tr new file mode 100644 index 00000000..410d7448 --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_blinkyplant + +### init.lua ### +Blinky Plant=Plante clignotante diff --git a/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.ru.tr b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.ru.tr new file mode 100644 index 00000000..6f252954 --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_blinkyplant + +### init.lua ### +Blinky Plant=Мигающий цветок diff --git a/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.uk.tr b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.uk.tr new file mode 100644 index 00000000..ffe12f51 --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/locale/mesecons_blinkyplant.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_blinkyplant + +### init.lua ### +Blinky Plant=Миготлива квітка diff --git a/mods/mesecons/mesecons_blinkyplant/locale/template.txt b/mods/mesecons/mesecons_blinkyplant/locale/template.txt new file mode 100644 index 00000000..e2f5e443 --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_blinkyplant + +### init.lua ### +Blinky Plant= diff --git a/mods/mesecons/mesecons_blinkyplant/mod.conf b/mods/mesecons/mesecons_blinkyplant/mod.conf new file mode 100644 index 00000000..3f234489 --- /dev/null +++ b/mods/mesecons/mesecons_blinkyplant/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_blinkyplant +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_off.png b/mods/mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_off.png new file mode 100644 index 00000000..a8c22fc4 Binary files /dev/null and b/mods/mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_off.png differ diff --git a/mods/mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_on.png b/mods/mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_on.png new file mode 100644 index 00000000..3ac576db Binary files /dev/null and b/mods/mesecons/mesecons_blinkyplant/textures/jeija_blinky_plant_on.png differ diff --git a/mods/mesecons/mesecons_button/doc/button/description.html b/mods/mesecons/mesecons_button/doc/button/description.html new file mode 100644 index 00000000..ae6bf07f --- /dev/null +++ b/mods/mesecons/mesecons_button/doc/button/description.html @@ -0,0 +1 @@ +This receptor can be attached to walls. It turns on for 1 second if it's punched. diff --git a/mods/mesecons/mesecons_button/doc/button/preview.png b/mods/mesecons/mesecons_button/doc/button/preview.png new file mode 100644 index 00000000..8c54020a Binary files /dev/null and b/mods/mesecons/mesecons_button/doc/button/preview.png differ diff --git a/mods/mesecons/mesecons_button/doc/button/recipe.png b/mods/mesecons/mesecons_button/doc/button/recipe.png new file mode 100644 index 00000000..67d83cf5 Binary files /dev/null and b/mods/mesecons/mesecons_button/doc/button/recipe.png differ diff --git a/mods/mesecons/mesecons_button/init.lua b/mods/mesecons/mesecons_button/init.lua new file mode 100644 index 00000000..878a6e1e --- /dev/null +++ b/mods/mesecons/mesecons_button/init.lua @@ -0,0 +1,111 @@ +-- WALL BUTTON +-- A button that when pressed emits power for 1 second +-- and then turns off again +local S = minetest.get_translator(minetest.get_current_modname()) + +mesecon.button_turnoff = function (pos) + local node = minetest.get_node(pos) + if node.name ~= "mesecons_button:button_on" then -- has been dug + return + end + minetest.swap_node(pos, {name = "mesecons_button:button_off", param2 = node.param2}) + minetest.sound_play("mesecons_button_pop", { pos = pos }, true) + local rules = mesecon.rules.buttonlike_get(node) + mesecon.receptor_off(pos, rules) +end + +local use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or nil + +minetest.register_node("mesecons_button:button_off", { + drawtype = "nodebox", + tiles = { + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_off.png" + }, + use_texture_alpha = use_texture_alpha, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + legacy_wallmounted = true, + walkable = false, + on_rotate = mesecon.buttonlike_onrotate, + sunlight_propagates = true, + selection_box = { + type = "fixed", + fixed = { -6/16, -6/16, 5/16, 6/16, 6/16, 8/16 } + }, + node_box = { + type = "fixed", + fixed = { + { -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the thin plate behind the button + { -4/16, -2/16, 4/16, 4/16, 2/16, 6/16 } -- the button itself + } + }, + groups = {dig_immediate=2, mesecon_needs_receiver = 1}, + description = S("Button"), + on_rightclick = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2}) + mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node)) + minetest.sound_play("mesecons_button_push", { pos = pos }, true) + minetest.get_node_timer(pos):start(1) + end, + sounds = mesecon.node_sound.stone, + mesecons = {receptor = { + state = mesecon.state.off, + rules = mesecon.rules.buttonlike_get + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_button:button_on", { + drawtype = "nodebox", + tiles = { + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_sides.png", + "jeija_wall_button_on.png" + }, + use_texture_alpha = use_texture_alpha, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + legacy_wallmounted = true, + walkable = false, + on_rotate = false, + light_source = minetest.LIGHT_MAX-7, + sunlight_propagates = true, + selection_box = { + type = "fixed", + fixed = { -6/16, -6/16, 5/16, 6/16, 6/16, 8/16 } + }, + node_box = { + type = "fixed", + fixed = { + { -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, + { -4/16, -2/16, 11/32, 4/16, 2/16, 6/16 } + } + }, + groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon_needs_receiver = 1}, + drop = 'mesecons_button:button_off', + description = S("Button"), + sounds = mesecon.node_sound.stone, + mesecons = {receptor = { + state = mesecon.state.on, + rules = mesecon.rules.buttonlike_get + }}, + on_timer = mesecon.button_turnoff, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_craft({ + output = "mesecons_button:button_off 2", + recipe = { + {"group:mesecon_conductor_craftable","mesecons_gamecompat:stone"}, + } +}) diff --git a/mods/mesecons/mesecons_button/locale/mesecons_button.de.tr b/mods/mesecons/mesecons_button/locale/mesecons_button.de.tr new file mode 100644 index 00000000..18811773 --- /dev/null +++ b/mods/mesecons/mesecons_button/locale/mesecons_button.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_button +Button=Taster diff --git a/mods/mesecons/mesecons_button/locale/mesecons_button.eo.tr b/mods/mesecons/mesecons_button/locale/mesecons_button.eo.tr new file mode 100644 index 00000000..463f65bf --- /dev/null +++ b/mods/mesecons/mesecons_button/locale/mesecons_button.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_button + +### init.lua ### +Button=Butono diff --git a/mods/mesecons/mesecons_button/locale/mesecons_button.fr.tr b/mods/mesecons/mesecons_button/locale/mesecons_button.fr.tr new file mode 100644 index 00000000..9ef7de50 --- /dev/null +++ b/mods/mesecons/mesecons_button/locale/mesecons_button.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_button + +### init.lua ### +Button=Bouton diff --git a/mods/mesecons/mesecons_button/locale/mesecons_button.ru.tr b/mods/mesecons/mesecons_button/locale/mesecons_button.ru.tr new file mode 100644 index 00000000..036723d2 --- /dev/null +++ b/mods/mesecons/mesecons_button/locale/mesecons_button.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_button + +### init.lua ### +Button=Кнопка diff --git a/mods/mesecons/mesecons_button/locale/mesecons_button.uk.tr b/mods/mesecons/mesecons_button/locale/mesecons_button.uk.tr new file mode 100644 index 00000000..036723d2 --- /dev/null +++ b/mods/mesecons/mesecons_button/locale/mesecons_button.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_button + +### init.lua ### +Button=Кнопка diff --git a/mods/mesecons/mesecons_button/locale/template.txt b/mods/mesecons/mesecons_button/locale/template.txt new file mode 100644 index 00000000..2a4d5b9a --- /dev/null +++ b/mods/mesecons/mesecons_button/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_button + +### init.lua ### +Button= diff --git a/mods/mesecons/mesecons_button/mod.conf b/mods/mesecons/mesecons_button/mod.conf new file mode 100644 index 00000000..cf67a2e9 --- /dev/null +++ b/mods/mesecons/mesecons_button/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_button +depends = mesecons, mesecons_gamecompat, mesecons_receiver diff --git a/mods/mesecons/mesecons_button/sounds/mesecons_button_pop.ogg b/mods/mesecons/mesecons_button/sounds/mesecons_button_pop.ogg new file mode 100644 index 00000000..9d56bb8c Binary files /dev/null and b/mods/mesecons/mesecons_button/sounds/mesecons_button_pop.ogg differ diff --git a/mods/mesecons/mesecons_button/sounds/mesecons_button_push.ogg b/mods/mesecons/mesecons_button/sounds/mesecons_button_push.ogg new file mode 100644 index 00000000..53d45c18 Binary files /dev/null and b/mods/mesecons/mesecons_button/sounds/mesecons_button_push.ogg differ diff --git a/mods/mesecons/mesecons_button/textures/jeija_wall_button_off.png b/mods/mesecons/mesecons_button/textures/jeija_wall_button_off.png new file mode 100644 index 00000000..d55f7c0a Binary files /dev/null and b/mods/mesecons/mesecons_button/textures/jeija_wall_button_off.png differ diff --git a/mods/mesecons/mesecons_button/textures/jeija_wall_button_on.png b/mods/mesecons/mesecons_button/textures/jeija_wall_button_on.png new file mode 100644 index 00000000..2286f539 Binary files /dev/null and b/mods/mesecons/mesecons_button/textures/jeija_wall_button_on.png differ diff --git a/mods/mesecons/mesecons_button/textures/jeija_wall_button_sides.png b/mods/mesecons/mesecons_button/textures/jeija_wall_button_sides.png new file mode 100644 index 00000000..59c72404 Binary files /dev/null and b/mods/mesecons/mesecons_button/textures/jeija_wall_button_sides.png differ diff --git a/mods/mesecons/mesecons_commandblock/doc/commandblock/description.html b/mods/mesecons/mesecons_commandblock/doc/commandblock/description.html new file mode 100644 index 00000000..9ba7ce58 --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/doc/commandblock/description.html @@ -0,0 +1,2 @@ +There is no crafting recipe as this should only be available for server admins. Quite similar to the Minecraft counterpart. Executes server commands. +It works in inactive blocks. diff --git a/mods/mesecons/mesecons_commandblock/doc/commandblock/preview.png b/mods/mesecons/mesecons_commandblock/doc/commandblock/preview.png new file mode 100644 index 00000000..50e2cc76 Binary files /dev/null and b/mods/mesecons/mesecons_commandblock/doc/commandblock/preview.png differ diff --git a/mods/mesecons/mesecons_commandblock/init.lua b/mods/mesecons/mesecons_commandblock/init.lua new file mode 100644 index 00000000..853f16c2 --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/init.lua @@ -0,0 +1,222 @@ +local S = minetest.get_translator(minetest.get_current_modname()) +local param_maxlen = mesecon.setting("commandblock_param_maxlen", 10000) + +minetest.register_chatcommand("say", { + params = "", + description = S("Say as the server"), + privs = {server=true}, + func = function(name, param) + minetest.chat_send_all(name .. ": " .. param) + end +}) + +minetest.register_chatcommand("tell", { + params = " ", + description = S("Say to privately"), + privs = {shout=true}, + func = function(name, param) + local found, _, target, message = param:find("^([^%s]+)%s+(.*)$") + if found == nil then + minetest.chat_send_player(name, "Invalid usage: " .. param) + return + end + if not minetest.get_player_by_name(target) then + minetest.chat_send_player(name, "Invalid target: " .. target) + end + minetest.chat_send_player(target, name .. " whispers: " .. message, false) + end +}) + +minetest.register_chatcommand("hp", { + params = " ", + description = S("Set health of to hitpoints"), + privs = {ban=true}, + func = function(name, param) + local found, _, target, value = param:find("^([^%s]+)%s+(%d+)$") + if found == nil then + minetest.chat_send_player(name, "Invalid usage: " .. param) + return + end + local player = minetest.get_player_by_name(target) + if player then + player:set_hp(value) + else + minetest.chat_send_player(name, "Invalid target: " .. target) + end + end +}) + +local function initialize_data(meta) + local commands = minetest.formspec_escape(meta:get_string("commands")) + meta:set_string("formspec", + "size[9,5]" .. + "textarea[0.5,0.5;8.5,4;commands;Commands;"..commands.."]" .. + "label[1,3.8;@nearest, @farthest, and @random are replaced by the respective player names]" .. + "button_exit[3.3,4.5;2,1;submit;Submit]") + local owner = meta:get_string("owner") + if owner == "" then + owner = "not owned" + else + owner = "owned by " .. owner + end + meta:set_string("infotext", "Command Block\n" .. + "(" .. owner .. ")\n" .. + "Commands: "..commands) +end + +local function construct(pos) + local meta = minetest.get_meta(pos) + + meta:set_string("commands", "tell @nearest Commandblock unconfigured") + + meta:set_string("owner", "") + + initialize_data(meta) +end + +local function after_place(pos, placer) + if placer then + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + initialize_data(meta) + end +end + +local function receive_fields(pos, _, fields, sender) + if not fields.submit then + return + end + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + if owner ~= "" and sender:get_player_name() ~= owner then + return + end + meta:set_string("commands", fields.commands) + + initialize_data(meta) +end + +local function resolve_commands(commands, pos) + local players = minetest.get_connected_players() + + -- No players online: remove all commands containing + -- @nearest, @farthest and @random + if #players == 0 then + commands = commands:gsub("[^\r\n]+", function (line) + if line:find("@nearest") then return "" end + if line:find("@farthest") then return "" end + if line:find("@random") then return "" end + return line + end) + return commands + end + + local nearest, farthest = nil, nil + local min_distance, max_distance = math.huge, -1 + for index, player in pairs(players) do + local distance = vector.distance(pos, player:get_pos()) + if distance < min_distance then + min_distance = distance + nearest = player:get_player_name() + end + if distance > max_distance then + max_distance = distance + farthest = player:get_player_name() + end + end + local random = players[math.random(#players)]:get_player_name() + commands = commands:gsub("@nearest", nearest) + commands = commands:gsub("@farthest", farthest) + commands = commands:gsub("@random", random) + return commands +end + +local function commandblock_action_on(pos, node) + if node.name ~= "mesecons_commandblock:commandblock_off" then + return + end + + minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"}) + + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + if owner == "" then + return + end + + local commands = resolve_commands(meta:get_string("commands"), pos) + for _, command in pairs(commands:split("\n")) do + local pos = command:find(" ") + local cmd, param = command, "" + if pos then + cmd = command:sub(1, pos - 1) + param = command:sub(pos + 1) + end + local cmddef = minetest.chatcommands[cmd] + if not cmddef then + minetest.chat_send_player(owner, "The command "..cmd.." does not exist") + return + end + if #param > param_maxlen then + minetest.chat_send_player(owner, "Command parameters are limited to max. " .. + param_maxlen .. " bytes.") + return + end + local has_privs, missing_privs = minetest.check_player_privs(owner, cmddef.privs) + if not has_privs then + minetest.chat_send_player(owner, "You don't have permission " + .."to run "..cmd + .." (missing privileges: " + ..table.concat(missing_privs, ", ")..")") + return + end + cmddef.func(owner, param) + end +end + +local function commandblock_action_off(pos, node) + if node.name == "mesecons_commandblock:commandblock_on" then + minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_off"}) + end +end + +local function can_dig(pos, player) + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + return owner == "" or owner == player:get_player_name() or + minetest.check_player_privs(player, "protection_bypass") +end + +minetest.register_node("mesecons_commandblock:commandblock_off", { + description = S("Command Block"), + tiles = {"jeija_commandblock_off.png"}, + inventory_image = minetest.inventorycube("jeija_commandblock_off.png"), + is_ground_content = false, + groups = {cracky=2, mesecon_effector_off=1}, + on_construct = construct, + after_place_node = after_place, + on_receive_fields = receive_fields, + can_dig = can_dig, + sounds = mesecon.node_sound.stone, + mesecons = {effector = { + action_on = commandblock_action_on + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_commandblock:commandblock_on", { + tiles = {"jeija_commandblock_on.png"}, + is_ground_content = false, + groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1}, + light_source = 10, + drop = "mesecons_commandblock:commandblock_off", + on_construct = construct, + after_place_node = after_place, + on_receive_fields = receive_fields, + can_dig = can_dig, + sounds = mesecon.node_sound.stone, + mesecons = {effector = { + action_off = commandblock_action_off + }}, + on_blast = mesecon.on_blastnode, +}) diff --git a/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.de.tr b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.de.tr new file mode 100644 index 00000000..592e7e51 --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.de.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_commandblock +Say as the server= als Server sagen +Say to privately= an privat senden +Set health of to hitpoints=Gesundheit von auf Trefferpunkte setzen +Command Block=Befehlsblock diff --git a/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.eo.tr b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.eo.tr new file mode 100644 index 00000000..3a9f0775 --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.eo.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_commandblock + +### init.lua ### +Say as the server=Diru kiel la servilo +Say to privately=Diru al private +Set health of to hitpoints=Agordu sanon de al +Command Block=Komando-Bloko diff --git a/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.fr.tr b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.fr.tr new file mode 100644 index 00000000..fa97d767 --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.fr.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_commandblock + +### init.lua ### +Say as the server=Dire au serveur +Say to privately=Dire à en privé +Set health of to hitpoints=Définir la vie de sur cœurs +Command Block=Bloc de commandes diff --git a/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.ru.tr b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.ru.tr new file mode 100644 index 00000000..64122e40 --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.ru.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_commandblock + +### init.lua ### +Say as the server=Сказать <текст> от имени сервера +Say to privately=Сказать <текст> игроку <имя> в личном сообщении +Set health of to hitpoints=Установить здоровье игрока <имя> на <значение> хитпоинтов +Command Block=Комадный блок diff --git a/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.uk.tr b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.uk.tr new file mode 100644 index 00000000..1af4842c --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/locale/mesecons_commandblock.uk.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_commandblock + +### init.lua ### +Say as the server=Сказати <текст> від імені сервера +Say to privately=Сказати <текст> гравцю <ім'я> в приватному повідомленні +Set health of to hitpoints=Встановити здоров'я гравця <ім'я> на <значення> ХП +Command Block=Командний блок diff --git a/mods/mesecons/mesecons_commandblock/locale/template.txt b/mods/mesecons/mesecons_commandblock/locale/template.txt new file mode 100644 index 00000000..1fdd37c3 --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/locale/template.txt @@ -0,0 +1,7 @@ +# textdomain: mesecons_commandblock + +### init.lua ### +Say as the server= +Say to privately= +Set health of to hitpoints= +Command Block= diff --git a/mods/mesecons/mesecons_commandblock/mod.conf b/mods/mesecons/mesecons_commandblock/mod.conf new file mode 100644 index 00000000..68cdc9ea --- /dev/null +++ b/mods/mesecons/mesecons_commandblock/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_commandblock +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_commandblock/textures/jeija_commandblock_off.png b/mods/mesecons/mesecons_commandblock/textures/jeija_commandblock_off.png new file mode 100644 index 00000000..1d989d9b Binary files /dev/null and b/mods/mesecons/mesecons_commandblock/textures/jeija_commandblock_off.png differ diff --git a/mods/mesecons/mesecons_commandblock/textures/jeija_commandblock_on.png b/mods/mesecons/mesecons_commandblock/textures/jeija_commandblock_on.png new file mode 100644 index 00000000..555f8a3d Binary files /dev/null and b/mods/mesecons/mesecons_commandblock/textures/jeija_commandblock_on.png differ diff --git a/mods/mesecons/mesecons_delayer/doc/delayer/description.html b/mods/mesecons/mesecons_delayer/doc/delayer/description.html new file mode 100644 index 00000000..966d7292 --- /dev/null +++ b/mods/mesecons/mesecons_delayer/doc/delayer/description.html @@ -0,0 +1 @@ +The delayer delays the signal from the input for a determined time. The time can be set by punching the delayer. Possible delays are: 0.1 seconds, 0.3 seconds, 0.5 seconds and 1 second. You may try to use it for creating songs with the noteblock. It works in unloaded blocks. diff --git a/mods/mesecons/mesecons_delayer/doc/delayer/preview.png b/mods/mesecons/mesecons_delayer/doc/delayer/preview.png new file mode 100644 index 00000000..d1909008 Binary files /dev/null and b/mods/mesecons/mesecons_delayer/doc/delayer/preview.png differ diff --git a/mods/mesecons/mesecons_delayer/doc/delayer/recipe.png b/mods/mesecons/mesecons_delayer/doc/delayer/recipe.png new file mode 100644 index 00000000..3713b39a Binary files /dev/null and b/mods/mesecons/mesecons_delayer/doc/delayer/recipe.png differ diff --git a/mods/mesecons/mesecons_delayer/init.lua b/mods/mesecons/mesecons_delayer/init.lua new file mode 100644 index 00000000..ab0063e2 --- /dev/null +++ b/mods/mesecons/mesecons_delayer/init.lua @@ -0,0 +1,159 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- Function that get the input/output rules of the delayer +local delayer_get_output_rules = mesecon.horiz_rules_getter({{x = 1, y = 0, z = 0}}) + +local delayer_get_input_rules = mesecon.horiz_rules_getter({{x = -1, y = 0, z = 0}}) + +-- Functions that are called after the delay time + +local delayer_activate = function(pos, node) + local def = minetest.registered_nodes[node.name] + local time = def.delayer_time + minetest.swap_node(pos, {name = def.delayer_onstate, param2=node.param2}) + mesecon.queue:add_action(pos, "receptor_on", {delayer_get_output_rules(node)}, time, nil) +end + +local delayer_deactivate = function(pos, node) + local def = minetest.registered_nodes[node.name] + local time = def.delayer_time + minetest.swap_node(pos, {name = def.delayer_offstate, param2=node.param2}) + mesecon.queue:add_action(pos, "receptor_off", {delayer_get_output_rules(node)}, time, nil) +end + +-- Register the 2 (states) x 4 (delay times) delayers + +local delaytime = { 0.1, 0.3, 0.5, 1.0 } + +for i = 1, 4 do + +-- Delayer definition defaults +local def = { + drawtype = "nodebox", + use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or nil, + walkable = true, + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, + }, + node_box = { + type = "fixed", + fixed = { + { -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab + { -6/16, -7/16, -6/16, 6/16, -6/16, 6/16 } + }, + }, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + is_ground_content = false, + delayer_time = delaytime[i], + sounds = mesecon.node_sound.stone, + on_blast = mesecon.on_blastnode, + drop = "mesecons_delayer:delayer_off_1", + delayer_onstate = "mesecons_delayer:delayer_on_"..tostring(i), + delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i), +} + +-- Deactivated delayer definition defaults +local off_groups = {bendy=2,snappy=1,dig_immediate=2} +if i > 1 then + off_groups.not_in_creative_inventory = 1 +end + +local off_state = { + description = S("Delayer"), + inventory_image = "jeija_gate_off.png^jeija_delayer.png", + wield_image = "jeija_gate_off.png^jeija_delayer.png", + tiles = { + "jeija_microcontroller_bottom.png^jeija_gate_output_off.png^jeija_gate_off.png^".. + "jeija_delayer.png^mesecons_delayer_"..tostring(i)..".png", + "jeija_microcontroller_bottom.png^jeija_gate_output_off.png", + "jeija_gate_side.png^jeija_gate_side_output_off.png", + "jeija_gate_side.png", + "jeija_gate_side.png", + "jeija_gate_side.png", + }, + groups = off_groups, + on_punch = function(pos, node, puncher) + if minetest.is_protected(pos, puncher and puncher:get_player_name() or "") then + return + end + + minetest.swap_node(pos, { + name = "mesecons_delayer:delayer_off_"..tostring(i % 4 + 1), + param2 = node.param2 + }) + end, + mesecons = { + receptor = + { + state = mesecon.state.off, + rules = delayer_get_output_rules + }, + effector = + { + rules = delayer_get_input_rules, + action_off = delayer_deactivate, + action_on = delayer_activate + } + }, +} +for k, v in pairs(def) do + off_state[k] = off_state[k] or v +end +minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), off_state) + +-- Activated delayer definition defaults +local on_state = { + description = S("You hacker you"), + inventory_image = "jeija_gate_on.png^jeija_delayer.png", + wield_image = "jeija_gate_on.png^jeija_delayer.png", + tiles = { + "jeija_microcontroller_bottom.png^jeija_gate_output_on.png^jeija_gate_on.png^".. + "jeija_delayer.png^mesecons_delayer_"..tostring(i)..".png", + "jeija_microcontroller_bottom.png^jeija_gate_output_on.png", + "jeija_gate_side.png^jeija_gate_side_output_on.png", + "jeija_gate_side.png", + "jeija_gate_side.png", + "jeija_gate_side.png", + }, + groups = {bendy = 2, snappy = 1, dig_immediate = 2, not_in_creative_inventory = 1}, + on_punch = function(pos, node, puncher) + if minetest.is_protected(pos, puncher and puncher:get_player_name() or "") then + return + end + + minetest.swap_node(pos, { + name = "mesecons_delayer:delayer_on_"..tostring(i % 4 + 1), + param2 = node.param2 + }) + end, + mesecons = { + receptor = + { + state = mesecon.state.on, + rules = delayer_get_output_rules + }, + effector = + { + rules = delayer_get_input_rules, + action_off = delayer_deactivate, + action_on = delayer_activate + } + }, +} +for k, v in pairs(def) do + on_state[k] = on_state[k] or v +end +minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), on_state) + +end + +minetest.register_craft({ + output = "mesecons_delayer:delayer_off_1", + recipe = { + {"mesecons_torch:mesecon_torch_on", "group:mesecon_conductor_craftable", "mesecons_torch:mesecon_torch_on"}, + {"mesecons_gamecompat:cobble","mesecons_gamecompat:cobble", "mesecons_gamecompat:cobble"}, + } +}) diff --git a/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.de.tr b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.de.tr new file mode 100644 index 00000000..15db723c --- /dev/null +++ b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.de.tr @@ -0,0 +1,3 @@ +# textdomain: mesecons_delayer +Delayer=Verzögerer +You hacker you=Du Hacker, Du diff --git a/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.eo.tr b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.eo.tr new file mode 100644 index 00000000..f6d43501 --- /dev/null +++ b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.eo.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_delayer + +### init.lua ### +Delayer=Prokrasto +You hacker you=Vi hakisto diff --git a/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.fr.tr b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.fr.tr new file mode 100644 index 00000000..c4ff30eb --- /dev/null +++ b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.fr.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_delayer + +### init.lua ### +Delayer=Retardateur +You hacker you=Vous êtes un pirate informatique diff --git a/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.ru.tr b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.ru.tr new file mode 100644 index 00000000..53ab893b --- /dev/null +++ b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.ru.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_delayer + +### init.lua ### +Delayer=Элемент задержки +You hacker you=Ти хакер, ти diff --git a/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.uk.tr b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.uk.tr new file mode 100644 index 00000000..c262bcc6 --- /dev/null +++ b/mods/mesecons/mesecons_delayer/locale/mesecons_delayer.uk.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_delayer + +### init.lua ### +Delayer=Затримувач +You hacker you=Ти хакер, ти diff --git a/mods/mesecons/mesecons_delayer/locale/template.txt b/mods/mesecons/mesecons_delayer/locale/template.txt new file mode 100644 index 00000000..e5e06f27 --- /dev/null +++ b/mods/mesecons/mesecons_delayer/locale/template.txt @@ -0,0 +1,5 @@ +# textdomain: mesecons_delayer + +### init.lua ### +Delayer= +You hacker you= diff --git a/mods/mesecons/mesecons_delayer/mod.conf b/mods/mesecons/mesecons_delayer/mod.conf new file mode 100644 index 00000000..33a2ef58 --- /dev/null +++ b/mods/mesecons/mesecons_delayer/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_delayer +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_delayer/textures/jeija_delayer.png b/mods/mesecons/mesecons_delayer/textures/jeija_delayer.png new file mode 100644 index 00000000..e33fe12f Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/jeija_delayer.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/jeija_gate_off.png b/mods/mesecons/mesecons_delayer/textures/jeija_gate_off.png new file mode 100644 index 00000000..2f77aeb1 Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/jeija_gate_off.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/jeija_gate_on.png b/mods/mesecons/mesecons_delayer/textures/jeija_gate_on.png new file mode 100644 index 00000000..406e4f6e Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/jeija_gate_on.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/jeija_gate_output_off.png b/mods/mesecons/mesecons_delayer/textures/jeija_gate_output_off.png new file mode 100644 index 00000000..bee3942d Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/jeija_gate_output_off.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/jeija_gate_output_on.png b/mods/mesecons/mesecons_delayer/textures/jeija_gate_output_on.png new file mode 100644 index 00000000..b3b6d217 Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/jeija_gate_output_on.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/jeija_gate_side.png b/mods/mesecons/mesecons_delayer/textures/jeija_gate_side.png new file mode 100644 index 00000000..1223b54d Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/jeija_gate_side.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/jeija_gate_side_output_off.png b/mods/mesecons/mesecons_delayer/textures/jeija_gate_side_output_off.png new file mode 100644 index 00000000..785e7c6b Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/jeija_gate_side_output_off.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/jeija_gate_side_output_on.png b/mods/mesecons/mesecons_delayer/textures/jeija_gate_side_output_on.png new file mode 100644 index 00000000..0aaa4a5d Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/jeija_gate_side_output_on.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_1.png b/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_1.png new file mode 100644 index 00000000..973d6849 Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_1.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_2.png b/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_2.png new file mode 100644 index 00000000..a5f0b9f3 Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_2.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_3.png b/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_3.png new file mode 100644 index 00000000..c8bf24e5 Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_3.png differ diff --git a/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_4.png b/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_4.png new file mode 100644 index 00000000..74a59127 Binary files /dev/null and b/mods/mesecons/mesecons_delayer/textures/mesecons_delayer_4.png differ diff --git a/mods/mesecons/mesecons_detector/doc/nodedetector/description.html b/mods/mesecons/mesecons_detector/doc/nodedetector/description.html new file mode 100644 index 00000000..4c62359b --- /dev/null +++ b/mods/mesecons/mesecons_detector/doc/nodedetector/description.html @@ -0,0 +1,11 @@ +The node detector is a receptor. It changes its state when either any node +or a specific node is detected. Right-click it to set a nodename to scan for. +It can also receive digiline signals. For example, you can send +{distance=4, scanname="default:dirt"} +to set distance to 4 and scan for dirt. You can omit either parameter. +There is also a command parameter: {command="get"} will respond +with the detected nodename and {command="scan"} will respond with +a boolean using the distance and nodename of the detector. +Nodenames must include the mod they reside in, so for instance default:dirt, not just dirt. +The distance parameter specifies how many blocks are between the node detector and the node to detect. +Automatic scanning with Mesecons output only works when the detector is in an active block, but Digilines queries always work. diff --git a/mods/mesecons/mesecons_detector/doc/nodedetector/preview.png b/mods/mesecons/mesecons_detector/doc/nodedetector/preview.png new file mode 100644 index 00000000..759a9fa9 Binary files /dev/null and b/mods/mesecons/mesecons_detector/doc/nodedetector/preview.png differ diff --git a/mods/mesecons/mesecons_detector/doc/nodedetector/recipe.png b/mods/mesecons/mesecons_detector/doc/nodedetector/recipe.png new file mode 100644 index 00000000..13ab5703 Binary files /dev/null and b/mods/mesecons/mesecons_detector/doc/nodedetector/recipe.png differ diff --git a/mods/mesecons/mesecons_detector/doc/objectdetector/description.html b/mods/mesecons/mesecons_detector/doc/objectdetector/description.html new file mode 100644 index 00000000..a9284346 --- /dev/null +++ b/mods/mesecons/mesecons_detector/doc/objectdetector/description.html @@ -0,0 +1,5 @@ +The object detector is a receptor. It changes its state when a player approaches. +Right-click it to set a name to scan for. +You can also search for comma-separated lists of players where the detector gets activated if any of the names in the list are found. +It can also receive digiline signals which are the name to scan for on the specified channel in the right-click menu. +Automatic scanning with Mesecons output only works when the detector is in an active block, but Digilines queries always work. diff --git a/mods/mesecons/mesecons_detector/doc/objectdetector/preview.png b/mods/mesecons/mesecons_detector/doc/objectdetector/preview.png new file mode 100644 index 00000000..edee1109 Binary files /dev/null and b/mods/mesecons/mesecons_detector/doc/objectdetector/preview.png differ diff --git a/mods/mesecons/mesecons_detector/doc/objectdetector/recipe.png b/mods/mesecons/mesecons_detector/doc/objectdetector/recipe.png new file mode 100644 index 00000000..0081b360 Binary files /dev/null and b/mods/mesecons/mesecons_detector/doc/objectdetector/recipe.png differ diff --git a/mods/mesecons/mesecons_detector/init.lua b/mods/mesecons/mesecons_detector/init.lua new file mode 100644 index 00000000..354f3dca --- /dev/null +++ b/mods/mesecons/mesecons_detector/init.lua @@ -0,0 +1,336 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local side_texture = mesecon.texture.steel_block or "mesecons_detector_side.png" + +local GET_COMMAND = "GET" + + +local function comma_list_to_table(comma_list) + local tbl = {} + for _, str in ipairs(string.split(comma_list:gsub("%s", ""), ",")) do + tbl[str] = true + end + return tbl +end + + +-- Object detector +-- Detects players in a certain radius +-- The radius can be specified in mesecons/settings.lua + +local function object_detector_make_formspec(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", "size[9,2.5]" .. + "field[0.3, 0;9,2;scanname;Name of player to scan for (empty for any):;${scanname}]".. + "field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]".. + "button_exit[7,0.75;2,3;;Save]") +end + +local function object_detector_on_receive_fields(pos, _, fields, sender) + if not fields.scanname or not fields.digiline_channel then return end + + if minetest.is_protected(pos, sender:get_player_name()) then return end + + local meta = minetest.get_meta(pos) + meta:set_string("scanname", fields.scanname) + meta:set_string("digiline_channel", fields.digiline_channel) + object_detector_make_formspec(pos) +end + +-- returns true if player was found, false if not +local function object_detector_scan(pos) + local objs = minetest.get_objects_inside_radius(pos, mesecon.setting("detector_radius", 6)) + + -- abort if no scan results were found + if next(objs) == nil then return false end + + local scanname = minetest.get_meta(pos):get_string("scanname") + local scan_for = comma_list_to_table(scanname) + + local every_player = scanname == "" + for _, obj in pairs(objs) do + -- "" is returned if it is not a player; "" ~= nil; so only handle objects with foundname ~= "" + local foundname = obj:get_player_name() + if foundname ~= "" then + if every_player or scan_for[foundname] then + return true + end + end + end + + return false +end + +-- set player name when receiving a digiline signal on a specific channel +local object_detector_digiline = { + effector = { + action = function(pos, _, channel, msg) + local meta = minetest.get_meta(pos) + if channel == meta:get_string("digiline_channel") and + (type(msg) == "string" or type(msg) == "number") then + meta:set_string("scanname", msg) + object_detector_make_formspec(pos) + end + end, + } +} + +minetest.register_node("mesecons_detector:object_detector_off", { + tiles = {side_texture, side_texture, "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png"}, + paramtype = "light", + is_ground_content = false, + walkable = true, + groups = {cracky=3}, + description= S("Player Detector"), + mesecons = {receptor = { + state = mesecon.state.off, + rules = mesecon.rules.pplate + }}, + on_construct = object_detector_make_formspec, + on_receive_fields = object_detector_on_receive_fields, + sounds = mesecon.node_sound.stone, + digiline = object_detector_digiline, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_detector:object_detector_on", { + tiles = {side_texture, side_texture, "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png"}, + paramtype = "light", + is_ground_content = false, + walkable = true, + groups = {cracky=3,not_in_creative_inventory=1}, + drop = 'mesecons_detector:object_detector_off', + mesecons = {receptor = { + state = mesecon.state.on, + rules = mesecon.rules.pplate + }}, + on_construct = object_detector_make_formspec, + on_receive_fields = object_detector_on_receive_fields, + sounds = mesecon.node_sound.stone, + digiline = object_detector_digiline, + on_blast = mesecon.on_blastnode, +}) + +if minetest.get_modpath("mesecons_luacontroller") then + minetest.register_craft({ + output = 'mesecons_detector:object_detector_off', + recipe = { + {"mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:steel_ingot", "mesecons_luacontroller:luacontroller0000", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:steel_ingot", "group:mesecon_conductor_craftable", "mesecons_gamecompat:steel_ingot"}, + } + }) +end + +minetest.register_craft({ + output = 'mesecons_detector:object_detector_off', + recipe = { + {"mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:steel_ingot", "mesecons_microcontroller:microcontroller0000", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:steel_ingot", "group:mesecon_conductor_craftable", "mesecons_gamecompat:steel_ingot"}, + } +}) + +minetest.register_abm({ + nodenames = {"mesecons_detector:object_detector_off"}, + interval = 1, + chance = 1, + action = function(pos, node) + if not object_detector_scan(pos) then return end + + node.name = "mesecons_detector:object_detector_on" + minetest.swap_node(pos, node) + mesecon.receptor_on(pos, mesecon.rules.pplate) + end, +}) + +minetest.register_abm({ + nodenames = {"mesecons_detector:object_detector_on"}, + interval = 1, + chance = 1, + action = function(pos, node) + if object_detector_scan(pos) then return end + + node.name = "mesecons_detector:object_detector_off" + minetest.swap_node(pos, node) + mesecon.receptor_off(pos, mesecon.rules.pplate) + end, +}) + +-- Node detector +-- Detects the node in front of it + +local function node_detector_make_formspec(pos) + local meta = minetest.get_meta(pos) + if meta:get_string("distance") == "" then meta:set_string("distance", "0") end + meta:set_string("formspec", "size[9,2.5]" .. + "field[0.3, 0;9,2;scanname;Name of node to scan for (empty for any):;${scanname}]".. + "field[0.3,1.5;2.5,2;distance;Distance (0-"..mesecon.setting("node_detector_distance_max", 10).."):;${distance}]".. + "field[3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]".. + "button_exit[7,0.75;2,3;;Save]") +end + +local function node_detector_on_receive_fields(pos, _, fields, sender) + if not fields.scanname or not fields.digiline_channel then return end + + if minetest.is_protected(pos, sender:get_player_name()) then return end + + local meta = minetest.get_meta(pos) + meta:set_string("scanname", fields.scanname) + meta:set_string("distance", fields.distance or "0") + meta:set_string("digiline_channel", fields.digiline_channel) + node_detector_make_formspec(pos) +end + +-- returns true if node was found, false if not +local function node_detector_scan(pos) + local node = minetest.get_node_or_nil(pos) + if not node then return end + + local meta = minetest.get_meta(pos) + + local distance = meta:get_int("distance") + local distance_max = mesecon.setting("node_detector_distance_max", 10) + if distance < 0 then distance = 0 end + if distance > distance_max then distance = distance_max end + + local frontname = minetest.get_node( + vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1)) + ).name + local scanname = meta:get_string("scanname") + local scan_for = comma_list_to_table(scanname) + + return (scan_for[frontname]) or + (frontname ~= "air" and frontname ~= "ignore" and scanname == "") +end + +local function node_detector_send_node_name(pos, node, channel, meta) + local distance = meta:get_int("distance") + local distance_max = mesecon.setting("node_detector_distance_max", 10) + if distance < 0 then distance = 0 end + if distance > distance_max then distance = distance_max end + local nodename = minetest.get_node( + vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1)) + ).name + + digiline:receptor_send(pos, digiline.rules.default, channel, nodename) +end + +-- set player name when receiving a digiline signal on a specific channel +local node_detector_digiline = { + effector = { + action = function(pos, node, channel, msg) + local meta = minetest.get_meta(pos) + + if channel ~= meta:get_string("digiline_channel") then return end + + if type(msg) == "table" then + if msg.distance or msg.scanname then + if type(msg.distance) == "number" or type(msg.distance) == "string" then + meta:set_string("distance", msg.distance) + end + if type(msg.scanname) == "string" then + meta:set_string("scanname", msg.scanname) + end + node_detector_make_formspec(pos) + end + if msg.command == "get" then + node_detector_send_node_name(pos, node, channel, meta) + elseif msg.command == "scan" then + local result = node_detector_scan(pos) + digiline:receptor_send(pos, digiline.rules.default, channel, result) + end + else + if msg == GET_COMMAND then + node_detector_send_node_name(pos, node, channel, meta) + elseif type(msg) == "string" then + meta:set_string("scanname", msg) + node_detector_make_formspec(pos) + end + end + end, + }, + receptor = {} +} + +minetest.register_node("mesecons_detector:node_detector_off", { + tiles = {side_texture, side_texture, side_texture, side_texture, side_texture, "jeija_node_detector_off.png"}, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + walkable = true, + groups = {cracky=3}, + description = S("Node Detector"), + mesecons = {receptor = { + state = mesecon.state.off + }}, + on_construct = node_detector_make_formspec, + on_receive_fields = node_detector_on_receive_fields, + sounds = mesecon.node_sound.stone, + digiline = node_detector_digiline, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_detector:node_detector_on", { + tiles = {side_texture, side_texture, side_texture, side_texture, side_texture, "jeija_node_detector_on.png"}, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + walkable = true, + groups = {cracky=3,not_in_creative_inventory=1}, + drop = 'mesecons_detector:node_detector_off', + mesecons = {receptor = { + state = mesecon.state.on + }}, + on_construct = node_detector_make_formspec, + on_receive_fields = node_detector_on_receive_fields, + sounds = mesecon.node_sound.stone, + digiline = node_detector_digiline, + on_blast = mesecon.on_blastnode, +}) + +if minetest.get_modpath("mesecons_luacontroller") then + minetest.register_craft({ + output = 'mesecons_detector:node_detector_off', + recipe = { + {"mesecons_gamecompat:steel_ingot", "group:mesecon_conductor_craftable", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:steel_ingot", "mesecons_luacontroller:luacontroller0000", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:steel_ingot"}, + } + }) +end + +minetest.register_craft({ + output = 'mesecons_detector:node_detector_off', + recipe = { + {"mesecons_gamecompat:steel_ingot", "group:mesecon_conductor_craftable", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:steel_ingot", "mesecons_microcontroller:microcontroller0000", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:steel_ingot"}, + } +}) + +minetest.register_abm({ + nodenames = {"mesecons_detector:node_detector_off"}, + interval = 1, + chance = 1, + action = function(pos, node) + if not node_detector_scan(pos) then return end + + node.name = "mesecons_detector:node_detector_on" + minetest.swap_node(pos, node) + mesecon.receptor_on(pos) + end, +}) + +minetest.register_abm({ + nodenames = {"mesecons_detector:node_detector_on"}, + interval = 1, + chance = 1, + action = function(pos, node) + if node_detector_scan(pos) then return end + + node.name = "mesecons_detector:node_detector_off" + minetest.swap_node(pos, node) + mesecon.receptor_off(pos) + end, +}) diff --git a/mods/mesecons/mesecons_detector/locale/mesecons_detector.de.tr b/mods/mesecons/mesecons_detector/locale/mesecons_detector.de.tr new file mode 100644 index 00000000..d58625e8 --- /dev/null +++ b/mods/mesecons/mesecons_detector/locale/mesecons_detector.de.tr @@ -0,0 +1,3 @@ +# textdomain: mesecons_detector +Player Detector=Spielerdetektor +Node Detector=Blockdetektor diff --git a/mods/mesecons/mesecons_detector/locale/mesecons_detector.eo.tr b/mods/mesecons/mesecons_detector/locale/mesecons_detector.eo.tr new file mode 100644 index 00000000..0db21e2a --- /dev/null +++ b/mods/mesecons/mesecons_detector/locale/mesecons_detector.eo.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_detector + +### init.lua ### +Player Detector=Ludanta Detektilo +Node Detector=Noda Detektilo diff --git a/mods/mesecons/mesecons_detector/locale/mesecons_detector.fr.tr b/mods/mesecons/mesecons_detector/locale/mesecons_detector.fr.tr new file mode 100644 index 00000000..dadfa903 --- /dev/null +++ b/mods/mesecons/mesecons_detector/locale/mesecons_detector.fr.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_detector + +### init.lua ### +Player Detector=Détecteur de joueur +Node Detector=Détecteur de bloc diff --git a/mods/mesecons/mesecons_detector/locale/mesecons_detector.ru.tr b/mods/mesecons/mesecons_detector/locale/mesecons_detector.ru.tr new file mode 100644 index 00000000..3b19412f --- /dev/null +++ b/mods/mesecons/mesecons_detector/locale/mesecons_detector.ru.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_detector + +### init.lua ### +Player Detector=Детектор игрока +Node Detector=Детектор блока diff --git a/mods/mesecons/mesecons_detector/locale/mesecons_detector.uk.tr b/mods/mesecons/mesecons_detector/locale/mesecons_detector.uk.tr new file mode 100644 index 00000000..9f8d58d8 --- /dev/null +++ b/mods/mesecons/mesecons_detector/locale/mesecons_detector.uk.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_detector + +### init.lua ### +Player Detector=Детектор гравця +Node Detector=Детектор блоку diff --git a/mods/mesecons/mesecons_detector/locale/template.txt b/mods/mesecons/mesecons_detector/locale/template.txt new file mode 100644 index 00000000..1a8a6a78 --- /dev/null +++ b/mods/mesecons/mesecons_detector/locale/template.txt @@ -0,0 +1,5 @@ +# textdomain: mesecons_detector + +### init.lua ### +Player Detector= +Node Detector= diff --git a/mods/mesecons/mesecons_detector/mod.conf b/mods/mesecons/mesecons_detector/mod.conf new file mode 100644 index 00000000..ee5611be --- /dev/null +++ b/mods/mesecons/mesecons_detector/mod.conf @@ -0,0 +1,3 @@ +name = mesecons_detector +depends = mesecons, mesecons_gamecompat, mesecons_materials +optional_depends = mesecons_luacontroller diff --git a/mods/mesecons/mesecons_detector/textures/jeija_node_detector_off.png b/mods/mesecons/mesecons_detector/textures/jeija_node_detector_off.png new file mode 100644 index 00000000..bfd7b214 Binary files /dev/null and b/mods/mesecons/mesecons_detector/textures/jeija_node_detector_off.png differ diff --git a/mods/mesecons/mesecons_detector/textures/jeija_node_detector_on.png b/mods/mesecons/mesecons_detector/textures/jeija_node_detector_on.png new file mode 100644 index 00000000..69305ea3 Binary files /dev/null and b/mods/mesecons/mesecons_detector/textures/jeija_node_detector_on.png differ diff --git a/mods/mesecons/mesecons_detector/textures/jeija_object_detector_off.png b/mods/mesecons/mesecons_detector/textures/jeija_object_detector_off.png new file mode 100644 index 00000000..104a12b0 Binary files /dev/null and b/mods/mesecons/mesecons_detector/textures/jeija_object_detector_off.png differ diff --git a/mods/mesecons/mesecons_detector/textures/jeija_object_detector_on.png b/mods/mesecons/mesecons_detector/textures/jeija_object_detector_on.png new file mode 100644 index 00000000..ccbdccbc Binary files /dev/null and b/mods/mesecons/mesecons_detector/textures/jeija_object_detector_on.png differ diff --git a/mods/mesecons/mesecons_detector/textures/mesecons_detector_side.png b/mods/mesecons/mesecons_detector/textures/mesecons_detector_side.png new file mode 100644 index 00000000..5e421f02 Binary files /dev/null and b/mods/mesecons/mesecons_detector/textures/mesecons_detector_side.png differ diff --git a/mods/mesecons/mesecons_extrawires/corner.lua b/mods/mesecons/mesecons_extrawires/corner.lua new file mode 100644 index 00000000..7075c5f4 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/corner.lua @@ -0,0 +1,77 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local corner_selectionbox = { + type = "fixed", + fixed = { -16/32, -16/32, -16/32, 5/32, -12/32, 5/32 }, +} + +local corner_get_rules = mesecon.horiz_rules_getter({ + {x = 0, y = 0, z = -1}, + {x = -1, y = 0, z = 0}, +}) + +minetest.register_node("mesecons_extrawires:corner_on", { + drawtype = "mesh", + mesh = "mesecons_extrawires_corner.obj", + tiles = { + { name = "jeija_insulated_wire_sides_on.png", backface_culling = true }, + { name = "jeija_insulated_wire_ends_on.png", backface_culling = true }, + }, + paramtype = "light", + paramtype2 = "4dir", + is_ground_content = false, + walkable = false, + sunlight_propagates = true, + selection_box = corner_selectionbox, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons_extrawires:corner_off", + sounds = mesecon.node_sound.default, + mesecons = {conductor = + { + state = mesecon.state.on, + rules = corner_get_rules, + offstate = "mesecons_extrawires:corner_off" + }}, + on_blast = mesecon.on_blastnode, + on_rotate = mesecon.on_rotate, +}) + +minetest.register_node("mesecons_extrawires:corner_off", { + drawtype = "mesh", + description = S("Insulated Mesecon Corner"), + mesh = "mesecons_extrawires_corner.obj", + tiles = { + { name = "jeija_insulated_wire_sides_off.png", backface_culling = true }, + { name = "jeija_insulated_wire_ends_off.png", backface_culling = true }, + }, + paramtype = "light", + paramtype2 = "4dir", + is_ground_content = false, + walkable = false, + sunlight_propagates = true, + selection_box = corner_selectionbox, + groups = {dig_immediate = 3}, + sounds = mesecon.node_sound.default, + mesecons = {conductor = + { + state = mesecon.state.off, + rules = corner_get_rules, + onstate = "mesecons_extrawires:corner_on" + }}, + on_blast = mesecon.on_blastnode, + on_rotate = mesecon.on_rotate, +}) + +minetest.register_craft({ + output = "mesecons_extrawires:corner_off 3", + recipe = { + {"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off"}, + {"", "mesecons_insulated:insulated_off"}, + } +}) + +minetest.register_craft({ + output = "mesecons_insulated:insulated_off", + type = "shapeless", + recipe = {"mesecons_extrawires:corner_off"} +}) diff --git a/mods/mesecons/mesecons_extrawires/crossover.lua b/mods/mesecons/mesecons_extrawires/crossover.lua new file mode 100644 index 00000000..1001467a --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/crossover.lua @@ -0,0 +1,143 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local crossover_rules = { + {--first wire + {x=-1,y=0,z=0}, + {x=1,y=0,z=0}, + }, + {--second wire + {x=0,y=0,z=-1}, + {x=0,y=0,z=1}, + }, +} + +local crossover_states = { + "mesecons_extrawires:crossover_off", + "mesecons_extrawires:crossover_01", + "mesecons_extrawires:crossover_10", + "mesecons_extrawires:crossover_on", +} + +minetest.register_node("mesecons_extrawires:crossover_off", { + description = S("Insulated Mesecon Crossover"), + drawtype = "mesh", + mesh = "mesecons_extrawires_crossover.b3d", + tiles = { + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_ends_off.png" + }, + paramtype = "light", + is_ground_content = false, + walkable = false, + stack_max = 99, + selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}}, + groups = {dig_immediate=3, mesecon=3}, + sounds = mesecon.node_sound.default, + mesecons = { + conductor = { + states = crossover_states, + rules = crossover_rules, + } + }, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_extrawires:crossover_01", { + description = S("You hacker you!"), + drop = "mesecons_extrawires:crossover_off", + drawtype = "mesh", + mesh = "mesecons_extrawires_crossover.b3d", + tiles = { + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_ends_off.png" + }, + paramtype = "light", + is_ground_content = false, + walkable = false, + stack_max = 99, + selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}}, + groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, + sounds = mesecon.node_sound.default, + mesecons = { + conductor = { + states = crossover_states, + rules = crossover_rules, + } + }, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_extrawires:crossover_10", { + description = S("You hacker you!"), + drop = "mesecons_extrawires:crossover_off", + drawtype = "mesh", + mesh = "mesecons_extrawires_crossover.b3d", + tiles = { + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_ends_on.png" + }, + paramtype = "light", + is_ground_content = false, + walkable = false, + stack_max = 99, + selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}}, + groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, + sounds = mesecon.node_sound.default, + mesecons = { + conductor = { + states = crossover_states, + rules = crossover_rules, + } + }, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_extrawires:crossover_on", { + description = S("You hacker you!"), + drop = "mesecons_extrawires:crossover_off", + drawtype = "mesh", + mesh = "mesecons_extrawires_crossover.b3d", + tiles = { + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_ends_on.png" + }, + paramtype = "light", + is_ground_content = false, + walkable = false, + stack_max = 99, + selection_box = {type="fixed", fixed={-16/32, -16/32, -16/32, 16/32, -5/32, 16/32}}, + groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, + sounds = mesecon.node_sound.default, + mesecons = { + conductor = { + states = crossover_states, + rules = crossover_rules, + } + }, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_extrawires:crossover_off", + recipe = { + "mesecons_insulated:insulated_off", + "mesecons_insulated:insulated_off", + }, +}) + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_insulated:insulated_off 2", + recipe = { + "mesecons_extrawires:crossover_off", + }, +}) diff --git a/mods/mesecons/mesecons_extrawires/doc/corner/description.html b/mods/mesecons/mesecons_extrawires/doc/corner/description.html new file mode 100644 index 00000000..fc420d11 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/doc/corner/description.html @@ -0,0 +1 @@ +Insulated corners are conductors that only conduct between the inputs (also not up or down). When placing they always point to the left in direction of your vision. Like uninsulated wires, they work through unloaded blocks. diff --git a/mods/mesecons/mesecons_extrawires/doc/corner/preview.png b/mods/mesecons/mesecons_extrawires/doc/corner/preview.png new file mode 100644 index 00000000..7fbb0dc3 Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/corner/preview.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/corner/recipe.png b/mods/mesecons/mesecons_extrawires/doc/corner/recipe.png new file mode 100644 index 00000000..ce6e86ea Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/corner/recipe.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/crossing/description.html b/mods/mesecons/mesecons_extrawires/doc/crossing/description.html new file mode 100644 index 00000000..5f023828 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/doc/crossing/description.html @@ -0,0 +1 @@ +Insulated crossing are conductors that conduct two signals between the opposing sides, the signals are insulated to each other. Like uninsulated wires, they work through unloaded blocks. diff --git a/mods/mesecons/mesecons_extrawires/doc/crossing/preview.png b/mods/mesecons/mesecons_extrawires/doc/crossing/preview.png new file mode 100644 index 00000000..b5466a57 Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/crossing/preview.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/crossing/recipe.png b/mods/mesecons/mesecons_extrawires/doc/crossing/recipe.png new file mode 100644 index 00000000..6beac96d Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/crossing/recipe.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/mese/description.html b/mods/mesecons/mesecons_extrawires/doc/mese/description.html new file mode 100644 index 00000000..b29e92c2 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/doc/mese/description.html @@ -0,0 +1 @@ +The basic prerequesite for mesecons, can be crafted into wires and other stuff. Have a look at the Minetest Wiki for more information. Mese is a conductor. It conducts in all six directions: Up/Down/Left/Right/Forward/Backward. Like horizontal wires, Mese conduction works through unloaded blocks. diff --git a/mods/mesecons/mesecons_extrawires/doc/mese/preview.png b/mods/mesecons/mesecons_extrawires/doc/mese/preview.png new file mode 100644 index 00000000..ed1a1628 Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/mese/preview.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/mese/recipe.png b/mods/mesecons/mesecons_extrawires/doc/mese/recipe.png new file mode 100644 index 00000000..e4bb08c1 Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/mese/recipe.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/tjunction/description.html b/mods/mesecons/mesecons_extrawires/doc/tjunction/description.html new file mode 100644 index 00000000..647bba6a --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/doc/tjunction/description.html @@ -0,0 +1 @@ +Insulated T-Junctions are conductors that only conduct between the inputs (also not up or down). Like uninsulated wires, they work through unloaded blocks. diff --git a/mods/mesecons/mesecons_extrawires/doc/tjunction/preview.png b/mods/mesecons/mesecons_extrawires/doc/tjunction/preview.png new file mode 100644 index 00000000..8407d15b Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/tjunction/preview.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/tjunction/recipe.png b/mods/mesecons/mesecons_extrawires/doc/tjunction/recipe.png new file mode 100644 index 00000000..7358d913 Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/tjunction/recipe.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/vertical/description.html b/mods/mesecons/mesecons_extrawires/doc/vertical/description.html new file mode 100644 index 00000000..85085424 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/doc/vertical/description.html @@ -0,0 +1 @@ +Vertical Mesecons only conduct up and down. Plates appear at the ends, at that place they also conduct to the side. Like horizontal wires, they work through unloaded blocks. diff --git a/mods/mesecons/mesecons_extrawires/doc/vertical/preview.png b/mods/mesecons/mesecons_extrawires/doc/vertical/preview.png new file mode 100644 index 00000000..eea55714 Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/vertical/preview.png differ diff --git a/mods/mesecons/mesecons_extrawires/doc/vertical/recipe.png b/mods/mesecons/mesecons_extrawires/doc/vertical/recipe.png new file mode 100644 index 00000000..b12ccdea Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/doc/vertical/recipe.png differ diff --git a/mods/mesecons/mesecons_extrawires/doublecorner.lua b/mods/mesecons/mesecons_extrawires/doublecorner.lua new file mode 100644 index 00000000..d8c238c2 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/doublecorner.lua @@ -0,0 +1,78 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local doublecorner_selectionbox = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, +} + +local doublecorner_get_rules = mesecon.horiz_rules_getter({ + { + { x = 1, y = 0, z = 0 }, + { x = 0, y = 0, z = 1 }, + }, + { + { x = -1, y = 0, z = 0 }, + { x = 0, y = 0, z = -1 }, + }, +}) + +local doublecorner_states = { + "mesecons_extrawires:doublecorner_00", + "mesecons_extrawires:doublecorner_01", + "mesecons_extrawires:doublecorner_10", + "mesecons_extrawires:doublecorner_11", +} +local wire1_states = { "off", "off", "on", "on" } +local wire2_states = { "off", "on", "off", "on" } + +for k, state in ipairs(doublecorner_states) do + local w1 = wire1_states[k] + local w2 = wire2_states[k] + local groups = { dig_immediate = 3 } + if k ~= 1 then groups.not_in_creative_inventory = 1 end + minetest.register_node(state, { + drawtype = "mesh", + mesh = "mesecons_extrawires_doublecorner.obj", + description = S("Insulated Mesecon Double Corner"), + tiles = { + { name = "jeija_insulated_wire_sides_" .. w1 .. ".png", backface_culling = true }, + { name = "jeija_insulated_wire_ends_" .. w1 .. ".png", backface_culling = true }, + { name = "jeija_insulated_wire_sides_" .. w2 .. ".png", backface_culling = true }, + { name = "jeija_insulated_wire_ends_" .. w2 .. ".png", backface_culling = true }, + }, + paramtype = "light", + paramtype2 = "4dir", + is_ground_content = false, + walkable = false, + sunlight_propagates = true, + selection_box = doublecorner_selectionbox, + groups = groups, + drop = doublecorner_states[1], + sounds = mesecon.node_sound.default, + mesecons = { + conductor = { + states = doublecorner_states, + rules = doublecorner_get_rules, + }, + }, + on_blast = mesecon.on_blastnode, + on_rotate = mesecon.on_rotate, + }) +end + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_extrawires:doublecorner_00", + recipe = { + "mesecons_extrawires:corner_off", + "mesecons_extrawires:corner_off", + }, +}) + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_extrawires:corner_off 2", + recipe = { + "mesecons_extrawires:doublecorner_00", + }, +}) diff --git a/mods/mesecons/mesecons_extrawires/init.lua b/mods/mesecons/mesecons_extrawires/init.lua new file mode 100644 index 00000000..bed0e65d --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/init.lua @@ -0,0 +1,8 @@ +dofile(minetest.get_modpath("mesecons_extrawires").."/crossover.lua"); +dofile(minetest.get_modpath("mesecons_extrawires").."/tjunction.lua"); +dofile(minetest.get_modpath("mesecons_extrawires").."/corner.lua"); +dofile(minetest.get_modpath("mesecons_extrawires").."/doublecorner.lua"); +dofile(minetest.get_modpath("mesecons_extrawires").."/vertical.lua"); +if core.registered_nodes["mesecons_gamecompat:mese"] then + dofile(minetest.get_modpath("mesecons_extrawires").."/mesewire.lua"); +end diff --git a/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.de.tr b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.de.tr new file mode 100644 index 00000000..5df510e1 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.de.tr @@ -0,0 +1,8 @@ +# textdomain: mesecons_extrawires +Insulated Mesecon Corner=Isolierte Meseconecke +Insulated Mesecon Crossover=Isolierter Meseconübergang +You hacker you!=Sie Hacker! +Insulated Mesecon Double Corner=Isolierte Mesecondoppelecke +Mese Wire=Mesedraht +Insulated Mesecon T-junction=Isolierte Mesecongabelung +Vertical Mesecon=Vertikaler Mesecon diff --git a/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.eo.tr b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.eo.tr new file mode 100644 index 00000000..e8d8415c --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.eo.tr @@ -0,0 +1,20 @@ +# textdomain: mesecons_extrawires + +### corner.lua ### +Insulated Mesecon Corner=Izolita Mesekonduktila Angulo + +### crossover.lua ### +Insulated Mesecon Crossover=Izolita Mesekonduktila Interkruciĝo +You hacker you!=Vi hakisto + +### doublecorner.lua ### +Insulated Mesecon Double Corner=Izolita Mesekonduktila Duobla Angulo + +### mesewire.lua ### +Mese Wire=Mesea Drato + +### tjunction.lua ### +Insulated Mesecon T-junction=Izolita Mesekonduktila T-Kruciĝo + +### vertical.lua ### +Vertical Mesecon=Vertikala Mesekonduktilo diff --git a/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.fr.tr b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.fr.tr new file mode 100644 index 00000000..46992a6f --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.fr.tr @@ -0,0 +1,20 @@ +# textdomain: mesecons_extrawires + +### corner.lua ### +Insulated Mesecon Corner=Coin de Mesecon isolé + +### crossover.lua ### +Insulated Mesecon Crossover=Croisement de Mesecon isolé +You hacker you!=Vous êtes un pirate informatique ! + +### doublecorner.lua ### +Insulated Mesecon Double Corner=Double coin de Mesecon isolé + +### mesewire.lua ### +Mese Wire=Câble de Mesecon + +### tjunction.lua ### +Insulated Mesecon T-junction=Croisement en T de Mesecon isolé + +### vertical.lua ### +Vertical Mesecon=Mesecon vertical diff --git a/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.ru.tr b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.ru.tr new file mode 100644 index 00000000..3826f94d --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.ru.tr @@ -0,0 +1,20 @@ +# textdomain: mesecons_extrawires + +### corner.lua ### +Insulated Mesecon Corner=Изолированный мезекон (угол) + +### crossover.lua ### +Insulated Mesecon Crossover=Изолированный мезекон (перекрестие) +You hacker you!=Ти хакер ти! + +### doublecorner.lua ### +Insulated Mesecon Double Corner=Изолированный мезекон (двойной угол) + +### mesewire.lua ### +Mese Wire=Мезе-провод + +### tjunction.lua ### +Insulated Mesecon T-junction=Изолированный мезекон (Т-соединение) + +### vertical.lua ### +Vertical Mesecon=Вертикальный мезекон diff --git a/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.uk.tr b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.uk.tr new file mode 100644 index 00000000..3a3daa79 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/locale/mesecons_extrawires.uk.tr @@ -0,0 +1,20 @@ +# textdomain: mesecons_extrawires + +### corner.lua ### +Insulated Mesecon Corner=Ізольований месекон (кут) + +### crossover.lua ### +Insulated Mesecon Crossover=Ізольований месекон (перехрестя) +You hacker you!=Ти хакер ти! + +### doublecorner.lua ### +Insulated Mesecon Double Corner=Ізольований месекон (подвійний кут) + +### mesewire.lua ### +Mese Wire=Месе-дріт + +### tjunction.lua ### +Insulated Mesecon T-junction=Ізольований месекон (T-з'єднання) + +### vertical.lua ### +Vertical Mesecon=Вертикальний месекон diff --git a/mods/mesecons/mesecons_extrawires/locale/template.txt b/mods/mesecons/mesecons_extrawires/locale/template.txt new file mode 100644 index 00000000..44d3abb9 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/locale/template.txt @@ -0,0 +1,20 @@ +# textdomain: mesecons_extrawires + +### corner.lua ### +Insulated Mesecon Corner= + +### crossover.lua ### +Insulated Mesecon Crossover= +You hacker you!= + +### doublecorner.lua ### +Insulated Mesecon Double Corner= + +### mesewire.lua ### +Mese Wire= + +### tjunction.lua ### +Insulated Mesecon T-junction= + +### vertical.lua ### +Vertical Mesecon= diff --git a/mods/mesecons/mesecons_extrawires/mesewire.lua b/mods/mesecons/mesecons_extrawires/mesewire.lua new file mode 100644 index 00000000..cdb87a8d --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/mesewire.lua @@ -0,0 +1,58 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local mese_nodename = minetest.registered_aliases["mesecons_gamecompat:mese"] +if mese_nodename then + -- Convert placeholders. + minetest.register_alias("mesecons_extrawires:mese", mese_nodename) +else + -- Register placeholder. + mese_nodename = "mesecons_extrawires:mese" + minetest.register_node("mesecons_extrawires:mese", { + description = S("Mese Wire"), + tiles = {"mesecons_wire_off.png"}, + paramtype = "light", + light_source = 3, + groups = {cracky = 1}, + sounds = mesecon.node_sound.stone, + }) +end + +local mesewire_rules = +{ + {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}, +} + +minetest.override_item(mese_nodename, { + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_extrawires:mese_powered", + rules = mesewire_rules + }} +}) + +-- Copy node definition of powered mese from normal mese +-- and brighten texture tiles to indicate mese is powered +local unpowered_def = minetest.registered_nodes[mese_nodename] +local powered_def = mesecon.merge_tables(unpowered_def, { + drop = mese_nodename, + paramtype = "light", + light_source = math.min(unpowered_def.light_source + 2, minetest.LIGHT_MAX), + mesecons = {conductor = { + state = mesecon.state.on, + offstate = mese_nodename, + rules = mesewire_rules + }}, + groups = mesecon.merge_tables(unpowered_def.groups or {}, {not_in_creative_inventory = 1}), + on_blast = mesecon.on_blastnode, +}) + +for i, v in pairs(powered_def.tiles) do + powered_def.tiles[i] = v .. "^[brighten" +end + +minetest.register_node("mesecons_extrawires:mese_powered", powered_def) diff --git a/mods/mesecons/mesecons_extrawires/mod.conf b/mods/mesecons/mesecons_extrawires/mod.conf new file mode 100644 index 00000000..cd9e2d3c --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_extrawires +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_corner.obj b/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_corner.obj new file mode 100644 index 00000000..c7b6b160 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_corner.obj @@ -0,0 +1,125 @@ +# Вершины +# Провод 1 +# 1 (ниж. внутр.) +v 0.093750 -0.531250 -0.501000 +v 0.093750 -0.531250 -0.331726 +v 0.331726 -0.531250 -0.093750 +v 0.501000 -0.531250 -0.093750 +# 5 (ниж. наруж.) +v -0.093750 -0.531250 -0.501000 +v -0.093750 -0.531250 -0.254061 +v 0.254061 -0.531250 0.093750 +v 0.501000 -0.531250 0.093750 +# 9 (верх. внутр.) +v 0.093750 -0.406250 -0.501000 +v 0.093750 -0.406250 -0.331726 +v 0.331726 -0.406250 -0.093750 +v 0.501000 -0.406250 -0.093750 +# 13 (верх. наруж.) +v -0.093750 -0.406250 -0.501000 +v -0.093750 -0.406250 -0.254061 +v 0.254061 -0.406250 0.093750 +v 0.501000 -0.406250 0.093750 +# Текстурные координаты +# 1 (ниж.) +vt 0.000000 0.406250 +vt 0.168274 0.406250 +vt 0.331726 0.406250 +vt 0.668274 0.406250 +vt 0.831726 0.406250 +vt 1.000000 0.406250 +vt 0.000000 0.593750 +vt 0.245939 0.593750 +vt 0.254061 0.593750 +vt 0.745939 0.593750 +vt 0.754061 0.593750 +vt 1.000000 0.593750 +# 13 (верх.) +vt 0.000000 0.406250 +vt 0.245939 0.406250 +vt 0.254061 0.406250 +vt 0.745939 0.406250 +vt 0.754061 0.406250 +vt 1.000000 0.406250 +vt 0.000000 0.593750 +vt 0.168274 0.593750 +vt 0.331726 0.593750 +vt 0.668274 0.593750 +vt 0.831726 0.593750 +vt 1.000000 0.593750 +# 25 (внутр.) +vt 1.000000 0.093750 +vt 0.831726 0.093750 +vt 0.668274 0.093750 +vt 0.331726 0.093750 +vt 0.168274 0.093750 +vt 0.000000 0.093750 +vt 1.000000 -0.031250 +vt 0.831726 -0.031250 +vt 0.668274 -0.031250 +vt 0.331726 -0.031250 +vt 0.168274 -0.031250 +vt 0.000000 -0.031250 +# 37 (внеш.) +vt 0.000000 -0.031250 +vt 0.245939 -0.031250 +vt 0.254061 -0.031250 +vt 0.745939 -0.031250 +vt 0.754061 -0.031250 +vt 1.000000 -0.031250 +vt 0.000000 0.093750 +vt 0.245939 0.093750 +vt 0.254061 0.093750 +vt 0.745939 0.093750 +vt 0.754061 0.093750 +vt 1.000000 0.093750 +# 49 (торец) +vt 0.406250 -0.031250 +vt 0.406250 0.093750 +vt 0.593750 -0.031250 +vt 0.593750 0.093750 +# Нормали +# 1 +vn 1.000000 0.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 0.000000 1.000000 +vn 0.707107 0.000000 0.707107 +# 5 +vn -1.000000 0.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn -0.707107 0.000000 -0.707107 +# Грани +g Sides1 +# Часть 1 +f 5/37/1 6/38/1 14/44/1 +f 5/37/1 14/44/1 13/43/1 +f 13/13/2 14/14/2 10/20/2 +f 13/13/2 10/20/2 9/19/2 +f 9/25/5 10/26/5 2/32/5 +f 9/25/5 2/32/5 1/31/5 +f 1/1/6 2/2/6 6/8/6 +f 1/1/6 6/8/6 5/7/6 +# Часть 2 +f 6/39/4 7/40/4 15/46/4 +f 6/39/4 15/46/4 14/45/4 +f 14/15/2 15/16/2 11/22/2 +f 14/15/2 11/22/2 10/21/2 +f 10/27/8 11/28/8 3/34/8 +f 10/27/8 3/34/8 2/33/8 +f 2/3/6 3/4/6 7/10/6 +f 2/3/6 7/10/6 6/9/6 +# Часть 3 +f 7/41/3 8/42/3 16/48/3 +f 7/41/3 16/48/3 15/47/3 +f 15/17/2 16/18/2 12/24/2 +f 15/17/2 12/24/2 11/23/2 +f 11/29/7 12/30/7 4/36/7 +f 11/29/7 4/36/7 3/35/7 +f 3/5/6 4/6/6 8/12/6 +f 3/5/6 8/12/6 7/11/6 +g Ends1 +f 1/49/3 5/51/3 13/52/3 +f 1/49/3 13/52/3 9/50/3 +f 4/49/1 12/50/1 16/52/1 +f 4/49/1 16/52/1 8/51/1 diff --git a/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_crossover.b3d b/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_crossover.b3d new file mode 100644 index 00000000..e776535a Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_crossover.b3d differ diff --git a/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_doublecorner.obj b/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_doublecorner.obj new file mode 100644 index 00000000..a74aa019 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/models/mesecons_extrawires_doublecorner.obj @@ -0,0 +1,180 @@ +# Вершины +# Провод 1 +# 1 (ниж. внутр.) +v 0.093750 -0.531250 -0.501000 +v 0.093750 -0.531250 -0.331726 +v 0.331726 -0.531250 -0.093750 +v 0.501000 -0.531250 -0.093750 +# 5 (ниж. наруж.) +v -0.093750 -0.531250 -0.501000 +v -0.093750 -0.531250 -0.254061 +v 0.254061 -0.531250 0.093750 +v 0.501000 -0.531250 0.093750 +# 9 (верх. внутр.) +v 0.093750 -0.406250 -0.501000 +v 0.093750 -0.406250 -0.331726 +v 0.331726 -0.406250 -0.093750 +v 0.501000 -0.406250 -0.093750 +# 13 (верх. наруж.) +v -0.093750 -0.406250 -0.501000 +v -0.093750 -0.406250 -0.254061 +v 0.254061 -0.406250 0.093750 +v 0.501000 -0.406250 0.093750 +# Провод 2 +# 17 (ниж. внутр.) +v -0.093750 -0.531250 0.501000 +v -0.093750 -0.531250 0.331726 +v -0.331726 -0.531250 0.093750 +v -0.501000 -0.531250 0.093750 +# 21 (ниж. наруж.) +v 0.093750 -0.531250 0.501000 +v 0.093750 -0.531250 0.254061 +v -0.254061 -0.531250 -0.093750 +v -0.501000 -0.531250 -0.093750 +# 25 (верх. внутр.) +v -0.093750 -0.406250 0.501000 +v -0.093750 -0.406250 0.331726 +v -0.331726 -0.406250 0.093750 +v -0.501000 -0.406250 0.093750 +# 29 (верх. наруж.) +v 0.093750 -0.406250 0.501000 +v 0.093750 -0.406250 0.254061 +v -0.254061 -0.406250 -0.093750 +v -0.501000 -0.406250 -0.093750 +# Текстурные координаты +# 1 (ниж.) +vt 0.000000 0.406250 +vt 0.168274 0.406250 +vt 0.331726 0.406250 +vt 0.668274 0.406250 +vt 0.831726 0.406250 +vt 1.000000 0.406250 +vt 0.000000 0.593750 +vt 0.245939 0.593750 +vt 0.254061 0.593750 +vt 0.745939 0.593750 +vt 0.754061 0.593750 +vt 1.000000 0.593750 +# 13 (верх.) +vt 0.000000 0.406250 +vt 0.245939 0.406250 +vt 0.254061 0.406250 +vt 0.745939 0.406250 +vt 0.754061 0.406250 +vt 1.000000 0.406250 +vt 0.000000 0.593750 +vt 0.168274 0.593750 +vt 0.331726 0.593750 +vt 0.668274 0.593750 +vt 0.831726 0.593750 +vt 1.000000 0.593750 +# 25 (внутр.) +vt 1.000000 0.093750 +vt 0.831726 0.093750 +vt 0.668274 0.093750 +vt 0.331726 0.093750 +vt 0.168274 0.093750 +vt 0.000000 0.093750 +vt 1.000000 -0.031250 +vt 0.831726 -0.031250 +vt 0.668274 -0.031250 +vt 0.331726 -0.031250 +vt 0.168274 -0.031250 +vt 0.000000 -0.031250 +# 37 (внеш.) +vt 0.000000 -0.031250 +vt 0.245939 -0.031250 +vt 0.254061 -0.031250 +vt 0.745939 -0.031250 +vt 0.754061 -0.031250 +vt 1.000000 -0.031250 +vt 0.000000 0.093750 +vt 0.245939 0.093750 +vt 0.254061 0.093750 +vt 0.745939 0.093750 +vt 0.754061 0.093750 +vt 1.000000 0.093750 +# 49 (торец) +vt 0.406250 -0.031250 +vt 0.406250 0.093750 +vt 0.593750 -0.031250 +vt 0.593750 0.093750 +# Нормали +# 1 +vn 1.000000 0.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 0.000000 1.000000 +vn 0.707107 0.000000 0.707107 +# 5 +vn -1.000000 0.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn -0.707107 0.000000 -0.707107 +# Грани +# Грани +g Sides1 +# Часть 1 +f 5/37/1 6/38/1 14/44/1 +f 5/37/1 14/44/1 13/43/1 +f 13/13/2 14/14/2 10/20/2 +f 13/13/2 10/20/2 9/19/2 +f 9/25/5 10/26/5 2/32/5 +f 9/25/5 2/32/5 1/31/5 +f 1/1/6 2/2/6 6/8/6 +f 1/1/6 6/8/6 5/7/6 +# Часть 2 +f 6/39/4 7/40/4 15/46/4 +f 6/39/4 15/46/4 14/45/4 +f 14/15/2 15/16/2 11/22/2 +f 14/15/2 11/22/2 10/21/2 +f 10/27/8 11/28/8 3/34/8 +f 10/27/8 3/34/8 2/33/8 +f 2/3/6 3/4/6 7/10/6 +f 2/3/6 7/10/6 6/9/6 +# Часть 3 +f 7/41/3 8/42/3 16/48/3 +f 7/41/3 16/48/3 15/47/3 +f 15/17/2 16/18/2 12/24/2 +f 15/17/2 12/24/2 11/23/2 +f 11/29/7 12/30/7 4/36/7 +f 11/29/7 4/36/7 3/35/7 +f 3/5/6 4/6/6 8/12/6 +f 3/5/6 8/12/6 7/11/6 +g Ends1 +f 1/49/3 5/51/3 13/52/3 +f 1/49/3 13/52/3 9/50/3 +f 4/49/1 12/50/1 16/52/1 +f 4/49/1 16/52/1 8/51/1 +g Sides2 +# Часть 1 +f 21/37/1 22/38/1 30/44/1 +f 21/37/1 30/44/1 29/43/1 +f 29/13/2 30/14/2 26/20/2 +f 29/13/2 26/20/2 25/19/2 +f 25/25/5 26/26/5 18/32/5 +f 25/25/5 18/32/5 17/31/5 +f 17/1/6 18/2/6 22/8/6 +f 17/1/6 22/8/6 21/7/6 +# Часть 2 +f 22/39/4 23/40/4 31/46/4 +f 22/39/4 31/46/4 30/45/4 +f 30/15/2 31/16/2 27/22/2 +f 30/15/2 27/22/2 26/21/2 +f 26/27/8 27/28/8 19/34/8 +f 26/27/8 19/34/8 18/33/8 +f 18/3/6 19/4/6 23/10/6 +f 18/3/6 23/10/6 22/9/6 +# Часть 3 +f 23/41/3 24/42/3 32/48/3 +f 23/41/3 32/48/3 31/47/3 +f 31/17/2 32/18/2 28/24/2 +f 31/17/2 28/24/2 27/23/2 +f 27/29/7 28/30/7 20/36/7 +f 27/29/7 20/36/7 19/35/7 +f 19/5/6 20/6/6 24/12/6 +f 19/5/6 24/12/6 23/11/6 +g Ends2 +f 17/49/3 21/51/3 29/52/3 +f 17/49/3 29/52/3 25/50/3 +f 20/49/1 28/50/1 32/52/1 +f 20/49/1 32/52/1 24/51/1 diff --git a/mods/mesecons/mesecons_extrawires/src/mesecons_extrawires_crossover.blend b/mods/mesecons/mesecons_extrawires/src/mesecons_extrawires_crossover.blend new file mode 100644 index 00000000..9ad37496 Binary files /dev/null and b/mods/mesecons/mesecons_extrawires/src/mesecons_extrawires_crossover.blend differ diff --git a/mods/mesecons/mesecons_extrawires/tjunction.lua b/mods/mesecons/mesecons_extrawires/tjunction.lua new file mode 100644 index 00000000..0d3bf4b8 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/tjunction.lua @@ -0,0 +1,87 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local tjunction_nodebox = { + type = "fixed", + -- ±0.001 is to prevent z-fighting + fixed = {{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 }, + { -3/32, -17/32, -16/32+0.001, 3/32, -13/32, -3/32},} +} + +local tjunction_selectionbox = { + type = "fixed", + fixed = { -16/32, -16/32, -16/32, 16/32, -12/32, 7/32 }, +} + +local tjunction_get_rules = mesecon.horiz_rules_getter({ + {x = 1, y = 0, z = 0}, + {x = 0, y = 0, z = -1}, + {x = -1, y = 0, z = 0}, +}) + +minetest.register_node("mesecons_extrawires:tjunction_on", { + drawtype = "nodebox", + tiles = { + "jeija_insulated_wire_tjunction_tb_on.png", + "jeija_insulated_wire_tjunction_tb_on.png^[transformR180", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_ends_on.png" + }, + paramtype = "light", + paramtype2 = "4dir", + is_ground_content = false, + walkable = false, + sunlight_propagates = true, + selection_box = tjunction_selectionbox, + node_box = tjunction_nodebox, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons_extrawires:tjunction_off", + sounds = mesecon.node_sound.default, + mesecons = {conductor = + { + state = mesecon.state.on, + rules = tjunction_get_rules, + offstate = "mesecons_extrawires:tjunction_off" + }}, + on_blast = mesecon.on_blastnode, + on_rotate = mesecon.on_rotate, +}) + +minetest.register_node("mesecons_extrawires:tjunction_off", { + drawtype = "nodebox", + description = S("Insulated Mesecon T-junction"), + tiles = { + "jeija_insulated_wire_tjunction_tb_off.png", + "jeija_insulated_wire_tjunction_tb_off.png^[transformR180", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_ends_off.png" + }, + paramtype = "light", + paramtype2 = "4dir", + is_ground_content = false, + walkable = false, + sunlight_propagates = true, + selection_box = tjunction_selectionbox, + node_box = tjunction_nodebox, + groups = {dig_immediate = 3}, + sounds = mesecon.node_sound.default, + mesecons = {conductor = + { + state = mesecon.state.off, + rules = tjunction_get_rules, + onstate = "mesecons_extrawires:tjunction_on" + }}, + on_blast = mesecon.on_blastnode, + on_rotate = mesecon.on_rotate, +}) + +minetest.register_craft({ + output = "mesecons_extrawires:tjunction_off 3", + recipe = { + {"mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off", "mesecons_insulated:insulated_off"}, + {"", "mesecons_insulated:insulated_off", ""}, + } +}) diff --git a/mods/mesecons/mesecons_extrawires/vertical.lua b/mods/mesecons/mesecons_extrawires/vertical.lua new file mode 100644 index 00000000..925bee38 --- /dev/null +++ b/mods/mesecons/mesecons_extrawires/vertical.lua @@ -0,0 +1,198 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local vertical_box = { + type = "fixed", + fixed = {-1/16, -8/16, -1/16, 1/16, 8/16, 1/16} +} + +local top_box = { + type = "fixed", + fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}} +} + +local bottom_box = { + type = "fixed", + fixed = { + {-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, + {-1/16, -7/16, -1/16, 1/16, 8/16, 1/16}, + } +} + +local vertical_rules = { + {x=0, y=1, z=0}, + {x=0, y=-1, z=0} +} + +local top_rules = { + {x=1,y=0, z=0}, + {x=-1,y=0, z=0}, + {x=0,y=0, z=1}, + {x=0,y=0, z=-1}, + {x=0,y=-1, z=0} +} + +local bottom_rules = { + {x=1, y=0, z=0}, + {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=2, z=0} -- receive power from pressure plate / detector / ... 2 nodes above +} + +local use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or nil + +local function is_vertical_conductor(nodename) + local def = minetest.registered_nodes[nodename] + return def and def.is_vertical_conductor +end + +local vertical_updatepos = function (pos) + local node = minetest.get_node(pos) + if not is_vertical_conductor(node.name) then + return + end + + local node_above = minetest.get_node(vector.add(pos, vertical_rules[1])) + local node_below = minetest.get_node(vector.add(pos, vertical_rules[2])) + + local above = is_vertical_conductor(node_above.name) + local below = is_vertical_conductor(node_below.name) + + mesecon.on_dignode(pos, node) + + -- Always place offstate conductor and let mesecon.on_placenode take care + local newname = "mesecons_extrawires:vertical_" + if above and below then -- above and below: vertical mesecon + newname = newname .. "off" + elseif above and not below then -- above only: bottom + newname = newname .. "bottom_off" + elseif not above and below then -- below only: top + newname = newname .. "top_off" + else -- no vertical wire above, no vertical wire below: use bottom + newname = newname .. "bottom_off" + end + + minetest.set_node(pos, {name = newname}) + mesecon.on_placenode(pos, {name = newname}) +end + +local vertical_update = function (pos) + vertical_updatepos(pos) -- this one + vertical_updatepos(vector.add(pos, vertical_rules[1])) -- above + vertical_updatepos(vector.add(pos, vertical_rules[2])) -- below +end + +-- Vertical wire +mesecon.register_node("mesecons_extrawires:vertical", { + description = S("Vertical Mesecon"), + drawtype = "nodebox", + walkable = false, + paramtype = "light", + is_ground_content = false, + sunlight_propagates = true, + selection_box = vertical_box, + node_box = vertical_box, + is_vertical_conductor = true, + drop = "mesecons_extrawires:vertical_off", + after_place_node = vertical_update, + after_dig_node = vertical_update, + sounds = mesecon.node_sound.default, + use_texture_alpha = use_texture_alpha, +},{ + tiles = {"mesecons_wire_off.png"}, + groups = {dig_immediate=3}, + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_extrawires:vertical_on", + rules = vertical_rules, + }} +},{ + tiles = {"mesecons_wire_on.png"}, + groups = {dig_immediate=3, not_in_creative_inventory=1}, + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_extrawires:vertical_off", + rules = vertical_rules, + }} +}) + +-- Vertical wire top +mesecon.register_node("mesecons_extrawires:vertical_top", { + description = S("Vertical Mesecon"), + drawtype = "nodebox", + walkable = false, + paramtype = "light", + is_ground_content = false, + sunlight_propagates = true, + groups = {dig_immediate=3, not_in_creative_inventory=1}, + 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, + sounds = mesecon.node_sound.default, + use_texture_alpha = use_texture_alpha, +},{ + tiles = {"mesecons_wire_off.png"}, + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_extrawires:vertical_top_on", + rules = top_rules, + }} +},{ + tiles = {"mesecons_wire_on.png"}, + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_extrawires:vertical_top_off", + rules = top_rules, + }} +}) + +-- Vertical wire bottom +mesecon.register_node("mesecons_extrawires:vertical_bottom", { + description = S("Vertical Mesecon"), + drawtype = "nodebox", + walkable = false, + paramtype = "light", + is_ground_content = false, + sunlight_propagates = true, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + 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, + sounds = mesecon.node_sound.default, + use_texture_alpha = use_texture_alpha, +},{ + tiles = {"mesecons_wire_off.png"}, + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_extrawires:vertical_bottom_on", + rules = bottom_rules, + }} +},{ + tiles = {"mesecons_wire_on.png"}, + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_extrawires:vertical_bottom_off", + rules = bottom_rules, + }} +}) + +minetest.register_craft({ + output = "mesecons_extrawires:vertical_off 3", + recipe = { + {"group:mesecon_conductor_craftable"}, + {"group:mesecon_conductor_craftable"}, + {"group:mesecon_conductor_craftable"}, + } +}) + +minetest.register_craft({ + output = "mesecons:wire_00000000_off", + recipe = {{"mesecons_extrawires:vertical_off"}} +}) diff --git a/mods/mesecons/mesecons_fpga/doc/fpga/description.html b/mods/mesecons/mesecons_fpga/doc/fpga/description.html new file mode 100644 index 00000000..a4cbeed0 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/doc/fpga/description.html @@ -0,0 +1,6 @@ +FPGAs can be used to chain multiple logic gates together in a compact manner. +They come with 4 I/O ports and 10 internal registers, +which can then be connected with each other to form logic circuits. +They work fine in unloaded blocks.
+Supported gate types: AND, OR, NOT, XOR, NAND, XNOR, Buffer (=)
+I/O ports: A B C D; Registers: numbered 0 to 9 diff --git a/mods/mesecons/mesecons_fpga/doc/fpga/preview.png b/mods/mesecons/mesecons_fpga/doc/fpga/preview.png new file mode 100644 index 00000000..b4a2994f Binary files /dev/null and b/mods/mesecons/mesecons_fpga/doc/fpga/preview.png differ diff --git a/mods/mesecons/mesecons_fpga/doc/fpga/recipe.png b/mods/mesecons/mesecons_fpga/doc/fpga/recipe.png new file mode 100644 index 00000000..edb14f4b Binary files /dev/null and b/mods/mesecons/mesecons_fpga/doc/fpga/recipe.png differ diff --git a/mods/mesecons/mesecons_fpga/doc/programmer/description.html b/mods/mesecons/mesecons_fpga/doc/programmer/description.html new file mode 100644 index 00000000..39e23744 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/doc/programmer/description.html @@ -0,0 +1,3 @@ +The FPGA programmer can be used to copy gate configurations from one FPGA to another.
+Shift+Right-Click an FPGA to read its configuration and "remember" it. +Left-click (punch) FPGAs to write the saved configuration to them. diff --git a/mods/mesecons/mesecons_fpga/doc/programmer/preview.png b/mods/mesecons/mesecons_fpga/doc/programmer/preview.png new file mode 100644 index 00000000..b1bae7a2 Binary files /dev/null and b/mods/mesecons/mesecons_fpga/doc/programmer/preview.png differ diff --git a/mods/mesecons/mesecons_fpga/doc/programmer/recipe.png b/mods/mesecons/mesecons_fpga/doc/programmer/recipe.png new file mode 100644 index 00000000..a7c691b3 Binary files /dev/null and b/mods/mesecons/mesecons_fpga/doc/programmer/recipe.png differ diff --git a/mods/mesecons/mesecons_fpga/init.lua b/mods/mesecons/mesecons_fpga/init.lua new file mode 100644 index 00000000..0af9d1bd --- /dev/null +++ b/mods/mesecons/mesecons_fpga/init.lua @@ -0,0 +1,464 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local plg = {} +plg.rules = {} +-- per-player formspec positions +plg.open_formspecs = {} + +local lcore = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/logic.lua") +dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/tool.lua")(plg) + +plg.register_nodes = function(template) + -- each loop is for one of the 4 IO ports + for a = 0, 1 do + for b = 0, 1 do + for c = 0, 1 do + for d = 0, 1 do + local ndef = table.copy(template) + local nodename = "mesecons_fpga:fpga" + .. tostring(d) .. tostring(c) .. tostring(b) .. tostring(a) + + -- build top texture string + local texture = "jeija_fpga_top.png" + if a == 1 then texture = texture .. "^jeija_luacontroller_LED_A.png" end + if b == 1 then texture = texture .. "^jeija_luacontroller_LED_B.png" end + if c == 1 then texture = texture .. "^jeija_luacontroller_LED_C.png" end + if d == 1 then texture = texture .. "^jeija_luacontroller_LED_D.png" end + ndef.tiles[1] = texture + ndef.inventory_image = texture + + if (a + b + c + d) > 0 then + ndef.groups["not_in_creative_inventory"] = 1 + end + + -- interaction with mesecons (input / output) + local rules_out = {} + if a == 1 then table.insert(rules_out, {x = -1, y = 0, z = 0}) end + if b == 1 then table.insert(rules_out, {x = 0, y = 0, z = 1}) end + if c == 1 then table.insert(rules_out, {x = 1, y = 0, z = 0}) end + if d == 1 then table.insert(rules_out, {x = 0, y = 0, z = -1}) end + plg.rules[nodename] = rules_out + + local rules_in = {} + if a == 0 then table.insert(rules_in, {x = -1, y = 0, z = 0}) end + if b == 0 then table.insert(rules_in, {x = 0, y = 0, z = 1}) end + if c == 0 then table.insert(rules_in, {x = 1, y = 0, z = 0}) end + if d == 0 then table.insert(rules_in, {x = 0, y = 0, z = -1}) end + ndef.mesecons.effector.rules = rules_in + + if (a + b + c + d) > 0 then + ndef.mesecons.receptor = { + state = mesecon.state.on, + rules = rules_out, + } + end + + minetest.register_node(nodename, ndef) + end + end + end + end +end + +plg.register_nodes({ + description = S("FPGA"), + drawtype = "nodebox", + tiles = { + "", -- replaced later + "jeija_microcontroller_bottom.png", + "jeija_fpga_sides.png", + "jeija_fpga_sides.png", + "jeija_fpga_sides.png", + "jeija_fpga_sides.png" + }, + inventory_image = "", -- replaced later + is_ground_content = false, + sunlight_propagates = true, + paramtype = "light", + walkable = true, + groups = {dig_immediate = 2, mesecon = 3, overheat = 1}, + drop = "mesecons_fpga:fpga0000", + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 }, + }, + node_box = { + type = "fixed", + fixed = { + { -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab + { -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board + { -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC + } + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + local is = { {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} } + + meta:set_string("instr", lcore.serialize(is)) + meta:set_int("valid", 0) + meta:set_string("infotext", "FPGA") + end, + on_rightclick = function(pos, _, clicker) + if not minetest.is_player(clicker) then + return + end + local meta = minetest.get_meta(pos) + local name = clicker:get_player_name() + -- Erase formspecs of old FPGAs + meta:set_string("formspec", "") + + plg.open_formspecs[name] = pos + local is = lcore.deserialize(meta:get_string("instr")) + minetest.show_formspec(name, "mesecons:fpga", plg.to_formspec_string(is, nil)) + end, + sounds = mesecon.node_sound.stone, + mesecons = { + effector = { + rules = {}, -- replaced later + action_change = function(pos, _, rule, newstate) + if plg.ports_changed(pos, rule, newstate) then + plg.update(pos) + end + end + } + }, + after_dig_node = function(pos, node) + mesecon.receptor_off(pos, plg.rules[node.name]) + for name, open_pos in pairs(plg.open_formspecs) do + if vector.equals(pos, open_pos) then + minetest.close_formspec(name, "mesecons:fpga") + plg.open_formspecs[name] = nil + end + end + end, + on_blast = mesecon.on_blastnode, + on_rotate = function(pos, _, user, mode) + local abcd1 = {"A", "B", "C", "D"} + local abcd2 = {A = 1, B = 2, C = 3, D = 4} + local ops = {"op1", "op2", "dst"} + local dir = 0 + if mode == screwdriver.ROTATE_FACE then -- clock-wise + dir = 1 + if user and user:is_player() then + minetest.chat_send_player(user:get_player_name(), + "FPGA ports have been rotated clockwise.") + end + elseif mode == screwdriver.ROTATE_AXIS then -- counter-clockwise + dir = -1 + if user and user:is_player() then + minetest.chat_send_player(user:get_player_name(), + "FPGA ports have been rotated counter-clockwise.") + end + end + + local meta = minetest.get_meta(pos) + local instr = lcore.deserialize(meta:get_string("instr")) + for i = 1, #instr do + for _, op in ipairs(ops) do + local o = instr[i][op] + if o and o.type == "io" then + local num = abcd2[o.port] + num = num + dir + if num > 4 then num = 1 + elseif num < 1 then num = 4 end + instr[i][op].port = abcd1[num] + end + end + end + + meta:set_string("instr", lcore.serialize(instr)) + plg.update_meta(pos, instr) + return true + end, +}) + +plg.to_formspec_string = function(is, err) + local function dropdown_op(x, y, name, val) + local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";" + .. "0.75,0.5;" .. name .. ";" -- the height seems to be ignored? + s = s .. " ,A,B,C,D,0,1,2,3,4,5,6,7,8,9;" + if val == nil then + s = s .. "0" -- actually selects no field at all + elseif val.type == "io" then + local mapping = { + ["A"] = 1, + ["B"] = 2, + ["C"] = 3, + ["D"] = 4, + } + s = s .. tostring(1 + mapping[val.port]) + else -- "reg" + s = s .. tostring(6 + val.n) + end + return s .. "]" + end + local function dropdown_action(x, y, name, val) + local selected = 0 + local titles = { " " } + for i, data in ipairs(lcore.get_operations()) do + titles[i + 1] = data.fs_name + if val == data.gate then + selected = i + 1 + end + end + return ("dropdown[%f,%f;1.125,0.5;%s;%s;%i]"):format( + x, y, name, table.concat(titles, ","), selected) + end + local s = "size[9,9]".. + "label[3.4,-0.15;FPGA gate configuration]".. + "button[7,7.5;2,2.5;program;Program]".. + "box[4.2,0.5;0.03,7;#ffffff]".. + "label[0.25,0.25;op. 1]".. + "label[1.0,0.25;gate type]".. + "label[2.125,0.25;op. 2]".. + "label[3.15,0.25;dest]".. + "label[4.5,0.25;op. 1]".. + "label[5.25,0.25;gate type]".. + "label[6.375,0.25;op. 2]".. + "label[7.4,0.25;dest]" + local x = 1 - 0.75 + local y = 1 - 0.25 + for i = 1, 14 do + local cur = is[i] + s = s .. dropdown_op (x , y, tostring(i).."op1", cur.op1) + s = s .. dropdown_action(x+0.75 , y, tostring(i).."act", cur.action) + s = s .. dropdown_op (x+1.875, y, tostring(i).."op2", cur.op2) + s = s .. "label[" .. tostring(x+2.625) .. "," .. tostring(y+0.1) .. "; ->]" + s = s .. dropdown_op (x+2.9 , y, tostring(i).."dst", cur.dst) + y = y + 1 + + if i == 7 then + x = 4.5 + y = 1 - 0.25 + end + end + if err then + local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg)) + s = s .. plg.red_box_around(err.i) .. + "label[0.25,8.25;The gate configuration is erroneous in the marked area:]".. + "label[0.25,8.5;" .. fmsg .. "]" + end + return s +end + +plg.from_formspec_fields = function(fields) + local function read_op(s) + if s == nil or s == " " then + return nil + elseif s == "A" or s == "B" or s == "C" or s == "D" then + return {type = "io", port = s} + else + return {type = "reg", n = tonumber(s)} + end + end + local function read_action(s) + for i, data in ipairs(lcore.get_operations()) do + if data.fs_name == s then + return data.gate + end + end + end + local is = {} + for i = 1, 14 do + local cur = {} + cur.op1 = read_op(fields[tonumber(i) .. "op1"]) + cur.action = read_action(fields[tonumber(i) .. "act"]) + cur.op2 = read_op(fields[tonumber(i) .. "op2"]) + cur.dst = read_op(fields[tonumber(i) .. "dst"]) + is[#is + 1] = cur + end + return is +end + +plg.update_meta = function(pos, is) + if type(is) == "string" then -- serialized string + is = lcore.deserialize(is) + end + local meta = minetest.get_meta(pos) + + local err = lcore.validate(is) + if err == nil then + meta:set_int("valid", 1) + meta:set_string("infotext", "FPGA (functional)") + else + meta:set_int("valid", 0) + meta:set_string("infotext", "FPGA") + end + + -- reset ports and run programmed logic + plg.setports(pos, false, false, false, false) + plg.update(pos) + + -- Refresh open formspecs + local form = plg.to_formspec_string(is, err) + for name, open_pos in pairs(plg.open_formspecs) do + if vector.equals(pos, open_pos) then + minetest.show_formspec(name, "mesecons:fpga", form) + end + end + return err +end + +plg.red_box_around = function(i) + local x, y + if i > 7 then + x = 4.5 + y = 0.75 + (i - 8) + else + x = 0.25 + y = 0.75 + (i - 1) + end + return string.format("box[%f,%f;3.8,0.8;#ff0000]", x-0.1, y-0.05) +end + + +plg.update = function(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("valid") ~= 1 then + return + elseif mesecon.do_overheat(pos) then + plg.setports(pos, false, false, false, false) + meta:set_int("valid", 0) + meta:set_string("infotext", "FPGA (overheated)") + return + end + + local is = lcore.deserialize(meta:get_string("instr")) + local A, B, C, D = plg.getports(pos) + A, B, C, D = lcore.interpret(is, A, B, C, D) + plg.setports(pos, A, B, C, D) +end + +-- Updates the port states according to the signal change. +-- Returns whether the port states actually changed. +plg.ports_changed = function(pos, rule, newstate) + if rule == nil then return false end + local meta = minetest.get_meta(pos) + local states + + local s = meta:get_string("portstates") + if s == nil then + states = {false, false, false, false} + else + states = { + s:sub(1, 1) == "1", + s:sub(2, 2) == "1", + s:sub(3, 3) == "1", + s:sub(4, 4) == "1", + } + end + + -- trick to transform rules (see register_node) into port number + local portno = ({4, 1, nil, 3, 2})[3 + rule.x + 2*rule.z] + states[portno] = (newstate == "on") + + local new_portstates = + (states[1] and "1" or "0") .. (states[2] and "1" or "0") .. + (states[3] and "1" or "0") .. (states[4] and "1" or "0") + if new_portstates ~= s then + meta:set_string("portstates", new_portstates) + return true + end + return false +end + +plg.getports = function(pos) -- gets merged states of INPUT & OUTPUT + local sin, sout + + local s = minetest.get_meta(pos):get_string("portstates") + if s == nil then + sin = {false, false, false, false} + else + sin = { + s:sub(1, 1) == "1", + s:sub(2, 2) == "1", + s:sub(3, 3) == "1", + s:sub(4, 4) == "1", + } + end + + local name = minetest.get_node(pos).name + assert(name:find("mesecons_fpga:fpga") == 1) + local off = #"mesecons_fpga:fpga" + sout = { + name:sub(off+4, off+4) == "1", + name:sub(off+3, off+3) == "1", + name:sub(off+2, off+2) == "1", + name:sub(off+1, off+1) == "1", + } + + return unpack({ + sin[1] or sout[1], + sin[2] or sout[2], + sin[3] or sout[3], + sin[4] or sout[4], + }) +end + +plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT + local base = "mesecons_fpga:fpga" + + local name = base + .. (D and "1" or "0") .. (C and "1" or "0") + .. (B and "1" or "0") .. (A and "1" or "0") + minetest.swap_node(pos, {name = name, param2 = minetest.get_node(pos).param2}) + + if A ~= nil then + local ru = plg.rules[base .. "0001"] + if A then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end + end + if B ~= nil then + local ru = plg.rules[base .. "0010"] + if B then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end + end + if C ~= nil then + local ru = plg.rules[base .. "0100"] + if C then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end + end + if D ~= nil then + local ru = plg.rules[base .. "1000"] + if D then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end + end +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + local player_name = player:get_player_name() + + if formname ~= "mesecons:fpga" or fields.quit then + plg.open_formspecs[player_name] = nil -- potential garbage + return + end + if not fields.program then + return -- we only care when the user clicks "Program" + end + local pos = plg.open_formspecs[player_name] + if minetest.is_protected(pos, player_name) then + minetest.record_protection_violation(pos, player_name) + return + end + + local meta = minetest.get_meta(pos) + local is = plg.from_formspec_fields(fields) + + meta:set_string("instr", lcore.serialize(is)) + local err = plg.update_meta(pos, is) + + if not err then + plg.open_formspecs[player_name] = nil + -- Close on success + minetest.close_formspec(player_name, "mesecons:fpga") + end +end) + +minetest.register_on_leaveplayer(function(player) + plg.open_formspecs[player:get_player_name()] = nil +end) + +minetest.register_craft({ + output = "mesecons_fpga:fpga0000 2", + recipe = { + {'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'}, + {'mesecons_materials:silicon', 'mesecons_materials:silicon'}, + {'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'}, + } +}) diff --git a/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.de.tr b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.de.tr new file mode 100644 index 00000000..b3f0dd26 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.de.tr @@ -0,0 +1,3 @@ +# textdomain: mesecons_fpga +FPGA=FPGA +FPGA Programmer=FPGA-Programmierer diff --git a/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.eo.tr b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.eo.tr new file mode 100644 index 00000000..5ad42b1d --- /dev/null +++ b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.eo.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_fpga + +### init.lua ### +FPGA=FPGA + +### tool.lua ### +FPGA Programmer=FPGA Programilo diff --git a/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.fr.tr b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.fr.tr new file mode 100644 index 00000000..c0fccab3 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.fr.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_fpga + +### init.lua ### +FPGA=Circuit logique programmable (FPGA) + +### tool.lua ### +FPGA Programmer=Programmateur de circuit logique diff --git a/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.ru.tr b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.ru.tr new file mode 100644 index 00000000..b3f5dfe9 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.ru.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_fpga + +### init.lua ### +FPGA=ПЛИС + +### tool.lua ### +FPGA Programmer=ПЛИС-программер diff --git a/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.uk.tr b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.uk.tr new file mode 100644 index 00000000..95094139 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/locale/mesecons_fpga.uk.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_fpga + +### init.lua ### +FPGA=ПКВМ + +### tool.lua ### +FPGA Programmer=ПКВМ-программер diff --git a/mods/mesecons/mesecons_fpga/locale/template.txt b/mods/mesecons/mesecons_fpga/locale/template.txt new file mode 100644 index 00000000..5764150e --- /dev/null +++ b/mods/mesecons/mesecons_fpga/locale/template.txt @@ -0,0 +1,7 @@ +# textdomain: mesecons_fpga + +### init.lua ### +FPGA= + +### tool.lua ### +FPGA Programmer= diff --git a/mods/mesecons/mesecons_fpga/logic.lua b/mods/mesecons/mesecons_fpga/logic.lua new file mode 100644 index 00000000..0e268a2a --- /dev/null +++ b/mods/mesecons/mesecons_fpga/logic.lua @@ -0,0 +1,222 @@ + +local lg = {} + +local operations = { + -- table index: Index in the formspec dropdown + -- gate: Internal name + -- short: Serialized form, single character + -- fs_name: Display name, padded to 4 characters + -- func: Function that applies the operation + -- unary: Whether this gate only has one input + { gate = "and", short = "&", fs_name = " AND", func = function(a, b) return a and b end }, + { gate = "or", short = "|", fs_name = " OR", func = function(a, b) return a or b end }, + { gate = "not", short = "~", fs_name = " NOT", func = function(_, b) return not b end, unary = true }, + { gate = "xor", short = "^", fs_name = " XOR", func = function(a, b) return a ~= b end }, + { gate = "nand", short = "?", fs_name = "NAND", func = function(a, b) return not (a and b) end }, + { gate = "buf", short = "_", fs_name = " =", func = function(_, b) return b end, unary = true }, + { gate = "xnor", short = "=", fs_name = "XNOR", func = function(a, b) return a == b end }, + { gate = "nor", short = "!", fs_name = " NOR", func = function(a, b) return not (a or b) end }, +} + +lg.get_operations = function() + return operations +end + +-- (de)serialize +lg.serialize = function(t) + local function _op(t) + if t == nil then + return " " + elseif t.type == "io" then + return t.port + else -- t.type == "reg" + return tostring(t.n) + end + end + -- Serialize actions (gates) from eg. "and" to "&" + local function _action(action) + for i, data in ipairs(operations) do + if data.gate == action then + return data.short + end + end + return " " + end + + local s = "" + for i = 1, 14 do + local cur = t[i] + if next(cur) ~= nil then + s = s .. _op(cur.op1) .. _action(cur.action) .. _op(cur.op2) .. _op(cur.dst) + end + s = s .. "/" + end + return s +end + +lg.deserialize = function(s) + local function _op(c) + if c == "A" or c == "B" or c == "C" or c == "D" then + return {type = "io", port = c} + elseif c == " " then + return nil + else + return {type = "reg", n = tonumber(c)} + end + end + -- Deserialize actions (gates) from eg. "&" to "and" + local function _action(action) + for i, data in ipairs(operations) do + if data.short == action then + return data.gate + end + end + -- nil + end + + local ret = {} + for part in s:gmatch("(.-)/") do + local parsed + if part == "" then + parsed = {} + else + parsed = { + action = _action( part:sub(2,2) ), + op1 = _op( part:sub(1,1) ), + op2 = _op( part:sub(3,3) ), + dst = _op( part:sub(4,4) ), + } + end + ret[#ret + 1] = parsed + end + -- More than 14 instructions (write to all 10 regs + 4 outputs) + -- will not pass the write-once requirement of the validator + assert(#ret == 14) + return ret +end + +-- validation +lg.validate_single = function(t, i) + local function is_reg_written_to(t, n, max) + for i = 1, max-1 do + if next(t[i]) ~= nil + and t[i].dst and t[i].dst.type == "reg" + and t[i].dst.n == n then + return true + end + end + return false + end + local function compare_op(t1, t2, allow_same_io) + if t1 == nil or t2 == nil then + return false + elseif t1.type ~= t2.type then + return false + end + if t1.type == "reg" and t1.n == t2.n then + return true + elseif t1.type == "io" and t1.port == t2.port then + return not allow_same_io + end + return false + end + local elem = t[i] + + local gate_data + for j, data in ipairs(operations) do + if data.gate == elem.action then + gate_data = data + break + end + end + + -- check for completeness + if not gate_data then + return {i = i, msg = "Gate type is required"} + elseif gate_data.unary then + if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil then + return {i = i, msg = "Second operand (only) and destination are required"} + end + else + if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then + return {i = i, msg = "Operands and destination are required"} + end + end + -- check whether operands/destination are identical + if compare_op(elem.op1, elem.op2) then + return {i = i, msg = "Operands cannot be identical"} + end + if compare_op(elem.op1, elem.dst, true) or compare_op(elem.op2, elem.dst, true) then + return {i = i, msg = "Destination and operands must be different"} + end + -- check whether operands point to defined registers + if elem.op1 ~= nil and elem.op1.type == "reg" + and not is_reg_written_to(t, elem.op1.n, i) then + return {i = i, msg = "First operand is undefined register"} + end + if elem.op2.type == "reg" and not is_reg_written_to(t, elem.op2.n, i) then + return {i = i, msg = "Second operand is undefined register"} + end + -- check whether destination points to undefined register + if elem.dst.type == "reg" and is_reg_written_to(t, elem.dst.n, i) then + return {i = i, msg = "Destination is already used register"} + end + + return nil +end + +lg.validate = function(t) + for i = 1, 14 do + if next(t[i]) ~= nil then + local r = lg.validate_single(t, i) + if r ~= nil then + return r + end + end + end + return nil +end + +-- interpreter +lg.interpret = function(t, a, b, c, d) + local function _action(s, v1, v2) + for i, data in ipairs(operations) do + if data.gate == s then + return data.func(v1, v2) + end + end + return false -- unknown gate + end + local function _op(t, regs, io_in) + if t.type == "reg" then + return regs[t.n] + else -- t.type == "io" + return io_in[t.port] + end + end + + local io_in = {A=a, B=b, C=c, D=d} + local regs = {} + local io_out = {} + for i = 1, 14 do + local cur = t[i] + if next(cur) ~= nil then + local v1, v2 + if cur.op1 ~= nil then + v1 = _op(cur.op1, regs, io_in) + end + v2 = _op(cur.op2, regs, io_in) + + local result = _action(cur.action, v1, v2) + + if cur.dst.type == "reg" then + regs[cur.dst.n] = result + else -- cur.dst.type == "io" + io_out[cur.dst.port] = result + end + end + end + return io_out.A, io_out.B, io_out.C, io_out.D +end + +return lg diff --git a/mods/mesecons/mesecons_fpga/mod.conf b/mods/mesecons/mesecons_fpga/mod.conf new file mode 100644 index 00000000..5cd52f54 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/mod.conf @@ -0,0 +1,3 @@ +name = mesecons_fpga +depends = mesecons, mesecons_gamecompat +optional_depends = screwdriver diff --git a/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_copy.ogg b/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_copy.ogg new file mode 100644 index 00000000..259a1bd2 Binary files /dev/null and b/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_copy.ogg differ diff --git a/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_fail.ogg b/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_fail.ogg new file mode 100644 index 00000000..5e9059f8 Binary files /dev/null and b/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_fail.ogg differ diff --git a/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_write.ogg b/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_write.ogg new file mode 100644 index 00000000..e781bff9 Binary files /dev/null and b/mods/mesecons/mesecons_fpga/sounds/mesecons_fpga_write.ogg differ diff --git a/mods/mesecons/mesecons_fpga/spec/helper_spec.lua b/mods/mesecons/mesecons_fpga/spec/helper_spec.lua new file mode 100644 index 00000000..5f71c038 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/spec/helper_spec.lua @@ -0,0 +1,106 @@ +require("mineunit") + +fixture("mesecons_fpga") +fixture("screwdriver") + +local pos = {x = 0, y = 0, z = 0} +local pos_a = {x = -1, y = 0, z = 0} +local pos_b = {x = 0, y = 0, z = 1} +local pos_c = {x = 1, y = 0, z = 0} +local pos_d = {x = 0, y = 0, z = -1} + +describe("FPGA rotation", function() + before_each(function() + world.set_node(pos, "mesecons_fpga:fpga0000") + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("rotates I/O operands clockwise", function() + mesecon._test_program_fpga(pos, {{"A", "OR", "B", "C"}}) + + local node = world.get_node(pos) + minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_FACE) + + mesecon._test_place(pos_b, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) + + mesecon._test_dig(pos_b) + mesecon._test_place(pos_c, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions + mineunit:execute_globalstep() -- Execute activate/deactivate/change actions + assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) + end) + + it("rotates I/O operands counterclockwise", function() + mesecon._test_program_fpga(pos, {{"A", "OR", "B", "C"}}) + + local node = world.get_node(pos) + minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_AXIS) + + mesecon._test_place(pos_d, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) + + mesecon._test_dig(pos_d) + mesecon._test_place(pos_a, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions + mineunit:execute_globalstep() -- Execute activate/deactivate/change actions + assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) + end) + + it("updates ports", function() + mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}}) + assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) + + local node = world.get_node(pos) + minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_AXIS) + assert.equal("mesecons_fpga:fpga0001", world.get_node(pos).name) + end) +end) + +describe("FPGA programmer", function() + local pos2 = {x = 10, y = 0, z = 0} + + before_each(function() + world.set_node(pos, "mesecons_fpga:fpga0000") + world.set_node(pos2, "mesecons_fpga:fpga0000") + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("transfers instructions", function() + mesecon._test_program_fpga(pos2, {{"NOT", "A", "B"}}) + mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2)) + assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) + end) + + it("does not copy from new FPGAs", function() + mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}}) + mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2)) + assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) + end) + + it("does not copy from cleared FPGAs", function() + mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}}) + mesecon._test_program_fpga(pos2, {{"=", "A", "B"}}) + mesecon._test_program_fpga(pos2, {}) + mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2)) + assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) + end) + + it("does not copy from non-FPGA nodes", function() + mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}}) + mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(vector.add(pos2, 1))) + assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name) + end) +end) diff --git a/mods/mesecons/mesecons_fpga/spec/logic_spec.lua b/mods/mesecons/mesecons_fpga/spec/logic_spec.lua new file mode 100644 index 00000000..73882dd6 --- /dev/null +++ b/mods/mesecons/mesecons_fpga/spec/logic_spec.lua @@ -0,0 +1,235 @@ +require("mineunit") + +fixture("mesecons_fpga") + +describe("FPGA logic", function() + local pos = {x = 0, y = 0, z = 0} + local pos_a = {x = -1, y = 0, z = 0} + local pos_b = {x = 0, y = 0, z = 1} + local pos_c = {x = 1, y = 0, z = 0} + local pos_d = {x = 0, y = 0, z = -1} + + local fpga_set = false + + local function set_fpga() + if not fpga_set then + world.set_node(pos, "mesecons_fpga:fpga0000") + fpga_set = true + end + end + before_each(set_fpga) + + local function reset_world() + if fpga_set then + mesecon._test_reset() + world.clear() + fpga_set = false + end + end + after_each(reset_world) + + local function test_program(inputs, outputs, program) + set_fpga() + + mesecon._test_program_fpga(pos, program) + + if inputs.a then mesecon._test_place(pos_a, "mesecons:test_receptor_on") end + if inputs.b then mesecon._test_place(pos_b, "mesecons:test_receptor_on") end + if inputs.c then mesecon._test_place(pos_c, "mesecons:test_receptor_on") end + if inputs.d then mesecon._test_place(pos_d, "mesecons:test_receptor_on") end + mineunit:execute_globalstep() -- Execute receptor_on actions + mineunit:execute_globalstep() -- Execute activate/change actions + + local expected_name = "mesecons_fpga:fpga" + .. (outputs.d and 1 or 0) .. (outputs.c and 1 or 0) + .. (outputs.b and 1 or 0) .. (outputs.a and 1 or 0) + assert.equal(expected_name, world.get_node(pos).name) + + reset_world() + end + + it("operator and", function() + local prog = {{"A", "AND", "B", "C"}} + test_program({}, {}, prog) + test_program({a = true}, {}, prog) + test_program({b = true}, {}, prog) + test_program({a = true, b = true}, {c = true}, prog) + end) + + it("operator or", function() + local prog = {{"A", "OR", "B", "C"}} + test_program({}, {}, prog) + test_program({a = true}, {c = true}, prog) + test_program({b = true}, {c = true}, prog) + test_program({a = true, b = true}, {c = true}, prog) + end) + + it("operator not", function() + local prog = {{"NOT", "A", "B"}} + test_program({}, {b = true}, prog) + test_program({a = true}, {}, prog) + end) + + it("operator xor", function() + local prog = {{"A", "XOR", "B", "C"}} + test_program({}, {}, prog) + test_program({a = true}, {c = true}, prog) + test_program({b = true}, {c = true}, prog) + test_program({a = true, b = true}, {}, prog) + end) + + it("operator nand", function() + local prog = {{"A", "NAND", "B", "C"}} + test_program({}, {c = true}, prog) + test_program({a = true}, {c = true}, prog) + test_program({b = true}, {c = true}, prog) + test_program({a = true, b = true}, {}, prog) + end) + + it("operator buf", function() + local prog = {{"=", "A", "B"}} + test_program({}, {}, prog) + test_program({a = true}, {b = true}, prog) + end) + + it("operator xnor", function() + local prog = {{"A", "XNOR", "B", "C"}} + test_program({}, {c = true}, prog) + test_program({a = true}, {}, prog) + test_program({b = true}, {}, prog) + test_program({a = true, b = true}, {c = true}, prog) + end) + + it("operator nor", function() + local prog = {{"A", "NOR", "B", "C"}} + test_program({}, {c = true}, prog) + test_program({a = true}, {}, prog) + test_program({b = true}, {}, prog) + test_program({a = true, b = true}, {}, prog) + end) + + it("rejects duplicate operands", function() + test_program({a = true}, {}, {{"A", "OR", "A", "B"}}) + test_program({a = true}, {}, {{"=", "A", "0"}, {"0", "OR", "0", "B"}}) + end) + + it("rejects unassigned memory operands", function() + test_program({a = true}, {}, {{"A", "OR", "0", "B"}}) + test_program({a = true}, {}, {{"0", "OR", "A", "B"}}) + end) + + it("rejects double memory assignment", function() + test_program({a = true}, {}, {{"=", "A", "0"}, {"=", "A", "0"}, {"=", "0", "B"}}) + end) + + it("rejects assignment to memory operand", function() + test_program({a = true}, {}, {{"=", "A", "0"}, {"A", "OR", "0", "0"}, {"=", "0", "B"}}) + end) + + it("allows double port assignment", function() + test_program({a = true}, {b = true}, {{"NOT", "A", "B"}, {"=", "A", "B"}}) + end) + + it("allows assignment to port operand", function() + test_program({a = true}, {b = true}, {{"A", "OR", "B", "B"}}) + end) + + it("preserves initial pin states", function() + test_program({a = true}, {b = true}, {{"=", "A", "B"}, {"=", "B", "C"}}) + end) + + it("rejects binary operations with single operands", function() + test_program({a = true}, {}, {{"=", "A", "B"}, {" ", "OR", "A", "C"}}) + test_program({a = true}, {}, {{"=", "A", "B"}, {"A", "OR", " ", "C"}}) + end) + + it("rejects unary operations with first operands", function() + test_program({a = true}, {}, {{"=", "A", "B"}, {"A", "=", " ", "C"}}) + end) + + it("rejects operations without destinations", function() + test_program({a = true}, {}, {{"=", "A", "B"}, {"=", "A", " "}}) + end) + + it("allows blank statements", function() + test_program({a = true}, {b = true, c = true}, { + {" ", " ", " ", " "}, + {"=", "A", "B"}, + {" ", " ", " ", " "}, + {" ", " ", " ", " "}, + {"=", "A", "C"}, + }) + end) + + it("transmits output signals to adjacent nodes", function() + mesecon._test_program_fpga(pos, { + {"=", "A", "B"}, + {"=", "A", "C"}, + {"NOT", "A", "D"}, + }) + mesecon._test_place(pos_b, "mesecons:test_effector") + mesecon._test_place(pos_c, "mesecons:test_effector") + mesecon._test_place(pos_d, "mesecons:test_effector") + mineunit:execute_globalstep() -- Execute receptor_on actions + mineunit:execute_globalstep() -- Execute activate/change actions + + -- Makes an object from the last three effector events in the list for use with assert.same. + -- This is necessary to ignore the ordering of events. + local function event_tester(list) + local o = {list[#list - 2], list[#list - 1], list[#list - 0]} + table.sort(o, function(a, b) + local fmt = "%s %d %d %d" + return fmt:format(a[1], a[2].x, a[2].y, a[2].z) < fmt:format(b[1], b[2].x, b[2].y, b[2].z) + end) + return o + end + + mesecon._test_place(pos_a, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions + mineunit:execute_globalstep() -- Execute activate/deactivate/change actions + assert.equal("mesecons_fpga:fpga0110", world.get_node(pos).name) + assert.same(event_tester({{"on", pos_b}, {"on", pos_c}, {"off", pos_d}}), event_tester(mesecon._test_effector_events)) + + mesecon._test_dig(pos_a) + mineunit:execute_globalstep() -- Execute receptor_off action + mineunit:execute_globalstep() -- Execute deactivate/change actions + mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions + mineunit:execute_globalstep() -- Execute activate/deactivate/change actions + assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) + assert.same(event_tester({{"off", pos_b}, {"off", pos_c}, {"on", pos_d}}), event_tester(mesecon._test_effector_events)) + end) + + it("considers past outputs in determining inputs", function() + -- Memory cell: Turning on A turns on C; turning on B turns off C. + mesecon._test_program_fpga(pos, { + {"A", "OR", "C", "0"}, + {"B", "OR", "D", "1"}, + {"NOT", "A", "2"}, + {"NOT", "B", "3"}, + {"0", "AND", "3", "C"}, + {"1", "AND", "2", "D"}, + }) + + mesecon._test_place(pos_a, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on actions + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal("mesecons_fpga:fpga0100", world.get_node(pos).name) + + mesecon._test_dig(pos_a) + mineunit:execute_globalstep() -- Execute receptor_off actions + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal("mesecons_fpga:fpga0100", world.get_node(pos).name) + + mesecon._test_place(pos_b, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on actions + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) + + mesecon._test_dig(pos_b) + mineunit:execute_globalstep() -- Execute receptor_off actions + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name) + end) +end) diff --git a/mods/mesecons/mesecons_fpga/spec/mineunit.conf b/mods/mesecons/mesecons_fpga/spec/mineunit.conf new file mode 100644 index 00000000..81bd36ce --- /dev/null +++ b/mods/mesecons/mesecons_fpga/spec/mineunit.conf @@ -0,0 +1 @@ +fixture_paths = {"../.test_fixtures"} diff --git a/mods/mesecons/mesecons_fpga/textures/jeija_fpga_programmer.png b/mods/mesecons/mesecons_fpga/textures/jeija_fpga_programmer.png new file mode 100644 index 00000000..78e7fb1f Binary files /dev/null and b/mods/mesecons/mesecons_fpga/textures/jeija_fpga_programmer.png differ diff --git a/mods/mesecons/mesecons_fpga/textures/jeija_fpga_sides.png b/mods/mesecons/mesecons_fpga/textures/jeija_fpga_sides.png new file mode 100644 index 00000000..ed4f97dd Binary files /dev/null and b/mods/mesecons/mesecons_fpga/textures/jeija_fpga_sides.png differ diff --git a/mods/mesecons/mesecons_fpga/textures/jeija_fpga_top.png b/mods/mesecons/mesecons_fpga/textures/jeija_fpga_top.png new file mode 100644 index 00000000..8382486f Binary files /dev/null and b/mods/mesecons/mesecons_fpga/textures/jeija_fpga_top.png differ diff --git a/mods/mesecons/mesecons_fpga/tool.lua b/mods/mesecons/mesecons_fpga/tool.lua new file mode 100644 index 00000000..e0aff3bc --- /dev/null +++ b/mods/mesecons/mesecons_fpga/tool.lua @@ -0,0 +1,73 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +return function(plg) + + +minetest.register_tool("mesecons_fpga:programmer", { + description = S("FPGA Programmer"), + inventory_image = "jeija_fpga_programmer.png", + stack_max = 1, + on_place = function(itemstack, placer, pointed_thing) + if pointed_thing.type ~= "node" then + return itemstack + end + + local pos = pointed_thing.under + if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then + return itemstack + end + + local meta = minetest.get_meta(pos) + if meta:get_string("instr") == "//////////////" then + minetest.chat_send_player(placer:get_player_name(), "This FPGA is unprogrammed.") + minetest.sound_play("mesecons_fpga_fail", { pos = placer:get_pos(), gain = 0.1, max_hear_distance = 4 }, true) + return itemstack + end + itemstack:get_meta():set_string("", meta:get_string("instr")) + minetest.chat_send_player(placer:get_player_name(), "FPGA gate configuration was successfully copied!") + minetest.sound_play("mesecons_fpga_copy", { pos = placer:get_pos(), gain = 0.1, max_hear_distance = 4 }, true) + + return itemstack + end, + on_use = function(itemstack, user, pointed_thing) + if pointed_thing.type ~= "node" then + return itemstack + end + + local pos = pointed_thing.under + if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then + return itemstack + end + local player_name = user:get_player_name() + if minetest.is_protected(pos, player_name) then + minetest.record_protection_violation(pos, player_name) + return itemstack + end + + local imeta = itemstack:get_meta():get_string("") + if imeta == "" then + minetest.chat_send_player(player_name, "Use shift+right-click to copy a gate configuration first.") + minetest.sound_play("mesecons_fpga_fail", { pos = user:get_pos(), gain = 0.1, max_hear_distance = 4 }, true) + return itemstack + end + + local meta = minetest.get_meta(pos) + meta:set_string("instr", imeta) + plg.update_meta(pos, imeta) + minetest.chat_send_player(player_name, "Gate configuration was successfully written to FPGA!") + minetest.sound_play("mesecons_fpga_write", { pos = user:get_pos(), gain = 0.1, max_hear_distance = 4 }, true) + + return itemstack + end +}) + +minetest.register_craft({ + output = "mesecons_fpga:programmer", + recipe = { + {'group:mesecon_conductor_craftable'}, + {'mesecons_materials:silicon'}, + } +}) + + +end diff --git a/mods/mesecons/mesecons_gamecompat/compat_hades.lua b/mods/mesecons/mesecons_gamecompat/compat_hades.lua new file mode 100644 index 00000000..9dbe5399 --- /dev/null +++ b/mods/mesecons/mesecons_gamecompat/compat_hades.lua @@ -0,0 +1,72 @@ +--Aliases + +core.register_alias("mesecons_gamecompat:chest", "hades_chests:chest") +core.register_alias("mesecons_gamecompat:chest_locked", "hades_chests:chest_locked") +core.register_alias("mesecons_gamecompat:coalblock", "hades_core:coalblock") +core.register_alias("mesecons_gamecompat:cobble", "hades_core:cobble") +core.register_alias("mesecons_gamecompat:glass", "hades_core:glass") +core.register_alias("mesecons_gamecompat:lava_source", "hades_core:lava_source") +core.register_alias("mesecons_gamecompat:mese", "hades_core:mese") +core.register_alias("mesecons_gamecompat:mese_crystal", "hades_core:mese_crystal") +core.register_alias("mesecons_gamecompat:mese_crystal_fragment", "hades_core:mese_crystal_fragment") +core.register_alias("mesecons_gamecompat:obsidian_glass", "hades_core:obsidian_glass") +core.register_alias("mesecons_gamecompat:stone", "hades_core:stone") +core.register_alias("mesecons_gamecompat:steel_ingot", "hades_core:steel_ingot") +core.register_alias("mesecons_gamecompat:steelblock", "hades_core:steelblock") +core.register_alias("mesecons_gamecompat:torch", "hades_torches:torch") + +if core.get_modpath("hades_dye") then + for _, color in ipairs(mesecon.dye_colors) do + core.register_alias("mesecons_gamecompat:dye_" .. color, "hades_dye:" .. color) + end +end + +-- Sounds + +mesecon.node_sound.default = hades_sounds.node_sound_defaults() +mesecon.node_sound.glass = hades_sounds.node_sound_glass_defaults() +mesecon.node_sound.leaves = hades_sounds.node_sound_leaves_defaults() +mesecon.node_sound.stone = hades_sounds.node_sound_stone_defaults() +mesecon.node_sound.wood = hades_sounds.node_sound_wood_defaults() + +if core.get_modpath("hades_fire") then + mesecon.sound_name.fire = "fire_fire" +end + +if core.get_modpath("hades_tnt") then + mesecon.sound_name.explode = "tnt_explode" +end + +-- Textures + +mesecon.texture.steel_block = "default_steel_block.png" + +-- MVPS stoppers + +if core.get_modpath("mesecons_mvps") then + -- All of the locked and internal nodes in Hades Revisited + for _, name in ipairs({ + "hades_chests:chest_locked", + "hades_chests:chest_locked_open", + "hades_doors:hidden", + "hades_doors:hidden_center", + }) do + mesecon.register_mvps_stopper(name) + end + core.register_on_mods_loaded(function() + if core.get_modpath("hades_doors") then + for _,v in pairs(core.registered_nodes) do + if v.groups and (v.groups.door or v.groups.trapdoor) then + mesecon.register_mvps_stopper(v.name) + end + end + end + if core.get_modpath("hades_beds") then + for _,v in pairs(core.registered_nodes) do + if v.groups and v.groups.bed then + mesecon.register_mvps_stopper(v.name) + end + end + end + end) +end diff --git a/mods/mesecons/mesecons_gamecompat/compat_mcla.lua b/mods/mesecons/mesecons_gamecompat/compat_mcla.lua new file mode 100644 index 00000000..384dbc65 --- /dev/null +++ b/mods/mesecons/mesecons_gamecompat/compat_mcla.lua @@ -0,0 +1,88 @@ + +--Aliases + +minetest.register_alias("mesecons_gamecompat:chest", "mcl_chests:chest") +minetest.register_alias("mesecons_gamecompat:chest_locked", "mcl_chests:chest") +minetest.register_alias("mesecons_gamecompat:coalblock", "mcl_core:coalblock") +minetest.register_alias("mesecons_gamecompat:cobble", "mcl_core:cobble") +minetest.register_alias("mesecons_gamecompat:glass", "mcl_core:glass") +minetest.register_alias("mesecons_gamecompat:lava_source", "mcl_core:lava_source") +minetest.register_alias("mesecons_gamecompat:mese", "mcl_redstone_torch:redstoneblock") +minetest.register_alias("mesecons_gamecompat:mese_crystal", "mcl_redstone:redstone") +minetest.register_alias("mesecons_gamecompat:mese_crystal_fragment", "mcl_redstone:redstone") +minetest.register_alias("mesecons_gamecompat:obsidian_glass", "mcl_core:glass") +minetest.register_alias("mesecons_gamecompat:stone", "mcl_core:stone") +minetest.register_alias("mesecons_gamecompat:steel_ingot", "mcl_core:iron_ingot") +minetest.register_alias("mesecons_gamecompat:steelblock", "mcl_core:ironblock") +minetest.register_alias("mesecons_gamecompat:torch", "mcl_torches:torch") + +if minetest.get_modpath("mcl_dyes") then + for color, def in ipairs(mcl_dyes.colors) do + minetest.register_alias("mesecons_gamecompat:dye_" .. def.mcl2, "mcl_dyes:" .. color) + end +end + +-- Sounds + +mesecon.node_sound.default = mcl_sounds.node_sound_defaults() +mesecon.node_sound.glass = mcl_sounds.node_sound_glass_defaults() +mesecon.node_sound.leaves = mcl_sounds.node_sound_leaves_defaults() +mesecon.node_sound.stone = mcl_sounds.node_sound_stone_defaults() +mesecon.node_sound.wood = mcl_sounds.node_sound_wood_defaults() + +if minetest.get_modpath("mcl_fire") then + mesecon.sound_name.fire = "fire_fire" +end + +if minetest.get_modpath("mcl_tnt") then + mesecon.sound_name.explode = "tnt_explode" +end + +-- Textures + +mesecon.texture.steel_block = "default_steel_block.png" + +if minetest.get_modpath("mesecons_mvps") then + for k,v in pairs(core.registered_nodes) do + local is_stopper = mesecon.mvps_stoppers[k] + if v.groups and v.groups.unmovable_by_piston then + mesecon.register_mvps_stopper(k) + end + if is_stopper then + local groups = table.copy(v.groups or {}) + groups.unmovable_by_piston = 1 + v.groups = groups + core.register_node(":"..k, v) + end + end + for k,v in pairs(core.registered_entities) do + local is_unmov = mesecon.mvps_unmov[k] + if v._mcl_pistons_unmovable then + mesecon.register_mvps_unmov(k) + end + if is_unmov then + v._mcl_pistons_unmovable = true + core.register_entity(":"..k, v) + end + end + + core.register_on_mods_loaded(function() + for _,v in pairs(core.registered_nodes) do + if v.groups and v.groups.bed then + mesecon.register_mvps_stopper(v.name) + end + if v.groups and v.groups.door then + mesecon.register_mvps_stopper(v.name) + end + end + end) +end + +core.register_craft({ + output = "mesecons:wire_00000000_off", + recipe = {{"mcl_redstone:redstone"}} +}) +core.register_craft({ + output = "mcl_redstone:redstone", + recipe = {{"mesecons:wire_00000000_off"}} +}) diff --git a/mods/mesecons/mesecons_gamecompat/compat_mtg.lua b/mods/mesecons/mesecons_gamecompat/compat_mtg.lua new file mode 100644 index 00000000..15a0abe3 --- /dev/null +++ b/mods/mesecons/mesecons_gamecompat/compat_mtg.lua @@ -0,0 +1,73 @@ +--Aliases + +minetest.register_alias("mesecons_gamecompat:chest", "default:chest") +minetest.register_alias("mesecons_gamecompat:chest_locked", "default:chest_locked") +minetest.register_alias("mesecons_gamecompat:coalblock", "default:coalblock") +minetest.register_alias("mesecons_gamecompat:cobble", "default:cobble") +minetest.register_alias("mesecons_gamecompat:glass", "default:glass") +minetest.register_alias("mesecons_gamecompat:lava_source", "default:lava_source") +minetest.register_alias("mesecons_gamecompat:mese", "default:mese") +minetest.register_alias("mesecons_gamecompat:mese_crystal", "default:mese_crystal") +minetest.register_alias("mesecons_gamecompat:mese_crystal_fragment", "default:mese_crystal_fragment") +minetest.register_alias("mesecons_gamecompat:obsidian_glass", "default:obsidian_glass") +minetest.register_alias("mesecons_gamecompat:stone", "default:stone") +minetest.register_alias("mesecons_gamecompat:steel_ingot", "default:steel_ingot") +minetest.register_alias("mesecons_gamecompat:steelblock", "default:steelblock") +minetest.register_alias("mesecons_gamecompat:torch", "default:torch") + +if minetest.get_modpath("dye") then + for _, color in ipairs(mesecon.dye_colors) do + minetest.register_alias("mesecons_gamecompat:dye_" .. color, "dye:" .. color) + end +end + +-- Sounds + +mesecon.node_sound.default = default.node_sound_defaults() +mesecon.node_sound.glass = default.node_sound_glass_defaults() +mesecon.node_sound.leaves = default.node_sound_leaves_defaults() +mesecon.node_sound.stone = default.node_sound_stone_defaults() +mesecon.node_sound.wood = default.node_sound_wood_defaults() + +if minetest.get_modpath("fire") then + mesecon.sound_name.fire = "fire_fire" +end + +if minetest.get_modpath("tnt") then + mesecon.sound_name.explode = "tnt_explode" +end + +-- Textures + +mesecon.texture.steel_block = "default_steel_block.png" + +-- MVPS stoppers + +if minetest.get_modpath("mesecons_mvps") then + -- All of the locked and internal nodes in Minetest Game + for _, name in ipairs({ + "default:chest_locked", + "default:chest_locked_open", + "doors:hidden", + "doors:trapdoor_steel", + "doors:trapdoor_steel_open", + "xpanes:trapdoor_steel_bar", + "xpanes:trapdoor_steel_bar_open", + }) do + mesecon.register_mvps_stopper(name) + end + core.register_on_mods_loaded(function() + if minetest.get_modpath("doors") then + for k,_ in pairs(doors.registered_doors) do + mesecon.register_mvps_stopper(k) + end + end + if minetest.get_modpath("beds") then + for _,v in pairs(core.registered_nodes) do + if v.groups and v.groups.bed then + mesecon.register_mvps_stopper(v.name) + end + end + end + end) +end diff --git a/mods/mesecons/mesecons_gamecompat/doors.lua b/mods/mesecons/mesecons_gamecompat/doors.lua new file mode 100644 index 00000000..8b6b33cb --- /dev/null +++ b/mods/mesecons/mesecons_gamecompat/doors.lua @@ -0,0 +1,145 @@ +-- Modified, from minetest_game/mods/doors/init.lua +local function on_rightclick(pos, dir, check_name, replace, replace_dir, params) + pos.y = pos.y + dir + if minetest.get_node(pos).name ~= check_name then + return + end + local p2 = minetest.get_node(pos).param2 + p2 = params[p2 + 1] + + minetest.swap_node(pos, {name = replace_dir, param2 = p2}) + + pos.y = pos.y - dir + minetest.swap_node(pos, {name = replace, param2 = p2}) + + if (minetest.get_meta(pos):get_int("right") ~= 0) == (params[1] ~= 3) then + minetest.sound_play("doors_door_close", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true) + else + minetest.sound_play("doors_door_open", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true) + end +end + +local function meseconify_door(name) + if minetest.registered_items[name .. "_b_1"] then + -- old style double-node doors + if minetest.registered_items[name .. "_b_1"].mesecons then + minetest.log("info", "[mesecons_doors] Not touching door " .. name) + return + end + + local function toggle_state1 (pos) + on_rightclick(pos, 1, name.."_t_1", name.."_b_2", name.."_t_2", {1,2,3,0}) + end + + local function toggle_state2 (pos) + on_rightclick(pos, 1, name.."_t_2", name.."_b_1", name.."_t_1", {3,0,1,2}) + end + + minetest.override_item(name.."_b_1", { + mesecons = {effector = { + action_on = toggle_state1, + action_off = toggle_state1, + rules = mesecon.rules.pplate + }} + }) + + minetest.override_item(name.."_b_2", { + mesecons = {effector = { + action_on = toggle_state2, + action_off = toggle_state2, + rules = mesecon.rules.pplate + }} + }) + elseif minetest.registered_items[name .. "_a"] then + -- new style mesh node based doors + if minetest.registered_items[name .. "_a"].mesecons then + minetest.log("info", "[mesecons_doors] Not touching door " .. name) + return + end + local override = { + mesecons = {effector = { + action_on = function(pos) + local door = doors.get(pos) + if door then + door:open() + end + end, + action_off = function(pos) + local door = doors.get(pos) + if door then + door:close() + end + end, + rules = mesecon.rules.pplate + }} + } + minetest.override_item(name .. "_a", override) + minetest.override_item(name .. "_b", override) + if minetest.registered_items[name .. "_c"] then + minetest.override_item(name .. "_c", override) + minetest.override_item(name .. "_d", override) + end + end +end + +-- Trapdoor +local function trapdoor_switch(name) + return function(pos, node) + local state = minetest.get_meta(pos):get_int("state") + if state == 1 then + minetest.sound_play("doors_door_close", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true) + minetest.set_node(pos, {name=name, param2 = node.param2}) + else + minetest.sound_play("doors_door_open", { pos = pos, gain = 0.3, max_hear_distance = 10 }, true) + minetest.set_node(pos, {name=name.."_open", param2 = node.param2}) + end + minetest.get_meta(pos):set_int("state", state == 1 and 0 or 1) + end +end + +local function meseconify_trapdoor(name) + local override + if doors and doors.get then + override = { + mesecons = {effector = { + action_on = function(pos) + local door = doors.get(pos) + if door then + door:open() + end + end, + action_off = function(pos) + local door = doors.get(pos) + if door then + door:close() + end + end, + }}, + } + else + override = { + mesecons = {effector = { + action_on = trapdoor_switch(name), + action_off = trapdoor_switch(name) + }}, + } + end + + if minetest.registered_items[name] then + minetest.override_item(name, override) + minetest.override_item(name.."_open", override) + end +end + +minetest.register_on_mods_loaded(function() + for k,_ in pairs(doors.registered_doors) do + if k:find("_a$") then + meseconify_door(k:sub(1,-3)) + end + end + for k,_ in pairs(doors.registered_trapdoors) do + if not k:find("_open$") then + meseconify_trapdoor(k) + end + end +end) diff --git a/mods/mesecons/mesecons_gamecompat/init.lua b/mods/mesecons/mesecons_gamecompat/init.lua new file mode 100644 index 00000000..d657fc85 --- /dev/null +++ b/mods/mesecons/mesecons_gamecompat/init.lua @@ -0,0 +1,29 @@ +mesecon.node_sound = {} + +mesecon.sound_name = {} + +mesecon.texture = {} + +mesecon.dye_colors = { + "red", "green", "blue", "grey", "dark_grey", "yellow", + "orange", "white", "pink", "magenta", "cyan", "violet", +} + +if minetest.get_modpath("default") then + minetest.log("info", "Mesecons: detected Minetest Game for game compatibility") + dofile(minetest.get_modpath("mesecons_gamecompat").."/compat_mtg.lua") +end + +if minetest.get_modpath("mcl_redstone") then + minetest.log("info", "Mesecons: detected MineClonia Game for game compatibility") + dofile(minetest.get_modpath("mesecons_gamecompat").."/compat_mcla.lua") +end + +if minetest.get_modpath("hades_core") then + minetest.log("info", "Mesecons: detected Hades Revisited Game for game compatibility") + dofile(minetest.get_modpath("mesecons_gamecompat").."/compat_hades.lua") +end + +if minetest.get_modpath("doors") then + dofile(minetest.get_modpath("mesecons_gamecompat").."/doors.lua") +end diff --git a/mods/mesecons/mesecons_gamecompat/mod.conf b/mods/mesecons/mesecons_gamecompat/mod.conf new file mode 100644 index 00000000..e2ca69dd --- /dev/null +++ b/mods/mesecons/mesecons_gamecompat/mod.conf @@ -0,0 +1,3 @@ +name = mesecons_gamecompat +depends = mesecons +optional_depends = fire, default, dye, mesecons_mvps, tnt, doors, beds, mcl_fire, mcl_core, mcl_dye, mcl_tnt, hades_sounds diff --git a/mods/mesecons/mesecons_gates/doc/and/description.html b/mods/mesecons/mesecons_gates/doc/and/description.html new file mode 100644 index 00000000..e8aff919 --- /dev/null +++ b/mods/mesecons/mesecons_gates/doc/and/description.html @@ -0,0 +1,2 @@ +AND gates power their output if both inputs (from left and right) are powered. +They work in unloaded blocks. diff --git a/mods/mesecons/mesecons_gates/doc/and/preview.png b/mods/mesecons/mesecons_gates/doc/and/preview.png new file mode 100644 index 00000000..d3b29365 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/and/preview.png differ diff --git a/mods/mesecons/mesecons_gates/doc/and/recipe.png b/mods/mesecons/mesecons_gates/doc/and/recipe.png new file mode 100644 index 00000000..b81680a1 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/and/recipe.png differ diff --git a/mods/mesecons/mesecons_gates/doc/diode/description.html b/mods/mesecons/mesecons_gates/doc/diode/description.html new file mode 100644 index 00000000..b96aced5 --- /dev/null +++ b/mods/mesecons/mesecons_gates/doc/diode/description.html @@ -0,0 +1,2 @@ +Diodes conduct signals in one direction only. +They work in unloaded blocks. diff --git a/mods/mesecons/mesecons_gates/doc/diode/preview.png b/mods/mesecons/mesecons_gates/doc/diode/preview.png new file mode 100644 index 00000000..dc961d90 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/diode/preview.png differ diff --git a/mods/mesecons/mesecons_gates/doc/diode/recipe.png b/mods/mesecons/mesecons_gates/doc/diode/recipe.png new file mode 100644 index 00000000..bce3562d Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/diode/recipe.png differ diff --git a/mods/mesecons/mesecons_gates/doc/nand/description.html b/mods/mesecons/mesecons_gates/doc/nand/description.html new file mode 100644 index 00000000..c46a7e1a --- /dev/null +++ b/mods/mesecons/mesecons_gates/doc/nand/description.html @@ -0,0 +1,2 @@ +NAND gates do not power their output if both inputs (from left and right) are powered, but power it in every other case. +They work in unloaded blocks. diff --git a/mods/mesecons/mesecons_gates/doc/nand/preview.png b/mods/mesecons/mesecons_gates/doc/nand/preview.png new file mode 100644 index 00000000..364d6c37 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/nand/preview.png differ diff --git a/mods/mesecons/mesecons_gates/doc/nand/recipe.png b/mods/mesecons/mesecons_gates/doc/nand/recipe.png new file mode 100644 index 00000000..a1ee6189 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/nand/recipe.png differ diff --git a/mods/mesecons/mesecons_gates/doc/nor/description.html b/mods/mesecons/mesecons_gates/doc/nor/description.html new file mode 100644 index 00000000..7d539536 --- /dev/null +++ b/mods/mesecons/mesecons_gates/doc/nor/description.html @@ -0,0 +1,2 @@ +NOR gates only power their output if none of their two inputs is powered. They are basically OR gates with a NOT gate at their output. +They work in unloaded blocks. diff --git a/mods/mesecons/mesecons_gates/doc/nor/preview.png b/mods/mesecons/mesecons_gates/doc/nor/preview.png new file mode 100644 index 00000000..d733fd7d Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/nor/preview.png differ diff --git a/mods/mesecons/mesecons_gates/doc/nor/recipe.png b/mods/mesecons/mesecons_gates/doc/nor/recipe.png new file mode 100644 index 00000000..a801d8ff Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/nor/recipe.png differ diff --git a/mods/mesecons/mesecons_gates/doc/not/description.html b/mods/mesecons/mesecons_gates/doc/not/description.html new file mode 100644 index 00000000..5a08423e --- /dev/null +++ b/mods/mesecons/mesecons_gates/doc/not/description.html @@ -0,0 +1,2 @@ +NOT gates invert signals, just like a mesecon torch does, but faster. The input is at the opposite side of the output. +They work in unloaded blocks. diff --git a/mods/mesecons/mesecons_gates/doc/not/preview.png b/mods/mesecons/mesecons_gates/doc/not/preview.png new file mode 100644 index 00000000..3680c155 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/not/preview.png differ diff --git a/mods/mesecons/mesecons_gates/doc/not/recipe.png b/mods/mesecons/mesecons_gates/doc/not/recipe.png new file mode 100644 index 00000000..b5ec6a87 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/not/recipe.png differ diff --git a/mods/mesecons/mesecons_gates/doc/or/description.html b/mods/mesecons/mesecons_gates/doc/or/description.html new file mode 100644 index 00000000..15d598f7 --- /dev/null +++ b/mods/mesecons/mesecons_gates/doc/or/description.html @@ -0,0 +1,2 @@ +OR gates power their output if either of their inputs (or both) are powered. You could basically get the same behaviour with two diodes, but OR gates save some space. +They work in unloaded blocks. diff --git a/mods/mesecons/mesecons_gates/doc/or/preview.png b/mods/mesecons/mesecons_gates/doc/or/preview.png new file mode 100644 index 00000000..0c46aa1e Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/or/preview.png differ diff --git a/mods/mesecons/mesecons_gates/doc/or/recipe.png b/mods/mesecons/mesecons_gates/doc/or/recipe.png new file mode 100644 index 00000000..58a12564 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/or/recipe.png differ diff --git a/mods/mesecons/mesecons_gates/doc/xor/description.html b/mods/mesecons/mesecons_gates/doc/xor/description.html new file mode 100644 index 00000000..74f8b5fd --- /dev/null +++ b/mods/mesecons/mesecons_gates/doc/xor/description.html @@ -0,0 +1,2 @@ +XOR gates power their output if only one input is powered, they're off if either both or none of the inputs is powered. +They work in unloaded blocks. diff --git a/mods/mesecons/mesecons_gates/doc/xor/preview.png b/mods/mesecons/mesecons_gates/doc/xor/preview.png new file mode 100644 index 00000000..0bc24c6c Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/xor/preview.png differ diff --git a/mods/mesecons/mesecons_gates/doc/xor/recipe.png b/mods/mesecons/mesecons_gates/doc/xor/recipe.png new file mode 100644 index 00000000..f7108993 Binary files /dev/null and b/mods/mesecons/mesecons_gates/doc/xor/recipe.png differ diff --git a/mods/mesecons/mesecons_gates/init.lua b/mods/mesecons/mesecons_gates/init.lua new file mode 100644 index 00000000..23208fa2 --- /dev/null +++ b/mods/mesecons/mesecons_gates/init.lua @@ -0,0 +1,185 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 } +} + +local nodebox = { + type = "fixed", + fixed = { + { -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab + { -6/16, -7/16, -6/16, 6/16, -6/16, 6/16 } + }, +} + +local gate_get_output_rules = mesecon.horiz_rules_getter({{x = 1, y = 0, z = 0}}) + +local gate_get_input_rules_oneinput = mesecon.horiz_rules_getter({{x =-1, y = 0, z = 0}}) + +local gate_get_input_rules_twoinputs = mesecon.horiz_rules_getter({ + {x = 0, y = 0, z = 1, name = "input1"}, + {x = 0, y = 0, z = -1, name = "input2"}, +}) + +local function set_gate(pos, node, state) + local gate = minetest.registered_nodes[node.name] + + local new_nodename = state and gate.onstate or gate.offstate + minetest.swap_node(pos, {name = new_nodename, param2 = node.param2}) + if new_nodename ~= node.name then + if mesecon.do_overheat(pos) then + minetest.remove_node(pos) + mesecon.receptor_off(pos, gate_get_output_rules(node)) + minetest.add_item(pos, gate.drop) + elseif state then + mesecon.receptor_on(pos, gate_get_output_rules(node)) + else + mesecon.receptor_off(pos, gate_get_output_rules(node)) + end + end +end + +local function update_gate(pos, node, link, newstate) + local gate = minetest.registered_nodes[node.name] + + if gate.inputnumber == 1 then + set_gate(pos, node, gate.assess(newstate == "on")) + elseif gate.inputnumber == 2 then + -- Inputs are stored in param2. Bit 5 is always set. + -- input1 is bit 6 and input2 is bit 7. + local val1, val2 + if node.param2 >= 32 then + -- Bit 5 is set, so param2 is in the proper format. + if link.name == "input1" then + val1 = newstate == "on" + val2 = node.param2 >= 128 + else + val1 = node.param2 % 128 >= 64 + val2 = newstate == "on" + end + else + -- Migrate old gates where the inputs are stored as metadata. + -- This also triggers for newly placed gates. + local meta = minetest.get_meta(pos) + if link.name == "input1" then + val1 = newstate == "on" + val2 = meta:get_int("input2") == 1 + else + val1 = meta:get_int("input1") == 1 + val2 = newstate == "on" + end + -- Set bit 5 so this won't happen again. + node.param2 = node.param2 + 32 + -- Clear the metadata. + meta:set_string("input1", "") + meta:set_string("input2", "") + end + node.param2 = node.param2 % 64 + (val1 and 64 or 0) + (val2 and 128 or 0) + set_gate(pos, node, gate.assess(val1, val2)) + end +end + +local function register_gate(name, inputnumber, assess, recipe, description) + local get_inputrules = inputnumber == 2 and gate_get_input_rules_twoinputs or + gate_get_input_rules_oneinput + + local basename = "mesecons_gates:"..name + mesecon.register_node(basename, { + description = description, + inventory_image = "jeija_gate_off.png^jeija_gate_"..name..".png", + paramtype = "light", + paramtype2 = "4dir", + is_ground_content = false, + drawtype = "nodebox", + drop = basename.."_off", + selection_box = selection_box, + node_box = nodebox, + walkable = true, + sounds = mesecon.node_sound.stone, + assess = assess, + onstate = basename.."_on", + offstate = basename.."_off", + inputnumber = inputnumber, + after_dig_node = mesecon.do_cooldown, + on_rotate = mesecon.on_rotate, + },{ + tiles = { + "jeija_microcontroller_bottom.png^".."jeija_gate_off.png^".. + "jeija_gate_output_off.png^".."jeija_gate_"..name..".png", + "jeija_microcontroller_bottom.png^".."jeija_gate_output_off.png^".. + "[transformFY", + "jeija_gate_side.png^".."jeija_gate_side_output_off.png", + "jeija_gate_side.png", + "jeija_gate_side.png", + "jeija_gate_side.png" + }, + groups = {dig_immediate = 2, overheat = 1}, + mesecons = { receptor = { + state = "off", + rules = gate_get_output_rules + }, effector = { + rules = get_inputrules, + action_change = update_gate + }} + },{ + tiles = { + "jeija_microcontroller_bottom.png^".."jeija_gate_on.png^".. + "jeija_gate_output_on.png^".."jeija_gate_"..name..".png", + "jeija_microcontroller_bottom.png^".."jeija_gate_output_on.png^".. + "[transformFY", + "jeija_gate_side.png^".."jeija_gate_side_output_on.png", + "jeija_gate_side.png", + "jeija_gate_side.png", + "jeija_gate_side.png" + }, + groups = {dig_immediate = 2, not_in_creative_inventory = 1, overheat = 1}, + mesecons = { receptor = { + state = "on", + rules = gate_get_output_rules + }, effector = { + rules = get_inputrules, + action_change = update_gate + }} + }) + + minetest.register_craft({output = basename.."_off", recipe = recipe}) +end + +register_gate("diode", 1, function (input) return input end, + {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons_torch:mesecon_torch_on"}}, + S("Diode")) + +register_gate("not", 1, function (input) return not input end, + {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons:mesecon"}}, + S("NOT Gate")) + +register_gate("and", 2, function (val1, val2) return val1 and val2 end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons:mesecon"}, + {"mesecons:mesecon", "", ""}}, + S("AND Gate")) + +register_gate("nand", 2, function (val1, val2) return not (val1 and val2) end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons_torch:mesecon_torch_on"}, + {"mesecons:mesecon", "", ""}}, + S("NAND Gate")) + +register_gate("xor", 2, function (val1, val2) return (val1 or val2) and not (val1 and val2) end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons_materials:silicon", "mesecons_materials:silicon"}, + {"mesecons:mesecon", "", ""}}, + S("XOR Gate")) + +register_gate("nor", 2, function (val1, val2) return not (val1 or val2) end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons:mesecon", "mesecons_torch:mesecon_torch_on"}, + {"mesecons:mesecon", "", ""}}, + S("NOR Gate")) + +register_gate("or", 2, function (val1, val2) return (val1 or val2) end, + {{"mesecons:mesecon", "", ""}, + {"", "mesecons:mesecon", "mesecons:mesecon"}, + {"mesecons:mesecon", "", ""}}, + S("OR Gate")) diff --git a/mods/mesecons/mesecons_gates/locale/mesecons_gates.ru.tr b/mods/mesecons/mesecons_gates/locale/mesecons_gates.ru.tr new file mode 100644 index 00000000..a2187828 --- /dev/null +++ b/mods/mesecons/mesecons_gates/locale/mesecons_gates.ru.tr @@ -0,0 +1,8 @@ +# textdomain: mesecons_gates +Diode=Диод +NOT Gate=НЕ-шлюз +AND Gate=И-шлюз +NAND Gate=NAND-шлюз +XOR Gate=XOR-шлюз +NOR Gate=NOR-шлюз +OR Gate=ИЛИ-шлюз diff --git a/mods/mesecons/mesecons_gates/locale/mesecons_gates.uk.tr b/mods/mesecons/mesecons_gates/locale/mesecons_gates.uk.tr new file mode 100644 index 00000000..46b16821 --- /dev/null +++ b/mods/mesecons/mesecons_gates/locale/mesecons_gates.uk.tr @@ -0,0 +1,8 @@ +# textdomain: mesecons_gates +Diode=Діод +NOT Gate=NOT перехідник +AND Gate=AND перехідник +NAND Gate=NAND перехідник +XOR Gate=XOR перехідник +NOR Gate=NOR перехідник +OR Gate=OR перехідник diff --git a/mods/mesecons/mesecons_gates/locale/template.txt b/mods/mesecons/mesecons_gates/locale/template.txt new file mode 100644 index 00000000..899b1390 --- /dev/null +++ b/mods/mesecons/mesecons_gates/locale/template.txt @@ -0,0 +1,8 @@ +# textdomain: mesecons_gates +Diode= +NOT Gate= +AND Gate= +NAND Gate= +XOR Gate= +NOR Gate= +OR Gate= diff --git a/mods/mesecons/mesecons_gates/mod.conf b/mods/mesecons/mesecons_gates/mod.conf new file mode 100644 index 00000000..f89c8842 --- /dev/null +++ b/mods/mesecons/mesecons_gates/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_gates +depends = mesecons, mesecons_gamecompat, mesecons_microcontroller, mesecons_delayer, mesecons_torch, mesecons_materials diff --git a/mods/mesecons/mesecons_gates/textures/jeija_gate_and.png b/mods/mesecons/mesecons_gates/textures/jeija_gate_and.png new file mode 100644 index 00000000..825a22be Binary files /dev/null and b/mods/mesecons/mesecons_gates/textures/jeija_gate_and.png differ diff --git a/mods/mesecons/mesecons_gates/textures/jeija_gate_diode.png b/mods/mesecons/mesecons_gates/textures/jeija_gate_diode.png new file mode 100644 index 00000000..49c2076a Binary files /dev/null and b/mods/mesecons/mesecons_gates/textures/jeija_gate_diode.png differ diff --git a/mods/mesecons/mesecons_gates/textures/jeija_gate_nand.png b/mods/mesecons/mesecons_gates/textures/jeija_gate_nand.png new file mode 100644 index 00000000..f14567bc Binary files /dev/null and b/mods/mesecons/mesecons_gates/textures/jeija_gate_nand.png differ diff --git a/mods/mesecons/mesecons_gates/textures/jeija_gate_nor.png b/mods/mesecons/mesecons_gates/textures/jeija_gate_nor.png new file mode 100644 index 00000000..c4218bc1 Binary files /dev/null and b/mods/mesecons/mesecons_gates/textures/jeija_gate_nor.png differ diff --git a/mods/mesecons/mesecons_gates/textures/jeija_gate_not.png b/mods/mesecons/mesecons_gates/textures/jeija_gate_not.png new file mode 100644 index 00000000..27b7281a Binary files /dev/null and b/mods/mesecons/mesecons_gates/textures/jeija_gate_not.png differ diff --git a/mods/mesecons/mesecons_gates/textures/jeija_gate_or.png b/mods/mesecons/mesecons_gates/textures/jeija_gate_or.png new file mode 100644 index 00000000..3180add9 Binary files /dev/null and b/mods/mesecons/mesecons_gates/textures/jeija_gate_or.png differ diff --git a/mods/mesecons/mesecons_gates/textures/jeija_gate_xor.png b/mods/mesecons/mesecons_gates/textures/jeija_gate_xor.png new file mode 100644 index 00000000..df13e969 Binary files /dev/null and b/mods/mesecons/mesecons_gates/textures/jeija_gate_xor.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/description.html b/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/description.html new file mode 100644 index 00000000..6153d515 --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/description.html @@ -0,0 +1,2 @@ +Water turbines are receptors that turn on if flowing water is above them. +They only work in active blocks; in inactive blocks they keep their old state. diff --git a/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/preview.png b/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/preview.png new file mode 100644 index 00000000..b45ca238 Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/preview.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/recipe.png b/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/recipe.png new file mode 100644 index 00000000..8c8141ee Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/doc/waterturbine/recipe.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/init.lua b/mods/mesecons/mesecons_hydroturbine/init.lua new file mode 100644 index 00000000..6d0038cc --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/init.lua @@ -0,0 +1,106 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- HYDRO_TURBINE +-- Water turbine: +-- Active if flowing >water< above it +-- (does not work with other liquids) + +minetest.register_node("mesecons_hydroturbine:hydro_turbine_off", { + drawtype = "mesh", + mesh = "jeija_hydro_turbine_off.obj", + tiles = { + "jeija_hydro_turbine_sides_off.png", + "jeija_hydro_turbine_top_bottom.png", + "jeija_hydro_turbine_turbine_top_bottom_off.png", + "jeija_hydro_turbine_turbine_misc_off.png" + }, + use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or nil, + inventory_image = "jeija_hydro_turbine_inv.png", + is_ground_content = false, + wield_scale = {x=0.75, y=0.75, z=0.75}, + groups = {dig_immediate=2}, + description = S("Water Turbine"), + paramtype = "light", + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }, + }, + sounds = mesecon.node_sound.metal, + mesecons = {receptor = { + state = mesecon.state.off + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_hydroturbine:hydro_turbine_on", { + drawtype = "mesh", + is_ground_content = false, + mesh = "jeija_hydro_turbine_on.obj", + wield_scale = {x=0.75, y=0.75, z=0.75}, + tiles = { + "jeija_hydro_turbine_sides_on.png", + "jeija_hydro_turbine_top_bottom.png", + { name = "jeija_hydro_turbine_turbine_top_bottom_on.png", + animation = {type = "vertical_frames", aspect_w = 128, aspect_h = 16, length = 1.6} }, + { name = "jeija_hydro_turbine_turbine_misc_on.png", + animation = {type = "vertical_frames", aspect_w = 256, aspect_h = 32, length = 0.4} } + }, + use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or nil, + inventory_image = "jeija_hydro_turbine_inv.png", + drop = "mesecons_hydroturbine:hydro_turbine_off 1", + groups = {dig_immediate=2,not_in_creative_inventory=1}, + description = S("Water Turbine"), + paramtype = "light", + selection_box = { + type = "fixed", + fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }, + }, + sounds = mesecon.node_sound.metal, + mesecons = {receptor = { + state = mesecon.state.on + }}, + on_blast = mesecon.on_blastnode, +}) + + +local function is_flowing_water(pos) + local name = minetest.get_node(pos).name + local is_water = minetest.get_item_group(name, "water") > 0 + local def = minetest.registered_items[name] + return is_water and (def and def.liquidtype == "flowing") +end + +minetest.register_abm({ +nodenames = {"mesecons_hydroturbine:hydro_turbine_off"}, + interval = 1, + chance = 1, + action = function(pos) + local waterpos={x=pos.x, y=pos.y+1, z=pos.z} + if is_flowing_water(waterpos) then + minetest.set_node(pos, {name="mesecons_hydroturbine:hydro_turbine_on"}) + mesecon.receptor_on(pos) + end + end, +}) + +minetest.register_abm({ +nodenames = {"mesecons_hydroturbine:hydro_turbine_on"}, + interval = 1, + chance = 1, + action = function(pos) + local waterpos={x=pos.x, y=pos.y+1, z=pos.z} + if not is_flowing_water(waterpos) then + minetest.set_node(pos, {name="mesecons_hydroturbine:hydro_turbine_off"}) + mesecon.receptor_off(pos) + end + end, +}) + +minetest.register_craft({ + output = "mesecons_hydroturbine:hydro_turbine_off 2", + recipe = { + {"","group:stick", ""}, + {"group:stick", "mesecons_gamecompat:steel_ingot", "group:stick"}, + {"","group:stick", ""}, + } +}) diff --git a/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.de.tr b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.de.tr new file mode 100644 index 00000000..6c5d8f96 --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_hydroturbine +Water Turbine=Wasserturbine diff --git a/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.eo.tr b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.eo.tr new file mode 100644 index 00000000..7ca3172c --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_hydroturbine + +### init.lua ### +Water Turbine=Akva Turbino diff --git a/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.fr.tr b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.fr.tr new file mode 100644 index 00000000..14e1267b --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_hydroturbine + +### init.lua ### +Water Turbine=Détecteur de courant diff --git a/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.ru.tr b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.ru.tr new file mode 100644 index 00000000..40558347 --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_hydroturbine + +### init.lua ### +Water Turbine=Гидротурбина diff --git a/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.uk.tr b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.uk.tr new file mode 100644 index 00000000..00cde3ef --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/locale/mesecons_hydroturbine.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_hydroturbine + +### init.lua ### +Water Turbine=Гідротурбіна diff --git a/mods/mesecons/mesecons_hydroturbine/locale/template.txt b/mods/mesecons/mesecons_hydroturbine/locale/template.txt new file mode 100644 index 00000000..ebf89211 --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_hydroturbine + +### init.lua ### +Water Turbine= diff --git a/mods/mesecons/mesecons_hydroturbine/mod.conf b/mods/mesecons/mesecons_hydroturbine/mod.conf new file mode 100644 index 00000000..98a3090b --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_hydroturbine +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_hydroturbine/models/jeija_hydro_turbine_off.obj b/mods/mesecons/mesecons_hydroturbine/models/jeija_hydro_turbine_off.obj new file mode 100644 index 00000000..5cd5c969 --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/models/jeija_hydro_turbine_off.obj @@ -0,0 +1,429 @@ +# Blender v2.72 (sub 0) OBJ File: 'mesecons-water-turbine.blend' +# www.blender.org +o Cylinder.002_Cylinder.003 +v 0.000000 0.496094 -0.150000 +v 0.000000 0.562500 -0.150000 +v 0.106066 0.496094 -0.106066 +v 0.106066 0.562500 -0.106066 +v 0.150000 0.496094 0.000000 +v 0.150000 0.562500 0.000000 +v 0.106066 0.496094 0.106066 +v 0.106066 0.562500 0.106066 +v -0.000000 0.496094 0.150000 +v -0.000000 0.562500 0.150000 +v -0.106066 0.496094 0.106066 +v -0.106066 0.562500 0.106066 +v -0.150000 0.496094 -0.000000 +v -0.150000 0.562500 -0.000000 +v -0.106066 0.496094 -0.106066 +v -0.106066 0.562500 -0.106066 +v 0.097545 0.625000 -0.490393 +v -0.097545 0.625000 -0.490393 +v -0.277785 0.625000 -0.415735 +v -0.415735 0.625000 -0.277785 +v -0.490393 0.625000 -0.097545 +v -0.490393 0.625000 0.097545 +v -0.415735 0.625000 0.277785 +v -0.277785 0.625000 0.415735 +v -0.097545 0.625000 0.490393 +v 0.097545 0.625000 0.490393 +v 0.277785 0.625000 0.415735 +v 0.415735 0.625000 0.277785 +v 0.490393 0.625000 0.097545 +v 0.490393 0.625000 -0.097545 +v 0.415735 0.625000 -0.277785 +v 0.277785 0.625000 -0.415735 +v 0.097545 0.656250 -0.490393 +v -0.097545 0.656250 -0.490393 +v -0.277785 0.656250 -0.415735 +v -0.415735 0.656250 -0.277785 +v -0.490393 0.656250 -0.097545 +v -0.490393 0.656250 0.097545 +v -0.415735 0.656250 0.277785 +v -0.277785 0.656250 0.415735 +v -0.097545 0.656250 0.490393 +v 0.097545 0.656250 0.490393 +v 0.277785 0.656250 0.415735 +v 0.415735 0.656250 0.277785 +v 0.490393 0.656250 0.097545 +v 0.490393 0.656250 -0.097545 +v 0.415735 0.656250 -0.277785 +v 0.277785 0.656250 -0.415735 +v 0.116233 0.634645 -0.436100 +v 0.116233 1.482640 -0.436100 +v 0.299524 0.634645 -0.186124 +v 0.299524 1.482640 -0.186124 +v 0.343405 0.634645 0.080186 +v 0.343405 1.482640 0.080186 +v 0.186124 0.634645 0.299524 +v 0.186124 1.482640 0.299524 +v -0.080186 0.634645 0.343405 +v -0.080186 1.482640 0.343405 +v -0.299524 0.634645 0.186124 +v -0.299524 1.482640 0.186124 +v -0.343405 0.634645 -0.080186 +v -0.343405 1.482640 -0.080186 +v -0.186124 0.634645 -0.299524 +v -0.186124 1.482640 -0.299524 +v 0.080186 0.634645 -0.343405 +v 0.080186 1.482640 -0.343405 +v 0.390559 1.482640 -0.226180 +v 0.390559 0.634645 -0.226180 +v 0.436100 1.482640 0.116233 +v 0.436100 0.634645 0.116233 +v 0.226180 1.482640 0.390559 +v 0.226180 0.634645 0.390559 +v -0.116233 1.482640 0.436100 +v -0.116233 0.634645 0.436100 +v -0.390559 1.482640 0.226180 +v -0.390559 0.634645 0.226180 +v -0.436100 1.482640 -0.116233 +v -0.436100 0.634645 -0.116233 +v -0.226180 1.482640 -0.390559 +v -0.226180 0.634645 -0.390559 +v 0.108975 0.634645 -0.430778 +v 0.292266 0.634645 -0.180802 +v 0.292266 1.482640 -0.180802 +v 0.108975 1.482640 -0.430778 +v 0.381664 0.634645 -0.227549 +v 0.334509 0.634645 0.078817 +v 0.334509 1.482640 0.078817 +v 0.381664 1.482640 -0.227549 +v 0.430778 0.634645 0.108975 +v 0.180802 0.634645 0.292266 +v 0.180802 1.482640 0.292266 +v 0.430778 1.482640 0.108975 +v 0.227549 0.634645 0.381664 +v -0.078817 0.634645 0.334509 +v -0.078817 1.482640 0.334509 +v 0.227549 1.482640 0.381664 +v -0.108975 0.634645 0.430778 +v -0.292266 0.634645 0.180802 +v -0.292266 1.482640 0.180802 +v -0.108975 1.482640 0.430778 +v -0.381664 0.634645 0.227549 +v -0.334509 0.634645 -0.078817 +v -0.334509 1.482640 -0.078817 +v -0.381664 1.482640 0.227549 +v -0.227549 0.634645 -0.381663 +v 0.078817 0.634645 -0.334509 +v 0.078817 1.482640 -0.334509 +v -0.227549 1.482640 -0.381663 +v -0.430779 0.634645 -0.108975 +v -0.180802 0.634645 -0.292266 +v -0.180802 1.482640 -0.292266 +v -0.430779 1.482640 -0.108975 +v 0.097545 1.496094 -0.490393 +v -0.097545 1.496094 -0.490393 +v -0.277785 1.496094 -0.415735 +v -0.415735 1.496094 -0.277785 +v -0.490393 1.496094 -0.097545 +v -0.490393 1.496094 0.097545 +v -0.415735 1.496094 0.277785 +v -0.277785 1.496094 0.415735 +v -0.097545 1.496094 0.490393 +v 0.097545 1.496094 0.490393 +v 0.277785 1.496094 0.415735 +v 0.415735 1.496094 0.277785 +v 0.490393 1.496094 0.097545 +v 0.490393 1.496094 -0.097545 +v 0.415735 1.496094 -0.277785 +v 0.277785 1.496094 -0.415735 +v 0.097545 1.464844 -0.490393 +v -0.097545 1.464844 -0.490393 +v -0.277785 1.464844 -0.415735 +v -0.415735 1.464844 -0.277785 +v -0.490393 1.464844 -0.097545 +v -0.490393 1.464844 0.097545 +v -0.415735 1.464844 0.277785 +v -0.277785 1.464844 0.415735 +v -0.097545 1.464844 0.490393 +v 0.097545 1.464844 0.490393 +v 0.277785 1.464844 0.415735 +v 0.415735 1.464844 0.277785 +v 0.490393 1.464844 0.097545 +v 0.490393 1.464844 -0.097545 +v 0.415735 1.464844 -0.277785 +v 0.277785 1.464844 -0.415735 +v 0.025624 0.559630 -0.061863 +v 0.025624 1.481372 -0.061863 +v 0.061863 0.559630 -0.025624 +v 0.061863 1.481372 -0.025624 +v 0.061863 0.559630 0.025624 +v 0.061863 1.481372 0.025624 +v 0.025624 0.559630 0.061863 +v 0.025624 1.481372 0.061863 +v -0.025624 0.559630 0.061863 +v -0.025624 1.481372 0.061863 +v -0.061863 0.559630 0.025624 +v -0.061863 1.481372 0.025624 +v -0.061863 0.559630 -0.025624 +v -0.061863 1.481372 -0.025624 +v -0.025624 0.559630 -0.061863 +v -0.025624 1.481372 -0.061863 +v 0.496094 -0.496094 -0.496094 +v 0.496094 -0.496094 0.496094 +v -0.496094 -0.496094 0.496094 +v -0.496094 -0.496094 -0.496094 +v 0.496094 0.496094 -0.496094 +v 0.496094 0.496094 0.496094 +v -0.496094 0.496094 0.496094 +v -0.496094 0.496094 -0.496094 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 0.400544 1.000000 +vt 0.599456 1.000000 +vt 0.783227 0.923880 +vt 0.923880 0.783227 +vt 1.000000 0.599456 +vt 1.000000 0.400544 +vt 0.923880 0.216773 +vt 0.783227 0.076120 +vt 0.599456 0.000000 +vt 0.400544 0.000000 +vt 0.216773 0.076121 +vt 0.076120 0.216773 +vt 0.000000 0.400544 +vt 0.000000 0.599456 +vt 0.076121 0.783227 +vt 0.216773 0.923880 +vt 0.500000 0.343750 +vt 0.531250 0.343750 +vt 0.531250 0.375000 +vt 0.500000 0.375000 +vt 0.531250 0.406250 +vt 0.500000 0.406250 +vt 0.500000 0.531250 +vt 0.531250 0.531250 +vt 0.531250 0.500000 +vt 0.500000 0.500000 +vt 0.531250 0.468750 +vt 0.500000 0.468750 +vt 0.531250 0.437500 +vt 0.500000 0.437500 +vt 0.593750 0.468750 +vt 0.625000 0.437500 +vt 0.656250 0.437500 +vt 0.687500 0.468750 +vt 0.687500 0.500000 +vt 0.656250 0.531250 +vt 0.625000 0.531250 +vt 0.593750 0.500000 +vt 0.500000 0.312500 +vt 0.531250 0.312500 +vt 0.500000 0.281250 +vt 0.531250 0.281250 +vt 0.156250 0.750000 +vt 0.156250 0.875000 +vt 0.125000 0.875000 +vt 0.125000 0.750000 +vt 0.156250 0.625000 +vt 0.125000 0.625000 +vt 0.156250 0.500000 +vt 0.125000 0.500000 +vt 0.156250 0.375000 +vt 0.125000 0.375000 +vt 0.156250 0.250000 +vt 0.125000 0.250000 +vt 0.250000 0.500000 +vt 0.250000 0.625000 +vt 0.218750 0.625000 +vt 0.218750 0.500000 +vt 0.156250 0.125000 +vt 0.125000 0.125000 +vt 0.156250 -0.000000 +vt 0.125000 -0.000000 +vt 0.250000 0.375000 +vt 0.218750 0.375000 +vt 0.250000 0.875000 +vt 0.250000 1.000000 +vt 0.218750 1.000000 +vt 0.218750 0.875000 +vt 0.250000 0.250000 +vt 0.218750 0.250000 +vt 0.250000 0.750000 +vt 0.218750 0.750000 +vt 0.250000 0.125000 +vt 0.218750 0.125000 +vt 0.250000 -0.000000 +vt 0.218750 -0.000000 +vt 0.156250 1.000000 +vt 0.125000 1.000000 +vt 0.781250 0.593750 +vt 0.781250 0.968750 +vt 0.656250 0.968750 +vt 0.656250 0.593750 +vt 0.625000 0.593750 +vt 0.625000 0.968750 +vt 0.500000 0.968750 +vt 0.500000 0.593750 +vt 0.406250 -0.000000 +vt 0.437500 -0.000000 +vt 0.437500 0.125000 +vt 0.406250 0.125000 +vt 0.312500 0.875000 +vt 0.343750 0.875000 +vt 0.343750 1.000000 +vt 0.312500 1.000000 +vt 0.312500 0.750000 +vt 0.343750 0.750000 +vt 0.312500 0.625000 +vt 0.343750 0.625000 +vt 0.312500 0.500000 +vt 0.343750 0.500000 +vt 0.406250 0.750000 +vt 0.437500 0.750000 +vt 0.437500 0.875000 +vt 0.406250 0.875000 +vt 0.312500 0.375000 +vt 0.343750 0.375000 +vt 0.312500 0.250000 +vt 0.343750 0.250000 +vt 0.406250 0.625000 +vt 0.437500 0.625000 +vt 0.312500 0.125000 +vt 0.343750 0.125000 +vt 0.406250 0.500000 +vt 0.437500 0.500000 +vt 0.312500 -0.000000 +vt 0.343750 -0.000000 +vt 0.406250 0.375000 +vt 0.437500 0.375000 +vt 0.437500 1.000000 +vt 0.406250 1.000000 +vt 0.406250 0.250000 +vt 0.437500 0.250000 +vt 0.031250 0.937500 +vt 0.062500 0.937500 +vt 0.062500 0.968750 +vt 0.031250 0.968750 +vt 0.031250 0.718750 +vt 0.062500 0.718750 +vt 0.062500 0.750000 +vt 0.031250 0.750000 +vt 0.062500 0.781250 +vt 0.031250 0.781250 +vt 0.062500 0.812500 +vt 0.031250 0.812500 +vt 0.062500 0.843750 +vt 0.031250 0.843750 +vt 0.062500 0.875000 +vt 0.031250 0.875000 +vt 0.031250 0.906250 +vt 0.062500 0.906250 +vn 1.000000 0.000000 0.000000 +vn 0.000000 0.000000 1.000000 +vn -1.000000 0.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.382700 0.000000 -0.923900 +vn 0.923900 0.000000 -0.382700 +vn 0.923900 0.000000 0.382700 +vn 0.382700 0.000000 0.923900 +vn -0.382700 0.000000 0.923900 +vn -0.923900 0.000000 0.382700 +vn -0.382700 0.000000 -0.923900 +vn -0.923900 0.000000 -0.382700 +vn 0.707100 0.000000 0.707100 +vn -0.707100 0.000000 0.707100 +vn 0.707100 0.000000 -0.707100 +vn -0.707100 0.000000 -0.707100 +vn 0.806400 0.000000 -0.591300 +vn 0.988400 0.000000 0.152100 +vn 0.591300 0.000000 0.806400 +vn -0.152100 0.000000 0.988400 +vn -0.806400 0.000000 0.591300 +vn -0.988400 0.000000 -0.152100 +vn 0.152100 0.000000 -0.988400 +vn -0.591300 0.000000 -0.806400 +g Cylinder.002_Cylinder.003_sides +s off +f 161/1/1 165/2/1 166/3/1 162/4/1 +f 162/1/2 166/2/2 167/3/2 163/4/2 +f 163/4/3 167/3/3 168/2/3 164/1/3 +f 165/2/4 161/1/4 164/4/4 168/3/4 +g Cylinder.002_Cylinder.003_top-bottom +f 161/2/5 162/1/5 163/4/5 164/3/5 +f 165/2/6 168/3/6 167/4/6 166/1/6 +g Cylinder.002_Cylinder.003_turbine-top-bottom +f 130/5/5 129/6/5 144/7/5 143/8/5 142/9/5 141/10/5 140/11/5 139/12/5 138/13/5 137/14/5 136/15/5 135/16/5 134/17/5 133/18/5 132/19/5 131/20/5 +f 18/5/5 17/6/5 32/7/5 31/8/5 30/9/5 29/10/5 28/11/5 27/12/5 26/13/5 25/14/5 24/15/5 23/16/5 22/17/5 21/18/5 20/19/5 19/20/5 +f 33/6/6 34/5/6 35/20/6 36/19/6 37/18/6 38/17/6 39/16/6 40/15/6 41/14/6 42/13/6 43/12/6 44/11/6 45/10/6 46/9/6 47/8/6 48/7/6 +f 113/6/6 114/5/6 115/20/6 116/19/6 117/18/6 118/17/6 119/16/6 120/15/6 121/14/6 122/13/6 123/12/6 124/11/6 125/10/6 126/9/6 127/8/6 128/7/6 +g Cylinder.002_Cylinder.003_turbine-blades-etc +f 1/21/7 2/22/7 4/23/7 3/24/7 +f 3/24/8 4/23/8 6/25/8 5/26/8 +f 5/27/9 6/28/9 8/29/9 7/30/9 +f 7/30/10 8/29/10 10/31/10 9/32/10 +f 9/32/11 10/31/11 12/33/11 11/34/11 +f 11/34/12 12/33/12 14/25/12 13/26/12 +f 4/35/6 2/36/6 16/37/6 14/38/6 12/39/6 10/40/6 8/41/6 6/42/6 +f 15/43/13 16/44/13 2/22/13 1/21/13 +f 13/45/14 14/46/14 16/44/14 15/43/14 +f 27/47/15 28/48/15 44/49/15 43/50/15 +f 26/51/10 27/47/10 43/50/10 42/52/10 +f 25/53/2 26/51/2 42/52/2 41/54/2 +f 24/55/11 25/53/11 41/54/11 40/56/11 +f 23/57/16 24/55/16 40/56/16 39/58/16 +f 17/59/4 18/60/4 34/61/4 33/62/4 +f 22/63/12 23/57/12 39/58/12 38/64/12 +f 21/65/3 22/63/3 38/64/3 37/66/3 +f 32/67/7 17/59/7 33/62/7 48/68/7 +f 20/69/14 21/70/14 37/71/14 36/72/14 +f 31/73/17 32/67/17 48/68/17 47/74/17 +f 19/75/18 20/69/18 36/72/18 35/76/18 +f 30/77/8 31/73/8 47/74/8 46/78/8 +f 18/60/13 19/75/13 35/76/13 34/61/13 +f 29/79/1 30/77/1 46/78/1 45/80/1 +f 28/48/9 29/81/9 45/82/9 44/49/9 +f 49/83/19 50/84/19 52/85/19 51/86/19 +f 68/86/20 67/83/20 54/84/20 53/85/20 +f 70/83/21 69/84/21 56/85/21 55/86/21 +f 72/84/22 71/85/22 58/86/22 57/83/22 +f 74/83/23 73/84/23 60/85/23 59/86/23 +f 76/83/24 75/84/24 62/85/24 61/86/24 +f 80/84/25 79/85/25 66/86/25 65/83/25 +f 78/83/26 77/84/26 64/85/26 63/86/26 +f 81/87/23 82/88/23 83/89/23 84/90/23 +f 85/88/24 86/89/24 87/90/24 88/87/24 +f 89/89/26 90/90/26 91/87/26 92/88/26 +f 93/90/25 94/87/25 95/88/25 96/89/25 +f 97/90/19 98/87/19 99/88/19 100/89/19 +f 101/87/20 102/88/20 103/89/20 104/90/20 +f 105/90/22 106/87/22 107/88/22 108/89/22 +f 109/89/21 110/90/21 111/87/21 112/88/21 +f 75/88/22 76/87/22 101/86/22 104/85/22 +f 71/88/20 72/87/20 93/86/20 96/85/20 +f 67/86/25 68/85/25 85/88/25 88/87/25 +f 79/86/24 80/85/24 105/88/24 108/87/24 +f 77/88/23 78/87/23 109/86/23 112/85/23 +f 73/88/21 74/87/21 97/86/21 100/85/21 +f 69/86/19 70/85/19 89/88/19 92/87/19 +f 50/86/26 49/85/26 81/88/26 84/87/26 +f 123/91/15 139/92/15 140/93/15 124/94/15 +f 122/95/10 138/96/10 139/97/10 123/98/10 +f 121/99/2 137/100/2 138/96/2 122/95/2 +f 120/101/11 136/102/11 137/100/11 121/99/11 +f 119/103/16 135/104/16 136/102/16 120/101/16 +f 113/105/4 129/106/4 130/107/4 114/108/4 +f 118/109/12 134/110/12 135/104/12 119/103/12 +f 117/111/3 133/112/3 134/110/3 118/109/3 +f 128/113/7 144/114/7 129/106/7 113/105/7 +f 116/115/14 132/116/14 133/112/14 117/111/14 +f 127/117/17 143/118/17 144/114/17 128/113/17 +f 115/119/18 131/120/18 132/116/18 116/115/18 +f 126/121/8 142/122/8 143/118/8 127/117/8 +f 114/108/13 130/107/13 131/123/13 115/124/13 +f 125/125/1 141/126/1 142/122/1 126/121/1 +f 124/94/9 140/93/9 141/126/9 125/125/9 +f 145/127/17 146/128/17 148/129/17 147/130/17 +f 147/131/1 148/132/1 150/133/1 149/134/1 +f 149/134/15 150/133/15 152/135/15 151/136/15 +f 151/136/2 152/135/2 154/137/2 153/138/2 +f 153/138/16 154/137/16 156/139/16 155/140/16 +f 155/140/3 156/139/3 158/141/3 157/142/3 +f 159/143/4 160/144/4 146/128/4 145/127/4 +f 157/142/18 158/141/18 160/144/18 159/143/18 diff --git a/mods/mesecons/mesecons_hydroturbine/models/jeija_hydro_turbine_on.obj b/mods/mesecons/mesecons_hydroturbine/models/jeija_hydro_turbine_on.obj new file mode 100644 index 00000000..52f87682 --- /dev/null +++ b/mods/mesecons/mesecons_hydroturbine/models/jeija_hydro_turbine_on.obj @@ -0,0 +1,2059 @@ +# Blender v2.72 (sub 0) OBJ File: 'mesecons-water-turbine_on.blend' +# www.blender.org +o Cylinder.002_Cylinder.003 +v 0.000000 0.496094 -0.150000 +v 0.000000 0.562500 -0.150000 +v 0.106066 0.496094 -0.106066 +v 0.106066 0.562500 -0.106066 +v 0.150000 0.496094 0.000000 +v 0.150000 0.562500 0.000000 +v 0.106066 0.496094 0.106066 +v 0.106066 0.562500 0.106066 +v -0.000000 0.496094 0.150000 +v -0.000000 0.562500 0.150000 +v -0.106066 0.496094 0.106066 +v -0.106066 0.562500 0.106066 +v -0.150000 0.496094 -0.000000 +v -0.150000 0.562500 -0.000000 +v -0.106066 0.496094 -0.106066 +v -0.106066 0.562500 -0.106066 +v 0.097545 0.625000 -0.490393 +v -0.097545 0.625000 -0.490393 +v -0.277785 0.625000 -0.415735 +v -0.415735 0.625000 -0.277785 +v -0.490393 0.625000 -0.097545 +v -0.490393 0.625000 0.097545 +v -0.415735 0.625000 0.277785 +v -0.277785 0.625000 0.415735 +v -0.097545 0.625000 0.490393 +v 0.097545 0.625000 0.490393 +v 0.277785 0.625000 0.415735 +v 0.415735 0.625000 0.277785 +v 0.490393 0.625000 0.097545 +v 0.490393 0.625000 -0.097545 +v 0.415735 0.625000 -0.277785 +v 0.277785 0.625000 -0.415735 +v 0.097545 0.656250 -0.490393 +v -0.097545 0.656250 -0.490393 +v -0.277785 0.656250 -0.415735 +v -0.415735 0.656250 -0.277785 +v -0.490393 0.656250 -0.097545 +v -0.490393 0.656250 0.097545 +v -0.415735 0.656250 0.277785 +v -0.277785 0.656250 0.415735 +v -0.097545 0.656250 0.490393 +v 0.097545 0.656250 0.490393 +v 0.277785 0.656250 0.415735 +v 0.415735 0.656250 0.277785 +v 0.490393 0.656250 0.097545 +v 0.490393 0.656250 -0.097545 +v 0.415735 0.656250 -0.277785 +v 0.277785 0.656250 -0.415735 +v 0.080186 0.634645 -0.343405 +v 0.080186 1.482640 -0.343405 +v -0.226180 1.482640 -0.390559 +v -0.226180 0.634645 -0.390559 +v -0.227549 0.634645 -0.381663 +v 0.078817 0.634645 -0.334509 +v 0.078817 1.482640 -0.334509 +v -0.227549 1.482640 -0.381663 +v 0.097545 1.496094 -0.490393 +v -0.097545 1.496094 -0.490393 +v -0.277785 1.496094 -0.415735 +v -0.415735 1.496094 -0.277785 +v -0.490393 1.496094 -0.097545 +v -0.490393 1.496094 0.097545 +v -0.415735 1.496094 0.277785 +v -0.277785 1.496094 0.415735 +v -0.097545 1.496094 0.490393 +v 0.097545 1.496094 0.490393 +v 0.277785 1.496094 0.415735 +v 0.415735 1.496094 0.277785 +v 0.490393 1.496094 0.097545 +v 0.490393 1.496094 -0.097545 +v 0.415735 1.496094 -0.277785 +v 0.277785 1.496094 -0.415735 +v 0.097545 1.464844 -0.490393 +v -0.097545 1.464844 -0.490393 +v -0.277785 1.464844 -0.415735 +v -0.415735 1.464844 -0.277785 +v -0.490393 1.464844 -0.097545 +v -0.490393 1.464844 0.097545 +v -0.415735 1.464844 0.277785 +v -0.277785 1.464844 0.415735 +v -0.097545 1.464844 0.490393 +v 0.097545 1.464844 0.490393 +v 0.277785 1.464844 0.415735 +v 0.415735 1.464844 0.277785 +v 0.490393 1.464844 0.097545 +v 0.490393 1.464844 -0.097545 +v 0.415735 1.464844 -0.277785 +v 0.277785 1.464844 -0.415735 +v 0.025624 0.559630 -0.061863 +v 0.025624 1.481372 -0.061863 +v 0.061863 0.559630 -0.025624 +v 0.061863 1.481372 -0.025624 +v 0.061863 0.559630 0.025624 +v 0.061863 1.481372 0.025624 +v 0.025624 0.559630 0.061863 +v 0.025624 1.481372 0.061863 +v -0.025624 0.559630 0.061863 +v -0.025624 1.481372 0.061863 +v -0.061863 0.559630 0.025624 +v -0.061863 1.481372 0.025624 +v -0.061863 0.559630 -0.025624 +v -0.061863 1.481372 -0.025624 +v -0.025624 0.559630 -0.061863 +v -0.025624 1.481372 -0.061863 +v 0.496094 -0.496094 -0.496094 +v 0.496094 -0.496094 0.496094 +v -0.496094 -0.496094 0.496094 +v -0.496094 -0.496094 -0.496094 +v 0.496094 0.496094 -0.496094 +v 0.496094 0.496094 0.496094 +v -0.496094 0.496094 0.496094 +v -0.496094 0.496094 -0.496094 +v 0.299524 0.634645 -0.186124 +v 0.299524 1.482640 -0.186124 +v 0.116233 1.482640 -0.436100 +v 0.116233 0.634645 -0.436100 +v 0.108975 0.634645 -0.430778 +v 0.292266 0.634645 -0.180802 +v 0.292266 1.482640 -0.180802 +v 0.108975 1.482640 -0.430778 +v 0.343405 0.634645 0.080186 +v 0.343405 1.482640 0.080186 +v 0.390559 1.482640 -0.226180 +v 0.390559 0.634645 -0.226180 +v 0.381663 0.634645 -0.227549 +v 0.334509 0.634645 0.078817 +v 0.334509 1.482640 0.078817 +v 0.381663 1.482640 -0.227549 +v 0.186124 0.634645 0.299524 +v 0.186124 1.482640 0.299524 +v 0.436100 1.482640 0.116233 +v 0.436100 0.634645 0.116233 +v 0.430778 0.634645 0.108975 +v 0.180802 0.634645 0.292266 +v 0.180802 1.482640 0.292266 +v 0.430778 1.482640 0.108975 +v -0.080186 0.634645 0.343405 +v -0.080186 1.482640 0.343405 +v 0.226180 1.482640 0.390559 +v 0.226180 0.634645 0.390559 +v 0.227549 0.634645 0.381663 +v -0.078817 0.634645 0.334509 +v -0.078817 1.482640 0.334509 +v 0.227549 1.482640 0.381663 +v -0.299524 0.634645 0.186124 +v -0.299524 1.482640 0.186124 +v -0.116233 1.482640 0.436100 +v -0.116233 0.634645 0.436100 +v -0.108975 0.634645 0.430778 +v -0.292266 0.634645 0.180802 +v -0.292266 1.482640 0.180802 +v -0.108975 1.482640 0.430778 +v -0.343404 0.634645 -0.080186 +v -0.343404 1.482640 -0.080186 +v -0.390559 1.482640 0.226180 +v -0.390559 0.634645 0.226180 +v -0.381663 0.634645 0.227549 +v -0.334509 0.634645 -0.078817 +v -0.334509 1.482640 -0.078817 +v -0.381663 1.482640 0.227549 +v -0.186124 0.634645 -0.299524 +v -0.186124 1.482640 -0.299524 +v -0.436100 1.482640 -0.116233 +v -0.436100 0.634645 -0.116233 +v -0.430778 0.634645 -0.108975 +v -0.180802 0.634645 -0.292266 +v -0.180802 1.482640 -0.292266 +v -0.430778 1.482640 -0.108975 +v 0.145640 0.634645 -0.321163 +v 0.145640 1.482640 -0.321163 +v -0.145640 1.482640 -0.427180 +v -0.145640 0.634645 -0.427180 +v -0.148718 0.634645 -0.418723 +v 0.142562 0.634645 -0.312705 +v 0.142562 1.482640 -0.312705 +v -0.148718 1.482640 -0.418723 +v 0.330079 0.634645 -0.124113 +v 0.330079 1.482640 -0.124113 +v 0.199079 1.482640 -0.405045 +v 0.199079 0.634645 -0.405045 +v 0.190922 0.634645 -0.401241 +v 0.321922 0.634645 -0.120310 +v 0.321922 1.482640 -0.120310 +v 0.190922 1.482640 -0.401241 +v 0.321163 0.634645 0.145640 +v 0.321163 1.482640 0.145640 +v 0.427180 1.482640 -0.145640 +v 0.427180 0.634645 -0.145640 +v 0.418723 0.634645 -0.148718 +v 0.312705 0.634645 0.142562 +v 0.312705 1.482640 0.142562 +v 0.418723 1.482640 -0.148718 +v 0.124113 0.634645 0.330079 +v 0.124113 1.482640 0.330079 +v 0.405045 1.482640 0.199079 +v 0.405045 0.634645 0.199079 +v 0.401241 0.634645 0.190922 +v 0.120310 0.634645 0.321922 +v 0.120310 1.482640 0.321922 +v 0.401241 1.482640 0.190922 +v -0.145640 0.634645 0.321163 +v -0.145640 1.482640 0.321163 +v 0.145640 1.482640 0.427180 +v 0.145640 0.634645 0.427180 +v 0.148718 0.634645 0.418723 +v -0.142562 0.634645 0.312705 +v -0.142562 1.482640 0.312705 +v 0.148718 1.482640 0.418723 +v -0.330079 0.634645 0.124113 +v -0.330079 1.482640 0.124113 +v -0.199079 1.482640 0.405045 +v -0.199079 0.634645 0.405045 +v -0.190922 0.634645 0.401241 +v -0.321923 0.634645 0.120309 +v -0.321923 1.482640 0.120309 +v -0.190922 1.482640 0.401241 +v -0.321163 0.634645 -0.145640 +v -0.321163 1.482640 -0.145640 +v -0.427180 1.482640 0.145640 +v -0.427180 0.634645 0.145640 +v -0.418723 0.634645 0.148718 +v -0.312705 0.634645 -0.142562 +v -0.312705 1.482640 -0.142562 +v -0.418723 1.482640 0.148718 +v -0.124113 0.634645 -0.330079 +v -0.124113 1.482640 -0.330079 +v -0.405045 1.482640 -0.199079 +v -0.405045 0.634645 -0.199079 +v -0.401241 0.634645 -0.190922 +v -0.120309 0.634645 -0.321923 +v -0.120309 1.482640 -0.321923 +v -0.401241 1.482640 -0.190922 +v 0.205497 0.634645 -0.286579 +v 0.205497 1.482640 -0.286579 +v -0.059503 1.482640 -0.447385 +v -0.059503 0.634645 -0.447385 +v -0.064172 0.634645 -0.439690 +v 0.200828 0.634645 -0.278884 +v 0.200828 1.482640 -0.278884 +v -0.064172 1.482640 -0.439690 +v 0.347950 0.634645 -0.057333 +v 0.347950 1.482640 -0.057333 +v 0.274274 1.482640 -0.358424 +v 0.274274 0.634645 -0.358424 +v 0.265532 0.634645 -0.356284 +v 0.339208 0.634645 -0.055194 +v 0.339208 1.482640 -0.055194 +v 0.265532 1.482640 -0.356284 +v 0.286579 0.634645 0.205497 +v 0.286579 1.482640 0.205497 +v 0.447385 1.482640 -0.059503 +v 0.447385 0.634645 -0.059503 +v 0.439690 0.634645 -0.064172 +v 0.278884 0.634645 0.200828 +v 0.278884 1.482640 0.200828 +v 0.439690 1.482640 -0.064172 +v 0.057333 0.634645 0.347950 +v 0.057333 1.482640 0.347950 +v 0.358423 1.482640 0.274274 +v 0.358423 0.634645 0.274274 +v 0.356284 0.634645 0.265532 +v 0.055194 0.634645 0.339208 +v 0.055194 1.482640 0.339208 +v 0.356284 1.482640 0.265532 +v -0.205497 0.634645 0.286579 +v -0.205497 1.482640 0.286579 +v 0.059503 1.482640 0.447385 +v 0.059503 0.634645 0.447385 +v 0.064172 0.634645 0.439690 +v -0.200828 0.634645 0.278884 +v -0.200828 1.482640 0.278884 +v 0.064172 1.482640 0.439690 +v -0.347950 0.634645 0.057333 +v -0.347950 1.482640 0.057333 +v -0.274274 1.482640 0.358423 +v -0.274274 0.634645 0.358423 +v -0.265532 0.634645 0.356284 +v -0.339208 0.634645 0.055194 +v -0.339208 1.482640 0.055194 +v -0.265532 1.482640 0.356284 +v -0.286579 0.634645 -0.205497 +v -0.286579 1.482640 -0.205497 +v -0.447385 1.482640 0.059503 +v -0.447385 0.634645 0.059503 +v -0.439690 0.634645 0.064172 +v -0.278884 0.634645 -0.200828 +v -0.278884 1.482640 -0.200828 +v -0.439690 1.482640 0.064172 +v -0.057333 0.634645 -0.347950 +v -0.057333 1.482640 -0.347950 +v -0.358423 1.482640 -0.274274 +v -0.358423 0.634645 -0.274274 +v -0.356284 0.634645 -0.265532 +v -0.055194 0.634645 -0.339208 +v -0.055194 1.482640 -0.339208 +v -0.356284 1.482640 -0.265532 +v 0.257457 0.634645 -0.240981 +v 0.257457 1.482640 -0.240981 +v 0.028921 1.482640 -0.450397 +v 0.028921 0.634645 -0.450397 +v 0.022841 0.634645 -0.443761 +v 0.251377 0.634645 -0.234346 +v 0.251377 1.482640 -0.234346 +v 0.022841 1.482640 -0.443761 +v 0.352450 0.634645 0.011650 +v 0.352450 1.482640 0.011650 +v 0.338929 1.482640 -0.298028 +v 0.338929 0.634645 -0.298028 +v 0.329937 0.634645 -0.297636 +v 0.343458 0.634645 0.012043 +v 0.343458 1.482640 0.012043 +v 0.329937 1.482640 -0.297636 +v 0.240981 0.634645 0.257458 +v 0.240981 1.482640 0.257458 +v 0.450397 1.482640 0.028921 +v 0.450397 0.634645 0.028921 +v 0.443761 0.634645 0.022841 +v 0.234346 0.634645 0.251377 +v 0.234346 1.482640 0.251377 +v 0.443761 1.482640 0.022841 +v -0.011650 0.634645 0.352450 +v -0.011650 1.482640 0.352450 +v 0.298028 1.482640 0.338929 +v 0.298028 0.634645 0.338929 +v 0.297636 0.634645 0.329937 +v -0.012043 0.634645 0.343458 +v -0.012043 1.482640 0.343458 +v 0.297636 1.482640 0.329937 +v -0.257458 0.634645 0.240981 +v -0.257458 1.482640 0.240981 +v -0.028921 1.482640 0.450397 +v -0.028921 0.634645 0.450397 +v -0.022841 0.634645 0.443761 +v -0.251377 0.634645 0.234346 +v -0.251377 1.482640 0.234346 +v -0.022841 1.482640 0.443761 +v -0.352450 0.634645 -0.011650 +v -0.352450 1.482640 -0.011650 +v -0.338929 1.482640 0.298028 +v -0.338929 0.634645 0.298028 +v -0.329937 0.634645 0.297636 +v -0.343458 0.634645 -0.012043 +v -0.343458 1.482640 -0.012043 +v -0.329937 1.482640 0.297636 +v -0.240981 0.634645 -0.257458 +v -0.240981 1.482640 -0.257458 +v -0.450397 1.482640 -0.028921 +v -0.450397 0.634645 -0.028921 +v -0.443761 0.634645 -0.022841 +v -0.234346 0.634645 -0.251377 +v -0.234346 1.482640 -0.251377 +v -0.443761 1.482640 -0.022841 +v 0.011651 0.634645 -0.352450 +v 0.011651 1.482640 -0.352450 +v -0.298028 1.482640 -0.338929 +v -0.298028 0.634645 -0.338929 +v -0.297635 0.634645 -0.329937 +v 0.012043 0.634645 -0.343458 +v 0.012043 1.482640 -0.343458 +v -0.297635 1.482640 -0.329937 +v 0.191342 0.625000 -0.461940 +v 0.000000 0.625000 -0.500000 +v -0.191342 0.625000 -0.461940 +v -0.353553 0.625000 -0.353554 +v -0.461940 0.625000 -0.191342 +v -0.500000 0.625000 -0.000000 +v -0.461940 0.625000 0.191342 +v -0.353553 0.625000 0.353553 +v -0.191342 0.625000 0.461940 +v -0.000000 0.625000 0.500000 +v 0.191342 0.625000 0.461940 +v 0.353553 0.625000 0.353553 +v 0.461940 0.625000 0.191341 +v 0.500000 0.625000 -0.000000 +v 0.461940 0.625000 -0.191342 +v 0.353553 0.625000 -0.353554 +v 0.191342 0.656250 -0.461940 +v 0.000000 0.656250 -0.500000 +v -0.191342 0.656250 -0.461940 +v -0.353553 0.656250 -0.353554 +v -0.461940 0.656250 -0.191342 +v -0.500000 0.656250 -0.000000 +v -0.461940 0.656250 0.191342 +v -0.353553 0.656250 0.353553 +v -0.191342 0.656250 0.461940 +v -0.000000 0.656250 0.500000 +v 0.191342 0.656250 0.461940 +v 0.353553 0.656250 0.353553 +v 0.461940 0.656250 0.191341 +v 0.500000 0.656250 -0.000000 +v 0.461940 0.656250 -0.191342 +v 0.353553 0.656250 -0.353554 +v 0.191342 1.496094 -0.461940 +v 0.000000 1.496094 -0.500000 +v -0.191342 1.496094 -0.461940 +v -0.353553 1.496094 -0.353554 +v -0.461940 1.496094 -0.191342 +v -0.500000 1.496094 -0.000000 +v -0.461940 1.496094 0.191342 +v -0.353553 1.496094 0.353553 +v -0.191342 1.496094 0.461940 +v -0.000000 1.496094 0.500000 +v 0.191341 1.496094 0.461940 +v 0.353553 1.496094 0.353553 +v 0.461940 1.496094 0.191342 +v 0.500000 1.496094 0.000000 +v 0.461940 1.496094 -0.191342 +v 0.353553 1.496094 -0.353554 +v 0.191342 1.464844 -0.461940 +v 0.000000 1.464844 -0.500000 +v -0.191342 1.464844 -0.461940 +v -0.353553 1.464844 -0.353554 +v -0.461940 1.464844 -0.191342 +v -0.500000 1.464844 -0.000000 +v -0.461940 1.464844 0.191342 +v -0.353553 1.464844 0.353553 +v -0.191342 1.464844 0.461940 +v -0.000000 1.464844 0.500000 +v 0.191341 1.464844 0.461940 +v 0.353553 1.464844 0.353553 +v 0.461940 1.464844 0.191342 +v 0.500000 1.464844 0.000000 +v 0.461940 1.464844 -0.191342 +v 0.353553 1.464844 -0.353554 +v 0.277785 0.625000 -0.415735 +v 0.097545 0.625000 -0.490393 +v -0.097545 0.625000 -0.490393 +v -0.277785 0.625000 -0.415735 +v -0.415735 0.625000 -0.277785 +v -0.490393 0.625000 -0.097545 +v -0.490393 0.625000 0.097545 +v -0.415735 0.625000 0.277785 +v -0.277785 0.625000 0.415735 +v -0.097545 0.625000 0.490392 +v 0.097545 0.625000 0.490393 +v 0.277785 0.625000 0.415735 +v 0.415735 0.625000 0.277785 +v 0.490393 0.625000 0.097545 +v 0.490393 0.625000 -0.097545 +v 0.415735 0.625000 -0.277786 +v 0.277785 0.656250 -0.415735 +v 0.097545 0.656250 -0.490393 +v -0.097545 0.656250 -0.490393 +v -0.277785 0.656250 -0.415735 +v -0.415735 0.656250 -0.277785 +v -0.490393 0.656250 -0.097545 +v -0.490393 0.656250 0.097545 +v -0.415735 0.656250 0.277785 +v -0.277785 0.656250 0.415735 +v -0.097545 0.656250 0.490392 +v 0.097545 0.656250 0.490393 +v 0.277785 0.656250 0.415735 +v 0.415735 0.656250 0.277785 +v 0.490393 0.656250 0.097545 +v 0.490393 0.656250 -0.097545 +v 0.415735 0.656250 -0.277786 +v 0.277785 1.496094 -0.415735 +v 0.097545 1.496094 -0.490393 +v -0.097545 1.496094 -0.490393 +v -0.277785 1.496094 -0.415735 +v -0.415735 1.496094 -0.277785 +v -0.490393 1.496094 -0.097545 +v -0.490393 1.496094 0.097545 +v -0.415735 1.496094 0.277785 +v -0.277785 1.496094 0.415735 +v -0.097545 1.496094 0.490393 +v 0.097545 1.496094 0.490393 +v 0.277785 1.496094 0.415735 +v 0.415735 1.496094 0.277785 +v 0.490393 1.496094 0.097545 +v 0.490393 1.496094 -0.097545 +v 0.415735 1.496094 -0.277785 +v 0.277785 1.464844 -0.415735 +v 0.097545 1.464844 -0.490393 +v -0.097545 1.464844 -0.490393 +v -0.277785 1.464844 -0.415735 +v -0.415735 1.464844 -0.277785 +v -0.490393 1.464844 -0.097545 +v -0.490393 1.464844 0.097545 +v -0.415735 1.464844 0.277785 +v -0.277785 1.464844 0.415735 +v -0.097545 1.464844 0.490393 +v 0.097545 1.464844 0.490393 +v 0.277785 1.464844 0.415735 +v 0.415735 1.464844 0.277785 +v 0.490393 1.464844 0.097545 +v 0.490393 1.464844 -0.097545 +v 0.415735 1.464844 -0.277785 +v 0.353554 0.625000 -0.353554 +v 0.191342 0.625000 -0.461940 +v 0.000000 0.625000 -0.500000 +v -0.191342 0.625000 -0.461940 +v -0.353553 0.625000 -0.353554 +v -0.461940 0.625000 -0.191342 +v -0.500000 0.625000 -0.000000 +v -0.461940 0.625000 0.191341 +v -0.353554 0.625000 0.353553 +v -0.191342 0.625000 0.461940 +v 0.000000 0.625000 0.500000 +v 0.191342 0.625000 0.461940 +v 0.353554 0.625000 0.353553 +v 0.461940 0.625000 0.191341 +v 0.500000 0.625000 -0.000000 +v 0.461940 0.625000 -0.191342 +v 0.353554 0.656250 -0.353554 +v 0.191342 0.656250 -0.461940 +v 0.000000 0.656250 -0.500000 +v -0.191342 0.656250 -0.461940 +v -0.353553 0.656250 -0.353554 +v -0.461940 0.656250 -0.191342 +v -0.500000 0.656250 -0.000000 +v -0.461940 0.656250 0.191341 +v -0.353554 0.656250 0.353553 +v -0.191342 0.656250 0.461940 +v 0.000000 0.656250 0.500000 +v 0.191342 0.656250 0.461940 +v 0.353554 0.656250 0.353553 +v 0.461940 0.656250 0.191341 +v 0.500000 0.656250 -0.000000 +v 0.461940 0.656250 -0.191342 +v 0.353553 1.496094 -0.353553 +v 0.191342 1.496094 -0.461940 +v 0.000000 1.496094 -0.500000 +v -0.191342 1.496094 -0.461940 +v -0.353554 1.496094 -0.353553 +v -0.461940 1.496094 -0.191342 +v -0.500000 1.496094 -0.000000 +v -0.461940 1.496094 0.191342 +v -0.353554 1.496094 0.353553 +v -0.191342 1.496094 0.461940 +v -0.000000 1.496094 0.500000 +v 0.191342 1.496094 0.461940 +v 0.353554 1.496094 0.353553 +v 0.461940 1.496094 0.191342 +v 0.500000 1.496094 -0.000000 +v 0.461940 1.496094 -0.191342 +v 0.353553 1.464844 -0.353553 +v 0.191342 1.464844 -0.461940 +v 0.000000 1.464844 -0.500000 +v -0.191342 1.464844 -0.461940 +v -0.353554 1.464844 -0.353553 +v -0.461940 1.464844 -0.191342 +v -0.500000 1.464844 -0.000000 +v -0.461940 1.464844 0.191342 +v -0.353554 1.464844 0.353553 +v -0.191342 1.464844 0.461940 +v -0.000000 1.464844 0.500000 +v 0.191342 1.464844 0.461940 +v 0.353554 1.464844 0.353553 +v 0.461940 1.464844 0.191342 +v 0.500000 1.464844 -0.000000 +v 0.461940 1.464844 -0.191342 +v 0.415735 0.625000 -0.277785 +v 0.277785 0.625000 -0.415735 +v 0.097545 0.625000 -0.490393 +v -0.097545 0.625000 -0.490393 +v -0.277785 0.625000 -0.415735 +v -0.415735 0.625000 -0.277785 +v -0.490393 0.625000 -0.097545 +v -0.490393 0.625000 0.097545 +v -0.415735 0.625000 0.277785 +v -0.277785 0.625000 0.415735 +v -0.097545 0.625000 0.490393 +v 0.097545 0.625000 0.490393 +v 0.277785 0.625000 0.415735 +v 0.415735 0.625000 0.277785 +v 0.490393 0.625000 0.097545 +v 0.490393 0.625000 -0.097546 +v 0.415735 0.656250 -0.277785 +v 0.277785 0.656250 -0.415735 +v 0.097545 0.656250 -0.490393 +v -0.097545 0.656250 -0.490393 +v -0.277785 0.656250 -0.415735 +v -0.415735 0.656250 -0.277785 +v -0.490393 0.656250 -0.097545 +v -0.490393 0.656250 0.097545 +v -0.415735 0.656250 0.277785 +v -0.277785 0.656250 0.415735 +v -0.097545 0.656250 0.490393 +v 0.097545 0.656250 0.490393 +v 0.277785 0.656250 0.415735 +v 0.415735 0.656250 0.277785 +v 0.490393 0.656250 0.097545 +v 0.490393 0.656250 -0.097546 +v 0.415735 1.496094 -0.277785 +v 0.277785 1.496094 -0.415735 +v 0.097545 1.496094 -0.490392 +v -0.097545 1.496094 -0.490393 +v -0.277785 1.496094 -0.415735 +v -0.415735 1.496094 -0.277785 +v -0.490393 1.496094 -0.097545 +v -0.490393 1.496094 0.097545 +v -0.415735 1.496094 0.277785 +v -0.277785 1.496094 0.415735 +v -0.097545 1.496094 0.490393 +v 0.097545 1.496094 0.490393 +v 0.277785 1.496094 0.415735 +v 0.415735 1.496094 0.277785 +v 0.490393 1.496094 0.097545 +v 0.490393 1.496094 -0.097545 +v 0.415735 1.464844 -0.277785 +v 0.277785 1.464844 -0.415735 +v 0.097545 1.464844 -0.490392 +v -0.097545 1.464844 -0.490393 +v -0.277785 1.464844 -0.415735 +v -0.415735 1.464844 -0.277785 +v -0.490393 1.464844 -0.097545 +v -0.490393 1.464844 0.097545 +v -0.415735 1.464844 0.277785 +v -0.277785 1.464844 0.415735 +v -0.097545 1.464844 0.490393 +v 0.097545 1.464844 0.490393 +v 0.277785 1.464844 0.415735 +v 0.415735 1.464844 0.277785 +v 0.490393 1.464844 0.097545 +v 0.490393 1.464844 -0.097545 +v 0.461939 0.625000 -0.191342 +v 0.353554 0.625000 -0.353553 +v 0.191342 0.625000 -0.461940 +v -0.000000 0.625000 -0.500000 +v -0.191342 0.625000 -0.461940 +v -0.353554 0.625000 -0.353554 +v -0.461940 0.625000 -0.191342 +v -0.500000 0.625000 -0.000000 +v -0.461940 0.625000 0.191341 +v -0.353554 0.625000 0.353553 +v -0.191342 0.625000 0.461940 +v -0.000000 0.625000 0.500000 +v 0.191342 0.625000 0.461940 +v 0.353554 0.625000 0.353553 +v 0.461939 0.625000 0.191342 +v 0.500000 0.625000 -0.000000 +v 0.461939 0.656250 -0.191342 +v 0.353554 0.656250 -0.353553 +v 0.191342 0.656250 -0.461940 +v -0.000000 0.656250 -0.500000 +v -0.191342 0.656250 -0.461940 +v -0.353554 0.656250 -0.353554 +v -0.461940 0.656250 -0.191342 +v -0.500000 0.656250 -0.000000 +v -0.461940 0.656250 0.191341 +v -0.353554 0.656250 0.353553 +v -0.191342 0.656250 0.461940 +v -0.000000 0.656250 0.500000 +v 0.191342 0.656250 0.461940 +v 0.353554 0.656250 0.353553 +v 0.461939 0.656250 0.191342 +v 0.500000 0.656250 -0.000000 +v 0.461939 1.496094 -0.191342 +v 0.353553 1.496094 -0.353553 +v 0.191342 1.496094 -0.461940 +v -0.000000 1.496094 -0.500000 +v -0.191342 1.496094 -0.461940 +v -0.353554 1.496094 -0.353553 +v -0.461940 1.496094 -0.191342 +v -0.500000 1.496094 -0.000000 +v -0.461940 1.496094 0.191342 +v -0.353554 1.496094 0.353553 +v -0.191342 1.496094 0.461940 +v -0.000000 1.496094 0.500000 +v 0.191342 1.496094 0.461940 +v 0.353553 1.496094 0.353553 +v 0.461939 1.496094 0.191342 +v 0.500000 1.496094 -0.000000 +v 0.461939 1.464844 -0.191342 +v 0.353553 1.464844 -0.353553 +v 0.191342 1.464844 -0.461940 +v -0.000000 1.464844 -0.500000 +v -0.191342 1.464844 -0.461940 +v -0.353554 1.464844 -0.353553 +v -0.461940 1.464844 -0.191342 +v -0.500000 1.464844 -0.000000 +v -0.461940 1.464844 0.191342 +v -0.353554 1.464844 0.353553 +v -0.191342 1.464844 0.461940 +v -0.000000 1.464844 0.500000 +v 0.191342 1.464844 0.461940 +v 0.353553 1.464844 0.353553 +v 0.461939 1.464844 0.191342 +v 0.500000 1.464844 -0.000000 +v 0.490393 0.625000 -0.097545 +v 0.415735 0.625000 -0.277785 +v 0.277785 0.625000 -0.415735 +v 0.097545 0.625000 -0.490393 +v -0.097545 0.625000 -0.490393 +v -0.277785 0.625000 -0.415735 +v -0.415735 0.625000 -0.277785 +v -0.490393 0.625000 -0.097545 +v -0.490393 0.625000 0.097545 +v -0.415735 0.625000 0.277785 +v -0.277785 0.625000 0.415735 +v -0.097545 0.625000 0.490393 +v 0.097545 0.625000 0.490393 +v 0.277785 0.625000 0.415735 +v 0.415735 0.625000 0.277785 +v 0.490393 0.625000 0.097545 +v 0.490393 0.656250 -0.097545 +v 0.415735 0.656250 -0.277785 +v 0.277785 0.656250 -0.415735 +v 0.097545 0.656250 -0.490393 +v -0.097545 0.656250 -0.490393 +v -0.277785 0.656250 -0.415735 +v -0.415735 0.656250 -0.277785 +v -0.490393 0.656250 -0.097545 +v -0.490393 0.656250 0.097545 +v -0.415735 0.656250 0.277785 +v -0.277785 0.656250 0.415735 +v -0.097545 0.656250 0.490393 +v 0.097545 0.656250 0.490393 +v 0.277785 0.656250 0.415735 +v 0.415735 0.656250 0.277785 +v 0.490393 0.656250 0.097545 +v 0.490393 1.496094 -0.097545 +v 0.415735 1.496094 -0.277785 +v 0.277785 1.496094 -0.415735 +v 0.097545 1.496094 -0.490393 +v -0.097545 1.496094 -0.490393 +v -0.277785 1.496094 -0.415735 +v -0.415735 1.496094 -0.277785 +v -0.490393 1.496094 -0.097545 +v -0.490393 1.496094 0.097545 +v -0.415735 1.496094 0.277785 +v -0.277785 1.496094 0.415735 +v -0.097545 1.496094 0.490393 +v 0.097545 1.496094 0.490393 +v 0.277785 1.496094 0.415735 +v 0.415735 1.496094 0.277785 +v 0.490393 1.496094 0.097545 +v 0.490393 1.464844 -0.097545 +v 0.415735 1.464844 -0.277785 +v 0.277785 1.464844 -0.415735 +v 0.097545 1.464844 -0.490393 +v -0.097545 1.464844 -0.490393 +v -0.277785 1.464844 -0.415735 +v -0.415735 1.464844 -0.277785 +v -0.490393 1.464844 -0.097545 +v -0.490393 1.464844 0.097545 +v -0.415735 1.464844 0.277785 +v -0.277785 1.464844 0.415735 +v -0.097545 1.464844 0.490393 +v 0.097545 1.464844 0.490393 +v 0.277785 1.464844 0.415735 +v 0.415735 1.464844 0.277785 +v 0.490393 1.464844 0.097545 +v 0.500001 0.625000 -0.000000 +v 0.461940 0.625000 -0.191342 +v 0.353554 0.625000 -0.353553 +v 0.191342 0.625000 -0.461940 +v 0.000000 0.625000 -0.500000 +v -0.191342 0.625000 -0.461940 +v -0.353553 0.625000 -0.353553 +v -0.461939 0.625000 -0.191342 +v -0.500000 0.625000 -0.000000 +v -0.461939 0.625000 0.191342 +v -0.353553 0.625000 0.353553 +v -0.191342 0.625000 0.461940 +v 0.000001 0.625000 0.500000 +v 0.191342 0.625000 0.461940 +v 0.353554 0.625000 0.353553 +v 0.461940 0.625000 0.191341 +v 0.500001 0.656250 -0.000000 +v 0.461940 0.656250 -0.191342 +v 0.353554 0.656250 -0.353553 +v 0.191342 0.656250 -0.461940 +v 0.000000 0.656250 -0.500000 +v -0.191342 0.656250 -0.461940 +v -0.353553 0.656250 -0.353553 +v -0.461939 0.656250 -0.191342 +v -0.500000 0.656250 -0.000000 +v -0.461939 0.656250 0.191342 +v -0.353553 0.656250 0.353553 +v -0.191342 0.656250 0.461940 +v 0.000001 0.656250 0.500000 +v 0.191342 0.656250 0.461940 +v 0.353554 0.656250 0.353553 +v 0.461940 0.656250 0.191341 +v 0.500000 1.496094 -0.000000 +v 0.461940 1.496094 -0.191342 +v 0.353554 1.496094 -0.353553 +v 0.191342 1.496094 -0.461940 +v 0.000000 1.496094 -0.500000 +v -0.191342 1.496094 -0.461940 +v -0.353553 1.496094 -0.353553 +v -0.461939 1.496094 -0.191342 +v -0.500000 1.496094 -0.000000 +v -0.461939 1.496094 0.191342 +v -0.353554 1.496094 0.353553 +v -0.191342 1.496094 0.461940 +v 0.000000 1.496094 0.500000 +v 0.191342 1.496094 0.461940 +v 0.353554 1.496094 0.353553 +v 0.461940 1.496094 0.191341 +v 0.500000 1.464844 -0.000000 +v 0.461940 1.464844 -0.191342 +v 0.353554 1.464844 -0.353553 +v 0.191342 1.464844 -0.461940 +v 0.000000 1.464844 -0.500000 +v -0.191342 1.464844 -0.461940 +v -0.353553 1.464844 -0.353553 +v -0.461939 1.464844 -0.191342 +v -0.500000 1.464844 -0.000000 +v -0.461939 1.464844 0.191342 +v -0.353554 1.464844 0.353553 +v -0.191342 1.464844 0.461940 +v 0.000000 1.464844 0.500000 +v 0.191342 1.464844 0.461940 +v 0.353554 1.464844 0.353553 +v 0.461940 1.464844 0.191341 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 0.050068 0.998878 +vt 0.074932 0.998878 +vt 0.097903 0.922758 +vt 0.115485 0.782105 +vt 0.125000 0.598334 +vt 0.125000 0.399421 +vt 0.115485 0.215651 +vt 0.097903 0.074998 +vt 0.074932 -0.001122 +vt 0.050068 -0.001122 +vt 0.027097 0.074998 +vt 0.009515 0.215650 +vt 0.000000 0.399421 +vt 0.000000 0.598334 +vt 0.009515 0.782105 +vt 0.027097 0.922758 +vt 0.175068 0.998878 +vt 0.199932 0.998878 +vt 0.222903 0.922758 +vt 0.240485 0.782105 +vt 0.250000 0.598334 +vt 0.250000 0.399421 +vt 0.240485 0.215651 +vt 0.222903 0.074998 +vt 0.199932 -0.001122 +vt 0.175068 -0.001122 +vt 0.152097 0.074998 +vt 0.134515 0.215650 +vt 0.134515 0.782105 +vt 0.152097 0.922758 +vt 0.300068 0.998878 +vt 0.324932 0.998878 +vt 0.347903 0.922758 +vt 0.365485 0.782105 +vt 0.375000 0.598334 +vt 0.375000 0.399421 +vt 0.365485 0.215651 +vt 0.347903 0.074998 +vt 0.324932 -0.001122 +vt 0.300068 -0.001122 +vt 0.277097 0.074998 +vt 0.259515 0.215650 +vt 0.259515 0.782105 +vt 0.277097 0.922758 +vt 0.425068 0.998878 +vt 0.449932 0.998878 +vt 0.472903 0.922758 +vt 0.490485 0.782105 +vt 0.500000 0.598334 +vt 0.500000 0.399421 +vt 0.490485 0.215651 +vt 0.472903 0.074998 +vt 0.449932 -0.001122 +vt 0.425068 -0.001122 +vt 0.402097 0.074998 +vt 0.384515 0.215650 +vt 0.384515 0.782105 +vt 0.402097 0.922758 +vt 0.550068 0.998878 +vt 0.574932 0.998878 +vt 0.597903 0.922758 +vt 0.615485 0.782105 +vt 0.625000 0.598334 +vt 0.625000 0.399421 +vt 0.615485 0.215651 +vt 0.597903 0.074998 +vt 0.574932 -0.001122 +vt 0.550068 -0.001122 +vt 0.527097 0.074998 +vt 0.509515 0.215650 +vt 0.509515 0.782105 +vt 0.527097 0.922758 +vt 0.675068 0.998878 +vt 0.699932 0.998878 +vt 0.722903 0.922758 +vt 0.740485 0.782105 +vt 0.750000 0.598334 +vt 0.750000 0.399421 +vt 0.740485 0.215651 +vt 0.722903 0.074998 +vt 0.699932 -0.001122 +vt 0.675068 -0.001122 +vt 0.652097 0.074998 +vt 0.634515 0.215650 +vt 0.634515 0.782105 +vt 0.652097 0.922758 +vt 0.800068 0.998878 +vt 0.824932 0.998878 +vt 0.847903 0.922758 +vt 0.865485 0.782105 +vt 0.875000 0.598334 +vt 0.875000 0.399421 +vt 0.865485 0.215651 +vt 0.847903 0.074998 +vt 0.824932 -0.001122 +vt 0.800068 -0.001122 +vt 0.777097 0.074998 +vt 0.759515 0.215650 +vt 0.759515 0.782105 +vt 0.777097 0.922758 +vt 0.925068 0.998878 +vt 0.949932 0.998878 +vt 0.972903 0.922758 +vt 0.990485 0.782105 +vt 1.000000 0.598334 +vt 1.000000 0.399421 +vt 0.990485 0.215651 +vt 0.972903 0.074998 +vt 0.949932 -0.001122 +vt 0.925068 -0.001122 +vt 0.902097 0.074998 +vt 0.884515 0.215650 +vt 0.884515 0.782105 +vt 0.902097 0.922758 +vt 0.062500 0.343750 +vt 0.066406 0.343750 +vt 0.066406 0.375000 +vt 0.062500 0.375000 +vt 0.066406 0.406250 +vt 0.062500 0.406250 +vt 0.062500 0.531250 +vt 0.066406 0.531250 +vt 0.066406 0.500000 +vt 0.062500 0.500000 +vt 0.066406 0.468750 +vt 0.062500 0.468750 +vt 0.066406 0.437500 +vt 0.062500 0.437500 +vt 0.074219 0.468750 +vt 0.078125 0.437500 +vt 0.082031 0.437500 +vt 0.085938 0.468750 +vt 0.085938 0.500000 +vt 0.082031 0.531250 +vt 0.078125 0.531250 +vt 0.074219 0.500000 +vt 0.062500 0.312500 +vt 0.066406 0.312500 +vt 0.062500 0.281250 +vt 0.066406 0.281250 +vt 0.023438 0.750000 +vt 0.023438 0.875000 +vt 0.019531 0.875000 +vt 0.019531 0.750000 +vt 0.023438 0.625000 +vt 0.019531 0.625000 +vt 0.023438 0.500000 +vt 0.019531 0.500000 +vt 0.023438 0.375000 +vt 0.019531 0.375000 +vt 0.023438 0.250000 +vt 0.019531 0.250000 +vt 0.035156 0.500000 +vt 0.035156 0.625000 +vt 0.027344 0.625000 +vt 0.027344 0.500000 +vt 0.023438 0.125000 +vt 0.019531 0.125000 +vt 0.023438 0.000000 +vt 0.019531 0.000000 +vt 0.035156 0.375000 +vt 0.027344 0.375000 +vt 0.035156 0.875000 +vt 0.035156 1.000000 +vt 0.027344 1.000000 +vt 0.027344 0.875000 +vt 0.035156 0.250000 +vt 0.027344 0.250000 +vt 0.035156 0.750000 +vt 0.027344 0.750000 +vt 0.035156 0.125000 +vt 0.027344 0.125000 +vt 0.035156 0.000000 +vt 0.027344 0.000000 +vt 0.023438 1.000000 +vt 0.019531 1.000000 +vt 0.078125 0.593750 +vt 0.078125 0.968750 +vt 0.062500 0.968750 +vt 0.062500 0.593750 +vt 0.082031 0.593750 +vt 0.097656 0.593750 +vt 0.097656 0.968750 +vt 0.082031 0.968750 +vt 0.046875 0.000000 +vt 0.054688 0.000000 +vt 0.054688 0.125000 +vt 0.046875 0.125000 +vt 0.039062 0.875000 +vt 0.042969 0.875000 +vt 0.042969 1.000000 +vt 0.039062 1.000000 +vt 0.039062 0.750000 +vt 0.042969 0.750000 +vt 0.039062 0.625000 +vt 0.042969 0.625000 +vt 0.039062 0.500000 +vt 0.042969 0.500000 +vt 0.046875 0.750000 +vt 0.054688 0.750000 +vt 0.054688 0.875000 +vt 0.046875 0.875000 +vt 0.039062 0.375000 +vt 0.042969 0.375000 +vt 0.039062 0.250000 +vt 0.042969 0.250000 +vt 0.046875 0.625000 +vt 0.054688 0.625000 +vt 0.039062 0.125000 +vt 0.042969 0.125000 +vt 0.046875 0.500000 +vt 0.054688 0.500000 +vt 0.039062 0.000000 +vt 0.042969 0.000000 +vt 0.046875 0.375000 +vt 0.054688 0.375000 +vt 0.054688 1.000000 +vt 0.046875 1.000000 +vt 0.046875 0.250000 +vt 0.054688 0.250000 +vt 0.003906 0.937500 +vt 0.007812 0.937500 +vt 0.007812 0.968750 +vt 0.003906 0.968750 +vt 0.003906 0.718750 +vt 0.007812 0.718750 +vt 0.007812 0.750000 +vt 0.003906 0.750000 +vt 0.007812 0.781250 +vt 0.003906 0.781250 +vt 0.007812 0.812500 +vt 0.003906 0.812500 +vt 0.007812 0.843750 +vt 0.003906 0.843750 +vt 0.007812 0.875000 +vt 0.003906 0.875000 +vt 0.003906 0.906250 +vt 0.007812 0.906250 +vt 0.203125 0.593750 +vt 0.203125 0.968750 +vt 0.187500 0.968750 +vt 0.187500 0.593750 +vt 0.207031 0.593750 +vt 0.222656 0.593750 +vt 0.222656 0.968750 +vt 0.207031 0.968750 +vt 0.328125 0.593750 +vt 0.328125 0.968750 +vt 0.312500 0.968750 +vt 0.312500 0.593750 +vt 0.332031 0.593750 +vt 0.347656 0.593750 +vt 0.347656 0.968750 +vt 0.332031 0.968750 +vt 0.453125 0.593750 +vt 0.453125 0.968750 +vt 0.437500 0.968750 +vt 0.437500 0.593750 +vt 0.457031 0.593750 +vt 0.472656 0.593750 +vt 0.472656 0.968750 +vt 0.457031 0.968750 +vt 0.148438 0.750000 +vt 0.148438 0.875000 +vt 0.144531 0.875000 +vt 0.144531 0.750000 +vt 0.148438 0.625000 +vt 0.144531 0.625000 +vt 0.148438 0.500000 +vt 0.144531 0.500000 +vt 0.148438 0.375000 +vt 0.144531 0.375000 +vt 0.148438 0.250000 +vt 0.144531 0.250000 +vt 0.160156 0.500000 +vt 0.160156 0.625000 +vt 0.152344 0.625000 +vt 0.152344 0.500000 +vt 0.148438 0.125000 +vt 0.144531 0.125000 +vt 0.148438 0.000000 +vt 0.144531 0.000000 +vt 0.160156 0.375000 +vt 0.152344 0.375000 +vt 0.160156 0.875000 +vt 0.160156 1.000000 +vt 0.152344 1.000000 +vt 0.152344 0.875000 +vt 0.160156 0.250000 +vt 0.152344 0.250000 +vt 0.160156 0.750000 +vt 0.152344 0.750000 +vt 0.160156 0.125000 +vt 0.152344 0.125000 +vt 0.160156 0.000000 +vt 0.152344 0.000000 +vt 0.148438 1.000000 +vt 0.144531 1.000000 +vt 0.171875 0.000000 +vt 0.179688 0.000000 +vt 0.179688 0.125000 +vt 0.171875 0.125000 +vt 0.164062 0.875000 +vt 0.167969 0.875000 +vt 0.167969 1.000000 +vt 0.164062 1.000000 +vt 0.164062 0.750000 +vt 0.167969 0.750000 +vt 0.164062 0.625000 +vt 0.167969 0.625000 +vt 0.164062 0.500000 +vt 0.167969 0.500000 +vt 0.171875 0.750000 +vt 0.179688 0.750000 +vt 0.179688 0.875000 +vt 0.171875 0.875000 +vt 0.164062 0.375000 +vt 0.167969 0.375000 +vt 0.164062 0.250000 +vt 0.167969 0.250000 +vt 0.171875 0.625000 +vt 0.179688 0.625000 +vt 0.164062 0.125000 +vt 0.167969 0.125000 +vt 0.171875 0.500000 +vt 0.179688 0.500000 +vt 0.164062 0.000000 +vt 0.167969 0.000000 +vt 0.171875 0.375000 +vt 0.179688 0.375000 +vt 0.179688 1.000000 +vt 0.171875 1.000000 +vt 0.171875 0.250000 +vt 0.179688 0.250000 +vt 0.273438 0.750000 +vt 0.273438 0.875000 +vt 0.269531 0.875000 +vt 0.269531 0.750000 +vt 0.273438 0.625000 +vt 0.269531 0.625000 +vt 0.273438 0.500000 +vt 0.269531 0.500000 +vt 0.273438 0.375000 +vt 0.269531 0.375000 +vt 0.273438 0.250000 +vt 0.269531 0.250000 +vt 0.285156 0.500000 +vt 0.285156 0.625000 +vt 0.277344 0.625000 +vt 0.277344 0.500000 +vt 0.273438 0.125000 +vt 0.269531 0.125000 +vt 0.273438 0.000000 +vt 0.269531 0.000000 +vt 0.285156 0.375000 +vt 0.277344 0.375000 +vt 0.285156 0.875000 +vt 0.285156 1.000000 +vt 0.277344 1.000000 +vt 0.277344 0.875000 +vt 0.285156 0.250000 +vt 0.277344 0.250000 +vt 0.285156 0.750000 +vt 0.277344 0.750000 +vt 0.285156 0.125000 +vt 0.277344 0.125000 +vt 0.285156 0.000000 +vt 0.277344 0.000000 +vt 0.273438 1.000000 +vt 0.269531 1.000000 +vt 0.296875 0.000000 +vt 0.304688 0.000000 +vt 0.304688 0.125000 +vt 0.296875 0.125000 +vt 0.289062 0.875000 +vt 0.292969 0.875000 +vt 0.292969 1.000000 +vt 0.289062 1.000000 +vt 0.289062 0.750000 +vt 0.292969 0.750000 +vt 0.289062 0.625000 +vt 0.292969 0.625000 +vt 0.289062 0.500000 +vt 0.292969 0.500000 +vt 0.296875 0.750000 +vt 0.304688 0.750000 +vt 0.304688 0.875000 +vt 0.296875 0.875000 +vt 0.289062 0.375000 +vt 0.292969 0.375000 +vt 0.289062 0.250000 +vt 0.292969 0.250000 +vt 0.296875 0.625000 +vt 0.304688 0.625000 +vt 0.289062 0.125000 +vt 0.292969 0.125000 +vt 0.296875 0.500000 +vt 0.304688 0.500000 +vt 0.289062 0.000000 +vt 0.292969 0.000000 +vt 0.296875 0.375000 +vt 0.304688 0.375000 +vt 0.304688 1.000000 +vt 0.296875 1.000000 +vt 0.296875 0.250000 +vt 0.304688 0.250000 +vt 0.398438 0.750000 +vt 0.398438 0.875000 +vt 0.394531 0.875000 +vt 0.394531 0.750000 +vt 0.398438 0.625000 +vt 0.394531 0.625000 +vt 0.398438 0.500000 +vt 0.394531 0.500000 +vt 0.398438 0.375000 +vt 0.394531 0.375000 +vt 0.398438 0.250000 +vt 0.394531 0.250000 +vt 0.410156 0.500000 +vt 0.410156 0.625000 +vt 0.402344 0.625000 +vt 0.402344 0.500000 +vt 0.398438 0.125000 +vt 0.394531 0.125000 +vt 0.398438 0.000000 +vt 0.394531 0.000000 +vt 0.410156 0.375000 +vt 0.402344 0.375000 +vt 0.410156 0.875000 +vt 0.410156 1.000000 +vt 0.402344 1.000000 +vt 0.402344 0.875000 +vt 0.410156 0.250000 +vt 0.402344 0.250000 +vt 0.410156 0.750000 +vt 0.402344 0.750000 +vt 0.410156 0.125000 +vt 0.402344 0.125000 +vt 0.410156 0.000000 +vt 0.402344 0.000000 +vt 0.398438 1.000000 +vt 0.394531 1.000000 +vt 0.421875 0.000000 +vt 0.429688 0.000000 +vt 0.429688 0.125000 +vt 0.421875 0.125000 +vt 0.414062 0.875000 +vt 0.417969 0.875000 +vt 0.417969 1.000000 +vt 0.414062 1.000000 +vt 0.414062 0.750000 +vt 0.417969 0.750000 +vt 0.414062 0.625000 +vt 0.417969 0.625000 +vt 0.414062 0.500000 +vt 0.417969 0.500000 +vt 0.421875 0.750000 +vt 0.429688 0.750000 +vt 0.429688 0.875000 +vt 0.421875 0.875000 +vt 0.414062 0.375000 +vt 0.417969 0.375000 +vt 0.414062 0.250000 +vt 0.417969 0.250000 +vt 0.421875 0.625000 +vt 0.429688 0.625000 +vt 0.414062 0.125000 +vt 0.417969 0.125000 +vt 0.421875 0.500000 +vt 0.429688 0.500000 +vt 0.414062 0.000000 +vt 0.417969 0.000000 +vt 0.421875 0.375000 +vt 0.429688 0.375000 +vt 0.429688 1.000000 +vt 0.421875 1.000000 +vt 0.421875 0.250000 +vt 0.429688 0.250000 +vt 0.523438 0.750000 +vt 0.523438 0.875000 +vt 0.519531 0.875000 +vt 0.519531 0.750000 +vt 0.523438 0.625000 +vt 0.519531 0.625000 +vt 0.523438 0.500000 +vt 0.519531 0.500000 +vt 0.523438 0.375000 +vt 0.519531 0.375000 +vt 0.523438 0.250000 +vt 0.519531 0.250000 +vt 0.535156 0.500000 +vt 0.535156 0.625000 +vt 0.527344 0.625000 +vt 0.527344 0.500000 +vt 0.523438 0.125000 +vt 0.519531 0.125000 +vt 0.523438 0.000000 +vt 0.519531 0.000000 +vt 0.535156 0.375000 +vt 0.527344 0.375000 +vt 0.535156 0.875000 +vt 0.535156 1.000000 +vt 0.527344 1.000000 +vt 0.527344 0.875000 +vt 0.535156 0.250000 +vt 0.527344 0.250000 +vt 0.535156 0.750000 +vt 0.527344 0.750000 +vt 0.535156 0.125000 +vt 0.527344 0.125000 +vt 0.535156 0.000000 +vt 0.527344 0.000000 +vt 0.523438 1.000000 +vt 0.519531 1.000000 +vt 0.546875 0.000000 +vt 0.554688 0.000000 +vt 0.554688 0.125000 +vt 0.546875 0.125000 +vt 0.539062 0.875000 +vt 0.542969 0.875000 +vt 0.542969 1.000000 +vt 0.539062 1.000000 +vt 0.539062 0.750000 +vt 0.542969 0.750000 +vt 0.539062 0.625000 +vt 0.542969 0.625000 +vt 0.539062 0.500000 +vt 0.542969 0.500000 +vt 0.546875 0.750000 +vt 0.554688 0.750000 +vt 0.554688 0.875000 +vt 0.546875 0.875000 +vt 0.539062 0.375000 +vt 0.542969 0.375000 +vt 0.539062 0.250000 +vt 0.542969 0.250000 +vt 0.546875 0.625000 +vt 0.554688 0.625000 +vt 0.539062 0.125000 +vt 0.542969 0.125000 +vt 0.546875 0.500000 +vt 0.554688 0.500000 +vt 0.539062 0.000000 +vt 0.542969 0.000000 +vt 0.546875 0.375000 +vt 0.554688 0.375000 +vt 0.554688 1.000000 +vt 0.546875 1.000000 +vt 0.546875 0.250000 +vt 0.554688 0.250000 +vt 0.648438 0.750000 +vt 0.648438 0.875000 +vt 0.644531 0.875000 +vt 0.644531 0.750000 +vt 0.648438 0.625000 +vt 0.644531 0.625000 +vt 0.648438 0.500000 +vt 0.644531 0.500000 +vt 0.648438 0.375000 +vt 0.644531 0.375000 +vt 0.648438 0.250000 +vt 0.644531 0.250000 +vt 0.660156 0.500000 +vt 0.660156 0.625000 +vt 0.652344 0.625000 +vt 0.652344 0.500000 +vt 0.648438 0.125000 +vt 0.644531 0.125000 +vt 0.648438 0.000000 +vt 0.644531 0.000000 +vt 0.660156 0.375000 +vt 0.652344 0.375000 +vt 0.660156 0.875000 +vt 0.660156 1.000000 +vt 0.652344 1.000000 +vt 0.652344 0.875000 +vt 0.660156 0.250000 +vt 0.652344 0.250000 +vt 0.660156 0.750000 +vt 0.652344 0.750000 +vt 0.660156 0.125000 +vt 0.652344 0.125000 +vt 0.660156 0.000000 +vt 0.652344 0.000000 +vt 0.648438 1.000000 +vt 0.644531 1.000000 +vt 0.671875 0.000000 +vt 0.679688 0.000000 +vt 0.679688 0.125000 +vt 0.671875 0.125000 +vt 0.664062 0.875000 +vt 0.667969 0.875000 +vt 0.667969 1.000000 +vt 0.664062 1.000000 +vt 0.664062 0.750000 +vt 0.667969 0.750000 +vt 0.664062 0.625000 +vt 0.667969 0.625000 +vt 0.664062 0.500000 +vt 0.667969 0.500000 +vt 0.671875 0.750000 +vt 0.679688 0.750000 +vt 0.679688 0.875000 +vt 0.671875 0.875000 +vt 0.664062 0.375000 +vt 0.667969 0.375000 +vt 0.664062 0.250000 +vt 0.667969 0.250000 +vt 0.671875 0.625000 +vt 0.679688 0.625000 +vt 0.664062 0.125000 +vt 0.667969 0.125000 +vt 0.671875 0.500000 +vt 0.679688 0.500000 +vt 0.664062 0.000000 +vt 0.667969 0.000000 +vt 0.671875 0.375000 +vt 0.679688 0.375000 +vt 0.679688 1.000000 +vt 0.671875 1.000000 +vt 0.671875 0.250000 +vt 0.679688 0.250000 +vt 0.773438 0.750000 +vt 0.773438 0.875000 +vt 0.769531 0.875000 +vt 0.769531 0.750000 +vt 0.773438 0.625000 +vt 0.769531 0.625000 +vt 0.773438 0.500000 +vt 0.769531 0.500000 +vt 0.773438 0.375000 +vt 0.769531 0.375000 +vt 0.773438 0.250000 +vt 0.769531 0.250000 +vt 0.785156 0.500000 +vt 0.785156 0.625000 +vt 0.777344 0.625000 +vt 0.777344 0.500000 +vt 0.773438 0.125000 +vt 0.769531 0.125000 +vt 0.773438 0.000000 +vt 0.769531 0.000000 +vt 0.785156 0.375000 +vt 0.777344 0.375000 +vt 0.785156 0.875000 +vt 0.785156 1.000000 +vt 0.777344 1.000000 +vt 0.777344 0.875000 +vt 0.785156 0.250000 +vt 0.777344 0.250000 +vt 0.785156 0.750000 +vt 0.777344 0.750000 +vt 0.785156 0.125000 +vt 0.777344 0.125000 +vt 0.785156 0.000000 +vt 0.777344 0.000000 +vt 0.773438 1.000000 +vt 0.769531 1.000000 +vt 0.796875 0.000000 +vt 0.804688 0.000000 +vt 0.804688 0.125000 +vt 0.796875 0.125000 +vt 0.789062 0.875000 +vt 0.792969 0.875000 +vt 0.792969 1.000000 +vt 0.789062 1.000000 +vt 0.789062 0.750000 +vt 0.792969 0.750000 +vt 0.789062 0.625000 +vt 0.792969 0.625000 +vt 0.789062 0.500000 +vt 0.792969 0.500000 +vt 0.796875 0.750000 +vt 0.804688 0.750000 +vt 0.804688 0.875000 +vt 0.796875 0.875000 +vt 0.789062 0.375000 +vt 0.792969 0.375000 +vt 0.789062 0.250000 +vt 0.792969 0.250000 +vt 0.796875 0.625000 +vt 0.804688 0.625000 +vt 0.789062 0.125000 +vt 0.792969 0.125000 +vt 0.796875 0.500000 +vt 0.804688 0.500000 +vt 0.789062 0.000000 +vt 0.792969 0.000000 +vt 0.796875 0.375000 +vt 0.804688 0.375000 +vt 0.804688 1.000000 +vt 0.796875 1.000000 +vt 0.796875 0.250000 +vt 0.804688 0.250000 +vt 0.898438 0.750000 +vt 0.898438 0.875000 +vt 0.894531 0.875000 +vt 0.894531 0.750000 +vt 0.898438 0.625000 +vt 0.894531 0.625000 +vt 0.898438 0.500000 +vt 0.894531 0.500000 +vt 0.898438 0.375000 +vt 0.894531 0.375000 +vt 0.898438 0.250000 +vt 0.894531 0.250000 +vt 0.910156 0.500000 +vt 0.910156 0.625000 +vt 0.902344 0.625000 +vt 0.902344 0.500000 +vt 0.898438 0.125000 +vt 0.894531 0.125000 +vt 0.898438 0.000000 +vt 0.894531 0.000000 +vt 0.910156 0.375000 +vt 0.902344 0.375000 +vt 0.910156 0.875000 +vt 0.910156 1.000000 +vt 0.902344 1.000000 +vt 0.902344 0.875000 +vt 0.910156 0.250000 +vt 0.902344 0.250000 +vt 0.910156 0.750000 +vt 0.902344 0.750000 +vt 0.910156 0.125000 +vt 0.902344 0.125000 +vt 0.910156 0.000000 +vt 0.902344 0.000000 +vt 0.898438 1.000000 +vt 0.894531 1.000000 +vt 0.921875 0.000000 +vt 0.929688 0.000000 +vt 0.929688 0.125000 +vt 0.921875 0.125000 +vt 0.914062 0.875000 +vt 0.917969 0.875000 +vt 0.917969 1.000000 +vt 0.914062 1.000000 +vt 0.914062 0.750000 +vt 0.917969 0.750000 +vt 0.914062 0.625000 +vt 0.917969 0.625000 +vt 0.914062 0.500000 +vt 0.917969 0.500000 +vt 0.921875 0.750000 +vt 0.929688 0.750000 +vt 0.929688 0.875000 +vt 0.921875 0.875000 +vt 0.914062 0.375000 +vt 0.917969 0.375000 +vt 0.914062 0.250000 +vt 0.917969 0.250000 +vt 0.921875 0.625000 +vt 0.929688 0.625000 +vt 0.914062 0.125000 +vt 0.917969 0.125000 +vt 0.921875 0.500000 +vt 0.929688 0.500000 +vt 0.914062 0.000000 +vt 0.917969 0.000000 +vt 0.921875 0.375000 +vt 0.929688 0.375000 +vt 0.929688 1.000000 +vt 0.921875 1.000000 +vt 0.921875 0.250000 +vt 0.929688 0.250000 +vn 1.000000 0.000000 0.000000 +vn 0.000000 0.000000 1.000000 +vn -1.000000 0.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.382700 0.000000 -0.923900 +vn 0.923900 0.000000 -0.382700 +vn 0.923900 0.000000 0.382700 +vn 0.382700 0.000000 0.923900 +vn -0.382700 0.000000 0.923900 +vn -0.923900 0.000000 0.382700 +vn -0.382700 0.000000 -0.923900 +vn -0.923900 0.000000 -0.382700 +vn 0.707100 0.000000 0.707100 +vn -0.707100 0.000000 0.707100 +vn 0.707100 0.000000 -0.707100 +vn -0.707100 0.000000 -0.707100 +vn 0.152100 0.000000 -0.988400 +vn -0.152100 0.000000 0.988400 +vn -0.988400 0.000000 -0.152100 +vn 0.806400 0.000000 -0.591300 +vn -0.806400 0.000000 0.591300 +vn -0.591300 0.000000 -0.806400 +vn 0.988400 0.000000 0.152100 +vn 0.591300 0.000000 0.806400 +vn 0.342000 0.000000 -0.939700 +vn -0.342000 0.000000 0.939700 +vn -0.939700 0.000000 -0.342000 +vn 0.906300 0.000000 -0.422600 +vn -0.906300 0.000000 0.422600 +vn -0.422600 0.000000 -0.906300 +vn 0.939700 0.000000 0.342000 +vn 0.422600 0.000000 0.906300 +vn 0.518800 0.000000 -0.854900 +vn -0.518800 0.000000 0.854900 +vn -0.854900 0.000000 -0.518800 +vn 0.971300 0.000000 -0.237700 +vn -0.971300 0.000000 0.237700 +vn -0.237700 0.000000 -0.971300 +vn 0.854900 0.000000 0.518800 +vn 0.237700 0.000000 0.971300 +vn 0.675600 0.000000 -0.737300 +vn -0.675600 0.000000 0.737300 +vn -0.737300 0.000000 -0.675600 +vn 0.999000 0.000000 -0.043600 +vn -0.999000 0.000000 0.043600 +vn -0.043600 0.000000 -0.999000 +vn 0.737300 0.000000 0.675600 +vn 0.043600 0.000000 0.999000 +vn 0.555600 0.000000 0.831500 +vn 0.195100 0.000000 0.980800 +vn -0.195100 0.000000 0.980800 +vn -0.555600 0.000000 0.831500 +vn -0.831500 0.000000 0.555600 +vn 0.195100 0.000000 -0.980800 +vn -0.980800 0.000000 0.195100 +vn -0.980800 0.000000 -0.195100 +vn 0.555600 0.000000 -0.831500 +vn -0.831500 0.000000 -0.555600 +vn 0.831500 0.000000 -0.555600 +vn -0.555600 0.000000 -0.831500 +vn 0.980800 0.000000 -0.195100 +vn -0.195100 0.000000 -0.980800 +vn 0.980800 0.000000 0.195100 +vn 0.831500 0.000000 0.555600 +g Cylinder.002_Cylinder.003_sides +s off +f 105/1/1 109/2/1 110/3/1 106/4/1 +f 106/1/2 110/2/2 111/3/2 107/4/2 +f 107/4/3 111/3/3 112/2/3 108/1/3 +f 109/2/4 105/1/4 108/4/4 112/3/4 +g Cylinder.002_Cylinder.003_top-bottom +f 105/2/5 106/1/5 107/4/5 108/3/5 +f 109/2/6 112/3/6 111/4/6 110/1/6 +g Cylinder.002_Cylinder.003_turbine-top-bottom +f 74/5/5 73/6/5 88/7/5 87/8/5 86/9/5 85/10/5 84/11/5 83/12/5 82/13/5 81/14/5 80/15/5 79/16/5 78/17/5 77/18/5 76/19/5 75/20/5 +f 18/5/5 17/6/5 32/7/5 31/8/5 30/9/5 29/10/5 28/11/5 27/12/5 26/13/5 25/14/5 24/15/5 23/16/5 22/17/5 21/18/5 20/19/5 19/20/5 +f 33/6/6 34/5/6 35/20/6 36/19/6 37/18/6 38/17/6 39/16/6 40/15/6 41/14/6 42/13/6 43/12/6 44/11/6 45/10/6 46/9/6 47/8/6 48/7/6 +f 57/6/6 58/5/6 59/20/6 60/19/6 61/18/6 62/17/6 63/16/6 64/15/6 65/14/6 66/13/6 67/12/6 68/11/6 69/10/6 70/9/6 71/8/6 72/7/6 +f 410/21/5 409/22/5 424/23/5 423/24/5 422/25/5 421/26/5 420/27/5 419/28/5 418/29/5 417/30/5 416/31/5 415/32/5 414/10/5 413/9/5 412/33/5 411/34/5 +f 362/21/5 361/22/5 376/23/5 375/24/5 374/25/5 373/26/5 372/27/5 371/28/5 370/29/5 369/30/5 368/31/5 367/32/5 366/10/5 365/9/5 364/33/5 363/34/5 +f 377/22/6 378/21/6 379/34/6 380/33/6 381/9/6 382/10/6 383/32/6 384/31/6 385/30/6 386/29/6 387/28/6 388/27/6 389/26/6 390/25/6 391/24/6 392/23/6 +f 393/22/6 394/21/6 395/34/6 396/33/6 397/9/6 398/10/6 399/32/6 400/31/6 401/30/6 402/29/6 403/28/6 404/27/6 405/26/6 406/25/6 407/24/6 408/23/6 +f 474/35/5 473/36/5 488/37/5 487/38/5 486/39/5 485/40/5 484/41/5 483/42/5 482/43/5 481/44/5 480/45/5 479/46/5 478/26/5 477/25/5 476/47/5 475/48/5 +f 426/35/5 425/36/5 440/37/5 439/38/5 438/39/5 437/40/5 436/41/5 435/42/5 434/43/5 433/44/5 432/45/5 431/46/5 430/26/5 429/25/5 428/47/5 427/48/5 +f 441/36/6 442/35/6 443/48/6 444/47/6 445/25/6 446/26/6 447/46/6 448/45/6 449/44/6 450/43/6 451/42/6 452/41/6 453/40/6 454/39/6 455/38/6 456/37/6 +f 457/36/6 458/35/6 459/48/6 460/47/6 461/25/6 462/26/6 463/46/6 464/45/6 465/44/6 466/43/6 467/42/6 468/41/6 469/40/6 470/39/6 471/38/6 472/37/6 +f 538/49/5 537/50/5 552/51/5 551/52/5 550/53/5 549/54/5 548/55/5 547/56/5 546/57/5 545/58/5 544/59/5 543/60/5 542/40/5 541/39/5 540/61/5 539/62/5 +f 490/49/5 489/50/5 504/51/5 503/52/5 502/53/5 501/54/5 500/55/5 499/56/5 498/57/5 497/58/5 496/59/5 495/60/5 494/40/5 493/39/5 492/61/5 491/62/5 +f 505/50/6 506/49/6 507/62/6 508/61/6 509/39/6 510/40/6 511/60/6 512/59/6 513/58/6 514/57/6 515/56/6 516/55/6 517/54/6 518/53/6 519/52/6 520/51/6 +f 521/50/6 522/49/6 523/62/6 524/61/6 525/39/6 526/40/6 527/60/6 528/59/6 529/58/6 530/57/6 531/56/6 532/55/6 533/54/6 534/53/6 535/52/6 536/51/6 +f 602/63/5 601/64/5 616/65/5 615/66/5 614/67/5 613/68/5 612/69/5 611/70/5 610/71/5 609/72/5 608/73/5 607/74/5 606/54/5 605/53/5 604/75/5 603/76/5 +f 554/63/5 553/64/5 568/65/5 567/66/5 566/67/5 565/68/5 564/69/5 563/70/5 562/71/5 561/72/5 560/73/5 559/74/5 558/54/5 557/53/5 556/75/5 555/76/5 +f 569/64/6 570/63/6 571/76/6 572/75/6 573/53/6 574/54/6 575/74/6 576/73/6 577/72/6 578/71/6 579/70/6 580/69/6 581/68/6 582/67/6 583/66/6 584/65/6 +f 585/64/6 586/63/6 587/76/6 588/75/6 589/53/6 590/54/6 591/74/6 592/73/6 593/72/6 594/71/6 595/70/6 596/69/6 597/68/6 598/67/6 599/66/6 600/65/6 +f 666/77/5 665/78/5 680/79/5 679/80/5 678/81/5 677/82/5 676/83/5 675/84/5 674/85/5 673/86/5 672/87/5 671/88/5 670/68/5 669/67/5 668/89/5 667/90/5 +f 618/77/5 617/78/5 632/79/5 631/80/5 630/81/5 629/82/5 628/83/5 627/84/5 626/85/5 625/86/5 624/87/5 623/88/5 622/68/5 621/67/5 620/89/5 619/90/5 +f 633/78/6 634/77/6 635/90/6 636/89/6 637/67/6 638/68/6 639/88/6 640/87/6 641/86/6 642/85/6 643/84/6 644/83/6 645/82/6 646/81/6 647/80/6 648/79/6 +f 649/78/6 650/77/6 651/90/6 652/89/6 653/67/6 654/68/6 655/88/6 656/87/6 657/86/6 658/85/6 659/84/6 660/83/6 661/82/6 662/81/6 663/80/6 664/79/6 +f 730/91/5 729/92/5 744/93/5 743/94/5 742/95/5 741/96/5 740/97/5 739/98/5 738/99/5 737/100/5 736/101/5 735/102/5 734/82/5 733/81/5 732/103/5 731/104/5 +f 682/91/5 681/92/5 696/93/5 695/94/5 694/95/5 693/96/5 692/97/5 691/98/5 690/99/5 689/100/5 688/101/5 687/102/5 686/82/5 685/81/5 684/103/5 683/104/5 +f 697/92/6 698/91/6 699/104/6 700/103/6 701/81/6 702/82/6 703/102/6 704/101/6 705/100/6 706/99/6 707/98/6 708/97/6 709/96/6 710/95/6 711/94/6 712/93/6 +f 713/92/6 714/91/6 715/104/6 716/103/6 717/81/6 718/82/6 719/102/6 720/101/6 721/100/6 722/99/6 723/98/6 724/97/6 725/96/6 726/95/6 727/94/6 728/93/6 +f 794/105/5 793/106/5 808/107/5 807/108/5 806/109/5 805/110/5 804/111/5 803/112/5 802/113/5 801/114/5 800/115/5 799/116/5 798/96/5 797/95/5 796/117/5 795/118/5 +f 746/105/5 745/106/5 760/107/5 759/108/5 758/109/5 757/110/5 756/111/5 755/112/5 754/113/5 753/114/5 752/115/5 751/116/5 750/96/5 749/95/5 748/117/5 747/118/5 +f 761/106/6 762/105/6 763/118/6 764/117/6 765/95/6 766/96/6 767/116/6 768/115/6 769/114/6 770/113/6 771/112/6 772/111/6 773/110/6 774/109/6 775/108/6 776/107/6 +f 777/106/6 778/105/6 779/118/6 780/117/6 781/95/6 782/96/6 783/116/6 784/115/6 785/114/6 786/113/6 787/112/6 788/111/6 789/110/6 790/109/6 791/108/6 792/107/6 +g Cylinder.002_Cylinder.003_turbine-blades-etc +f 1/119/7 2/120/7 4/121/7 3/122/7 +f 3/122/8 4/121/8 6/123/8 5/124/8 +f 5/125/9 6/126/9 8/127/9 7/128/9 +f 7/128/10 8/127/10 10/129/10 9/130/10 +f 9/130/11 10/129/11 12/131/11 11/132/11 +f 11/132/12 12/131/12 14/123/12 13/124/12 +f 4/133/6 2/134/6 16/135/6 14/136/6 12/137/6 10/138/6 8/139/6 6/140/6 +f 15/141/13 16/142/13 2/120/13 1/119/13 +f 13/143/14 14/144/14 16/142/14 15/141/14 +f 27/145/15 28/146/15 44/147/15 43/148/15 +f 26/149/10 27/145/10 43/148/10 42/150/10 +f 25/151/2 26/149/2 42/150/2 41/152/2 +f 24/153/11 25/151/11 41/152/11 40/154/11 +f 23/155/16 24/153/16 40/154/16 39/156/16 +f 17/157/4 18/158/4 34/159/4 33/160/4 +f 22/161/12 23/155/12 39/156/12 38/162/12 +f 21/163/3 22/161/3 38/162/3 37/164/3 +f 32/165/7 17/157/7 33/160/7 48/166/7 +f 20/167/14 21/168/14 37/169/14 36/170/14 +f 31/171/17 32/165/17 48/166/17 47/172/17 +f 19/173/18 20/167/18 36/170/18 35/174/18 +f 30/175/8 31/171/8 47/172/8 46/176/8 +f 18/158/13 19/173/13 35/174/13 34/159/13 +f 29/177/1 30/175/1 46/176/1 45/178/1 +f 28/146/9 29/179/9 45/180/9 44/147/9 +f 52/181/19 51/182/19 50/183/19 49/184/19 +f 53/185/20 54/186/20 55/187/20 56/188/20 +f 51/182/21 52/181/21 53/185/21 56/188/21 +f 67/189/15 83/190/15 84/191/15 68/192/15 +f 66/193/10 82/194/10 83/195/10 67/196/10 +f 65/197/2 81/198/2 82/194/2 66/193/2 +f 64/199/11 80/200/11 81/198/11 65/197/11 +f 63/201/16 79/202/16 80/200/16 64/199/16 +f 57/203/4 73/204/4 74/205/4 58/206/4 +f 62/207/12 78/208/12 79/202/12 63/201/12 +f 61/209/3 77/210/3 78/208/3 62/207/3 +f 72/211/7 88/212/7 73/204/7 57/203/7 +f 60/213/14 76/214/14 77/210/14 61/209/14 +f 71/215/17 87/216/17 88/212/17 72/211/17 +f 59/217/18 75/218/18 76/214/18 60/213/18 +f 70/219/8 86/220/8 87/216/8 71/215/8 +f 58/206/13 74/205/13 75/221/13 59/222/13 +f 69/223/1 85/224/1 86/220/1 70/219/1 +f 68/192/9 84/191/9 85/224/9 69/223/9 +f 89/225/17 90/226/17 92/227/17 91/228/17 +f 91/229/1 92/230/1 94/231/1 93/232/1 +f 93/232/15 94/231/15 96/233/15 95/234/15 +f 95/234/2 96/233/2 98/235/2 97/236/2 +f 97/236/16 98/235/16 100/237/16 99/238/16 +f 99/238/3 100/237/3 102/239/3 101/240/3 +f 103/241/4 104/242/4 90/226/4 89/225/4 +f 101/240/18 102/239/18 104/242/18 103/241/18 +f 116/181/22 115/182/22 114/183/22 113/184/22 +f 117/185/23 118/186/23 119/187/23 120/188/23 +f 115/182/24 116/181/24 117/185/24 120/188/24 +f 124/181/25 123/182/25 122/183/25 121/184/25 +f 125/185/21 126/186/21 127/187/21 128/188/21 +f 123/182/19 124/181/19 125/185/19 128/188/19 +f 132/181/26 131/182/26 130/183/26 129/184/26 +f 133/185/24 134/186/24 135/187/24 136/188/24 +f 131/182/22 132/181/22 133/185/22 136/188/22 +f 140/181/20 139/182/20 138/183/20 137/184/20 +f 141/185/19 142/186/19 143/187/19 144/188/19 +f 139/182/25 140/181/25 141/185/25 144/188/25 +f 148/181/23 147/182/23 146/183/23 145/184/23 +f 149/185/22 150/186/22 151/187/22 152/188/22 +f 147/182/26 148/181/26 149/185/26 152/188/26 +f 156/181/21 155/182/21 154/183/21 153/184/21 +f 157/185/25 158/186/25 159/187/25 160/188/25 +f 155/182/20 156/181/20 157/185/20 160/188/20 +f 164/181/24 163/182/24 162/183/24 161/184/24 +f 165/185/26 166/186/26 167/187/26 168/188/26 +f 163/182/23 164/181/23 165/185/23 168/188/23 +f 172/243/27 171/244/27 170/245/27 169/246/27 +f 173/247/28 174/248/28 175/249/28 176/250/28 +f 171/244/29 172/243/29 173/247/29 176/250/29 +f 180/243/30 179/244/30 178/245/30 177/246/30 +f 181/247/31 182/248/31 183/249/31 184/250/31 +f 179/244/32 180/243/32 181/247/32 184/250/32 +f 188/243/33 187/244/33 186/245/33 185/246/33 +f 189/247/29 190/248/29 191/249/29 192/250/29 +f 187/244/27 188/243/27 189/247/27 192/250/27 +f 196/243/34 195/244/34 194/245/34 193/246/34 +f 197/247/32 198/248/32 199/249/32 200/250/32 +f 195/244/30 196/243/30 197/247/30 200/250/30 +f 204/243/28 203/244/28 202/245/28 201/246/28 +f 205/247/27 206/248/27 207/249/27 208/250/27 +f 203/244/33 204/243/33 205/247/33 208/250/33 +f 212/243/31 211/244/31 210/245/31 209/246/31 +f 213/247/30 214/248/30 215/249/30 216/250/30 +f 211/244/34 212/243/34 213/247/34 216/250/34 +f 220/243/29 219/244/29 218/245/29 217/246/29 +f 221/247/33 222/248/33 223/249/33 224/250/33 +f 219/244/28 220/243/28 221/247/28 224/250/28 +f 228/243/32 227/244/32 226/245/32 225/246/32 +f 229/247/34 230/248/34 231/249/34 232/250/34 +f 227/244/31 228/243/31 229/247/31 232/250/31 +f 236/251/35 235/252/35 234/253/35 233/254/35 +f 237/255/36 238/256/36 239/257/36 240/258/36 +f 235/252/37 236/251/37 237/255/37 240/258/37 +f 244/251/38 243/252/38 242/253/38 241/254/38 +f 245/255/39 246/256/39 247/257/39 248/258/39 +f 243/252/40 244/251/40 245/255/40 248/258/40 +f 252/251/41 251/252/41 250/253/41 249/254/41 +f 253/255/37 254/256/37 255/257/37 256/258/37 +f 251/252/35 252/251/35 253/255/35 256/258/35 +f 260/251/42 259/252/42 258/253/42 257/254/42 +f 261/255/40 262/256/40 263/257/40 264/258/40 +f 259/252/38 260/251/38 261/255/38 264/258/38 +f 268/251/36 267/252/36 266/253/36 265/254/36 +f 269/255/35 270/256/35 271/257/35 272/258/35 +f 267/252/41 268/251/41 269/255/41 272/258/41 +f 276/251/39 275/252/39 274/253/39 273/254/39 +f 277/255/38 278/256/38 279/257/38 280/258/38 +f 275/252/42 276/251/42 277/255/42 280/258/42 +f 284/251/37 283/252/37 282/253/37 281/254/37 +f 285/255/41 286/256/41 287/257/41 288/258/41 +f 283/252/36 284/251/36 285/255/36 288/258/36 +f 292/251/40 291/252/40 290/253/40 289/254/40 +f 293/255/42 294/256/42 295/257/42 296/258/42 +f 291/252/39 292/251/39 293/255/39 296/258/39 +f 300/259/43 299/260/43 298/261/43 297/262/43 +f 301/263/44 302/264/44 303/265/44 304/266/44 +f 299/260/45 300/259/45 301/263/45 304/266/45 +f 308/259/46 307/260/46 306/261/46 305/262/46 +f 309/263/47 310/264/47 311/265/47 312/266/47 +f 307/260/48 308/259/48 309/263/48 312/266/48 +f 316/259/49 315/260/49 314/261/49 313/262/49 +f 317/263/45 318/264/45 319/265/45 320/266/45 +f 315/260/43 316/259/43 317/263/43 320/266/43 +f 324/259/50 323/260/50 322/261/50 321/262/50 +f 325/263/48 326/264/48 327/265/48 328/266/48 +f 323/260/46 324/259/46 325/263/46 328/266/46 +f 332/259/44 331/260/44 330/261/44 329/262/44 +f 333/263/43 334/264/43 335/265/43 336/266/43 +f 331/260/49 332/259/49 333/263/49 336/266/49 +f 340/259/47 339/260/47 338/261/47 337/262/47 +f 341/263/46 342/264/46 343/265/46 344/266/46 +f 339/260/50 340/259/50 341/263/50 344/266/50 +f 348/259/45 347/260/45 346/261/45 345/262/45 +f 349/263/49 350/264/49 351/265/49 352/266/49 +f 347/260/44 348/259/44 349/263/44 352/266/44 +f 356/259/48 355/260/48 354/261/48 353/262/48 +f 357/263/50 358/264/50 359/265/50 360/266/50 +f 355/260/47 356/259/47 357/263/47 360/266/47 +f 371/267/51 372/268/51 388/269/51 387/270/51 +f 370/271/52 371/267/52 387/270/52 386/272/52 +f 369/273/53 370/271/53 386/272/53 385/274/53 +f 368/275/54 369/273/54 385/274/54 384/276/54 +f 367/277/55 368/275/55 384/276/55 383/278/55 +f 361/279/56 362/280/56 378/281/56 377/282/56 +f 366/283/57 367/277/57 383/278/57 382/284/57 +f 365/285/58 366/283/58 382/284/58 381/286/58 +f 376/287/59 361/279/59 377/282/59 392/288/59 +f 364/289/60 365/290/60 381/291/60 380/292/60 +f 375/293/61 376/287/61 392/288/61 391/294/61 +f 363/295/62 364/289/62 380/292/62 379/296/62 +f 374/297/63 375/293/63 391/294/63 390/298/63 +f 362/280/64 363/295/64 379/296/64 378/281/64 +f 373/299/65 374/297/65 390/298/65 389/300/65 +f 372/268/66 373/301/66 389/302/66 388/269/66 +f 403/303/51 419/304/51 420/305/51 404/306/51 +f 402/307/52 418/308/52 419/309/52 403/310/52 +f 401/311/53 417/312/53 418/308/53 402/307/53 +f 400/313/54 416/314/54 417/312/54 401/311/54 +f 399/315/55 415/316/55 416/314/55 400/313/55 +f 393/317/56 409/318/56 410/319/56 394/320/56 +f 398/321/57 414/322/57 415/316/57 399/315/57 +f 397/323/58 413/324/58 414/322/58 398/321/58 +f 408/325/59 424/326/59 409/318/59 393/317/59 +f 396/327/60 412/328/60 413/324/60 397/323/60 +f 407/329/61 423/330/61 424/326/61 408/325/61 +f 395/331/62 411/332/62 412/328/62 396/327/62 +f 406/333/63 422/334/63 423/330/63 407/329/63 +f 394/320/64 410/319/64 411/335/64 395/336/64 +f 405/337/65 421/338/65 422/334/65 406/333/65 +f 404/306/66 420/305/66 421/338/66 405/337/66 +f 435/339/10 436/340/10 452/341/10 451/342/10 +f 434/343/2 435/339/2 451/342/2 450/344/2 +f 433/345/11 434/343/11 450/344/11 449/346/11 +f 432/347/16 433/345/16 449/346/16 448/348/16 +f 431/349/12 432/347/12 448/348/12 447/350/12 +f 425/351/7 426/352/7 442/353/7 441/354/7 +f 430/355/3 431/349/3 447/350/3 446/356/3 +f 429/357/14 430/355/14 446/356/14 445/358/14 +f 440/359/17 425/351/17 441/354/17 456/360/17 +f 428/361/18 429/362/18 445/363/18 444/364/18 +f 439/365/8 440/359/8 456/360/8 455/366/8 +f 427/367/13 428/361/13 444/364/13 443/368/13 +f 438/369/1 439/365/1 455/366/1 454/370/1 +f 426/352/4 427/367/4 443/368/4 442/353/4 +f 437/371/9 438/369/9 454/370/9 453/372/9 +f 436/340/15 437/373/15 453/374/15 452/341/15 +f 467/375/10 483/376/10 484/377/10 468/378/10 +f 466/379/2 482/380/2 483/381/2 467/382/2 +f 465/383/11 481/384/11 482/380/11 466/379/11 +f 464/385/16 480/386/16 481/384/16 465/383/16 +f 463/387/12 479/388/12 480/386/12 464/385/12 +f 457/389/7 473/390/7 474/391/7 458/392/7 +f 462/393/3 478/394/3 479/388/3 463/387/3 +f 461/395/14 477/396/14 478/394/14 462/393/14 +f 472/397/17 488/398/17 473/390/17 457/389/17 +f 460/399/18 476/400/18 477/396/18 461/395/18 +f 471/401/8 487/402/8 488/398/8 472/397/8 +f 459/403/13 475/404/13 476/400/13 460/399/13 +f 470/405/1 486/406/1 487/402/1 471/401/1 +f 458/392/4 474/391/4 475/407/4 459/408/4 +f 469/409/9 485/410/9 486/406/9 470/405/9 +f 468/378/15 484/377/15 485/410/15 469/409/15 +f 499/411/52 500/412/52 516/413/52 515/414/52 +f 498/415/53 499/411/53 515/414/53 514/416/53 +f 497/417/54 498/415/54 514/416/54 513/418/54 +f 496/419/55 497/417/55 513/418/55 512/420/55 +f 495/421/57 496/419/57 512/420/57 511/422/57 +f 489/423/59 490/424/59 506/425/59 505/426/59 +f 494/427/58 495/421/58 511/422/58 510/428/58 +f 493/429/60 494/427/60 510/428/60 509/430/60 +f 504/431/61 489/423/61 505/426/61 520/432/61 +f 492/433/62 493/434/62 509/435/62 508/436/62 +f 503/437/63 504/431/63 520/432/63 519/438/63 +f 491/439/64 492/433/64 508/436/64 507/440/64 +f 502/441/65 503/437/65 519/438/65 518/442/65 +f 490/424/56 491/439/56 507/440/56 506/425/56 +f 501/443/66 502/441/66 518/442/66 517/444/66 +f 500/412/51 501/445/51 517/446/51 516/413/51 +f 531/447/52 547/448/52 548/449/52 532/450/52 +f 530/451/53 546/452/53 547/453/53 531/454/53 +f 529/455/54 545/456/54 546/452/54 530/451/54 +f 528/457/55 544/458/55 545/456/55 529/455/55 +f 527/459/57 543/460/57 544/458/57 528/457/57 +f 521/461/59 537/462/59 538/463/59 522/464/59 +f 526/465/58 542/466/58 543/460/58 527/459/58 +f 525/467/60 541/468/60 542/466/60 526/465/60 +f 536/469/61 552/470/61 537/462/61 521/461/61 +f 524/471/62 540/472/62 541/468/62 525/467/62 +f 535/473/63 551/474/63 552/470/63 536/469/63 +f 523/475/64 539/476/64 540/472/64 524/471/64 +f 534/477/65 550/478/65 551/474/65 535/473/65 +f 522/464/56 538/463/56 539/479/56 523/480/56 +f 533/481/66 549/482/66 550/478/66 534/477/66 +f 532/450/51 548/449/51 549/482/51 533/481/51 +f 563/483/2 564/484/2 580/485/2 579/486/2 +f 562/487/11 563/483/11 579/486/11 578/488/11 +f 561/489/16 562/487/16 578/488/16 577/490/16 +f 560/491/12 561/489/12 577/490/12 576/492/12 +f 559/493/3 560/491/3 576/492/3 575/494/3 +f 553/495/17 554/496/17 570/497/17 569/498/17 +f 558/499/14 559/493/14 575/494/14 574/500/14 +f 557/501/18 558/499/18 574/500/18 573/502/18 +f 568/503/8 553/495/8 569/498/8 584/504/8 +f 556/505/13 557/506/13 573/507/13 572/508/13 +f 567/509/1 568/503/1 584/504/1 583/510/1 +f 555/511/4 556/505/4 572/508/4 571/512/4 +f 566/513/9 567/509/9 583/510/9 582/514/9 +f 554/496/7 555/511/7 571/512/7 570/497/7 +f 565/515/15 566/513/15 582/514/15 581/516/15 +f 564/484/10 565/517/10 581/518/10 580/485/10 +f 595/519/2 611/520/2 612/521/2 596/522/2 +f 594/523/11 610/524/11 611/525/11 595/526/11 +f 593/527/16 609/528/16 610/524/16 594/523/16 +f 592/529/12 608/530/12 609/528/12 593/527/12 +f 591/531/3 607/532/3 608/530/3 592/529/3 +f 585/533/17 601/534/17 602/535/17 586/536/17 +f 590/537/14 606/538/14 607/532/14 591/531/14 +f 589/539/18 605/540/18 606/538/18 590/537/18 +f 600/541/8 616/542/8 601/534/8 585/533/8 +f 588/543/13 604/544/13 605/540/13 589/539/13 +f 599/545/1 615/546/1 616/542/1 600/541/1 +f 587/547/4 603/548/4 604/544/4 588/543/4 +f 598/549/9 614/550/9 615/546/9 599/545/9 +f 586/536/7 602/535/7 603/551/7 587/552/7 +f 597/553/15 613/554/15 614/550/15 598/549/15 +f 596/522/10 612/521/10 613/554/10 597/553/10 +f 627/555/53 628/556/53 644/557/53 643/558/53 +f 626/559/54 627/555/54 643/558/54 642/560/54 +f 625/561/55 626/559/55 642/560/55 641/562/55 +f 624/563/57 625/561/57 641/562/57 640/564/57 +f 623/565/58 624/563/58 640/564/58 639/566/58 +f 617/567/61 618/568/61 634/569/61 633/570/61 +f 622/571/60 623/565/60 639/566/60 638/572/60 +f 621/573/62 622/571/62 638/572/62 637/574/62 +f 632/575/63 617/567/63 633/570/63 648/576/63 +f 620/577/64 621/578/64 637/579/64 636/580/64 +f 631/581/65 632/575/65 648/576/65 647/582/65 +f 619/583/56 620/577/56 636/580/56 635/584/56 +f 630/585/66 631/581/66 647/582/66 646/586/66 +f 618/568/59 619/583/59 635/584/59 634/569/59 +f 629/587/51 630/585/51 646/586/51 645/588/51 +f 628/556/52 629/589/52 645/590/52 644/557/52 +f 659/591/53 675/592/53 676/593/53 660/594/53 +f 658/595/54 674/596/54 675/597/54 659/598/54 +f 657/599/55 673/600/55 674/596/55 658/595/55 +f 656/601/57 672/602/57 673/600/57 657/599/57 +f 655/603/58 671/604/58 672/602/58 656/601/58 +f 649/605/61 665/606/61 666/607/61 650/608/61 +f 654/609/60 670/610/60 671/604/60 655/603/60 +f 653/611/62 669/612/62 670/610/62 654/609/62 +f 664/613/63 680/614/63 665/606/63 649/605/63 +f 652/615/64 668/616/64 669/612/64 653/611/64 +f 663/617/65 679/618/65 680/614/65 664/613/65 +f 651/619/56 667/620/56 668/616/56 652/615/56 +f 662/621/66 678/622/66 679/618/66 663/617/66 +f 650/608/59 666/607/59 667/623/59 651/624/59 +f 661/625/51 677/626/51 678/622/51 662/621/51 +f 660/594/52 676/593/52 677/626/52 661/625/52 +f 691/627/11 692/628/11 708/629/11 707/630/11 +f 690/631/16 691/627/16 707/630/16 706/632/16 +f 689/633/12 690/631/12 706/632/12 705/634/12 +f 688/635/3 689/633/3 705/634/3 704/636/3 +f 687/637/14 688/635/14 704/636/14 703/638/14 +f 681/639/8 682/640/8 698/641/8 697/642/8 +f 686/643/18 687/637/18 703/638/18 702/644/18 +f 685/645/13 686/643/13 702/644/13 701/646/13 +f 696/647/1 681/639/1 697/642/1 712/648/1 +f 684/649/4 685/650/4 701/651/4 700/652/4 +f 695/653/9 696/647/9 712/648/9 711/654/9 +f 683/655/7 684/649/7 700/652/7 699/656/7 +f 694/657/15 695/653/15 711/654/15 710/658/15 +f 682/640/17 683/655/17 699/656/17 698/641/17 +f 693/659/10 694/657/10 710/658/10 709/660/10 +f 692/628/2 693/661/2 709/662/2 708/629/2 +f 723/663/11 739/664/11 740/665/11 724/666/11 +f 722/667/16 738/668/16 739/669/16 723/670/16 +f 721/671/12 737/672/12 738/668/12 722/667/12 +f 720/673/3 736/674/3 737/672/3 721/671/3 +f 719/675/14 735/676/14 736/674/14 720/673/14 +f 713/677/8 729/678/8 730/679/8 714/680/8 +f 718/681/18 734/682/18 735/676/18 719/675/18 +f 717/683/13 733/684/13 734/682/13 718/681/13 +f 728/685/1 744/686/1 729/678/1 713/677/1 +f 716/687/4 732/688/4 733/684/4 717/683/4 +f 727/689/9 743/690/9 744/686/9 728/685/9 +f 715/691/7 731/692/7 732/688/7 716/687/7 +f 726/693/15 742/694/15 743/690/15 727/689/15 +f 714/680/17 730/679/17 731/695/17 715/696/17 +f 725/697/10 741/698/10 742/694/10 726/693/10 +f 724/666/2 740/665/2 741/698/2 725/697/2 +f 755/699/54 756/700/54 772/701/54 771/702/54 +f 754/703/55 755/699/55 771/702/55 770/704/55 +f 753/705/57 754/703/57 770/704/57 769/706/57 +f 752/707/58 753/705/58 769/706/58 768/708/58 +f 751/709/60 752/707/60 768/708/60 767/710/60 +f 745/711/63 746/712/63 762/713/63 761/714/63 +f 750/715/62 751/709/62 767/710/62 766/716/62 +f 749/717/64 750/715/64 766/716/64 765/718/64 +f 760/719/65 745/711/65 761/714/65 776/720/65 +f 748/721/56 749/722/56 765/723/56 764/724/56 +f 759/725/66 760/719/66 776/720/66 775/726/66 +f 747/727/59 748/721/59 764/724/59 763/728/59 +f 758/729/51 759/725/51 775/726/51 774/730/51 +f 746/712/61 747/727/61 763/728/61 762/713/61 +f 757/731/52 758/729/52 774/730/52 773/732/52 +f 756/700/53 757/733/53 773/734/53 772/701/53 +f 787/735/54 803/736/54 804/737/54 788/738/54 +f 786/739/55 802/740/55 803/741/55 787/742/55 +f 785/743/57 801/744/57 802/740/57 786/739/57 +f 784/745/58 800/746/58 801/744/58 785/743/58 +f 783/747/60 799/748/60 800/746/60 784/745/60 +f 777/749/63 793/750/63 794/751/63 778/752/63 +f 782/753/62 798/754/62 799/748/62 783/747/62 +f 781/755/64 797/756/64 798/754/64 782/753/64 +f 792/757/65 808/758/65 793/750/65 777/749/65 +f 780/759/56 796/760/56 797/756/56 781/755/56 +f 791/761/66 807/762/66 808/758/66 792/757/66 +f 779/763/59 795/764/59 796/760/59 780/759/59 +f 790/765/51 806/766/51 807/762/51 791/761/51 +f 778/752/61 794/751/61 795/767/61 779/768/61 +f 789/769/52 805/770/52 806/766/52 790/765/52 +f 788/738/53 804/737/53 805/770/53 789/769/53 diff --git a/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_inv.png b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_inv.png new file mode 100644 index 00000000..7453d610 Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_inv.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_sides_off.png b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_sides_off.png new file mode 100644 index 00000000..6e128340 Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_sides_off.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_sides_on.png b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_sides_on.png new file mode 100644 index 00000000..c8a2f396 Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_sides_on.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_top_bottom.png b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_top_bottom.png new file mode 100644 index 00000000..37d634fa Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_top_bottom.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_misc_off.png b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_misc_off.png new file mode 100644 index 00000000..c6ed54d2 Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_misc_off.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_misc_on.png b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_misc_on.png new file mode 100644 index 00000000..2d6b9fae Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_misc_on.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_top_bottom_off.png b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_top_bottom_off.png new file mode 100644 index 00000000..fa76591f Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_top_bottom_off.png differ diff --git a/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_top_bottom_on.png b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_top_bottom_on.png new file mode 100644 index 00000000..8d93f9d1 Binary files /dev/null and b/mods/mesecons/mesecons_hydroturbine/textures/jeija_hydro_turbine_turbine_top_bottom_on.png differ diff --git a/mods/mesecons/mesecons_insulated/doc/insulated/description.html b/mods/mesecons/mesecons_insulated/doc/insulated/description.html new file mode 100644 index 00000000..deb344dc --- /dev/null +++ b/mods/mesecons/mesecons_insulated/doc/insulated/description.html @@ -0,0 +1 @@ + Insulated mesecons are conductors that only conduct in one direction (and also not up or down). Like uninsulated wires, they work through unloaded blocks. diff --git a/mods/mesecons/mesecons_insulated/doc/insulated/preview.png b/mods/mesecons/mesecons_insulated/doc/insulated/preview.png new file mode 100644 index 00000000..04356d57 Binary files /dev/null and b/mods/mesecons/mesecons_insulated/doc/insulated/preview.png differ diff --git a/mods/mesecons/mesecons_insulated/doc/insulated/recipe.png b/mods/mesecons/mesecons_insulated/doc/insulated/recipe.png new file mode 100644 index 00000000..e2a7f44c Binary files /dev/null and b/mods/mesecons/mesecons_insulated/doc/insulated/recipe.png differ diff --git a/mods/mesecons/mesecons_insulated/init.lua b/mods/mesecons/mesecons_insulated/init.lua new file mode 100644 index 00000000..ef22f11c --- /dev/null +++ b/mods/mesecons/mesecons_insulated/init.lua @@ -0,0 +1,88 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local insulated_wire_get_rules = mesecon.horiz_rules_getter({ + {x = 1, y = 0, z = 0}, + {x = -1, y = 0, z = 0}, +}) + +minetest.register_node("mesecons_insulated:insulated_on", { + drawtype = "nodebox", + description = S("Straight Insulated Mesecon"), + tiles = { + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_ends_on.png", + "jeija_insulated_wire_sides_on.png", + "jeija_insulated_wire_sides_on.png" + }, + paramtype = "light", + paramtype2 = "4dir", + is_ground_content = false, + walkable = false, + sunlight_propagates = true, + selection_box = { + type = "fixed", + fixed = { -16/32, -16/32, -7/32, 16/32, -12/32, 7/32 } + }, + node_box = { + type = "fixed", + -- ±0.001 is to prevent z-fighting + fixed = { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 } + }, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons_insulated:insulated_off", + sounds = mesecon.node_sound.default, + mesecons = {conductor = { + state = mesecon.state.on, + offstate = "mesecons_insulated:insulated_off", + rules = insulated_wire_get_rules + }}, + on_blast = mesecon.on_blastnode, + on_rotate = mesecon.on_rotate, +}) + +minetest.register_node("mesecons_insulated:insulated_off", { + drawtype = "nodebox", + description = S("Straight Insulated Mesecon"), + tiles = { + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_ends_off.png", + "jeija_insulated_wire_sides_off.png", + "jeija_insulated_wire_sides_off.png" + }, + paramtype = "light", + paramtype2 = "4dir", + is_ground_content = false, + walkable = false, + sunlight_propagates = true, + selection_box = { + type = "fixed", + fixed = { -16/32, -16/32, -7/32, 16/32, -12/32, 7/32 } + }, + node_box = { + type = "fixed", + -- ±0.001 is to prevent z-fighting + fixed = { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 } + }, + groups = {dig_immediate = 3}, + sounds = mesecon.node_sound.default, + mesecons = {conductor = { + state = mesecon.state.off, + onstate = "mesecons_insulated:insulated_on", + rules = insulated_wire_get_rules + }}, + on_blast = mesecon.on_blastnode, + on_rotate = mesecon.on_rotate, +}) + +minetest.register_craft({ + output = "mesecons_insulated:insulated_off 3", + recipe = { + {"mesecons_materials:fiber", "mesecons_materials:fiber", "mesecons_materials:fiber"}, + {"group:mesecon_conductor_craftable", "group:mesecon_conductor_craftable", "group:mesecon_conductor_craftable"}, + {"mesecons_materials:fiber", "mesecons_materials:fiber", "mesecons_materials:fiber"}, + } +}) diff --git a/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.de.tr b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.de.tr new file mode 100644 index 00000000..550a1219 --- /dev/null +++ b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_insulated +Straight Insulated Mesecon=Isolierte Mesecongerade diff --git a/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.eo.tr b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.eo.tr new file mode 100644 index 00000000..878908bd --- /dev/null +++ b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_insulated + +### init.lua ### +Straight Insulated Mesecon=Rekta Izolita Mesekonduktilo diff --git a/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.fr.tr b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.fr.tr new file mode 100644 index 00000000..82faee94 --- /dev/null +++ b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_insulated + +### init.lua ### +Straight Insulated Mesecon=Mesecon isolé droit diff --git a/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.ru.tr b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.ru.tr new file mode 100644 index 00000000..9ba1004c --- /dev/null +++ b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_insulated + +### init.lua ### +Straight Insulated Mesecon=Прямой изолированный мезекон diff --git a/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.uk.tr b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.uk.tr new file mode 100644 index 00000000..83d4a211 --- /dev/null +++ b/mods/mesecons/mesecons_insulated/locale/mesecons_insulated.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_insulated + +### init.lua ### +Straight Insulated Mesecon=Прямий ізольований месекон diff --git a/mods/mesecons/mesecons_insulated/locale/template.txt b/mods/mesecons/mesecons_insulated/locale/template.txt new file mode 100644 index 00000000..8fbde4f5 --- /dev/null +++ b/mods/mesecons/mesecons_insulated/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_insulated + +### init.lua ### +Straight Insulated Mesecon= diff --git a/mods/mesecons/mesecons_insulated/mod.conf b/mods/mesecons/mesecons_insulated/mod.conf new file mode 100644 index 00000000..2f7f5b62 --- /dev/null +++ b/mods/mesecons/mesecons_insulated/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_insulated +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_off.png b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_off.png new file mode 100644 index 00000000..d457dde7 Binary files /dev/null and b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_off.png differ diff --git a/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_on.png b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_on.png new file mode 100644 index 00000000..48df808d Binary files /dev/null and b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_ends_on.png differ diff --git a/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_off.png b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_off.png new file mode 100644 index 00000000..da933e0a Binary files /dev/null and b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_off.png differ diff --git a/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_on.png b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_on.png new file mode 100644 index 00000000..cdc37981 Binary files /dev/null and b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_sides_on.png differ diff --git a/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_off.png b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_off.png new file mode 100644 index 00000000..451fbc26 Binary files /dev/null and b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_off.png differ diff --git a/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_on.png b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_on.png new file mode 100644 index 00000000..e30dad4f Binary files /dev/null and b/mods/mesecons/mesecons_insulated/textures/jeija_insulated_wire_tjunction_tb_on.png differ diff --git a/mods/mesecons/mesecons_lamp/doc/lamp/description.html b/mods/mesecons/mesecons_lamp/doc/lamp/description.html new file mode 100644 index 00000000..72f24ed1 --- /dev/null +++ b/mods/mesecons/mesecons_lamp/doc/lamp/description.html @@ -0,0 +1 @@ +Mesecon lamps are effectors that if powered emit light. diff --git a/mods/mesecons/mesecons_lamp/doc/lamp/preview.png b/mods/mesecons/mesecons_lamp/doc/lamp/preview.png new file mode 100644 index 00000000..5de07f08 Binary files /dev/null and b/mods/mesecons/mesecons_lamp/doc/lamp/preview.png differ diff --git a/mods/mesecons/mesecons_lamp/doc/lamp/recipe.png b/mods/mesecons/mesecons_lamp/doc/lamp/recipe.png new file mode 100644 index 00000000..145e6f3a Binary files /dev/null and b/mods/mesecons/mesecons_lamp/doc/lamp/recipe.png differ diff --git a/mods/mesecons/mesecons_lamp/init.lua b/mods/mesecons/mesecons_lamp/init.lua new file mode 100644 index 00000000..ff183fd8 --- /dev/null +++ b/mods/mesecons/mesecons_lamp/init.lua @@ -0,0 +1,73 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- MESELAMPS +-- A lamp is "is an electrical device used to create artificial light" (wikipedia) +-- guess what? + +local mesecon_lamp_box = { + type = "wallmounted", + wall_top = {-0.3125,0.375,-0.3125,0.3125,0.5,0.3125}, + wall_bottom = {-0.3125,-0.5,-0.3125,0.3125,-0.375,0.3125}, + wall_side = {-0.375,-0.3125,-0.3125,-0.5,0.3125,0.3125}, +} + +local use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or nil + +minetest.register_node("mesecons_lamp:lamp_on", { + drawtype = "nodebox", + tiles = {"jeija_meselamp_on.png"}, + use_texture_alpha = use_texture_alpha, + paramtype = "light", + paramtype2 = "wallmounted", + is_ground_content = false, + legacy_wallmounted = true, + sunlight_propagates = true, + walkable = true, + light_source = minetest.LIGHT_MAX, + node_box = mesecon_lamp_box, + selection_box = mesecon_lamp_box, + groups = {dig_immediate = 3,not_in_creative_inventory = 1, mesecon_effector_on = 1}, + drop = "mesecons_lamp:lamp_off 1", + sounds = mesecon.node_sound.glass, + mesecons = {effector = { + action_off = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_lamp:lamp_off", param2 = node.param2}) + end, + rules = mesecon.rules.wallmounted_get, + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_lamp:lamp_off", { + drawtype = "nodebox", + tiles = {"jeija_meselamp_off.png"}, + use_texture_alpha = use_texture_alpha, + inventory_image = "jeija_meselamp.png", + wield_image = "jeija_meselamp.png", + paramtype = "light", + paramtype2 = "wallmounted", + is_ground_content = false, + sunlight_propagates = true, + walkable = true, + node_box = mesecon_lamp_box, + selection_box = mesecon_lamp_box, + groups = {dig_immediate=3, mesecon_receptor_off = 1, mesecon_effector_off = 1}, + description = S("Mesecon Lamp"), + sounds = mesecon.node_sound.glass, + mesecons = {effector = { + action_on = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_lamp:lamp_on", param2 = node.param2}) + end, + rules = mesecon.rules.wallmounted_get, + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_craft({ + output = "mesecons_lamp:lamp_off 1", + recipe = { + {"", "mesecons_gamecompat:glass", ""}, + {"group:mesecon_conductor_craftable", "mesecons_gamecompat:steel_ingot", "group:mesecon_conductor_craftable"}, + {"", "mesecons_gamecompat:glass", ""}, + } +}) diff --git a/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.de.tr b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.de.tr new file mode 100644 index 00000000..488d5348 --- /dev/null +++ b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_lamp +Mesecon Lamp=Meseconlampe diff --git a/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.eo.tr b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.eo.tr new file mode 100644 index 00000000..3434e652 --- /dev/null +++ b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_lamp + +### init.lua ### +Mesecon Lamp=Mesekonduktila Lampo diff --git a/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.fr.tr b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.fr.tr new file mode 100644 index 00000000..a85896e4 --- /dev/null +++ b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_lamp + +### init.lua ### +Mesecon Lamp=Lampe de Mesecon diff --git a/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.ru.tr b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.ru.tr new file mode 100644 index 00000000..72803075 --- /dev/null +++ b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_lamp + +### init.lua ### +Mesecon Lamp=Мезеконовая лампа diff --git a/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.uk.tr b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.uk.tr new file mode 100644 index 00000000..a7e7652d --- /dev/null +++ b/mods/mesecons/mesecons_lamp/locale/mesecons_lamp.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_lamp + +### init.lua ### +Mesecon Lamp=Месеконова лампа diff --git a/mods/mesecons/mesecons_lamp/locale/template.txt b/mods/mesecons/mesecons_lamp/locale/template.txt new file mode 100644 index 00000000..208d3c23 --- /dev/null +++ b/mods/mesecons/mesecons_lamp/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_lamp + +### init.lua ### +Mesecon Lamp= diff --git a/mods/mesecons/mesecons_lamp/mod.conf b/mods/mesecons/mesecons_lamp/mod.conf new file mode 100644 index 00000000..15364470 --- /dev/null +++ b/mods/mesecons/mesecons_lamp/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_lamp +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_lamp/textures/jeija_meselamp.png b/mods/mesecons/mesecons_lamp/textures/jeija_meselamp.png new file mode 100644 index 00000000..b0bc8179 Binary files /dev/null and b/mods/mesecons/mesecons_lamp/textures/jeija_meselamp.png differ diff --git a/mods/mesecons/mesecons_lamp/textures/jeija_meselamp_off.png b/mods/mesecons/mesecons_lamp/textures/jeija_meselamp_off.png new file mode 100644 index 00000000..be6ad5f3 Binary files /dev/null and b/mods/mesecons/mesecons_lamp/textures/jeija_meselamp_off.png differ diff --git a/mods/mesecons/mesecons_lamp/textures/jeija_meselamp_on.png b/mods/mesecons/mesecons_lamp/textures/jeija_meselamp_on.png new file mode 100644 index 00000000..a91e1b1b Binary files /dev/null and b/mods/mesecons/mesecons_lamp/textures/jeija_meselamp_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/description.html b/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/description.html new file mode 100644 index 00000000..5397a96f --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/description.html @@ -0,0 +1,2 @@ +Effector, glows blue when powered. +It works in an inactive block. diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/preview.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/preview.png new file mode 100644 index 00000000..085c6194 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/preview.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/recipe.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/recipe.png new file mode 100644 index 00000000..f72d00f0 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_blue/recipe.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/description.html b/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/description.html new file mode 100644 index 00000000..aad59ea2 --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/description.html @@ -0,0 +1,2 @@ +Effector, glows dark grey when powered. +It works in an inactive block. diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/preview.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/preview.png new file mode 100644 index 00000000..f24c8ab3 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/preview.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/recipe.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/recipe.png new file mode 100644 index 00000000..193a37da Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_darkgrey/recipe.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_green/description.html b/mods/mesecons/mesecons_lightstone/doc/lightstone_green/description.html new file mode 100644 index 00000000..11913342 --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/doc/lightstone_green/description.html @@ -0,0 +1,2 @@ +Effector, glows green when powered. +It works in an inactive block. diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_green/preview.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_green/preview.png new file mode 100644 index 00000000..1cff1840 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_green/preview.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_green/recipe.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_green/recipe.png new file mode 100644 index 00000000..35b3523b Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_green/recipe.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/description.html b/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/description.html new file mode 100644 index 00000000..b3003d26 --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/description.html @@ -0,0 +1,2 @@ +Effector, glows light grey when powered. +It works in an inactive block. diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/preview.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/preview.png new file mode 100644 index 00000000..0347c216 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/preview.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/recipe.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/recipe.png new file mode 100644 index 00000000..37dba5bb Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_lightgrey/recipe.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_red/description.html b/mods/mesecons/mesecons_lightstone/doc/lightstone_red/description.html new file mode 100644 index 00000000..f49aeacd --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/doc/lightstone_red/description.html @@ -0,0 +1,2 @@ +Effector, glows red when powered. +It works in an inactive block. diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_red/preview.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_red/preview.png new file mode 100644 index 00000000..f802d3dc Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_red/preview.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_red/recipe.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_red/recipe.png new file mode 100644 index 00000000..dd5811ae Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_red/recipe.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/description.html b/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/description.html new file mode 100644 index 00000000..a97839ba --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/description.html @@ -0,0 +1,2 @@ +Effector, glows yellow when powered. +It works in an inactive block. diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/preview.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/preview.png new file mode 100644 index 00000000..fa975c58 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/preview.png differ diff --git a/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/recipe.png b/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/recipe.png new file mode 100644 index 00000000..1ca449f6 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/doc/lightstone_yellow/recipe.png differ diff --git a/mods/mesecons/mesecons_lightstone/init.lua b/mods/mesecons/mesecons_lightstone/init.lua new file mode 100644 index 00000000..d601f072 --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/init.lua @@ -0,0 +1,75 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local lightstone_rules = { + {x=0, y=0, z=-1}, + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=1, y=1, z=0}, + {x=1, y=-1, z=0}, + {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=0, y=1, z=-1}, + {x=0, y=-1, z=-1}, + {x=0, y=-1, z=0}, +} + +function mesecon.lightstone_add(name, base_item, texture_off, texture_on, desc) + if not desc then + desc = name .. " Lightstone" + end + minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_off", { + tiles = {texture_off}, + is_ground_content = false, + groups = {cracky = 2, mesecon_effector_off = 1, mesecon = 2}, + description = desc, + sounds = mesecon.node_sound.stone, + mesecons = {effector = { + rules = lightstone_rules, + action_on = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_lightstone:lightstone_" .. name .. "_on", param2 = node.param2}) + end, + }}, + on_blast = mesecon.on_blastnode, + }) + minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_on", { + tiles = {texture_on}, + is_ground_content = false, + groups = {cracky = 2, not_in_creative_inventory = 1, mesecon = 2}, + drop = "mesecons_lightstone:lightstone_" .. name .. "_off", + light_source = minetest.LIGHT_MAX - 2, + sounds = mesecon.node_sound.stone, + mesecons = {effector = { + rules = lightstone_rules, + action_off = function (pos, node) + minetest.swap_node(pos, {name = "mesecons_lightstone:lightstone_" .. name .. "_off", param2 = node.param2}) + end, + }}, + on_blast = mesecon.on_blastnode, + }) + + minetest.register_craft({ + output = "mesecons_lightstone:lightstone_" .. name .. "_off", + recipe = { + {"",base_item,""}, + {base_item,"mesecons_gamecompat:torch",base_item}, + {"","group:mesecon_conductor_craftable",""} + } + }) +end + + +mesecon.lightstone_add("red", "mesecons_gamecompat:dye_red", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png", S("Red Lightstone")) +mesecon.lightstone_add("green", "mesecons_gamecompat:dye_green", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png", S("Green Lightstone")) +mesecon.lightstone_add("blue", "mesecons_gamecompat:dye_blue", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png", S("Blue Lightstone")) +mesecon.lightstone_add("gray", "mesecons_gamecompat:dye_grey", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png", S("Grey Lightstone")) +mesecon.lightstone_add("darkgray", "mesecons_gamecompat:dye_dark_grey", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png", S("Dark Grey Lightstone")) +mesecon.lightstone_add("yellow", "mesecons_gamecompat:dye_yellow", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png", S("Yellow Lightstone")) +mesecon.lightstone_add("orange", "mesecons_gamecompat:dye_orange", "jeija_lightstone_orange_off.png", "jeija_lightstone_orange_on.png", S("Orange Lightstone")) +mesecon.lightstone_add("white", "mesecons_gamecompat:dye_white", "jeija_lightstone_white_off.png", "jeija_lightstone_white_on.png", S("White Lightstone")) +mesecon.lightstone_add("pink", "mesecons_gamecompat:dye_pink", "jeija_lightstone_pink_off.png", "jeija_lightstone_pink_on.png", S("Pink Lightstone")) +mesecon.lightstone_add("magenta", "mesecons_gamecompat:dye_magenta", "jeija_lightstone_magenta_off.png", "jeija_lightstone_magenta_on.png", S("Magenta Lightstone")) +mesecon.lightstone_add("cyan", "mesecons_gamecompat:dye_cyan", "jeija_lightstone_cyan_off.png", "jeija_lightstone_cyan_on.png", S("Cyan Lightstone")) +mesecon.lightstone_add("violet", "mesecons_gamecompat:dye_violet", "jeija_lightstone_violet_off.png", "jeija_lightstone_violet_on.png", S("Violet Lightstone")) diff --git a/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.de.tr b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.de.tr new file mode 100644 index 00000000..18e88531 --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.de.tr @@ -0,0 +1,13 @@ +# textdomain: mesecons_lightstone +Red Lightstone=Roter Leuchtstein +Green Lightstone=Grüner Leuchtstein +Blue Lightstone=Blauer Leuchtstein +Grey Lightstone=Grauer Leuchtstein +Dark Grey Lightstone=Dunkelgrauer Leuchtstein +Yellow Lightstone=Gelber Leuchtstein +Orange Lightstone=Orange Leuchtstein +White Lightstone=Weißer Leuchtstein +Pink Lightstone=Rosa Leuchtstein +Magenta Lightstone=Magenta Leuchtstein +Cyan Lightstone=Türkiser Leuchtstein +Violet Lightstone=Violetter Leuchtstein diff --git a/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.eo.tr b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.eo.tr new file mode 100644 index 00000000..7dab604d --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.eo.tr @@ -0,0 +1,15 @@ +# textdomain: mesecons_lightstone + +### init.lua ### +Red Lightstone=Ruĝa Lumŝtono +Green Lightstone=Verda Lumŝtono +Blue Lightstone=Blua Lumŝtono +Grey Lightstone=Griza Lumŝtono +Dark Grey Lightstone=Malhela Griza Lumŝtono +Yellow Lightstone=Flava Lumŝtono +Orange Lightstone=Oranĝa Lumŝtono +White Lightstone=Blanka Lumŝtono +Pink Lightstone=Rozkolora Lumŝtono +Magenta Lightstone=Magenta Lumŝtono +Cyan Lightstone=Cejana Lumŝtono +Violet Lightstone=Viola Lumŝtono diff --git a/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.fr.tr b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.fr.tr new file mode 100644 index 00000000..6e44c578 --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.fr.tr @@ -0,0 +1,15 @@ +# textdomain: mesecons_lightstone + +### init.lua ### +Red Lightstone=Pierre lumineuse rouge +Green Lightstone=Pierre lumineuse verte +Blue Lightstone=Pierre lumineuse bleue +Grey Lightstone=Pierre lumineuse grise +Dark Grey Lightstone=Pierre lumineuse gris foncée +Yellow Lightstone=Pierre lumineuse jaune +Orange Lightstone=Pierre lumineuse orange +White Lightstone=Pierre lumineuse blanche +Pink Lightstone=Pierre lumineuse rose +Magenta Lightstone=Pierre lumineuse magenta +Cyan Lightstone=Pierre lumineuse bleu clair +Violet Lightstone=Pierre lumineuse violette diff --git a/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.ru.tr b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.ru.tr new file mode 100644 index 00000000..3867c7db --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.ru.tr @@ -0,0 +1,15 @@ +# textdomain: mesecons_lightstone + +### init.lua ### +Red Lightstone=Красный светящийся камень +Green Lightstone=Зеленый светящийся камень +Blue Lightstone=Синий светящийся камень +Grey Lightstone=Серый светящийся камень +Dark Grey Lightstone=Темно-серый светящийся камень +Yellow Lightstone=Желтый светящийся камень +Orange Lightstone=Оранжевый светящийся камень +White Lightstone=Белый светящийся камень +Pink Lightstone=Розовый светящийся камень +Magenta Lightstone=Пурпурный светящийся камень +Cyan Lightstone=Голубой светящийся камень +Violet Lightstone=Фиолетовый светящийся камень diff --git a/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.uk.tr b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.uk.tr new file mode 100644 index 00000000..5ebe462f --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/locale/mesecons_lightstone.uk.tr @@ -0,0 +1,15 @@ +# textdomain: mesecons_lightstone + +### init.lua ### +Red Lightstone=Червоний світловий камінь +Green Lightstone=Зелений світловий камінь +Blue Lightstone=Синій світловий камінь +Grey Lightstone=Сірий світловий камінь +Dark Grey Lightstone=Темно-сірий світловий камінь +Yellow Lightstone=Жовтий світловий камінь +Orange Lightstone=Оранжевий світловий камінь +White Lightstone=Білий світловий камінь +Pink Lightstone=Рожевий світловий камінь +Magenta Lightstone=Пурпуровий світловий камінь +Cyan Lightstone=Блакитний світловий камінь +Violet Lightstone=Фіолетовий світловий камінь diff --git a/mods/mesecons/mesecons_lightstone/locale/template.txt b/mods/mesecons/mesecons_lightstone/locale/template.txt new file mode 100644 index 00000000..884c66fa --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/locale/template.txt @@ -0,0 +1,15 @@ +# textdomain: mesecons_lightstone + +### init.lua ### +Red Lightstone= +Green Lightstone= +Blue Lightstone= +Grey Lightstone= +Dark Grey Lightstone= +Yellow Lightstone= +Orange Lightstone= +White Lightstone= +Pink Lightstone= +Magenta Lightstone= +Cyan Lightstone= +Violet Lightstone= diff --git a/mods/mesecons/mesecons_lightstone/mod.conf b/mods/mesecons/mesecons_lightstone/mod.conf new file mode 100644 index 00000000..7929e49c --- /dev/null +++ b/mods/mesecons/mesecons_lightstone/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_lightstone +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_off.png new file mode 100644 index 00000000..87f753c4 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_on.png new file mode 100644 index 00000000..008a5fe6 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_blue_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_cyan_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_cyan_off.png new file mode 100644 index 00000000..1c9168c4 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_cyan_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_cyan_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_cyan_on.png new file mode 100644 index 00000000..92edf58b Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_cyan_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_off.png new file mode 100644 index 00000000..f7ded2a1 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_on.png new file mode 100644 index 00000000..cfffb096 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_darkgray_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_off.png new file mode 100644 index 00000000..1c5c28d7 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_on.png new file mode 100644 index 00000000..ba067ba0 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_gray_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_green_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_green_off.png new file mode 100644 index 00000000..9051fee2 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_green_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_green_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_green_on.png new file mode 100644 index 00000000..0cadbc9c Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_green_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_magenta_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_magenta_off.png new file mode 100644 index 00000000..9c50f684 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_magenta_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_magenta_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_magenta_on.png new file mode 100644 index 00000000..d46f2952 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_magenta_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_orange_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_orange_off.png new file mode 100644 index 00000000..f62bc62f Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_orange_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_orange_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_orange_on.png new file mode 100644 index 00000000..e3935851 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_orange_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_pink_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_pink_off.png new file mode 100644 index 00000000..89a358c6 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_pink_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_pink_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_pink_on.png new file mode 100644 index 00000000..8df940b1 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_pink_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_red_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_red_off.png new file mode 100644 index 00000000..32c22cda Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_red_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_red_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_red_on.png new file mode 100644 index 00000000..b1ffd57d Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_red_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_violet_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_violet_off.png new file mode 100644 index 00000000..514528c3 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_violet_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_violet_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_violet_on.png new file mode 100644 index 00000000..d607f323 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_violet_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_white_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_white_off.png new file mode 100644 index 00000000..ddb7ebb8 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_white_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_white_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_white_on.png new file mode 100644 index 00000000..9caac0c6 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_white_on.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_off.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_off.png new file mode 100644 index 00000000..5280e91a Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_off.png differ diff --git a/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_on.png b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_on.png new file mode 100644 index 00000000..806efbe1 Binary files /dev/null and b/mods/mesecons/mesecons_lightstone/textures/jeija_lightstone_yellow_on.png differ diff --git a/mods/mesecons/mesecons_luacontroller/doc/luacontroller/description.html b/mods/mesecons/mesecons_luacontroller/doc/luacontroller/description.html new file mode 100644 index 00000000..8c5d0234 --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/doc/luacontroller/description.html @@ -0,0 +1,7 @@ +The Luacontroller is an advanced programmable component. +You can simply code it in the language Mesecons uses itself: Lua! +All the code runs in a sandbox, so it's completely safe (but I won't guarantee that for absolute certainty!). +It works fine in an unloaded block, loading the block when the program needs to run. +Events are properly delivered after a server restart. + +Documentation is available here! diff --git a/mods/mesecons/mesecons_luacontroller/doc/luacontroller/preview.png b/mods/mesecons/mesecons_luacontroller/doc/luacontroller/preview.png new file mode 100644 index 00000000..d5babfc1 Binary files /dev/null and b/mods/mesecons/mesecons_luacontroller/doc/luacontroller/preview.png differ diff --git a/mods/mesecons/mesecons_luacontroller/doc/luacontroller/recipe.png b/mods/mesecons/mesecons_luacontroller/doc/luacontroller/recipe.png new file mode 100644 index 00000000..fca9b061 Binary files /dev/null and b/mods/mesecons/mesecons_luacontroller/doc/luacontroller/recipe.png differ diff --git a/mods/mesecons/mesecons_luacontroller/init.lua b/mods/mesecons/mesecons_luacontroller/init.lua new file mode 100644 index 00000000..9e2d3c82 --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/init.lua @@ -0,0 +1,966 @@ +-- ______ +-- | +-- | +-- | __ ___ _ __ _ _ +-- | | | | | |\ | | |_| | | | | |_ |_| +-- |___| |______ |__| | \| | | \ |__| |_ |_ |_ |\ +-- | +-- | +-- + +-- Reference +-- ports = get_real_port_states(pos): gets if inputs are powered from outside +-- newport = merge_port_states(state1, state2): just does result = state1 or state2 for every port +-- set_port(pos, rule, state): activates/deactivates the mesecons according to the port states +-- set_port_states(pos, ports): Applies new port states to a Luacontroller at pos +-- run_inner(pos, code, event): runs code on the controller at pos and event +-- reset_formspec(pos, code, errmsg): installs new code and prints error messages, without resetting LCID +-- reset_meta(pos, code, errmsg): performs a software-reset, installs new code and prints error message +-- run(pos, event): a wrapper for run_inner which gets code & handles errors via reset_meta +-- resetn(pos): performs a hardware reset, turns off all ports +-- +-- The Sandbox +-- The whole code of the controller runs in a sandbox, +-- a very restricted environment. +-- Actually the only way to damage the server is to +-- use too much memory from the sandbox. +-- You can add more functions to the environment +-- (see where local env is defined) +-- Something nice to play is is appending minetest.env to it. + +local S = minetest.get_translator(minetest.get_current_modname()) + +local BASENAME = "mesecons_luacontroller:luacontroller" + +local rules = { + a = {x = -1, y = 0, z = 0, name="A"}, + b = {x = 0, y = 0, z = 1, name="B"}, + c = {x = 1, y = 0, z = 0, name="C"}, + d = {x = 0, y = 0, z = -1, name="D"}, +} + + +------------------ +-- Action stuff -- +------------------ +-- These helpers are required to set the port states of the luacontroller + +-- Updates the real port states according to the signal change. +-- Returns whether the real port states actually changed. +local function update_real_port_states(pos, rule_name, new_state) + local meta = minetest.get_meta(pos) + if rule_name == nil then + meta:set_int("real_portstates", 1) + return true + end + local real_portstates = meta:get_int("real_portstates") + local n = real_portstates - 1 + local L = {} + for i = 1, 4 do + L[i] = n % 2 + n = math.floor(n / 2) + end + -- (0,-1) (-1,0) (1,0) (0,1) + local pos_to_side = { 4, 1, nil, 3, 2 } + if rule_name.x == nil then + for _, rname in ipairs(rule_name) do + local port = pos_to_side[rname.x + (2 * rname.z) + 3] + L[port] = (new_state == "on") and 1 or 0 + end + else + local port = pos_to_side[rule_name.x + (2 * rule_name.z) + 3] + L[port] = (new_state == "on") and 1 or 0 + end + local new_portstates = 1 + 1 * L[1] + 2 * L[2] + 4 * L[3] + 8 * L[4] + if new_portstates ~= real_portstates then + meta:set_int("real_portstates", new_portstates) + return true + end + return false +end + + +local port_names = {"a", "b", "c", "d"} + +local function get_real_port_states(pos) + -- Determine if ports are powered (by itself or from outside) + local meta = minetest.get_meta(pos) + local L = {} + local n = meta:get_int("real_portstates") - 1 + for _, name in ipairs(port_names) do + L[name] = ((n % 2) == 1) + n = math.floor(n / 2) + end + return L +end + + +local function merge_port_states(ports, vports) + return { + a = ports.a or vports.a, + b = ports.b or vports.b, + c = ports.c or vports.c, + d = ports.d or vports.d, + } +end + +local function generate_name(ports) + local d = ports.d and 1 or 0 + local c = ports.c and 1 or 0 + local b = ports.b and 1 or 0 + local a = ports.a and 1 or 0 + return BASENAME..d..c..b..a +end + + +local function set_port(pos, rule, state) + if state then + mesecon.receptor_on(pos, {rule}) + else + mesecon.receptor_off(pos, {rule}) + end +end + + +local function clean_port_states(ports) + ports.a = ports.a and true or false + ports.b = ports.b and true or false + ports.c = ports.c and true or false + ports.d = ports.d and true or false +end + + +local function set_port_states(pos, ports) + local node = minetest.get_node(pos) + local name = node.name + clean_port_states(ports) + local vports = minetest.registered_nodes[name].virtual_portstates + local new_name = generate_name(ports) + + if name ~= new_name and vports then + -- Problem: + -- We need to place the new node first so that when turning + -- off some port, it won't stay on because the rules indicate + -- there is an onstate output port there. + -- When turning the output off then, it will however cause feedback + -- so that the luacontroller will receive an "off" event by turning + -- its output off. + -- Solution / Workaround: + -- Remember which output was turned off and ignore next "off" event. + local meta = minetest.get_meta(pos) + local ign = minetest.deserialize(meta:get_string("ignore_offevents"), true) or {} + if ports.a and not vports.a and not mesecon.is_powered(pos, rules.a) then ign.A = true end + if ports.b and not vports.b and not mesecon.is_powered(pos, rules.b) then ign.B = true end + if ports.c and not vports.c and not mesecon.is_powered(pos, rules.c) then ign.C = true end + if ports.d and not vports.d and not mesecon.is_powered(pos, rules.d) then ign.D = true end + meta:set_string("ignore_offevents", minetest.serialize(ign)) + + minetest.swap_node(pos, {name = new_name, param2 = node.param2}) + + if ports.a ~= vports.a then set_port(pos, rules.a, ports.a) end + if ports.b ~= vports.b then set_port(pos, rules.b, ports.b) end + if ports.c ~= vports.c then set_port(pos, rules.c, ports.c) end + if ports.d ~= vports.d then set_port(pos, rules.d, ports.d) end + end +end + + +----------------- +-- Overheating -- +----------------- +local function burn_controller(pos) + local node = minetest.get_node(pos) + node.name = BASENAME.."_burnt" + minetest.swap_node(pos, node) + minetest.get_meta(pos):set_string("lc_memory", ""); + -- Wait for pending operations + minetest.after(0.2, mesecon.receptor_off, pos, mesecon.rules.flat) +end + +local function overheat(pos) + if mesecon.do_overheat(pos) then -- If too hot + burn_controller(pos) + return true + end +end + +------------------------ +-- Ignored off events -- +------------------------ + +local function ignore_event(event, meta) + if event.type ~= "off" then return false end + local ignore_offevents = minetest.deserialize(meta:get_string("ignore_offevents"), true) or {} + if ignore_offevents[event.pin.name] then + ignore_offevents[event.pin.name] = nil + meta:set_string("ignore_offevents", minetest.serialize(ignore_offevents)) + return true + end +end + +------------------------- +-- Parsing and running -- +------------------------- + +local function safe_print(param) + if mesecon.setting("luacontroller_print_behavior", "log") == "log" then + local string_meta = getmetatable("") + local sandbox = string_meta.__index + string_meta.__index = string -- Leave string sandbox temporarily + minetest.log("action", string.format("[mesecons_luacontroller] print(%s)", dump(param))) + string_meta.__index = sandbox -- Restore string sandbox + end +end + +local function safe_date() + return(os.date("*t",os.time())) +end + +-- string.rep(str, n) with a high value for n can be used to DoS +-- the server. Therefore, limit max. length of generated string. +local function safe_string_rep(str, n) + if #str * n > mesecon.setting("luacontroller_string_rep_max", 64000) then + debug.sethook() -- Clear hook + error("string.rep: string length overflow", 2) + end + + return string.rep(str, n) +end + +-- string.find with a pattern can be used to DoS the server. +-- Therefore, limit string.find to patternless matching. +local function safe_string_find(...) + if (select(4, ...)) ~= true then + debug.sethook() -- Clear hook + error("string.find: 'plain' (fourth parameter) must always be true in a Luacontroller") + end + + return string.find(...) +end + +-- do not allow pattern matching in string.split (see string.find for details) +local function safe_string_split(...) + if select(5, ...) then + debug.sethook() -- Clear hook + error("string.split: 'sep_is_pattern' (fifth parameter) may not be used in a Luacontroller") + end + + return string.split(...) +end + +local function remove_functions(x) + local tp = type(x) + if tp == "function" then + return nil + end + + -- Make sure to not serialize the same table multiple times, otherwise + -- writing mem.test = mem in the Luacontroller will lead to infinite recursion + local seen = {} + + local function rfuncs(x) + if x == nil then return end + if seen[x] then return end + seen[x] = true + if type(x) ~= "table" then return end + + for key, value in pairs(x) do + if type(key) == "function" or type(value) == "function" then + x[key] = nil + else + if type(key) == "table" then + rfuncs(key) + end + if type(value) == "table" then + rfuncs(value) + end + end + end + end + + rfuncs(x) + + return x +end + +local function validate_iid(iid) + if not iid then return true end -- nil is OK + + local limit = mesecon.setting("luacontroller_interruptid_maxlen", 256) + if type(iid) == "string" then + if #iid <= limit then return true end -- string is OK unless too long + return false, "An interrupt ID was too large!" + end + if type(iid) == "number" or type(iid) == "boolean" then return true, "Non-string interrupt IDs are deprecated" end + + local warn + local seen = {} + local function check(t) + if type(t) == "function" then + warn = "Functions cannot be used in interrupt IDs" + return false + end + if type(t) ~= "table" then + return true + end + if seen[t] then + warn = "Non-tree-like tables are forbidden as interrupt IDs" + return false + end + seen[t] = true + for k, v in pairs(t) do + if not check(k) then return false end + if not check(v) then return false end + end + return true + end + if not check(iid) then return false, warn end + + if #minetest.serialize(iid) > limit then + return false, "An interrupt ID was too large!" + end + + return true, "Table interrupt IDs are deprecated and are unreliable; use strings instead" +end + +-- The setting affects API so is not intended to be changeable at runtime +local get_interrupt +if mesecon.setting("luacontroller_lightweight_interrupts", false) then + -- use node timer + get_interrupt = function(pos, itbl, send_warning) + return (function(time, iid) + if type(time) ~= "number" then error("Delay must be a number") end + if iid ~= nil then send_warning("Interrupt IDs are disabled on this server") end + table.insert(itbl, function() minetest.get_node_timer(pos):start(time) end) + end) + end +else + -- use global action queue + -- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards + get_interrupt = function(pos, itbl, send_warning) + -- iid = interrupt id + return function (time, iid) + -- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y + -- Hence the values get moved out. Should take less time than original, so totally compatible + if type(time) ~= "number" then error("Delay must be a number") end + table.insert(itbl, function () + -- Outside string metatable sandbox, can safely run this now + local luac_id = minetest.get_meta(pos):get_int("luac_id") + local ok, warn = validate_iid(iid) + if ok then mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1) end + if warn then send_warning(warn) end + end) + end + end +end + +-- Given a message object passed to digiline_send, clean it up into a form +-- which is safe to transmit over the network and compute its "cost" (a very +-- rough estimate of its memory usage). +-- +-- The cleaning comprises the following: +-- 1. Functions (and userdata, though user scripts ought not to get hold of +-- those in the first place) are removed, because they break the model of +-- Digilines as a network that carries basic data, and they could exfiltrate +-- references to mutable objects from one Luacontroller to another, allowing +-- inappropriate high-bandwidth, no-wires communication. +-- 2. Tables are duplicated because, being mutable, they could otherwise be +-- modified after the send is complete in order to change what data arrives +-- at the recipient, perhaps in violation of the previous cleaning rule or +-- in violation of the message size limit. +-- +-- The cost indication is only approximate; it’s not a perfect measurement of +-- the number of bytes of memory used by the message object. +-- +-- Parameters: +-- msg -- the message to clean +-- back_references -- for internal use only; do not provide +-- +-- Returns: +-- 1. The cleaned object. +-- 2. The approximate cost of the object. +local function clean_and_weigh_digiline_message(msg, back_references) + local t = type(msg) + if t == "string" then + -- Strings are immutable so can be passed by reference, and cost their + -- length plus the size of the Lua object header (24 bytes on a 64-bit + -- platform) plus one byte for the NUL terminator. + return msg, #msg + 25 + elseif t == "number" then + -- Numbers are passed by value so need not be touched, and cost 8 bytes + -- as all numbers in Lua are doubles. NaN values are removed. + if msg ~= msg then + return nil, 0 + end + return msg, 8 + elseif t == "boolean" then + -- Booleans are passed by value so need not be touched, and cost 1 + -- byte. + return msg, 1 + elseif t == "table" then + -- Tables are duplicated. Check if this table has been seen before + -- (self-referential or shared table); if so, reuse the cleaned value + -- of the previous occurrence, maintaining table topology and avoiding + -- infinite recursion, and charge zero bytes for this as the object has + -- already been counted. + back_references = back_references or {} + local bref = back_references[msg] + if bref then + return bref, 0 + end + -- Construct a new table by cleaning all the keys and values and adding + -- up their costs, plus 8 bytes as a rough estimate of table overhead. + local cost = 8 + local ret = {} + back_references[msg] = ret + for k, v in pairs(msg) do + local k_cost, v_cost + k, k_cost = clean_and_weigh_digiline_message(k, back_references) + v, v_cost = clean_and_weigh_digiline_message(v, back_references) + if k ~= nil and v ~= nil then + -- Only include an element if its key and value are of legal + -- types. + ret[k] = v + end + -- If we only counted the cost of a table element when we actually + -- used it, we would be vulnerable to the following attack: + -- 1. Construct a huge table (too large to pass the cost limit). + -- 2. Insert it somewhere in a table, with a function as a key. + -- 3. Insert it somewhere in another table, with a number as a key. + -- 4. The first occurrence doesn’t pay the cost because functions + -- are stripped and therefore the element is dropped. + -- 5. The second occurrence doesn’t pay the cost because it’s in + -- back_references. + -- By counting the costs regardless of whether the objects will be + -- included, we avoid this attack; it may overestimate the cost of + -- some messages, but only those that won’t be delivered intact + -- anyway because they contain illegal object types. + cost = cost + k_cost + v_cost + end + return ret, cost + else + return nil, 0 + end +end + + +-- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards +local function get_digiline_send(pos, itbl, send_warning) + if not minetest.global_exists("digilines") then return end + local chan_maxlen = mesecon.setting("luacontroller_digiline_channel_maxlen", 256) + local maxlen = mesecon.setting("luacontroller_digiline_maxlen", 50000) + return function(channel, msg) + -- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y + -- or via anything that could. + -- Make sure channel is string, number or boolean + if type(channel) == "string" then + if #channel > chan_maxlen then + send_warning("Channel string too long.") + return false + end + elseif (type(channel) ~= "string" and type(channel) ~= "number" and type(channel) ~= "boolean") then + send_warning("Channel must be string, number or boolean.") + return false + end + + local msg_cost + msg, msg_cost = clean_and_weigh_digiline_message(msg) + if msg == nil or msg_cost > maxlen then + send_warning("Message was too complex, or contained invalid data.") + return false + end + + table.insert(itbl, function () + -- Runs outside of string metatable sandbox + local luac_id = minetest.get_meta(pos):get_int("luac_id") + mesecon.queue:add_action(pos, "lc_digiline_relay", {channel, luac_id, msg}) + end) + return true + end +end + +local safe_globals = { + -- Don't add pcall/xpcall unless willing to deal with the consequences (unless very careful, incredibly likely to allow killing server indirectly) + "assert", "error", "ipairs", "next", "pairs", "select", + "tonumber", "tostring", "type", "unpack", "_VERSION" +} + +local function create_environment(pos, mem, event, itbl, send_warning) + -- Gather variables for the environment + local node_def = minetest.registered_nodes[minetest.get_node(pos).name] + if not node_def then return end + + local vports = node_def.virtual_portstates + if not vports then return end + + local vports_copy = {} + for k, v in pairs(vports) do vports_copy[k] = v end + local rports = get_real_port_states(pos) + + -- Create new library tables on each call to prevent one Luacontroller + -- from breaking a library and messing up other Luacontrollers. + local env = { + pin = merge_port_states(vports, rports), + port = vports_copy, + event = event, + mem = mem, + heat = mesecon.get_heat(pos), + heat_max = mesecon.setting("overheat_max", 20), + print = safe_print, + interrupt = get_interrupt(pos, itbl, send_warning), + digiline_send = get_digiline_send(pos, itbl, send_warning), + sha256sum = minetest.sha256, + string = { + byte = string.byte, + char = string.char, + format = string.format, + len = string.len, + lower = string.lower, + upper = string.upper, + rep = safe_string_rep, + reverse = string.reverse, + sub = string.sub, + find = safe_string_find, + split = safe_string_split, + }, + math = { + abs = math.abs, + acos = math.acos, + asin = math.asin, + atan = math.atan, + atan2 = math.atan2, + ceil = math.ceil, + cos = math.cos, + cosh = math.cosh, + deg = math.deg, + exp = math.exp, + floor = math.floor, + fmod = math.fmod, + frexp = math.frexp, + huge = math.huge, + ldexp = math.ldexp, + log = math.log, + log10 = math.log10, + max = math.max, + min = math.min, + modf = math.modf, + pi = math.pi, + pow = math.pow, + rad = math.rad, + random = math.random, + sin = math.sin, + sinh = math.sinh, + sqrt = math.sqrt, + tan = math.tan, + tanh = math.tanh, + }, + table = { + concat = table.concat, + insert = table.insert, + maxn = table.maxn, + remove = table.remove, + sort = table.sort, + }, + os = { + clock = os.clock, + difftime = os.difftime, + time = os.time, + datetable = safe_date, + }, + } + env._G = env + + for _, name in pairs(safe_globals) do + env[name] = _G[name] + end + + return env +end + + +local function timeout() + debug.sethook() -- Clear hook + error("Code timed out!", 2) +end + + +local function create_sandbox(code, env) + if code:byte(1) == 27 then + return nil, "Binary code prohibited." + end + local f, msg = loadstring(code) + if not f then return nil, msg end + setfenv(f, env) + + -- Turn off JIT optimization for user code so that count + -- events are generated when adding debug hooks + if rawget(_G, "jit") then + jit.off(f, true) + end + + local maxevents = mesecon.setting("luacontroller_maxevents", 10000) + return function(...) + -- NOTE: This runs within string metatable sandbox, so the setting's been moved out for safety + -- Use instruction counter to stop execution + -- after luacontroller_maxevents + debug.sethook(timeout, "", maxevents) + local ok, ret = pcall(f, ...) + debug.sethook() -- Clear hook + if not ok then error(ret, 0) end + return ret + end +end + + +local function load_memory(meta) + return minetest.deserialize(meta:get_string("lc_memory"), true) or {} +end + + +local function save_memory(pos, meta, mem) + local memstring = minetest.serialize(remove_functions(mem)) + local memsize_max = mesecon.setting("luacontroller_memsize", 100000) + + if (#memstring <= memsize_max) then + meta:set_string("lc_memory", memstring) + meta:mark_as_private("lc_memory") + else + print("Error: Luacontroller memory overflow. "..memsize_max.." bytes available, " + ..#memstring.." required. Controller overheats.") + burn_controller(pos) + end +end + +-- Returns success (boolean), errmsg (string) +-- run (as opposed to run_inner) is responsible for setting up meta according to this output +local function run_inner(pos, code, event) + local meta = minetest.get_meta(pos) + -- Note: These return success, presumably to avoid changing LC ID. + if overheat(pos) then return true, "" end + if ignore_event(event, meta) then return true, "" end + + -- Load mem from meta + local mem = load_memory(meta) + + -- 'Last warning' label. + local warning = "" + local function send_warning(str) + warning = "Warning: " .. str + end + + -- Create environment + local itbl = {} + local env = create_environment(pos, mem, event, itbl, send_warning) + if not env then return false, "Env does not exist. Controller has been moved?" end + + local success, msg + -- Create the sandbox and execute code + local f + f, msg = create_sandbox(code, env) + if not f then return false, msg end + -- Start string true sandboxing + local onetruestring = getmetatable("") + -- If a string sandbox is already up yet inconsistent, something is very wrong + assert(onetruestring.__index == string) + onetruestring.__index = env.string + success, msg = pcall(f) + onetruestring.__index = string + -- End string true sandboxing + if not success then return false, msg end + if type(env.port) ~= "table" then + return false, "Ports set are invalid." + end + + -- Actually set the ports + set_port_states(pos, env.port) + + -- Save memory. This may burn the luacontroller if a memory overflow occurs. + save_memory(pos, meta, env.mem) + + -- Execute deferred tasks + for _, v in ipairs(itbl) do + local failure = v() + if failure then + return false, failure + end + end + return true, warning +end + +local function reset_formspec(meta, code, errmsg) + meta:set_string("code", code) + meta:mark_as_private("code") + code = minetest.formspec_escape(code or "") + errmsg = minetest.formspec_escape(tostring(errmsg or "")) + meta:set_string("formspec", "size[12,10]" + .."style_type[label,textarea;font=mono]" + .."background[-0.2,-0.25;12.4,10.75;jeija_luac_background.png]" + .."label[0.1,8.3;"..errmsg.."]" + .."textarea[0.2,0.2;12.2,9.5;code;;"..code.."]" + .."image_button[4.75,8.75;2.5,1;jeija_luac_runbutton.png;program;]" + .."image_button_exit[11.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]" + ) +end + +local function reset_meta(pos, code, errmsg) + local meta = minetest.get_meta(pos) + reset_formspec(meta, code, errmsg) + meta:set_int("luac_id", math.random(1, 65535)) +end + +-- Wraps run_inner with LC-reset-on-error +local function run(pos, event) + local meta = minetest.get_meta(pos) + local code = meta:get_string("code") + local ok, errmsg = run_inner(pos, code, event) + if not ok then + reset_meta(pos, code, errmsg) + else + reset_formspec(meta, code, errmsg) + end + return ok, errmsg +end + +local function reset(pos) + set_port_states(pos, {a=false, b=false, c=false, d=false}) +end + +local function node_timer(pos) + if minetest.registered_nodes[minetest.get_node(pos).name].is_burnt then + return false + end + run(pos, {type="interrupt"}) + return false +end + +----------------------- +-- A.Queue callbacks -- +----------------------- + +mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid) + -- There is no luacontroller anymore / it has been reprogrammed / replaced / burnt + if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end + if (minetest.registered_nodes[minetest.get_node(pos).name].is_burnt) then return end + run(pos, {type="interrupt", iid = iid}) +end) + +mesecon.queue:add_function("lc_digiline_relay", function (pos, channel, luac_id, msg) + if not digiline then return end + -- This check is only really necessary because in case of server crash, old actions can be thrown into the future + if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end + if (minetest.registered_nodes[minetest.get_node(pos).name].is_burnt) then return end + -- The actual work + digiline:receptor_send(pos, digiline.rules.default, channel, msg) +end) + +----------------------- +-- Node Registration -- +----------------------- + +local output_rules = {} +local input_rules = {} + +local node_box = { + type = "fixed", + fixed = { + {-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, -- Bottom slab + {-5/16, -7/16, -5/16, 5/16, -6/16, 5/16}, -- Circuit board + {-3/16, -6/16, -3/16, 3/16, -5/16, 3/16}, -- IC + } +} + +local selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 }, +} + +local digiline = { + receptor = {}, + effector = { + action = function(pos, _, channel, msg) + msg = clean_and_weigh_digiline_message(msg) + run(pos, {type = "digiline", channel = channel, msg = msg}) + end + } +} + +local function get_program(pos) + local meta = minetest.get_meta(pos) + return meta:get_string("code") +end + +local function set_program(pos, code) + reset(pos) + reset_meta(pos, code) + return run(pos, {type="program"}) +end + +local function on_receive_fields(pos, _, fields, sender) + if not fields.program then + return + end + local name = sender:get_player_name() + if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then + minetest.record_protection_violation(pos, name) + return + end + local ok, err = set_program(pos, fields.code) + if not ok then + -- it's not an error from the server perspective + minetest.log("action", "Lua controller programming error: " .. tostring(err)) + end +end + +for a = 0, 1 do -- 0 = off 1 = on +for b = 0, 1 do +for c = 0, 1 do +for d = 0, 1 do + local cid = tostring(d)..tostring(c)..tostring(b)..tostring(a) + local node_name = BASENAME..cid + local top = "jeija_luacontroller_top.png" + if a == 1 then + top = top.."^jeija_luacontroller_LED_A.png" + end + if b == 1 then + top = top.."^jeija_luacontroller_LED_B.png" + end + if c == 1 then + top = top.."^jeija_luacontroller_LED_C.png" + end + if d == 1 then + top = top.."^jeija_luacontroller_LED_D.png" + end + + local groups + if a + b + c + d ~= 0 then + groups = {dig_immediate=2, not_in_creative_inventory=1, overheat = 1} + else + groups = {dig_immediate=2, overheat = 1} + end + + output_rules[cid] = {} + input_rules[cid] = {} + if a == 1 then table.insert(output_rules[cid], rules.a) end + if b == 1 then table.insert(output_rules[cid], rules.b) end + if c == 1 then table.insert(output_rules[cid], rules.c) end + if d == 1 then table.insert(output_rules[cid], rules.d) end + + if a == 0 then table.insert( input_rules[cid], rules.a) end + if b == 0 then table.insert( input_rules[cid], rules.b) end + if c == 0 then table.insert( input_rules[cid], rules.c) end + if d == 0 then table.insert( input_rules[cid], rules.d) end + + local mesecons = { + effector = { + rules = input_rules[cid], + action_change = function (pos, _, rule_name, new_state) + if update_real_port_states(pos, rule_name, new_state) then + run(pos, {type=new_state, pin=rule_name}) + end + end, + }, + receptor = { + state = mesecon.state.on, + rules = output_rules[cid] + }, + luacontroller = { + get_program = get_program, + set_program = set_program, + }, + } + + minetest.register_node(node_name, { + description = S("Luacontroller"), + drawtype = "nodebox", + tiles = { + top, + "jeija_microcontroller_bottom.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png" + }, + inventory_image = top, + paramtype = "light", + is_ground_content = false, + groups = groups, + drop = BASENAME.."0000", + sunlight_propagates = true, + selection_box = selection_box, + node_box = node_box, + on_construct = reset_meta, + on_receive_fields = on_receive_fields, + sounds = mesecon.node_sound.stone, + mesecons = mesecons, + digiline = digiline, + -- Virtual portstates are the ports that + -- the node shows as powered up (light up). + virtual_portstates = { + a = a == 1, + b = b == 1, + c = c == 1, + d = d == 1, + }, + after_dig_node = function (pos) + mesecon.do_cooldown(pos) + mesecon.receptor_off(pos, output_rules) + end, + is_luacontroller = true, + on_timer = node_timer, + on_blast = mesecon.on_blastnode, + }) +end +end +end +end + +------------------------------ +-- Overheated Luacontroller -- +------------------------------ + +minetest.register_node(BASENAME .. "_burnt", { + drawtype = "nodebox", + tiles = { + "jeija_luacontroller_burnt_top.png", + "jeija_microcontroller_bottom.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png" + }, + inventory_image = "jeija_luacontroller_burnt_top.png", + is_burnt = true, + paramtype = "light", + is_ground_content = false, + groups = {dig_immediate=2, not_in_creative_inventory=1}, + drop = BASENAME.."0000", + sunlight_propagates = true, + selection_box = selection_box, + node_box = node_box, + on_construct = reset_meta, + on_receive_fields = on_receive_fields, + sounds = mesecon.node_sound.stone, + virtual_portstates = {a = false, b = false, c = false, d = false}, + mesecons = { + effector = { + rules = mesecon.rules.flat, + action_change = function(pos, _, rule_name, new_state) + update_real_port_states(pos, rule_name, new_state) + end, + }, + }, + on_blast = mesecon.on_blastnode, +}) + +------------------------ +-- Craft Registration -- +------------------------ + +minetest.register_craft({ + output = BASENAME.."0000 2", + recipe = { + {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, + {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, + {'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''}, + } +}) diff --git a/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.de.tr b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.de.tr new file mode 100644 index 00000000..3ae02442 --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_luacontroller +Luacontroller=Luacontroller diff --git a/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.eo.tr b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.eo.tr new file mode 100644 index 00000000..f477ebd6 --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_luacontroller + +### init.lua ### +Luacontroller=Luaregilo diff --git a/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.fr.tr b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.fr.tr new file mode 100644 index 00000000..30fabac3 --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_luacontroller + +### init.lua ### +Luacontroller=Programmateur LUA diff --git a/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.ru.tr b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.ru.tr new file mode 100644 index 00000000..4924cd2a --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_luacontroller + +### init.lua ### +Luacontroller=Lua-контроллер diff --git a/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.uk.tr b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.uk.tr new file mode 100644 index 00000000..67f40d0d --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/locale/mesecons_luacontroller.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_luacontroller + +### init.lua ### +Luacontroller=Lua-контролер diff --git a/mods/mesecons/mesecons_luacontroller/locale/template.txt b/mods/mesecons/mesecons_luacontroller/locale/template.txt new file mode 100644 index 00000000..ece4275b --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_luacontroller + +### init.lua ### +Luacontroller= diff --git a/mods/mesecons/mesecons_luacontroller/mod.conf b/mods/mesecons/mesecons_luacontroller/mod.conf new file mode 100644 index 00000000..ca05feda --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_luacontroller +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_luacontroller/spec/lightweight_interrupt_spec.lua b/mods/mesecons/mesecons_luacontroller/spec/lightweight_interrupt_spec.lua new file mode 100644 index 00000000..045c9b47 --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/spec/lightweight_interrupt_spec.lua @@ -0,0 +1,38 @@ +require("mineunit") + +-- This test is done in a separate file since it requires different configuration at startup. +mineunit("core") +minetest.settings:set("mesecon.luacontroller_lightweight_interrupts", "true") + +fixture("mesecons_luacontroller") + +describe("LuaController lightweight interrupt", function() + local pos = {x = 0, y = 0, z = 0} + + before_each(function() + mesecon._test_place(pos, "mesecons_luacontroller:luacontroller0000") + mineunit:execute_globalstep() -- Execute receptor_on action + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("works", function() + mesecon._test_program_luac(pos, [[ + if event.type == "program" then + interrupt(5) + interrupt(10) + elseif event.type == "interrupt" then + port.a = not pin.a + end + ]]) + mineunit:execute_globalstep(0.1) + mineunit:execute_globalstep(9) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + mineunit:execute_globalstep(1) + mineunit:execute_globalstep(0.1) + assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) + end) +end) diff --git a/mods/mesecons/mesecons_luacontroller/spec/luac_spec.lua b/mods/mesecons/mesecons_luacontroller/spec/luac_spec.lua new file mode 100644 index 00000000..351b2e45 --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/spec/luac_spec.lua @@ -0,0 +1,176 @@ +require("mineunit") + +fixture("mesecons_luacontroller") + +-- Digiline is not tested, since that would require the digiline mod. + +describe("LuaController", function() + local pos = {x = 0, y = 0, z = 0} + local pos_a = {x = -1, y = 0, z = 0} + + before_each(function() + mesecon._test_place(pos, "mesecons_luacontroller:luacontroller0000") + mineunit:execute_globalstep() -- Execute receptor_on action + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("rejects binary code", function() + local ok = mesecon._test_program_luac(pos, string.dump(function() end)) + assert.is_false(ok) + end) + + it("I/O", function() + mesecon._test_place(pos_a, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + mesecon._test_program_luac(pos, [[ + port.a = not pin.a + port.b = not pin.b + port.c = not pin.c + port.d = not pin.d + ]]) + assert.equal("mesecons_luacontroller:luacontroller1110", world.get_node(pos).name) + mesecon._test_dig(pos_a) + mineunit:execute_globalstep() -- Execute receptor_off action + mineunit:execute_globalstep() -- Execute deactivate/change actions + assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) + end) + + it("memory", function() + mesecon._test_program_luac(pos, [[ + if not mem.x then + mem.x = {} + mem.x[mem.x] = {true, "", 1.2} + else + local b, s, n = unpack(mem.x[mem.x]) + if b == true and s == "" and n == 1.2 then + port.d = true + end + end + ]]) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + mesecon._test_place(pos_a, "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + assert.equal("mesecons_luacontroller:luacontroller1000", world.get_node(pos).name) + end) + + it("interrupts without IDs", function() + mesecon._test_program_luac(pos, [[ + if event.type == "program" then + interrupt(4) + interrupt(8) + elseif event.type == "interrupt" then + port.a = not pin.a + end + ]]) + mineunit:execute_globalstep(0.1) + mineunit:execute_globalstep(3) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + mineunit:execute_globalstep(1) + mineunit:execute_globalstep(0.1) + assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) + mineunit:execute_globalstep(3) + assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) + mineunit:execute_globalstep(1) + mineunit:execute_globalstep(0.1) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + end) + + it("interrupts with IDs", function() + mesecon._test_program_luac(pos, [[ + if event.type == "program" then + interrupt(2, "a") + interrupt(4, "a") + interrupt(16, "b") + elseif event.type == "interrupt" then + if event.iid == "a" then + interrupt(5, "b") + interrupt(4, "b") + end + port.a = not pin.a + end + ]]) + mineunit:execute_globalstep(0.1) + mineunit:execute_globalstep(3) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + mineunit:execute_globalstep(1) + mineunit:execute_globalstep(0.1) + assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) + mineunit:execute_globalstep(3) + assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) + mineunit:execute_globalstep(1) + mineunit:execute_globalstep(0.1) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + end) + + it("limits interrupt ID size", function() + mesecon._test_program_luac(pos, [[ + if event.type == "program" then + interrupt(0, (" "):rep(257)) + elseif event.type == "interrupt" then + port.a = not pin.a + end + ]]) + mineunit:execute_globalstep(3) + mineunit:execute_globalstep(3) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + end) + + it("string.rep", function() + mesecon._test_program_luac(pos, [[ + (" "):rep(64000) + port.a = true + ]]) + assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) + mesecon._test_program_luac(pos, [[ + (" "):rep(64001) + port.b = true + ]]) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + end) + + it("string.find", function() + mesecon._test_program_luac(pos, [[ + port.a = (" a"):find("a", nil, true) == 2 + ]]) + assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name) + mesecon._test_program_luac(pos, [[ + (" a"):find("a", nil) + port.b = true + ]]) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + end) + + it("overheats", function() + mesecon._test_program_luac(pos, [[ + interrupt(0) + interrupt(0) + ]]) + mineunit:execute_globalstep() -- Execute 2 interrupts + mineunit:execute_globalstep() -- Execute 4 interrupts + mineunit:execute_globalstep() -- Execute 8 interrupts + mineunit:execute_globalstep() -- Execute 16 interrupts + assert.equal("mesecons_luacontroller:luacontroller_burnt", world.get_node(pos).name) + end) + + it("limits memory", function() + mesecon._test_program_luac(pos, [[ + port.a = true + mem.x = (" "):rep(50000) .. (" "):rep(50000) + ]]) + assert.equal("mesecons_luacontroller:luacontroller_burnt", world.get_node(pos).name) + end) + + it("limits run time", function() + mesecon._test_program_luac(pos, [[ + port.a = true + for i = 1, 1000000 do end + ]]) + assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name) + end) +end) diff --git a/mods/mesecons/mesecons_luacontroller/spec/mineunit.conf b/mods/mesecons/mesecons_luacontroller/spec/mineunit.conf new file mode 100644 index 00000000..81bd36ce --- /dev/null +++ b/mods/mesecons/mesecons_luacontroller/spec/mineunit.conf @@ -0,0 +1 @@ +fixture_paths = {"../.test_fixtures"} diff --git a/mods/mesecons/mesecons_luacontroller/textures/jeija_luac_background.png b/mods/mesecons/mesecons_luacontroller/textures/jeija_luac_background.png new file mode 100644 index 00000000..f2a07e1b Binary files /dev/null and b/mods/mesecons/mesecons_luacontroller/textures/jeija_luac_background.png differ diff --git a/mods/mesecons/mesecons_luacontroller/textures/jeija_luac_runbutton.png b/mods/mesecons/mesecons_luacontroller/textures/jeija_luac_runbutton.png new file mode 100644 index 00000000..f43b571c Binary files /dev/null and b/mods/mesecons/mesecons_luacontroller/textures/jeija_luac_runbutton.png differ diff --git a/mods/mesecons/mesecons_luacontroller/textures/jeija_luacontroller_burnt_top.png b/mods/mesecons/mesecons_luacontroller/textures/jeija_luacontroller_burnt_top.png new file mode 100644 index 00000000..c9e1144f Binary files /dev/null and b/mods/mesecons/mesecons_luacontroller/textures/jeija_luacontroller_burnt_top.png differ diff --git a/mods/mesecons/mesecons_luacontroller/textures/jeija_luacontroller_top.png b/mods/mesecons/mesecons_luacontroller/textures/jeija_luacontroller_top.png new file mode 100644 index 00000000..848f4171 Binary files /dev/null and b/mods/mesecons/mesecons_luacontroller/textures/jeija_luacontroller_top.png differ diff --git a/mods/mesecons/mesecons_materials/doc/fiber/description.html b/mods/mesecons/mesecons_materials/doc/fiber/description.html new file mode 100644 index 00000000..23a414ac --- /dev/null +++ b/mods/mesecons/mesecons_materials/doc/fiber/description.html @@ -0,0 +1 @@ +Craftitem: It can't be placed! Made by cooking glue in the furnace. Used for insulated mesecon crafting. diff --git a/mods/mesecons/mesecons_materials/doc/fiber/preview.png b/mods/mesecons/mesecons_materials/doc/fiber/preview.png new file mode 100644 index 00000000..4b5dc058 Binary files /dev/null and b/mods/mesecons/mesecons_materials/doc/fiber/preview.png differ diff --git a/mods/mesecons/mesecons_materials/doc/fiber/recipe.png b/mods/mesecons/mesecons_materials/doc/fiber/recipe.png new file mode 100644 index 00000000..689adf68 Binary files /dev/null and b/mods/mesecons/mesecons_materials/doc/fiber/recipe.png differ diff --git a/mods/mesecons/mesecons_materials/doc/glue/description.html b/mods/mesecons/mesecons_materials/doc/glue/description.html new file mode 100644 index 00000000..a18490c2 --- /dev/null +++ b/mods/mesecons/mesecons_materials/doc/glue/description.html @@ -0,0 +1 @@ +Craftitem: It can't be placed! Made by cooking saplings in furnace. Used for sticky pistons and sticky movestones. diff --git a/mods/mesecons/mesecons_materials/doc/glue/preview.png b/mods/mesecons/mesecons_materials/doc/glue/preview.png new file mode 100644 index 00000000..71a58ef7 Binary files /dev/null and b/mods/mesecons/mesecons_materials/doc/glue/preview.png differ diff --git a/mods/mesecons/mesecons_materials/doc/glue/recipe.png b/mods/mesecons/mesecons_materials/doc/glue/recipe.png new file mode 100644 index 00000000..763e369b Binary files /dev/null and b/mods/mesecons/mesecons_materials/doc/glue/recipe.png differ diff --git a/mods/mesecons/mesecons_materials/doc/silicon/description.html b/mods/mesecons/mesecons_materials/doc/silicon/description.html new file mode 100644 index 00000000..a2ae598c --- /dev/null +++ b/mods/mesecons/mesecons_materials/doc/silicon/description.html @@ -0,0 +1 @@ +Silicon is just a craftitem: It can't be placed. You'll need it in order to craft other items. diff --git a/mods/mesecons/mesecons_materials/doc/silicon/preview.png b/mods/mesecons/mesecons_materials/doc/silicon/preview.png new file mode 100644 index 00000000..452ed403 Binary files /dev/null and b/mods/mesecons/mesecons_materials/doc/silicon/preview.png differ diff --git a/mods/mesecons/mesecons_materials/doc/silicon/recipe.png b/mods/mesecons/mesecons_materials/doc/silicon/recipe.png new file mode 100644 index 00000000..d73a6c28 Binary files /dev/null and b/mods/mesecons/mesecons_materials/doc/silicon/recipe.png differ diff --git a/mods/mesecons/mesecons_materials/init.lua b/mods/mesecons/mesecons_materials/init.lua new file mode 100644 index 00000000..9a0ce8f9 --- /dev/null +++ b/mods/mesecons/mesecons_materials/init.lua @@ -0,0 +1,43 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- Glue and fiber +minetest.register_craftitem("mesecons_materials:glue", { + inventory_image = "mesecons_glue.png", + on_place_on_ground = minetest.craftitem_place_item, + description = S("Glue"), +}) + +minetest.register_craftitem("mesecons_materials:fiber", { + inventory_image = "mesecons_fiber.png", + on_place_on_ground = minetest.craftitem_place_item, + description = S("Fiber"), +}) + +minetest.register_craft({ + output = "mesecons_materials:glue 2", + type = "cooking", + recipe = "group:sapling", + cooktime = 2 +}) + +minetest.register_craft({ + output = "mesecons_materials:fiber 6", + type = "cooking", + recipe = "mesecons_materials:glue", + cooktime = 4 +}) + +-- Silicon +minetest.register_craftitem("mesecons_materials:silicon", { + inventory_image = "mesecons_silicon.png", + on_place_on_ground = minetest.craftitem_place_item, + description = S("Silicon"), +}) + +minetest.register_craft({ + output = "mesecons_materials:silicon 4", + recipe = { + {"group:sand", "group:sand"}, + {"group:sand", "mesecons_gamecompat:steel_ingot"}, + } +}) diff --git a/mods/mesecons/mesecons_materials/locale/mesecons_materials.de.tr b/mods/mesecons/mesecons_materials/locale/mesecons_materials.de.tr new file mode 100644 index 00000000..56a350c5 --- /dev/null +++ b/mods/mesecons/mesecons_materials/locale/mesecons_materials.de.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_materials +Glue=Klebstoff +Fiber=Faser +Silicon=Silizium diff --git a/mods/mesecons/mesecons_materials/locale/mesecons_materials.eo.tr b/mods/mesecons/mesecons_materials/locale/mesecons_materials.eo.tr new file mode 100644 index 00000000..501c3869 --- /dev/null +++ b/mods/mesecons/mesecons_materials/locale/mesecons_materials.eo.tr @@ -0,0 +1,6 @@ +# textdomain: mesecons_materials + +### init.lua ### +Glue=Gluo +Fiber=Fibro +Silicon=Silicio diff --git a/mods/mesecons/mesecons_materials/locale/mesecons_materials.fr.tr b/mods/mesecons/mesecons_materials/locale/mesecons_materials.fr.tr new file mode 100644 index 00000000..ddec8293 --- /dev/null +++ b/mods/mesecons/mesecons_materials/locale/mesecons_materials.fr.tr @@ -0,0 +1,6 @@ +# textdomain: mesecons_materials + +### init.lua ### +Glue=Colle +Fiber=Fibre +Silicon=Silicone diff --git a/mods/mesecons/mesecons_materials/locale/mesecons_materials.ru.tr b/mods/mesecons/mesecons_materials/locale/mesecons_materials.ru.tr new file mode 100644 index 00000000..b418fe0c --- /dev/null +++ b/mods/mesecons/mesecons_materials/locale/mesecons_materials.ru.tr @@ -0,0 +1,6 @@ +# textdomain: mesecons_materials + +### init.lua ### +Glue=Клей +Fiber=Волокно +Silicon=Кремний diff --git a/mods/mesecons/mesecons_materials/locale/mesecons_materials.uk.tr b/mods/mesecons/mesecons_materials/locale/mesecons_materials.uk.tr new file mode 100644 index 00000000..e5fa75ca --- /dev/null +++ b/mods/mesecons/mesecons_materials/locale/mesecons_materials.uk.tr @@ -0,0 +1,6 @@ +# textdomain: mesecons_materials + +### init.lua ### +Glue=Клей +Fiber=Волокно +Silicon=Кремній diff --git a/mods/mesecons/mesecons_materials/locale/template.txt b/mods/mesecons/mesecons_materials/locale/template.txt new file mode 100644 index 00000000..4c1eb74e --- /dev/null +++ b/mods/mesecons/mesecons_materials/locale/template.txt @@ -0,0 +1,6 @@ +# textdomain: mesecons_materials + +### init.lua ### +Glue= +Fiber= +Silicon= diff --git a/mods/mesecons/mesecons_materials/mod.conf b/mods/mesecons/mesecons_materials/mod.conf new file mode 100644 index 00000000..6e109498 --- /dev/null +++ b/mods/mesecons/mesecons_materials/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_materials +depends = mesecons_gamecompat diff --git a/mods/mesecons/mesecons_materials/textures/mesecons_fiber.png b/mods/mesecons/mesecons_materials/textures/mesecons_fiber.png new file mode 100644 index 00000000..2a4b231b Binary files /dev/null and b/mods/mesecons/mesecons_materials/textures/mesecons_fiber.png differ diff --git a/mods/mesecons/mesecons_materials/textures/mesecons_glue.png b/mods/mesecons/mesecons_materials/textures/mesecons_glue.png new file mode 100644 index 00000000..28171f46 Binary files /dev/null and b/mods/mesecons/mesecons_materials/textures/mesecons_glue.png differ diff --git a/mods/mesecons/mesecons_materials/textures/mesecons_silicon.png b/mods/mesecons/mesecons_materials/textures/mesecons_silicon.png new file mode 100644 index 00000000..7014f3ff Binary files /dev/null and b/mods/mesecons/mesecons_materials/textures/mesecons_silicon.png differ diff --git a/mods/mesecons/mesecons_microcontroller/doc/microcontroller/description.html b/mods/mesecons/mesecons_microcontroller/doc/microcontroller/description.html new file mode 100644 index 00000000..af1e5c30 --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/doc/microcontroller/description.html @@ -0,0 +1,64 @@ + +

The Microcontroller is a semi-advanced programmable component with a persistent +256 bit EEPROM memory.

+

Warning: This device is largely considered deprecated and might contain bugs. It +is recommended to use a Luacontroller instead.

+

Detailed documentation can be found below:

+
    +
  • The Microcontroller's code is executed whenever any of the following events +happens:
      +
    • The Microcontroller is programmed. In this case the EEPROM and ports are all +reset to 0 before.
    • +
    • An incoming signal changes its state.
    • +
    • An after event happens (see command after below).
    • +
    +
  • +
  • There are 4 I/O ports (ABCD) and 256 EEPROM bits (1 to 256).
  • +
  • The code consists of a sequence of commands.
  • +
  • Everything after : is a comment.
  • +
  • Strings are enclosed in "s.
  • +
  • Spaces and tabs outside of strings are ignored.
  • +
  • Basic command syntax:
        command_name`(`param1`,` param2`,` ...`)`
    +
    +
  • +
  • Commands:
      +
    • if(condition) commands [> else_commands];: +Evaluates the given condition and takes the corresponding branch. +The else branch is optional (as indicated by the [ and ]). The > is part +of the syntax and indicates the start of the else branch. The ; marks the +end of the if command.
    • +
    • on(port1, port2, ...): +Sets the given ports to 1.
    • +
    • off(port1, port2, ...): +Sets the given ports to 0.
    • +
    • print("string" or codition, ...): +Evaluates the conditions and prints the concatenation of all params to stdout +(only useful in singleplayer).
    • +
    • after(time, "more commands"): +Executes the commands in the string after the given time in seconds. +There can only be one waiting after event at once. +Warning: This is not reliable, ie. minetest.after is used.
    • +
    • sbi(port_or_eeprom, condition): +Evaluates the condition and sets the port or EEPROM bit to the resulting value. +Note: EEPROM indices don't use # here, ie. it's sbi(1, #2), not sbi(#1, #2).
    • +
    +
  • +
  • Conditions (sorted by descending precedence; they are all evaluated from left +to right):
      +
    • 0, 1: constant
    • +
    • A, ..., D: value of a port. Takes writes that already happened during the +current execution into account.
    • +
    • #1, ..., #256: value of an EEPROM bit. Takes writes that already happened +during the current execution into account.
    • +
    • !condition: negation (can only be applied once, ie. not !!1)
    • +
    • condition1 = condition2: XNOR (equality)
    • +
    • condition1 op condition2 where op is one of:
        +
      • &: AND
      • +
      • |: OR
      • +
      • ~: XOR (inequality)
      • +
      +
    • +
    • Note: Explicit precedence using parentheses is not supported.
    • +
    +
  • +
diff --git a/mods/mesecons/mesecons_microcontroller/doc/microcontroller/description.md b/mods/mesecons/mesecons_microcontroller/doc/microcontroller/description.md new file mode 100644 index 00000000..a723537b --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/doc/microcontroller/description.md @@ -0,0 +1,59 @@ + + +The Microcontroller is a semi-advanced programmable component with a persistent +256 bit EEPROM memory. + +Warning: This device is largely considered deprecated and might contain bugs. It +is recommended to use a Luacontroller instead. + +Detailed documentation can be found below: + +* The Microcontroller's code is executed whenever any of the following events + happens: + * The Microcontroller is programmed. In this case the EEPROM and ports are all + reset to `0` before. + * An incoming signal changes its state. + * An `after` event happens (see command `after` below). +* There are 4 I/O ports (ABCD) and 256 EEPROM bits (1 to 256). +* The code consists of a sequence of commands. +* Everything after `:` is a comment. +* Strings are enclosed in `"`s. +* Spaces and tabs outside of strings are ignored. +* Basic command syntax: + ``` + command_name`(`param1`,` param2`,` ...`)` + ``` +* Commands: + * `if(condition) commands [> else_commands];`: + Evaluates the given condition and takes the corresponding branch. + The else branch is optional (as indicated by the `[` and `]`). The `>` is part + of the syntax and indicates the start of the else branch. The `;` marks the + end of the if command. + * `on(port1, port2, ...)`: + Sets the given ports to `1`. + * `off(port1, port2, ...)`: + Sets the given ports to `0`. + * `print("string" or codition, ...)`: + Evaluates the conditions and prints the concatenation of all params to stdout + (only useful in singleplayer). + * `after(time, "more commands")`: + Executes the commands in the string after the given time in seconds. + There can only be one waiting `after` event at once. + Warning: This is not reliable, ie. `minetest.after` is used. + * `sbi(port_or_eeprom, condition)`: + Evaluates the condition and sets the port or EEPROM bit to the resulting value. + Note: EEPROM indices don't use `#` here, ie. it's `sbi(1, #2)`, not `sbi(#1, #2)`. +* Conditions (sorted by descending precedence; they are all evaluated from left + to right): + * `0`, `1`: constant + * `A`, ..., `D`: value of a port. Takes writes that already happened during the + current execution into account. + * `#1`, ..., `#256`: value of an EEPROM bit. Takes writes that already happened + during the current execution into account. + * `!condition`: negation (can only be applied once, ie. not `!!1`) + * `condition1 = condition2`: XNOR (equality) + * `condition1 op condition2` where `op` is one of: + * `&`: AND + * `|`: OR + * `~`: XOR (inequality) + * Note: Explicit precedence using parentheses is not supported. diff --git a/mods/mesecons/mesecons_microcontroller/doc/microcontroller/preview.png b/mods/mesecons/mesecons_microcontroller/doc/microcontroller/preview.png new file mode 100644 index 00000000..cf158824 Binary files /dev/null and b/mods/mesecons/mesecons_microcontroller/doc/microcontroller/preview.png differ diff --git a/mods/mesecons/mesecons_microcontroller/doc/microcontroller/recipe.png b/mods/mesecons/mesecons_microcontroller/doc/microcontroller/recipe.png new file mode 100644 index 00000000..bf6ebd33 Binary files /dev/null and b/mods/mesecons/mesecons_microcontroller/doc/microcontroller/recipe.png differ diff --git a/mods/mesecons/mesecons_microcontroller/init.lua b/mods/mesecons/mesecons_microcontroller/init.lua new file mode 100644 index 00000000..271b17dc --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/init.lua @@ -0,0 +1,729 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local EEPROM_SIZE = 255 + +local microc_rules = {} +local yc = {} + +for a = 0, 1 do +for b = 0, 1 do +for c = 0, 1 do +for d = 0, 1 do +local nodename = "mesecons_microcontroller:microcontroller"..tostring(d)..tostring(c)..tostring(b)..tostring(a) +local top = "jeija_microcontroller_top.png" +if tostring(a) == "1" then + top = top.."^jeija_luacontroller_LED_A.png" +end +if tostring(b) == "1" then + top = top.."^jeija_luacontroller_LED_B.png" +end +if tostring(c) == "1" then + top = top.."^jeija_luacontroller_LED_C.png" +end +if tostring(d) == "1" then + top = top.."^jeija_luacontroller_LED_D.png" +end +local groups +if tostring(d)..tostring(c)..tostring(b)..tostring(a) ~= "0000" then + groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon = 3, overheat = 1} +else + groups = {dig_immediate=2, mesecon = 3, overheat = 1} +end +local rules={} +if (a == 1) then table.insert(rules, {x = -1, y = 0, z = 0}) end +if (b == 1) then table.insert(rules, {x = 0, y = 0, z = 1}) end +if (c == 1) then table.insert(rules, {x = 1, y = 0, z = 0}) end +if (d == 1) then table.insert(rules, {x = 0, y = 0, z = -1}) end + +local input_rules={} +if (a == 0) then table.insert(input_rules, {x = -1, y = 0, z = 0, name = "A"}) end +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 +microc_rules[nodename] = rules + +local mesecons = {effector = +{ + rules = input_rules, + action_change = function (pos, node, rulename, newstate) + if yc.update_real_portstates(pos, node, rulename, newstate) then + yc.update(pos) + end + end +}} +if nodename ~= "mesecons_microcontroller:microcontroller0000" then + mesecons.receptor = { + state = mesecon.state.on, + rules = rules + } +end + +minetest.register_node(nodename, { + description = S("Microcontroller"), + drawtype = "nodebox", + tiles = { + top, + "jeija_microcontroller_bottom.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png", + "jeija_microcontroller_sides.png" + }, + + sunlight_propagates = true, + paramtype = "light", + is_ground_content = false, + walkable = true, + groups = groups, + drop = "mesecons_microcontroller:microcontroller0000 1", + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 }, + }, + node_box = { + type = "fixed", + fixed = { + { -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab + { -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board + { -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC + } + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("code", "") + meta:set_string("formspec", "size[9,2.5]".. + "field[0.256,-0.2;9,2;code;Code:;]".. + "button[0 ,0.2;1.5,3;band;AND]".. + "button[1.5,0.2;1.5,3;bxor;XOR]".. + "button[3 ,0.2;1.5,3;bnot;NOT]".. + "button[4.5,0.2;1.5,3;bnand;NAND]".. + "button[6 ,0.2;1.5,3;btflop;T-Flop]".. + "button[7.5,0.2;1.5,3;brsflop;RS-Flop]".. + "button_exit[3.5,1;2,3;program;Program]") + meta:set_string("infotext", "Unprogrammed Microcontroller") + local r = "" + for i=1, EEPROM_SIZE+1 do r=r.."0" end --Generate a string with EEPROM_SIZE*"0" + meta:set_string("eeprom", r) + end, + on_receive_fields = function(pos, _, fields, sender) + local player_name = sender:get_player_name() + if minetest.is_protected(pos, player_name) and + not minetest.check_player_privs(player_name, {protection_bypass=true}) then + minetest.record_protection_violation(pos, player_name) + return + end + local meta = minetest.get_meta(pos) + if fields.band then + fields.code = "sbi(C, A&B) :A and B are inputs, C is output" + elseif fields.bxor then + fields.code = "sbi(C, A~B) :A and B are inputs, C is output" + elseif fields.bnot then + fields.code = "sbi(B, !A) :A is input, B is output" + elseif fields.bnand then + fields.code = "sbi(C, !A|!B) :A and B are inputs, C is output" + elseif fields.btflop then + fields.code = "if(A)sbi(1,1);if(!A)sbi(B,!B)sbi(1,0); if(C)off(B); :A is input, B is output (Q), C is reset, toggles with falling edge" + elseif fields.brsflop then + fields.code = "if(A)on(C);if(B)off(C); :A is S (Set), B is R (Reset), C is output (R dominates)" + end + if fields.code == nil then return end + + meta:set_string("code", fields.code) + meta:set_string("formspec", "size[9,2.5]".. + "field[0.256,-0.2;9,2;code;Code:;"..minetest.formspec_escape(fields.code).."]".. + "button[0 ,0.2;1.5,3;band;AND]".. + "button[1.5,0.2;1.5,3;bxor;XOR]".. + "button[3 ,0.2;1.5,3;bnot;NOT]".. + "button[4.5,0.2;1.5,3;bnand;NAND]".. + "button[6 ,0.2;1.5,3;btflop;T-Flop]".. + "button[7.5,0.2;1.5,3;brsflop;RS-Flop]".. + "button_exit[3.5,1;2,3;program;Program]") + meta:set_string("infotext", "Programmed Microcontroller") + yc.reset (pos) + yc.update(pos) + end, + sounds = mesecon.node_sound.stone, + mesecons = mesecons, + after_dig_node = function (pos, node) + rules = microc_rules[node.name] + mesecon.receptor_off(pos, rules) + end, + on_blast = mesecon.on_blastnode, +}) +end +end +end +end + +if minetest.get_modpath("mesecons_luacontroller") then + minetest.register_craft({ + type = "shapeless", + output = "mesecons_microcontroller:microcontroller0000", + recipe = {"mesecons_luacontroller:luacontroller0000"}, + }) + minetest.register_craft({ + type = "shapeless", + output = "mesecons_luacontroller:luacontroller0000", + recipe = {"mesecons_microcontroller:microcontroller0000"}, + }) +else + minetest.register_craft({ + output = 'craft "mesecons_microcontroller:microcontroller0000" 2', + recipe = { + {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, + {'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, + {'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''}, + } + }) +end + +yc.reset = function(pos) + yc.action(pos, {a=false, b=false, c=false, d=false}) + local meta = minetest.get_meta(pos) + meta:set_int("afterid", 0) + local r = "" + for i=1, EEPROM_SIZE+1 do r=r.."0" end --Generate a string with EEPROM_SIZE*"0" + meta:set_string("eeprom", r) +end + +yc.update = function(pos) + local meta = minetest.get_meta(pos) + + if (mesecon.do_overheat(pos)) then + minetest.remove_node(pos) + minetest.after(0.2, function (pos) + mesecon.receptor_off(pos, mesecon.rules.flat) + end , pos) -- wait for pending parsings + minetest.add_item(pos, "mesecons_microcontroller:microcontroller0000") + end + + local code = meta:get_string("code") + code = yc.code_remove_commentary(code) + code = string.gsub(code, " ", "") --Remove all spaces + code = string.gsub(code, " ", "") --Remove all tabs + if yc.parsecode(code, pos) == nil then + meta:set_string("infotext", "Code not valid!\n"..code) + else + meta:set_string("infotext", "Working Microcontroller\n"..code) + end +end + + +--Code Parsing +yc.code_remove_commentary = function(code) + local is_string = false + for i = 1, #code do + if code:sub(i, i) == '"' then + is_string = not is_string --toggle is_string + elseif code:sub(i, i) == ":" and not is_string then + return code:sub(1, i-1) + end + end + return code +end + +yc.parsecode = function(code, pos) + local meta = minetest.get_meta(pos) + local endi = 1 + local Lreal = yc.get_real_portstates(pos) + local Lvirtual = yc.get_virtual_portstates(pos) + if Lvirtual == nil then return nil end + local eeprom = meta:get_string("eeprom") + while true do + local command, params + command, endi = yc.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 + 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 + endi = endi_new + end + if endi == nil then return nil end + end + else + params, endi = yc.parse_get_params(code, endi) + if not params then return nil end + end + if command == "on" then + Lvirtual = yc.command_on (params, Lvirtual) + elseif command == "off" then + Lvirtual = yc.command_off(params, Lvirtual) + elseif command == "print" then + local su = yc.command_print(params, eeprom, yc.merge_portstates(Lreal, Lvirtual)) + if su ~= true then return nil end + elseif command == "after" then + 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 + elseif command == "if" then --nothing + else + return nil + end + if Lvirtual == nil then return nil end + if eeprom == nil then return nil else + minetest.get_meta(pos):set_string("eeprom", eeprom) end + end + yc.action(pos, Lvirtual) + return true +end + +yc.parse_get_command = function(code, starti) + local i = starti + local s + while s ~= "" do + s = string.sub(code, i, i) + if s == "(" then + return string.sub(code, starti, i-1), i + 1 -- i: ( i+1 after ( + end + if s == ";" and starti == i then + starti = starti + 1 + i = starti + elseif s == ">" then + starti = yc.skip_to_endif(code, starti) + if starti == nil then return nil end + i = starti + else + i = i + 1 + end + end + + if starti == i-1 then + return true, true + end + return nil, nil +end + +yc.parse_get_params = function(code, starti) + local i = starti + local s + local params = {} + local is_string = false + while s ~= "" do + s = string.sub(code, i, i) + if code:sub(i, i) == '"' then + is_string = (is_string==false) --toggle is_string + end + if s == ")" and is_string == false then + table.insert(params, string.sub(code, starti, i-1)) -- i: ) i+1 after ) + return params, i + 1 + end + if s == "," and is_string == false then + table.insert(params, string.sub(code, starti, i-1)) -- i: ) i+1 after ) + starti = i + 1 + end + i = i + 1 + end + return nil, nil +end + +yc.parse_get_eeprom_param = function(cond, starti) + local i = starti + local s + local addr + while s ~= "" do + s = string.sub(cond, i, i) + local b = s:byte() + if s == "" or 48 > b or b > 57 then + addr = string.sub(cond, starti, i-1) -- i: last number i+1 after last number + return addr, i + end + if s == "," then return nil, nil end + i = i + 1 + end + return nil, nil +end + +yc.skip_to_endif = function(code, starti) + local i = starti + local s = false + local open_ifs = 1 + while s ~= nil and s~= "" do + s = code:sub(i, i) + if s == "i" and code:sub(i+1, i+1) == "f" then --if in µCScript + open_ifs = open_ifs + 1 + end + if s == ";" then + open_ifs = open_ifs - 1 + end + if open_ifs == 0 then + return i + 1 + end + i = i + 1 + end + return nil +end + +yc.skip_to_else = function(code, starti) + local i = starti + local s = false + local open_ifs = 1 + while s ~= nil and s~= "" do + s = code:sub(i, i) + if s == "i" and code:sub(i+1, i+1) == "f" then --if in µCScript + open_ifs = open_ifs + 1 + end + if s == ";" then + open_ifs = open_ifs - 1 + end + if open_ifs == 1 and s == ">" then + return i + 1 + end + i = i + 1 + end + return nil +end + +--Commands +yc.command_on = function(params, L) + for i, port in ipairs(params) do + L = yc.set_portstate (port, true, L) + end + return L +end + +yc.command_off = function(params, L) + for i, port in ipairs(params) do + L = yc.set_portstate (port, false, L) + end + return L +end + +yc.command_print = function(params, eeprom, L) + local s = "" + for i, param in ipairs(params) do + if param:sub(1,1) == '"' and param:sub(#param, #param) == '"' then + s = s..param:sub(2, #param-1) + else + local r = yc.command_parsecondition(param, L, eeprom) + if r == "1" or r == "0" then + s = s..r + else return nil end + end + end + print(s) --don't remove + return true +end + +yc.command_sbi = function(params, eeprom, L, Lv) + if params[1]==nil or params[2]==nil or params[3] ~=nil then return nil end + local status = yc.command_parsecondition(params[2], L, eeprom) + + if status == nil then return nil, nil end + + if #params[1]==1 then + local b = params[1]:byte() + if 65 <= b and b <= 68 then -- is a port + if status == "1" then + Lv = yc.set_portstate (params[1], true, Lv) + else + Lv = yc.set_portstate (params[1], false, Lv) + end + return eeprom, Lv; + end + end + + --is an eeprom address + local new_eeprom = ""; + for i=1, #eeprom do + if tonumber(params[1])==i then + new_eeprom = new_eeprom..status + else + new_eeprom = new_eeprom..eeprom:sub(i, i) + end + end + return new_eeprom, Lv +end + +-- after (delay) +yc.command_after = function(params, pos) + if params[1] == nil or params[2] == nil or params[3] ~= nil then return nil end + + --get time (maximum time is 200) + local time = tonumber(params[1]) + if time == nil or time > 200 then + return nil + end + + --get code in quotes "code" + if string.sub(params[2], 1, 1) ~= '"' or string.sub(params[2], #params[2], #params[2]) ~= '"' then return nil end + local code = string.sub(params[2], 2, #params[2] - 1) + + local afterid = math.random(10000) + local meta = minetest.get_meta(pos) + meta:set_int("afterid", afterid) + minetest.after(time, yc.command_after_execute, {pos = pos, code = code, afterid = afterid}) + return true +end + +yc.command_after_execute = function(params) + local meta = minetest.get_meta(params.pos) + if meta:get_int("afterid") == params.afterid then --make sure the node has not been changed + if yc.parsecode(params.code, params.pos) == nil then + meta:set_string("infotext", "Code in after() not valid!") + else + if params.code ~= nil then + meta:set_string("infotext", "Working Microcontroller\n"..params.code) + else + meta:set_string("infotext", "Working Microcontroller") + end + end + end +end + +--If +yc.command_if = function(code, starti, L, eeprom) + local cond, endi = yc.command_if_getcondition(code, starti) + if cond == nil then return nil end + + cond = yc.command_parsecondition(cond, L, eeprom) + + local result + if cond == "0" then result = false + 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 +yc.command_if_getcondition = function(code, starti) + local i = starti + local s + local brackets = 1 --1 Bracket to close + while s ~= "" do + s = string.sub(code, i, i) + + if s == ")" then + brackets = brackets - 1 + end + + if s == "(" then + brackets = brackets + 1 + end + + if brackets == 0 then + return string.sub(code, starti, i-1), i + 1 -- i: ( i+1 after ( + end + + i = i + 1 + end + return nil, nil +end + +yc.command_parsecondition = function(cond, L, eeprom) + cond = string.gsub(cond, "A", tonumber(L.a and 1 or 0)) + cond = string.gsub(cond, "B", tonumber(L.b and 1 or 0)) + cond = string.gsub(cond, "C", tonumber(L.c and 1 or 0)) + cond = string.gsub(cond, "D", tonumber(L.d and 1 or 0)) + + + local i = 1 + local l = string.len(cond) + while i<=l do + local s = cond:sub(i,i) + if s == "#" then + 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) + i = 0 + l = string.len(cond) + end + i = i + 1 + end + + cond = string.gsub(cond, "!0", "1") + cond = string.gsub(cond, "!1", "0") + + i = 2 + l = string.len(cond) + while i<=l do + local s = cond:sub(i,i) + local b = tonumber(cond:sub(i-1, i-1)) + local a = tonumber(cond:sub(i+1, i+1)) + if cond:sub(i+1, i+1) == nil then break end + if s == "=" then + if a==nil then return nil end + if b==nil then return nil end + local buf = a == b and "1" or "0" + cond = string.gsub(cond, b..s..a, buf) + i = 1 + l = string.len(cond) + end + i = i + 1 + end + + i = 2 + l = string.len(cond) + while i<=l do + local s = cond:sub(i,i) + local b = tonumber(cond:sub(i-1, i-1)) + local a = tonumber(cond:sub(i+1, i+1)) + if cond:sub(i+1, i+1) == nil then break end + if s == "&" then + if a==nil then return nil end + if b==nil then return nil end + local buf = ((a==1) and (b==1)) + if buf == true then buf = "1" end + if buf == false then buf = "0" end + cond = string.gsub(cond, b..s..a, buf) + i = 1 + l = string.len(cond) + end + if s == "|" then + if a==nil then return nil end + if b==nil then return nil end + local buf = ((a == 1) or (b == 1)) + if buf == true then buf = "1" end + if buf == false then buf = "0" end + cond = string.gsub(cond, b..s..a, buf) + i = 1 + l = string.len(cond) + end + if s == "~" then + if a==nil then return nil end + if b==nil then return nil end + local buf = (((a == 1) or (b == 1)) and not((a==1) and (b==1))) + if buf == true then buf = "1" end + if buf == false then buf = "0" end + cond = string.gsub(cond, b..s..a, buf) + i = 1 + l = string.len(cond) + end + i = i + 1 + end + + return cond +end + +--Virtual-Hardware functions +yc.eeprom_read = function(number, eeprom) + if not number then return end + return eeprom:sub(number, number) +end + +--Real I/O functions +yc.action = function(pos, L) --L-->Lvirtual + local Lv = yc.get_virtual_portstates(pos) + local name = "mesecons_microcontroller:microcontroller" + ..tonumber(L.d and 1 or 0) + ..tonumber(L.c and 1 or 0) + ..tonumber(L.b and 1 or 0) + ..tonumber(L.a and 1 or 0) + local node = minetest.get_node(pos) + minetest.swap_node(pos, {name = name, param2 = node.param2}) + + yc.action_setports(pos, L, Lv) +end + +yc.action_setports = function(pos, L, Lv) + local name = "mesecons_microcontroller:microcontroller" + local rules + if Lv.a ~= L.a then + 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 = 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 = 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 = microc_rules[name.."1000"] + if L.d == true then mesecon.receptor_on(pos, rules) + else mesecon.receptor_off(pos, rules) end + end +end + +yc.set_portstate = function(port, state, L) + if port == "A" then L.a = state + elseif port == "B" then L.b = state + elseif port == "C" then L.c = state + elseif port == "D" then L.d = state + else return nil end + return L +end + +-- Updates the real port states according to the signal change. +-- Returns whether the real port states actually changed. +yc.update_real_portstates = function(pos, _, rulename, newstate) + local meta = minetest.get_meta(pos) + if rulename == nil then + meta:set_int("real_portstates", 1) + return true + end + local real_portstates = meta:get_int("real_portstates") + local n = real_portstates - 1 + local L = {} + for i = 1, 4 do + L[i] = n%2 + n = math.floor(n/2) + end + if rulename.x == nil then + for _, rname in ipairs(rulename) do + local port = ({4, 1, nil, 3, 2})[rname.x+2*rname.z+3] + L[port] = (newstate == "on") and 1 or 0 + end + else + local port = ({4, 1, nil, 3, 2})[rulename.x+2*rulename.z+3] + L[port] = (newstate == "on") and 1 or 0 + end + local new_portstates = 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4] + if new_portstates ~= real_portstates then + meta:set_int("real_portstates", new_portstates) + return true + end + return false +end + +yc.get_real_portstates = function(pos) -- determine if ports are powered (by itself or from outside) + local meta = minetest.get_meta(pos) + local L = {} + local n = meta:get_int("real_portstates") - 1 + for _, index in ipairs({"a", "b", "c", "d"}) do + L[index] = ((n%2) == 1) + n = math.floor(n/2) + end + return L +end + +yc.get_virtual_portstates = function(pos) -- portstates according to the name + local name = minetest.get_node(pos).name + local _, a = string.find(name, ":microcontroller") + if a == nil then return nil end + a = a + 1 + + 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 + if name:sub(a+3, a+3) == "1" then Lvirtual.a = true end + return Lvirtual +end + +yc.merge_portstates = function(Lreal, Lvirtual) + local L = {a=false, b=false, c=false, d=false} + if Lvirtual.a or Lreal.a then L.a = true end + if Lvirtual.b or Lreal.b then L.b = true end + if Lvirtual.c or Lreal.c then L.c = true end + if Lvirtual.d or Lreal.d then L.d = true end + return L +end diff --git a/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.de.tr b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.de.tr new file mode 100644 index 00000000..1348a6fd --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_microcontroller +Microcontroller=Mikrocontroller diff --git a/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.eo.tr b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.eo.tr new file mode 100644 index 00000000..39c2c907 --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_microcontroller + +### init.lua ### +Microcontroller=Mikroregilo diff --git a/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.fr.tr b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.fr.tr new file mode 100644 index 00000000..c81a75b8 --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_microcontroller + +### init.lua ### +Microcontroller=Micro-controlleur diff --git a/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.ru.tr b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.ru.tr new file mode 100644 index 00000000..0a6fdbb2 --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_microcontroller + +### init.lua ### +Microcontroller=Микроконтроллер diff --git a/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.uk.tr b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.uk.tr new file mode 100644 index 00000000..4e7978e7 --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/locale/mesecons_microcontroller.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_microcontroller + +### init.lua ### +Microcontroller=Мікроконтролер diff --git a/mods/mesecons/mesecons_microcontroller/locale/template.txt b/mods/mesecons/mesecons_microcontroller/locale/template.txt new file mode 100644 index 00000000..f4274a02 --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_microcontroller + +### init.lua ### +Microcontroller= diff --git a/mods/mesecons/mesecons_microcontroller/mod.conf b/mods/mesecons/mesecons_microcontroller/mod.conf new file mode 100644 index 00000000..a61475b2 --- /dev/null +++ b/mods/mesecons/mesecons_microcontroller/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_microcontroller +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_microcontroller/textures/jeija_microcontroller_top.png b/mods/mesecons/mesecons_microcontroller/textures/jeija_microcontroller_top.png new file mode 100644 index 00000000..e8ec99e8 Binary files /dev/null and b/mods/mesecons/mesecons_microcontroller/textures/jeija_microcontroller_top.png differ diff --git a/mods/mesecons/mesecons_movestones/doc/movestone/description.html b/mods/mesecons/mesecons_movestones/doc/movestone/description.html new file mode 100644 index 00000000..b7138a00 --- /dev/null +++ b/mods/mesecons/mesecons_movestones/doc/movestone/description.html @@ -0,0 +1,2 @@ +Movestones are effectors that push the blocks in front of them. They move along on the right side of a mesecon wire track. +A movestone trying to move into, or push other nodes into, an unloaded block doesn't move. diff --git a/mods/mesecons/mesecons_movestones/doc/movestone/preview.png b/mods/mesecons/mesecons_movestones/doc/movestone/preview.png new file mode 100644 index 00000000..fb6ab7cc Binary files /dev/null and b/mods/mesecons/mesecons_movestones/doc/movestone/preview.png differ diff --git a/mods/mesecons/mesecons_movestones/doc/movestone/recipe.png b/mods/mesecons/mesecons_movestones/doc/movestone/recipe.png new file mode 100644 index 00000000..61165b1c Binary files /dev/null and b/mods/mesecons/mesecons_movestones/doc/movestone/recipe.png differ diff --git a/mods/mesecons/mesecons_movestones/doc/movestone_sticky/description.html b/mods/mesecons/mesecons_movestones/doc/movestone_sticky/description.html new file mode 100644 index 00000000..f19d6a5e --- /dev/null +++ b/mods/mesecons/mesecons_movestones/doc/movestone_sticky/description.html @@ -0,0 +1,3 @@ +Movestones are effectors that push the blocks in front of them. They move along on the right side of a mesecon wire track. Sticky ones also pull blocks. +A sticky movestone trying to move into, or push other nodes into, an unloaded block doesn't move. +A sticky movestone trying to pull nodes from an unloaded block moves but leaves them behind. diff --git a/mods/mesecons/mesecons_movestones/doc/movestone_sticky/preview.png b/mods/mesecons/mesecons_movestones/doc/movestone_sticky/preview.png new file mode 100644 index 00000000..b9b2302f Binary files /dev/null and b/mods/mesecons/mesecons_movestones/doc/movestone_sticky/preview.png differ diff --git a/mods/mesecons/mesecons_movestones/doc/movestone_sticky/recipe.png b/mods/mesecons/mesecons_movestones/doc/movestone_sticky/recipe.png new file mode 100644 index 00000000..4ad08d94 Binary files /dev/null and b/mods/mesecons/mesecons_movestones/doc/movestone_sticky/recipe.png differ diff --git a/mods/mesecons/mesecons_movestones/init.lua b/mods/mesecons/mesecons_movestones/init.lua new file mode 100644 index 00000000..715e75c6 --- /dev/null +++ b/mods/mesecons/mesecons_movestones/init.lua @@ -0,0 +1,238 @@ +-- MOVESTONE +-- Non-sticky: +-- Moves along mesecon lines +-- Pushes all blocks in front of it +-- +-- Sticky one +-- Moves along mesecon lines +-- Pushes all block in front of it +-- Pull all blocks in its back + +local S = minetest.get_translator(minetest.get_current_modname()) + +-- settings: +local timer_interval = 1 / mesecon.setting("movestone_speed", 3) +local max_push = mesecon.setting("movestone_max_push", 50) +local max_pull = mesecon.setting("movestone_max_pull", 50) + +-- helper functions: +local function get_movestone_direction(rulename, is_vertical) + if is_vertical then + if rulename.z > 0 then + return {x = 0, y = -1, z = 0} + elseif rulename.z < 0 then + return {x = 0, y = 1, z = 0} + elseif rulename.x > 0 then + return {x = 0, y = -1, z = 0} + elseif rulename.x < 0 then + return {x = 0, y = 1, z = 0} + end + else + if rulename.z > 0 then + return {x = -1, y = 0, z = 0} + elseif rulename.z < 0 then + return {x = 1, y = 0, z = 0} + elseif rulename.x > 0 then + return {x = 0, y = 0, z = -1} + elseif rulename.x < 0 then + return {x = 0, y = 0, z = 1} + end + end +end + +-- registration functions: +function mesecon.register_movestone(name, def, is_sticky, is_vertical) + local function movestone_move(pos, node, rulename) + local direction = get_movestone_direction(rulename, is_vertical) + local frontpos = vector.add(pos, direction) + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + + -- ### Step 1: Push nodes in front ### + local success, stack, oldstack = mesecon.mvps_push(frontpos, direction, max_push, owner) + if not success then + if stack == "protected" then + meta:set_string("infotext", "Can't move: protected area on the way") + return + end + minetest.get_node_timer(pos):start(timer_interval) + return + end + mesecon.mvps_move_objects(frontpos, direction, oldstack) + + -- ### Step 2: Move the movestone ### + minetest.set_node(frontpos, node) + local meta2 = minetest.get_meta(frontpos) + meta2:set_string("owner", owner) + minetest.remove_node(pos) + mesecon.on_dignode(pos, node) + mesecon.on_placenode(frontpos, node) + minetest.get_node_timer(frontpos):start(timer_interval) + minetest.sound_play("movestone", { pos = pos, max_hear_distance = 20, gain = 0.5 }, true) + + -- ### Step 3: If sticky, pull stack behind ### + if is_sticky then + local backpos = vector.subtract(pos, direction) + local success, _, oldstack = mesecon.mvps_pull_all(backpos, direction, max_pull, owner) + if success then + mesecon.mvps_move_objects(backpos, vector.multiply(direction, -1), oldstack, -1) + end + end + + -- ### Step 4: Let things fall ### + minetest.check_for_falling(vector.add(pos, {x=0, y=1, z=0})) + end + + def.is_ground_content = false + + def.mesecons = {effector = { + action_on = function(pos, node, rulename) + if rulename and not minetest.get_node_timer(pos):is_started() then + movestone_move(pos, node, rulename) + end + end, + rules = mesecon.rules.default, + }} + + def.after_place_node = mesecon.mvps_set_owner + + def.on_punch = function(pos, _, player) + local player_name = player and player.get_player_name and player:get_player_name() + if mesecon.mvps_claim(pos, player_name) then + minetest.get_node_timer(pos):start(timer_interval) + minetest.chat_send_player(player_name, "Reclaimed movestone") + end + end + + def.on_timer = function(pos) + local sourcepos = mesecon.is_powered(pos) + if not sourcepos then + return + end + local rulename = vector.subtract(sourcepos[1], pos) + mesecon.activate(pos, minetest.get_node(pos), rulename, 0) + end + + def.on_blast = mesecon.on_blastnode + + minetest.register_node(name, def) +end + + +-- registration: +mesecon.register_movestone("mesecons_movestones:movestone", { + tiles = { + "jeija_movestone_side.png", + "jeija_movestone_side.png", + "jeija_movestone_arrows.png^[transformFX", + "jeija_movestone_arrows.png^[transformFX", + "jeija_movestone_arrows.png", + "jeija_movestone_arrows.png", + }, + groups = {cracky = 3}, + description = S("Movestone"), + sounds = mesecon.node_sound.stone +}, false, false) + +mesecon.register_movestone("mesecons_movestones:sticky_movestone", { + tiles = { + "jeija_movestone_side.png", + "jeija_movestone_side.png", + "jeija_sticky_movestone.png^[transformFX", + "jeija_sticky_movestone.png^[transformFX", + "jeija_sticky_movestone.png", + "jeija_sticky_movestone.png", + }, + groups = {cracky = 3}, + description = S("Sticky Movestone"), + sounds = mesecon.node_sound.stone, +}, true, false) + +mesecon.register_movestone("mesecons_movestones:movestone_vertical", { + tiles = { + "jeija_movestone_side.png", + "jeija_movestone_side.png", + "jeija_movestone_arrows.png^[transformFXR90", + "jeija_movestone_arrows.png^[transformR90", + "jeija_movestone_arrows.png^[transformFXR90", + "jeija_movestone_arrows.png^[transformR90", + }, + groups = {cracky = 3}, + description = S("Vertical Movestone"), + sounds = mesecon.node_sound.stone +}, false, true) + +mesecon.register_movestone("mesecons_movestones:sticky_movestone_vertical", { + tiles = { + "jeija_movestone_side.png^(mesecons_glue.png^[opacity:127)", + "jeija_movestone_side.png^(mesecons_glue.png^[opacity:127)", + "jeija_movestone_arrows.png^[transformFXR90", + "jeija_movestone_arrows.png^[transformR90", + "jeija_movestone_arrows.png^[transformFXR90", + "jeija_movestone_arrows.png^[transformR90", + }, + groups = {cracky = 3}, + description = S("Vertical Sticky Movestone"), + sounds = mesecon.node_sound.stone, +}, true, true) + + +-- crafting: +-- base recipe: +minetest.register_craft({ + output = "mesecons_movestones:movestone 2", + recipe = { + {"mesecons_gamecompat:stone", "mesecons_gamecompat:stone", "mesecons_gamecompat:stone"}, + {"group:mesecon_conductor_craftable", "group:mesecon_conductor_craftable", "group:mesecon_conductor_craftable"}, + {"mesecons_gamecompat:stone", "mesecons_gamecompat:stone", "mesecons_gamecompat:stone"}, + } +}) + +-- conversation: +minetest.register_craft({ + type = "shapeless", + output = "mesecons_movestones:movestone", + recipe = {"mesecons_movestones:movestone_vertical"}, +}) + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_movestones:movestone_vertical", + recipe = {"mesecons_movestones:movestone"}, +}) + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_movestones:sticky_movestone", + recipe = {"mesecons_movestones:sticky_movestone_vertical"}, +}) + +minetest.register_craft({ + type = "shapeless", + output = "mesecons_movestones:sticky_movestone_vertical", + recipe = {"mesecons_movestones:sticky_movestone"}, +}) + +-- make sticky: +minetest.register_craft({ + output = "mesecons_movestones:sticky_movestone", + recipe = { + {"mesecons_materials:glue", "mesecons_movestones:movestone", "mesecons_materials:glue"}, + } +}) + +minetest.register_craft({ + output = "mesecons_movestones:sticky_movestone_vertical", + recipe = { + {"mesecons_materials:glue"}, + {"mesecons_movestones:movestone_vertical"}, + {"mesecons_materials:glue"}, + } +}) + + +-- legacy code: +minetest.register_alias("mesecons_movestones:movestone_active", + "mesecons_movestones:movestone") +minetest.register_alias("mesecons_movestones:sticky_movestone_active", + "mesecons_movestones:sticky_movestone") diff --git a/mods/mesecons/mesecons_movestones/locale/mesecons_movestone.fr.tr b/mods/mesecons/mesecons_movestones/locale/mesecons_movestone.fr.tr new file mode 100644 index 00000000..3547c932 --- /dev/null +++ b/mods/mesecons/mesecons_movestones/locale/mesecons_movestone.fr.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_movestones + +### init.lua ### +Movestone=Pierre mouvante +Sticky Movestone=Pierre collante mouvante +Vertical Movestone=Pierre mouvante verticalement +Vertical Sticky Movestone=Pierre collante mouvante verticalement diff --git a/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.de.tr b/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.de.tr new file mode 100644 index 00000000..3f11ea27 --- /dev/null +++ b/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.de.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_movestones +Movestone=Laufstein +Sticky Movestone=Klebriger Laufstein +Vertical Movestone=Vertikaler Laufstein +Vertical Sticky Movestone=Vertikaler klebriger Laufstein diff --git a/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.eo.tr b/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.eo.tr new file mode 100644 index 00000000..b4f8d372 --- /dev/null +++ b/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.eo.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_movestones + +### init.lua ### +Movestone=Movŝtono +Sticky Movestone=Glueca Movŝtono +Vertical Movestone=Vertikala Movŝtono +Vertical Sticky Movestone=Vertikala Glueca Movŝtono diff --git a/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.ru.tr b/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.ru.tr new file mode 100644 index 00000000..3fd80650 --- /dev/null +++ b/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.ru.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_movestones + +### init.lua ### +Movestone=Ходовой камень +Sticky Movestone=Липкий ходовой камень +Vertical Movestone=Вертикальный ходовой камень +Vertical Sticky Movestone=Вертикальный липкий ходовой камень diff --git a/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.uk.tr b/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.uk.tr new file mode 100644 index 00000000..e5e7784f --- /dev/null +++ b/mods/mesecons/mesecons_movestones/locale/mesecons_movestones.uk.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_movestones + +### init.lua ### +Movestone=Ходовий камінь +Sticky Movestone=Липкий ходовий камінь +Vertical Movestone=Вертикальний ходовий камінь +Vertical Sticky Movestone=Вертикальний липкий ходовий камінь diff --git a/mods/mesecons/mesecons_movestones/locale/template.txt b/mods/mesecons/mesecons_movestones/locale/template.txt new file mode 100644 index 00000000..a35e6bc0 --- /dev/null +++ b/mods/mesecons/mesecons_movestones/locale/template.txt @@ -0,0 +1,7 @@ +# textdomain: mesecons_movestones + +### init.lua ### +Movestone= +Sticky Movestone= +Vertical Movestone= +Vertical Sticky Movestone= diff --git a/mods/mesecons/mesecons_movestones/mod.conf b/mods/mesecons/mesecons_movestones/mod.conf new file mode 100644 index 00000000..6ece2798 --- /dev/null +++ b/mods/mesecons/mesecons_movestones/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_movestones +depends = mesecons, mesecons_gamecompat, mesecons_materials, mesecons_mvps diff --git a/mods/mesecons/mesecons_movestones/sounds/movestone.ogg b/mods/mesecons/mesecons_movestones/sounds/movestone.ogg new file mode 100644 index 00000000..1910d0cb Binary files /dev/null and b/mods/mesecons/mesecons_movestones/sounds/movestone.ogg differ diff --git a/mods/mesecons/mesecons_movestones/textures/jeija_movestone_arrows.png b/mods/mesecons/mesecons_movestones/textures/jeija_movestone_arrows.png new file mode 100644 index 00000000..e1f2172b Binary files /dev/null and b/mods/mesecons/mesecons_movestones/textures/jeija_movestone_arrows.png differ diff --git a/mods/mesecons/mesecons_movestones/textures/jeija_movestone_side.png b/mods/mesecons/mesecons_movestones/textures/jeija_movestone_side.png new file mode 100644 index 00000000..971ee76f Binary files /dev/null and b/mods/mesecons/mesecons_movestones/textures/jeija_movestone_side.png differ diff --git a/mods/mesecons/mesecons_movestones/textures/jeija_sticky_movestone.png b/mods/mesecons/mesecons_movestones/textures/jeija_sticky_movestone.png new file mode 100644 index 00000000..cab3e965 Binary files /dev/null and b/mods/mesecons/mesecons_movestones/textures/jeija_sticky_movestone.png differ diff --git a/mods/mesecons/mesecons_mvps/init.lua b/mods/mesecons/mesecons_mvps/init.lua new file mode 100644 index 00000000..aacef336 --- /dev/null +++ b/mods/mesecons/mesecons_mvps/init.lua @@ -0,0 +1,340 @@ +--register stoppers for movestones/pistons + +mesecon.mvps_stoppers = {} +mesecon.on_mvps_move = {} +mesecon.mvps_unmov = {} + +--- Objects (entities) that cannot be moved +function mesecon.register_mvps_unmov(objectname) + mesecon.mvps_unmov[objectname] = true; +end + +function mesecon.is_mvps_unmov(objectname) + return mesecon.mvps_unmov[objectname] +end + +-- Nodes that cannot be pushed / pulled by movestones, pistons +function mesecon.is_mvps_stopper(node, pushdir, stack, stackid) + -- unknown nodes are always stoppers + if not minetest.registered_nodes[node.name] then + return true + end + + local get_stopper = mesecon.mvps_stoppers[node.name] + if type (get_stopper) == "function" then + get_stopper = get_stopper(node, pushdir, stack, stackid) + end + + return get_stopper +end + +function mesecon.register_mvps_stopper(nodename, get_stopper) + if get_stopper == nil then + get_stopper = true + end + mesecon.mvps_stoppers[nodename] = get_stopper +end + +-- Functions to be called on mvps movement +function mesecon.register_on_mvps_move(callback) + mesecon.on_mvps_move[#mesecon.on_mvps_move+1] = callback +end + +local function on_mvps_move(moved_nodes) + for _, callback in ipairs(mesecon.on_mvps_move) do + callback(moved_nodes) + end +end + +function mesecon.mvps_process_stack() + -- This function is kept for compatibility. + -- It used to call on_placenode on moved nodes, but that is now done automatically. +end + +-- tests if the node can be pushed into, e.g. air, water, grass +local function node_replaceable(name) + local nodedef = minetest.registered_nodes[name] + + -- everything that can be an mvps stopper (unknown nodes and nodes in the + -- mvps_stoppers table) must not be replacable + -- Note: ignore (a stopper) is buildable_to, but we do not want to push into it + if not nodedef or mesecon.mvps_stoppers[name] then + return false + end + + return nodedef.buildable_to or false +end + +function mesecon.mvps_get_stack(pos, dir, maximum, all_pull_sticky) + -- determine the number of nodes to be pushed + local nodes = {} + local pos_set = {} + local frontiers = mesecon.fifo_queue.new() + frontiers:add(vector.new(pos)) + + for np in frontiers:iter() do + local np_hash = minetest.hash_node_position(np) + local nn = not pos_set[np_hash] and minetest.get_node(np) + if nn and not node_replaceable(nn.name) then + pos_set[np_hash] = true + table.insert(nodes, {node = nn, pos = np}) + if #nodes > maximum then return nil end + + -- add connected nodes to frontiers + local nndef = minetest.registered_nodes[nn.name] + if nndef and nndef.mvps_sticky then + local connected = nndef.mvps_sticky(np, nn) + for _, cp in ipairs(connected) do + frontiers:add(cp) + end + end + + frontiers:add(vector.add(np, dir)) + + -- If adjacent node is sticky block and connects add that + -- position + for _, r in ipairs(mesecon.rules.alldirs) do + local adjpos = vector.add(np, r) + local adjnode = minetest.get_node(adjpos) + local adjdef = minetest.registered_nodes[adjnode.name] + if adjdef and adjdef.mvps_sticky then + local sticksto = adjdef.mvps_sticky(adjpos, adjnode) + + -- connects to this position? + for _, link in ipairs(sticksto) do + if vector.equals(link, np) then + frontiers:add(adjpos) + end + end + end + end + + if all_pull_sticky then + frontiers:add(vector.subtract(np, dir)) + end + end + end + + return nodes +end + +function mesecon.mvps_set_owner(pos, placer) + local meta = minetest.get_meta(pos) + local owner = placer and placer.get_player_name and placer:get_player_name() + if owner and owner ~= "" then + meta:set_string("owner", owner) + else + meta:set_string("owner", "$unknown") -- to distinguish from older pistons + end +end + +function mesecon.mvps_claim(pos, player_name) + if not player_name or player_name == "" then return end + local meta = minetest.get_meta(pos) + if meta:get_string("infotext") == "" then return end + if meta:get_string("owner") == player_name then return end -- already owned + if minetest.is_protected(pos, player_name) then + minetest.chat_send_player(player_name, "Can't reclaim: protected") + return + end + meta:set_string("owner", player_name) + meta:set_string("infotext", "") + return true +end + +local function add_pos(positions, pos) + local hash = minetest.hash_node_position(pos) + positions[hash] = pos +end + +local function are_protected(positions, player_name) + local mode = mesecon.setting("mvps_protection_mode", "compat") + if mode == "ignore" then + return false + end + local name = player_name + if player_name == "" or not player_name then -- legacy MVPS + if mode == "normal" then + name = "$unknown" -- sentinel, for checking for *any* protection + elseif mode == "compat" then + return false + elseif mode == "restrict" then + return true + else + error("Invalid protection mode") + end + end + local is_protected = minetest.is_protected + for _, pos in pairs(positions) do + if is_protected(pos, name) then + return true + end + end + return false +end + +function mesecon.mvps_push(pos, dir, maximum, player_name) + return mesecon.mvps_push_or_pull(pos, dir, dir, maximum, false, player_name) +end + +function mesecon.mvps_pull_all(pos, dir, maximum, player_name) + return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum, true, player_name) +end + +function mesecon.mvps_pull_single(pos, dir, maximum, player_name) + return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum, false, player_name) +end + +-- pos: pos of mvps +-- stackdir: direction of building the stack +-- movedir: direction of actual movement +-- maximum: maximum nodes to be pushed +-- all_pull_sticky: All nodes are sticky in the direction that they are pulled from +-- player_name: Player responsible for the action. +-- - empty string means legacy MVPS, actual check depends on configuration +-- - "$unknown" is a sentinel for forcing the check +function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sticky, player_name) + local nodes = mesecon.mvps_get_stack(pos, movedir, maximum, all_pull_sticky) + + if not nodes then return end + + local protection_check_set = {} + if vector.equals(stackdir, movedir) then -- pushing + add_pos(protection_check_set, pos) + end + -- determine if one of the nodes blocks the push / pull + for id, n in ipairs(nodes) do + if mesecon.is_mvps_stopper(n.node, movedir, nodes, id) then + return + end + add_pos(protection_check_set, n.pos) + add_pos(protection_check_set, vector.add(n.pos, movedir)) + end + if are_protected(protection_check_set, player_name) then + return false, "protected" + end + + -- remove all nodes + for _, n in ipairs(nodes) do + n.meta = minetest.get_meta(n.pos):to_table() + local node_timer = minetest.get_node_timer(n.pos) + if node_timer:is_started() then + n.node_timer = {node_timer:get_timeout(), node_timer:get_elapsed()} + end + minetest.remove_node(n.pos) + end + + local oldstack = mesecon.tablecopy(nodes) + + -- 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) + end + + -- add nodes + for _, n in ipairs(nodes) do + local np = vector.add(n.pos, movedir) + + -- Turn off conductors in transit + local conductor = mesecon.get_conductor(n.node.name) + if conductor and conductor.state ~= mesecon.state.off then + n.node.name = conductor.offstate or conductor.states[1] + end + + minetest.set_node(np, n.node) + minetest.get_meta(np):from_table(n.meta) + if n.node_timer then + minetest.get_node_timer(np):set(unpack(n.node_timer)) + end + end + + local moved_nodes = {} + for i in ipairs(nodes) do + moved_nodes[i] = {} + moved_nodes[i].oldpos = nodes[i].pos + nodes[i].pos = vector.add(nodes[i].pos, movedir) + moved_nodes[i].pos = nodes[i].pos + moved_nodes[i].node = nodes[i].node + moved_nodes[i].meta = nodes[i].meta + moved_nodes[i].node_timer = nodes[i].node_timer + end + + on_mvps_move(moved_nodes) + + return true, nodes, oldstack +end + +function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor) + local dir_k + local dir_l + for k, v in pairs(dir) do + if v ~= 0 then + dir_k = k + dir_l = v + break + end + end + movefactor = movefactor or 1 + dir = vector.multiply(dir, movefactor) + for id, obj in pairs(minetest.get_objects_inside_radius(pos, #nodestack + 1)) do + local obj_pos = obj:get_pos() + local cbox = obj:get_properties().collisionbox + local min_pos = vector.add(obj_pos, vector.new(cbox[1], cbox[2], cbox[3])) + local max_pos = vector.add(obj_pos, vector.new(cbox[4], cbox[5], cbox[6])) + local ok = true + for k, v in pairs(pos) do + local edge1, edge2 + if k ~= dir_k then + edge1 = v - 0.51 -- More than 0.5 to move objects near to the stack. + edge2 = v + 0.51 + else + edge1 = v - 0.5 * dir_l + edge2 = v + (#nodestack + 0.5 * movefactor) * dir_l + -- Make sure, edge1 is bigger than edge2: + if edge1 > edge2 then + edge1, edge2 = edge2, edge1 + end + end + if min_pos[k] > edge2 or max_pos[k] < edge1 then + ok = false + break + end + end + if ok then + local ent = obj:get_luaentity() + if obj:is_player() or (ent and not mesecon.is_mvps_unmov(ent.name)) then + local np = vector.add(obj_pos, dir) + -- Move only if destination is not solid or object is inside stack: + local nn = minetest.get_node(np) + local node_def = minetest.registered_nodes[nn.name] + local obj_offset = dir_l * (obj_pos[dir_k] - pos[dir_k]) + if (node_def and not node_def.walkable) or + (obj_offset >= 0 and + obj_offset <= #nodestack - 0.5) then + obj:move_to(np) + end + end + end + end +end + +-- Never push into unloaded blocks. Don’t try to pull from them, either. +-- TODO: load blocks instead, as with wires. +mesecon.register_mvps_stopper("ignore") + +mesecon.register_on_mvps_move(mesecon.move_hot_nodes) +mesecon.register_on_mvps_move(function(moved_nodes) + for i = 1, #moved_nodes do + local moved_node = moved_nodes[i] + mesecon.on_placenode(moved_node.pos, moved_node.node) + minetest.after(0, function() + minetest.check_for_falling(moved_node.oldpos) + minetest.check_for_falling(moved_node.pos) + end) + local node_def = minetest.registered_nodes[moved_node.node.name] + if node_def and node_def.mesecon and node_def.mesecon.on_mvps_move then + node_def.mesecon.on_mvps_move(moved_node.pos, moved_node.node, + moved_node.oldpos, moved_node.meta) + end + end +end) diff --git a/mods/mesecons/mesecons_mvps/mod.conf b/mods/mesecons/mesecons_mvps/mod.conf new file mode 100644 index 00000000..3e347879 --- /dev/null +++ b/mods/mesecons/mesecons_mvps/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_mvps +depends = mesecons diff --git a/mods/mesecons/mesecons_mvps/spec/mineunit.conf b/mods/mesecons/mesecons_mvps/spec/mineunit.conf new file mode 100644 index 00000000..81bd36ce --- /dev/null +++ b/mods/mesecons/mesecons_mvps/spec/mineunit.conf @@ -0,0 +1 @@ +fixture_paths = {"../.test_fixtures"} diff --git a/mods/mesecons/mesecons_mvps/spec/node_spec.lua b/mods/mesecons/mesecons_mvps/spec/node_spec.lua new file mode 100644 index 00000000..2a9d1705 --- /dev/null +++ b/mods/mesecons/mesecons_mvps/spec/node_spec.lua @@ -0,0 +1,297 @@ +require("mineunit") + +fixture("mesecons_mvps") + +world.set_default_node("air") + +describe("node movement", function() + after_each(function() + mesecon._test_reset() + world.clear() + end) + + it("works with no moved nodes", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + + assert.same({true, {}, {}}, {mesecon.mvps_push(pos, dir, 1, "")}) + assert.same({true, {}, {}}, {mesecon.mvps_pull_all(pos, dir, 1, "")}) + assert.same({true, {}, {}}, {mesecon.mvps_pull_single(pos, dir, 1, "")}) + end) + + it("works with simple stack", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + world.set_node(vector.add(pos, dir), "mesecons:test_conductor_off") + + assert.is_true((mesecon.mvps_push(pos, dir, 2, ""))) + assert.equal("air", world.get_node(pos).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, vector.multiply(dir, 2))).name) + + assert.is_true((mesecon.mvps_pull_all(vector.add(pos, dir), vector.multiply(dir, -1), 2, ""))) + assert.equal("mesecons:test_conductor_off", world.get_node(pos).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name) + assert.equal("air", world.get_node(vector.add(pos, vector.multiply(dir, 2))).name) + + assert.is_true((mesecon.mvps_pull_single(pos, vector.multiply(dir, -1), 1, ""))) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.subtract(pos, dir)).name) + assert.equal("air", world.get_node(pos).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name) + end) + + it("works with sticky nodes", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 0, y = 1, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + world.set_node(vector.offset(pos, 0, 1, 0), "mesecons_mvps:test_sticky") + world.set_node(vector.offset(pos, 1, 1, 0), "mesecons:test_conductor_off") + world.set_node(vector.offset(pos, 1, 2, 0), "mesecons:test_conductor_off") + + assert.is_true((mesecon.mvps_push(pos, dir, 4, ""))) + assert.equal("air", world.get_node(vector.offset(pos, 1, 1, 0)).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 2, 0)).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 3, 0)).name) + + assert.is_true((mesecon.mvps_pull_all(vector.add(pos, dir), vector.multiply(dir, -1), 4, ""))) + assert.equal("air", world.get_node(vector.offset(pos, 1, 0, 0)).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 1, 0)).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 2, 0)).name) + + assert.is_true((mesecon.mvps_pull_single(pos, vector.multiply(dir, -1), 3, ""))) + assert.equal("air", world.get_node(vector.offset(pos, 1, -1, 0)).name) + assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 0, 0)).name) + assert.equal("air", world.get_node(vector.offset(pos, 1, 1, 0)).name) + end) + + it("respects maximum", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + world.set_node(vector.add(pos, dir), "mesecons:test_conductor_off") + + assert.is_true(not mesecon.mvps_push(pos, dir, 1, "")) + end) + + it("is blocked by basic stopper", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + world.set_node(pos, "mesecons_mvps:test_stopper") + + assert.is_true(not mesecon.mvps_push(pos, dir, 1, "")) + end) + + it("is blocked by conditional stopper", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + + world.set_node(pos, {name = "mesecons_mvps:test_stopper_cond", param2 = 0}) + assert.is_true(not mesecon.mvps_push(pos, dir, 1, "")) + + world.set_node(pos, {name = "mesecons_mvps:test_stopper_cond", param2 = 1}) + assert.is_true((mesecon.mvps_push(pos, dir, 1, ""))) + end) + + -- TODO: I think this is supposed to work? + pending("is blocked by ignore", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + world.set_node(vector.add(pos, dir), "ignore") + + assert.is_true(not mesecon.mvps_push(pos, dir, 1, "")) + end) + + it("moves metadata", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + minetest.get_meta(pos):set_string("foo", "bar") + minetest.get_node_timer(pos):set(12, 34) + + mesecon.mvps_push(pos, dir, 1, "") + assert.equal("bar", minetest.get_meta(vector.add(pos, dir)):get("foo")) + local moved_timer = minetest.get_node_timer(vector.add(pos, dir)) + assert.equal(12, moved_timer:get_timeout()) + assert.equal(34, moved_timer:get_elapsed()) + moved_timer:stop() + assert.same({}, minetest.get_meta(pos):to_table().fields) + assert.is_false(minetest.get_node_timer(pos):is_started()) + end) + + it("calls move callbacks", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + world.set_node(pos, {name = "mesecons_mvps:test_on_move", param2 = 123}) + minetest.get_meta(pos):set_string("foo", "bar") + local move_info = {vector.add(pos, dir), world.get_node(pos), pos, minetest.get_meta(pos):to_table()} + + mesecon.mvps_push(pos, dir, 1, "") + assert.equal(1, #mesecon._test_moves) + assert.same(move_info, mesecon._test_moves[1]) + end) + + it("executes autoconnect hooks", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + + mesecon.mvps_push(pos, dir, 1, "") + mineunit:execute_globalstep() -- Execute delayed autoconnect hook + assert.equal(2, #mesecon._test_autoconnects) + end) + + it("updates moved receptors", function() + local pos1 = {x = 0, y = 0, z = 0} + local pos2 = vector.offset(pos1, 0, 1, 0) + local pos3 = vector.offset(pos1, 2, 0, 0) + local pos4 = vector.offset(pos1, 0, 0, 1) + local dir = {x = 1, y = 0, z = 0} + mesecon._test_place(pos1, "mesecons:test_receptor_on") + mesecon._test_place(pos2, "mesecons:test_conductor_off") + mesecon._test_place(pos3, "mesecons:test_conductor_off") + mesecon._test_place(pos4, "mesecons:test_conductor_off") + mesecon._test_place(vector.add(pos4, dir), "mesecons:test_conductor_off") + mineunit:execute_globalstep() -- Execute receptor_on action + + mesecon.mvps_push(pos1, dir, 1, "") + mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions + assert.equal("mesecons:test_conductor_off", world.get_node(pos2).name) + assert.equal("mesecons:test_conductor_on", world.get_node(pos3).name) + assert.equal("mesecons:test_conductor_on", world.get_node(pos4).name) + end) + + it("updates moved conductors", function() + local pos1 = {x = 0, y = 0, z = 0} + local pos2 = vector.offset(pos1, 0, 1, 0) + local pos3 = vector.offset(pos1, 0, -1, 0) + local dir = {x = 1, y = 0, z = 0} + mesecon._test_place(pos1, "mesecons:test_conductor_off") + mesecon._test_place(pos2, "mesecons:test_receptor_on") + mesecon._test_place(pos3, "mesecons:test_conductor_off") + mineunit:execute_globalstep() -- Execute receptor_on action + + mesecon.mvps_push(pos1, dir, 1, "") + mineunit:execute_globalstep() -- Execute receptor_off action + assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos1, dir)).name) + assert.equal("mesecons:test_conductor_off", world.get_node(pos3).name) + + mesecon.mvps_pull_all(vector.add(pos1, dir), vector.multiply(dir, -1), 1, "") + mineunit:execute_globalstep() -- Execute receptor_on action + assert.equal("mesecons:test_conductor_on", world.get_node(pos1).name) + assert.equal("mesecons:test_conductor_on", world.get_node(pos3).name) + end) + + it("updates moved effectors", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + mesecon._test_place(pos, "mesecons:test_effector") + mesecon._test_place(vector.offset(pos, 0, 1, 0), "mesecons:test_receptor_on") + mesecon._test_place(vector.add(pos, dir), "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + + mesecon.mvps_push(pos, dir, 2, "") + mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions + mineunit:execute_globalstep() -- Execute activate/deactivate/change actions + assert.equal(tonumber("10000001", 2), world.get_node(vector.add(pos, dir)).param2) + + mineunit:execute_globalstep() -- Let the component cool down + + mesecon.mvps_pull_single(vector.add(pos, dir), vector.multiply(dir, -1), 1, "") + mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions + mineunit:execute_globalstep() -- Execute activate/deactivate/change actions + assert.equal(tonumber("10000100", 2), world.get_node(pos).param2) + end) + + -- Since turnon is called before turnoff when pushing, effectors may be incorrectly turned off. + it("does not overwrite turnon with receptor_off", function() + local pos = {x = 0, y = 0, z = 0} + local dir = {x = 1, y = 0, z = 0} + mesecon._test_place(pos, "mesecons:test_effector") + mesecon._test_place(vector.add(pos, dir), "mesecons:test_conductor_off") + mesecon._test_place(vector.add(pos, vector.multiply(dir, 2)), "mesecons:test_receptor_on") + mineunit:execute_globalstep() -- Execute receptor_on action + mineunit:execute_globalstep() -- Execute activate/change actions + + mesecon.mvps_push(pos, dir, 3, "") + mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions + mineunit:execute_globalstep() -- Execute activate/deactivate/change actions + assert.equal(tonumber("10000001", 2), world.get_node(vector.add(pos, dir)).param2) + end) + + -- mineunit doesn't yet implement minetest.check_for_falling. + pending("causes nodes to fall", function() + end) +end) + +describe("protection", function() + teardown(function() + minetest.settings:remove("mesecon.mvps_protection_mode") + end) + + after_each(function() + mesecon._test_reset() + world.clear() + end) + + local protected_pos = {x = 1, y = 0, z = 0} + mineunit:protect(protected_pos, "Joe") + + it("blocks movement", function() + minetest.settings:set("mesecon.mvps_protection_mode", "restrict") + + local pos = {x = 0, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + + assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Bob")}) + end) + + it("allows owner's movement", function() + minetest.settings:set("mesecon.mvps_protection_mode", "restrict") + + local pos = {x = 0, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + + assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Joe"))) + end) + + it("'ignore'", function() + minetest.settings:set("mesecon.mvps_protection_mode", "ignore") + + local pos = {x = 0, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + + assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Bob"))) + end) + + it("'normal'", function() + minetest.settings:set("mesecon.mvps_protection_mode", "normal") + + local pos = {x = 0, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + + assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "")}) + + assert.is_true((mesecon.mvps_push(pos, {x = 0, y = 1, z = 0}, 1, ""))) + end) + + it("'compat'", function() + minetest.settings:set("mesecon.mvps_protection_mode", "compat") + + local pos = {x = 0, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + + assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, ""))) + end) + + it("'restrict'", function() + minetest.settings:set("mesecon.mvps_protection_mode", "restrict") + + local pos = {x = 0, y = 0, z = 0} + world.set_node(pos, "mesecons:test_conductor_off") + + assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 0, y = 1, z = 0}, 1, "")}) + end) +end) diff --git a/mods/mesecons/mesecons_mvps/spec/object_spec.lua b/mods/mesecons/mesecons_mvps/spec/object_spec.lua new file mode 100644 index 00000000..cc2ca8d0 --- /dev/null +++ b/mods/mesecons/mesecons_mvps/spec/object_spec.lua @@ -0,0 +1,3 @@ +-- mineunit doesn't yet implement minetest.get_objects_inside_radius +pending("object movement", function() +end) diff --git a/mods/mesecons/mesecons_noteblock/README.txt b/mods/mesecons/mesecons_noteblock/README.txt new file mode 100644 index 00000000..e0ad34ca --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/README.txt @@ -0,0 +1,15 @@ +Credits of sound files: + +Note: Most sounds have not been used verbatim, but tweaked a little to be more suitable for the noteblock mod. + +* mesecons_noteblock_litecrash.ogg + * License: CC BY 3.0 + * by freesound.org user ani_music + * Source: https://freesound.org/people/ani_music/sounds/219612/ + +Everything else: +Created by Mesecons authors, licensed CC BY 3.0. + +-------------------- +License links: +* CC BY 3.0: http://creativecommons.org/licenses/by/3.0/ diff --git a/mods/mesecons/mesecons_noteblock/doc/noteblock/description.html b/mods/mesecons/mesecons_noteblock/doc/noteblock/description.html new file mode 100644 index 00000000..a98c0f93 --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/doc/noteblock/description.html @@ -0,0 +1,13 @@ +This effector makes a sound if powered and can be used for making music. Normally it makes piano sounds. The sound frequency can be changed by punching the block (only works for piano). There are some special sounds that depend on the block below: + + + + + + + + + + + +
Block BelowEffect
Glass or Obsidian GlassHi-hat
Any stoneKick
Chest or Locked ChestSnare
Any treeCrash
Any wooden planksLite Crash
Coal BlockExplosion sound (fixed pitch)
Lava SourceFire sound (fixed pitch)
Steel BlockPiano (high pitch, one octave higher than normal)
Any other blockPiano (low pitch)
diff --git a/mods/mesecons/mesecons_noteblock/doc/noteblock/preview.png b/mods/mesecons/mesecons_noteblock/doc/noteblock/preview.png new file mode 100644 index 00000000..81a82f51 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/doc/noteblock/preview.png differ diff --git a/mods/mesecons/mesecons_noteblock/doc/noteblock/recipe.png b/mods/mesecons/mesecons_noteblock/doc/noteblock/recipe.png new file mode 100644 index 00000000..2023b44e Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/doc/noteblock/recipe.png differ diff --git a/mods/mesecons/mesecons_noteblock/init.lua b/mods/mesecons/mesecons_noteblock/init.lua new file mode 100644 index 00000000..847c40be --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/init.lua @@ -0,0 +1,120 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +minetest.register_node("mesecons_noteblock:noteblock", { + description = S("Noteblock"), + tiles = {"mesecons_noteblock.png"}, + is_ground_content = false, + groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}, + on_punch = function(pos, node, puncher) -- change sound when punched + if minetest.is_protected(pos, puncher and puncher:get_player_name() or "") then + return + end + + node.param2 = (node.param2+1)%12 + mesecon.noteblock_play(pos, node.param2) + minetest.set_node(pos, node) + end, + sounds = mesecon.node_sound.wood, + mesecons = {effector = { -- play sound when activated + action_on = function(pos, node) + mesecon.noteblock_play(pos, node.param2) + end + }}, + place_param2 = 11, -- initialize at C note + on_blast = mesecon.on_blastnode, +}) + +minetest.register_craft({ + output = "mesecons_noteblock:noteblock 1", + recipe = { + {"group:wood", "group:wood", "group:wood"}, + {"group:mesecon_conductor_craftable", "mesecons_gamecompat:steel_ingot", "group:mesecon_conductor_craftable"}, + {"group:wood", "group:wood", "group:wood"}, + } +}) + +local soundnames = { + [0] = "mesecons_noteblock_csharp", + "mesecons_noteblock_d", + "mesecons_noteblock_dsharp", + "mesecons_noteblock_e", + "mesecons_noteblock_f", + "mesecons_noteblock_fsharp", + "mesecons_noteblock_g", + "mesecons_noteblock_gsharp", + + "mesecons_noteblock_a", + "mesecons_noteblock_asharp", + "mesecons_noteblock_b", + "mesecons_noteblock_c" -- << noteblock is initialized here +} + +local node_sounds = {} +for alias, sound in pairs({ + ["mesecons_gamecompat:lava_source"] = mesecon.sound_name.fire, + ["mesecons_gamecompat:chest"] = "mesecons_noteblock_snare", + ["mesecons_gamecompat:chest_locked"] = "mesecons_noteblock_snare", + ["mesecons_gamecompat:coalblock"] = mesecon.sound_name.explode, + ["mesecons_gamecompat:glass"] = "mesecons_noteblock_hihat", + ["mesecons_gamecompat:obsidian_glass"] = "mesecons_noteblock_hihat", +}) do + local nodename = minetest.registered_aliases[alias] + if nodename then + node_sounds[nodename] = sound + end +end + +local node_sounds_group = { + ["stone"] = "mesecons_noteblock_kick", + ["tree"] = "mesecons_noteblock_crash", + ["wood"] = "mesecons_noteblock_litecrash", +} + +local steelblock_nodename = minetest.registered_aliases["mesecons_gamecompat:steelblock"] +mesecon.noteblock_play = function(pos, param2) + pos.y = pos.y-1 + local nodeunder = minetest.get_node(pos).name + local soundname = node_sounds[nodeunder] + local use_pitch = true + local pitch + -- Special sounds + if not soundname then + for k,v in pairs(node_sounds_group) do + local g = minetest.get_item_group(nodeunder, k) + if g ~= 0 then + soundname = v + break + end + end + end + -- Piano + if not soundname then + soundname = soundnames[param2] + if not soundname then + minetest.log("error", "[mesecons_noteblock] No soundname found, test param2") + return + end + if nodeunder == steelblock_nodename then + soundname = soundname.. 2 + end + use_pitch = false + end + -- Disable pitch for fire and explode because they'd sound too odd + if soundname == "fire_fire" or soundname == "tnt_explode" then + use_pitch = false + end + if use_pitch then + -- Calculate pitch + -- Adding 1 to param2 because param2=11 is *lowest* pitch sound + local val = (param2+1)%12 + pitch = 2^((val-6)/12) + end + pos.y = pos.y+1 + if soundname == "fire_fire" then + -- Smoothly fade out fire sound + local handle = minetest.sound_play(soundname, {pos = pos, loop = true}) + minetest.after(3.0, minetest.sound_fade, handle, -1.5, 0.0) + else + minetest.sound_play(soundname, {pos = pos, pitch = pitch}, true) + end +end diff --git a/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.de.tr b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.de.tr new file mode 100644 index 00000000..88d82c37 --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_noteblock +Noteblock=Notenblock diff --git a/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.eo.tr b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.eo.tr new file mode 100644 index 00000000..bea37358 --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_noteblock + +### init.lua ### +Noteblock=Sonbloko diff --git a/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.fr.tr b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.fr.tr new file mode 100644 index 00000000..8a2d6321 --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_noteblock + +### init.lua ### +Noteblock=Bloc de musique diff --git a/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.ru.tr b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.ru.tr new file mode 100644 index 00000000..29960eea --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_noteblock + +### init.lua ### +Noteblock=Нотный блок diff --git a/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.uk.tr b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.uk.tr new file mode 100644 index 00000000..bc2faec5 --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/locale/mesecons_noteblock.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_noteblock + +### init.lua ### +Noteblock=Нотний блок diff --git a/mods/mesecons/mesecons_noteblock/locale/template.txt b/mods/mesecons/mesecons_noteblock/locale/template.txt new file mode 100644 index 00000000..bcd37547 --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_noteblock + +### init.lua ### +Noteblock= diff --git a/mods/mesecons/mesecons_noteblock/mod.conf b/mods/mesecons/mesecons_noteblock/mod.conf new file mode 100644 index 00000000..261424b1 --- /dev/null +++ b/mods/mesecons/mesecons_noteblock/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_noteblock +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a.ogg new file mode 100644 index 00000000..331fc1cc Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a2.ogg new file mode 100644 index 00000000..695b0f4e Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_a2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp.ogg new file mode 100644 index 00000000..db96aedb Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp2.ogg new file mode 100644 index 00000000..27bd09df Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_asharp2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b.ogg new file mode 100644 index 00000000..810fe18f Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b2.ogg new file mode 100644 index 00000000..3de1250d Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_b2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c.ogg new file mode 100644 index 00000000..5c60d315 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c2.ogg new file mode 100644 index 00000000..724db7de Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_c2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_crash.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_crash.ogg new file mode 100644 index 00000000..0308d11a Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_crash.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp.ogg new file mode 100644 index 00000000..12c1ef38 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp2.ogg new file mode 100644 index 00000000..fc7f6c88 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_csharp2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d.ogg new file mode 100644 index 00000000..929b7fba Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d2.ogg new file mode 100644 index 00000000..dfd702b1 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_d2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp.ogg new file mode 100644 index 00000000..eb6045d4 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp2.ogg new file mode 100644 index 00000000..5ac16dde Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_dsharp2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e.ogg new file mode 100644 index 00000000..94977e0d Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e2.ogg new file mode 100644 index 00000000..1dcc0c4a Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_e2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f.ogg new file mode 100644 index 00000000..221d9264 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f2.ogg new file mode 100644 index 00000000..acf10dbb Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_f2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp.ogg new file mode 100644 index 00000000..7af83a8e Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp2.ogg new file mode 100644 index 00000000..a96f6371 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_fsharp2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g.ogg new file mode 100644 index 00000000..480ca367 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g2.ogg new file mode 100644 index 00000000..917b2b9c Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_g2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp.ogg new file mode 100644 index 00000000..2e71fea0 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp2.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp2.ogg new file mode 100644 index 00000000..941c6856 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_gsharp2.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_hihat.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_hihat.ogg new file mode 100644 index 00000000..0afa7c07 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_hihat.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_kick.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_kick.ogg new file mode 100644 index 00000000..10d585b8 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_kick.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_litecrash.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_litecrash.ogg new file mode 100644 index 00000000..36d83f39 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_litecrash.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_snare.ogg b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_snare.ogg new file mode 100644 index 00000000..83a79441 Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/sounds/mesecons_noteblock_snare.ogg differ diff --git a/mods/mesecons/mesecons_noteblock/textures/mesecons_noteblock.png b/mods/mesecons/mesecons_noteblock/textures/mesecons_noteblock.png new file mode 100644 index 00000000..be4dd1bd Binary files /dev/null and b/mods/mesecons/mesecons_noteblock/textures/mesecons_noteblock.png differ diff --git a/mods/mesecons/mesecons_pistons/doc/piston/description.html b/mods/mesecons/mesecons_pistons/doc/piston/description.html new file mode 100644 index 00000000..b9dffaab --- /dev/null +++ b/mods/mesecons/mesecons_pistons/doc/piston/description.html @@ -0,0 +1,3 @@ +Pistons are effectors, they push up to 20 blocks in front of them. The push direction can be set by placing them from different angles. +A piston pointing into an unloaded block won't extend. +A piston retracting from an unloaded block works, but gravity-sensitive nodes above the empty space may not fall. diff --git a/mods/mesecons/mesecons_pistons/doc/piston/preview.png b/mods/mesecons/mesecons_pistons/doc/piston/preview.png new file mode 100644 index 00000000..44e0ab0d Binary files /dev/null and b/mods/mesecons/mesecons_pistons/doc/piston/preview.png differ diff --git a/mods/mesecons/mesecons_pistons/doc/piston/recipe.png b/mods/mesecons/mesecons_pistons/doc/piston/recipe.png new file mode 100644 index 00000000..1b0f4a45 Binary files /dev/null and b/mods/mesecons/mesecons_pistons/doc/piston/recipe.png differ diff --git a/mods/mesecons/mesecons_pistons/doc/piston_sticky/description.html b/mods/mesecons/mesecons_pistons/doc/piston_sticky/description.html new file mode 100644 index 00000000..580b76f6 --- /dev/null +++ b/mods/mesecons/mesecons_pistons/doc/piston_sticky/description.html @@ -0,0 +1,4 @@ +Sticky pistons are effectors, they push up to 20 blocks in front of them. The push direction can be set by placing them from different angles. Sticky ones also pull 1 block. +A sticky piston pointing into an unloaded block won't extend. +A sticky piston retracting from within an unloaded block works and pulls a node, but if it doesn't pull anything, then gravity-sensitive nodes above the empty space may not fall. +An extended sticky piston that touches the surface of an unloaded block and loses signal retracts but doesn't pull anything. diff --git a/mods/mesecons/mesecons_pistons/doc/piston_sticky/preview.png b/mods/mesecons/mesecons_pistons/doc/piston_sticky/preview.png new file mode 100644 index 00000000..2c1911bb Binary files /dev/null and b/mods/mesecons/mesecons_pistons/doc/piston_sticky/preview.png differ diff --git a/mods/mesecons/mesecons_pistons/doc/piston_sticky/recipe.png b/mods/mesecons/mesecons_pistons/doc/piston_sticky/recipe.png new file mode 100644 index 00000000..a38e8bee Binary files /dev/null and b/mods/mesecons/mesecons_pistons/doc/piston_sticky/recipe.png differ diff --git a/mods/mesecons/mesecons_pistons/init.lua b/mods/mesecons/mesecons_pistons/init.lua new file mode 100644 index 00000000..052a5dcd --- /dev/null +++ b/mods/mesecons/mesecons_pistons/init.lua @@ -0,0 +1,470 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local specs = { + normal = { + offname = "mesecons_pistons:piston_normal_off", + onname = "mesecons_pistons:piston_normal_on", + pusher = "mesecons_pistons:piston_pusher_normal", + }, + sticky = { + offname = "mesecons_pistons:piston_sticky_off", + onname = "mesecons_pistons:piston_sticky_on", + pusher = "mesecons_pistons:piston_pusher_sticky", + sticky = true, + }, +} + +local function get_pistonspec_name(name, part) + if part then + for spec_name, spec in pairs(specs) do + if name == spec[part] then + return spec_name, part + end + end + return + end + for spec_name, spec in pairs(specs) do + for part, value in pairs(spec) do + if name == value then + return spec_name, part + end + end + end +end + +local function get_pistonspec(name, part) + return specs[get_pistonspec_name(name, part)] +end + +local max_push = mesecon.setting("piston_max_push", 15) +local max_pull = mesecon.setting("piston_max_pull", 15) + +-- Get mesecon rules of pistons +local function piston_get_rules(node) + local dir = minetest.facedir_to_dir(node.param2) + for k, v in pairs(dir) do + if v ~= 0 then + dir = {k, -v} + break + end + end + local rules = table.copy(mesecon.rules.default) + for i, rule in ipairs(rules) do + if rule[dir[1]] == dir[2] then + table.remove(rules, i) + end + end + return rules +end + +local function piston_remove_pusher(pos, node, check_falling) + local pistonspec = get_pistonspec(node.name, "onname") + local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1) + local pusherpos = vector.add(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 + + minetest.remove_node(pusherpos) + minetest.sound_play("piston_retract", { pos = pos, max_hear_distance = 20, gain = 0.3 }, true) + + if check_falling then + minetest.check_for_falling(pusherpos) + end +end + +local function piston_after_dig(pos, node) + piston_remove_pusher(pos, node, true) +end + +local piston_on = function(pos, node) + local pistonspec = get_pistonspec(node.name, "offname") + local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1) + local pusher_pos = vector.add(pos, dir) + local meta = minetest.get_meta(pos) + local success, stack, oldstack = mesecon.mvps_push(pusher_pos, dir, max_push, meta:get_string("owner")) + if not success then + if stack == "protected" then + meta:set_string("infotext", "Can't extend: protected area on the way") + end + return + end + minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.onname}) + minetest.set_node(pusher_pos, {param2 = node.param2, name = pistonspec.pusher}) + minetest.sound_play("piston_extend", { pos = pos, max_hear_distance = 20, gain = 0.3 }, true) + mesecon.mvps_move_objects(pusher_pos, dir, oldstack) +end + +local function piston_off(pos, node) + local pistonspec = get_pistonspec(node.name, "onname") + minetest.swap_node(pos, {param2 = node.param2, name = pistonspec.offname}) + piston_remove_pusher(pos, node, not pistonspec.sticky) -- allow that even in protected area + + if not pistonspec.sticky then + return + end + local dir = minetest.facedir_to_dir(node.param2) + local pullpos = vector.add(pos, vector.multiply(dir, -2)) + local meta = minetest.get_meta(pos) + local success, _, oldstack = mesecon.mvps_pull_single(pullpos, dir, max_pull, meta:get_string("owner")) + if success then + mesecon.mvps_move_objects(pullpos, vector.multiply(dir, -1), oldstack, -1) + end +end + +local function piston_orientate(pos, placer) + mesecon.mvps_set_owner(pos, placer) + if not placer then + return + end + local node = minetest.get_node(pos) + node.param2 = core.dir_to_facedir(placer:get_look_dir(), true) + minetest.swap_node(pos, node) + -- minetest.after, because on_placenode for unoriented piston must be processed first + minetest.after(0, mesecon.on_placenode, pos, node) +end + +local rotations = { + {0, 16, 20, 12}, + {2, 14, 22, 18}, + {1, 5, 23, 9}, + {3, 11, 21, 7}, + {4, 13, 10, 19}, + {6, 15, 8, 17}, +} + +local function get_rotation(param2) + for a = 1, #rotations do + for f = 1, #rotations[a] do + if rotations[a][f] == param2 then + return a, f + end + end + end +end + +local function rotate(param2, mode) + local axis, face = get_rotation(param2) + if mode == screwdriver.ROTATE_FACE then + face = face + 1 + if face > 4 then + face = 1 + end + elseif mode == screwdriver.ROTATE_AXIS then + axis = axis + 1 + if axis > 6 then + axis = 1 + end + face = 1 + else + return param2 + end + return rotations[axis][face] +end + +local function piston_rotate(pos, node, _, mode) + node.param2 = rotate(node.param2, mode) + minetest.swap_node(pos, node) + mesecon.execute_autoconnect_hooks_now(pos, node) + return true +end + +local function piston_rotate_on(pos, node, player, mode) + local pistonspec = get_pistonspec(node.name, "onname") + local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1) + local pusher_pos = vector.add(dir, pos) + local pusher_node = minetest.get_node(pusher_pos) + if pusher_node.name ~= pistonspec.pusher then + return piston_rotate(pos, node, nil, mode) + end + if mode == screwdriver.ROTATE_FACE then + piston_rotate(pusher_pos, pusher_node, nil, mode) + return piston_rotate(pos, node, nil, mode) + elseif mode ~= screwdriver.ROTATE_AXIS then + return false + end + local player_name = player and player:is_player() and player:get_player_name() or "" + local ok, dir_after, pusher_pos_after + for i = 1, 5 do + node.param2 = rotate(node.param2, mode) + dir_after = vector.multiply(minetest.facedir_to_dir(node.param2), -1) + pusher_pos_after = vector.add(dir_after, pos) + local pusher_pos_after_node_name = minetest.get_node(pusher_pos_after).name + local pusher_pos_after_node_def = minetest.registered_nodes[pusher_pos_after_node_name] + if pusher_pos_after_node_def and pusher_pos_after_node_def.buildable_to and + not minetest.is_protected(pusher_pos_after, player_name) then + ok = true + break + end + end + if not ok then + return false + end + pusher_node.param2 = node.param2 + minetest.remove_node(pusher_pos) + minetest.set_node(pusher_pos_after, pusher_node) + minetest.swap_node(pos, node) + mesecon.execute_autoconnect_hooks_now(pos, node) + return true +end + +local function piston_rotate_pusher(pos, node, player, mode) + local pistonspec = get_pistonspec(node.name, "pusher") + local piston_pos = vector.add(pos, minetest.facedir_to_dir(node.param2)) + local piston_node = minetest.get_node(piston_pos) + if piston_node.name ~= pistonspec.onname then + minetest.remove_node(pos) -- Make it possible to remove alone pushers. + return false + end + return piston_rotate_on(piston_pos, piston_node, player, mode) +end + +local function piston_punch(pos, _, player) + local player_name = player and player.get_player_name and player:get_player_name() + if mesecon.mvps_claim(pos, player_name) then + minetest.chat_send_player(player_name, "Reclaimed piston") + end +end + + +-- Boxes: + +local pt = 3/16 -- pusher thickness + +local piston_pusher_box = { + type = "fixed", + fixed = { + {-2/16, -2/16, -.5 + pt, 2/16, 2/16, .5 + pt}, + {-.5 , -.5 , -.5 , .5 , .5 , -.5 + pt}, + }, +} + +local piston_on_box = { + type = "fixed", + fixed = { + {-.5, -.5, -.5 + pt, .5, .5, .5} + }, +} + + +-- Normal (non-sticky) Pistons: +-- offstate +minetest.register_node("mesecons_pistons:piston_normal_off", { + description = S("Piston"), + tiles = { + "mesecons_piston_top.png", + "mesecons_piston_top.png^[transform2", + "mesecons_piston_top.png^[transform3", + "mesecons_piston_top.png^[transform1", + "mesecons_piston_back.png", + "mesecons_piston_pusher_front.png" + }, + groups = {cracky = 3}, + paramtype2 = "facedir", + is_ground_content = false, + after_place_node = piston_orientate, + sounds = mesecon.node_sound.wood, + mesecons = {effector={ + action_on = piston_on, + rules = piston_get_rules, + }}, + on_punch = piston_punch, + on_rotate = piston_rotate, + on_blast = mesecon.on_blastnode, +}) + +-- onstate +minetest.register_node("mesecons_pistons:piston_normal_on", { + description = S("Activated Piston Base"), + drawtype = "nodebox", + tiles = { + "mesecons_piston_top.png", + "mesecons_piston_top.png^[transform2", + "mesecons_piston_top.png^[transform3", + "mesecons_piston_top.png^[transform1", + "mesecons_piston_back.png", + "mesecons_piston_on_front.png" + }, + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + drop = "mesecons_pistons:piston_normal_off", + after_dig_node = piston_after_dig, + node_box = piston_on_box, + selection_box = piston_on_box, + sounds = mesecon.node_sound.wood, + mesecons = {effector={ + action_off = piston_off, + rules = piston_get_rules, + }}, + on_rotate = piston_rotate_on, + on_blast = mesecon.on_blastnode, +}) + +-- pusher +minetest.register_node("mesecons_pistons:piston_pusher_normal", { + description = S("Piston Pusher"), + drawtype = "nodebox", + tiles = { + "mesecons_piston_pusher_top.png", + "mesecons_piston_pusher_top.png^[transform2", + "mesecons_piston_pusher_top.png^[transform3", + "mesecons_piston_pusher_top.png^[transform1", + "mesecons_piston_pusher_back.png", + "mesecons_piston_pusher_front.png" + }, + groups = {not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + diggable = false, + selection_box = piston_pusher_box, + node_box = piston_pusher_box, + on_rotate = piston_rotate_pusher, + drop = "", + sounds = mesecon.node_sound.wood, +}) + +-- Sticky ones +-- offstate +minetest.register_node("mesecons_pistons:piston_sticky_off", { + description = S("Sticky Piston"), + tiles = { + "mesecons_piston_top.png", + "mesecons_piston_top.png^[transform2", + "mesecons_piston_top.png^[transform3", + "mesecons_piston_top.png^[transform1", + "mesecons_piston_back.png", + "mesecons_piston_pusher_front_sticky.png" + }, + groups = {cracky = 3}, + paramtype2 = "facedir", + is_ground_content = false, + after_place_node = piston_orientate, + sounds = mesecon.node_sound.wood, + mesecons = {effector={ + action_on = piston_on, + rules = piston_get_rules, + }}, + on_punch = piston_punch, + on_rotate = piston_rotate, + on_blast = mesecon.on_blastnode, +}) + +-- onstate +minetest.register_node("mesecons_pistons:piston_sticky_on", { + description = S("Activated Sticky Piston Base"), + drawtype = "nodebox", + tiles = { + "mesecons_piston_top.png", + "mesecons_piston_top.png^[transform2", + "mesecons_piston_top.png^[transform3", + "mesecons_piston_top.png^[transform1", + "mesecons_piston_back.png", + "mesecons_piston_on_front.png" + }, + groups = {cracky = 3, not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + drop = "mesecons_pistons:piston_sticky_off", + after_dig_node = piston_after_dig, + node_box = piston_on_box, + selection_box = piston_on_box, + sounds = mesecon.node_sound.wood, + mesecons = {effector={ + action_off = piston_off, + rules = piston_get_rules, + }}, + on_rotate = piston_rotate_on, + on_blast = mesecon.on_blastnode, +}) + +-- pusher +minetest.register_node("mesecons_pistons:piston_pusher_sticky", { + description = S("Sticky Piston Pusher"), + drawtype = "nodebox", + tiles = { + "mesecons_piston_pusher_top.png", + "mesecons_piston_pusher_top.png^[transform2", + "mesecons_piston_pusher_top.png^[transform3", + "mesecons_piston_pusher_top.png^[transform1", + "mesecons_piston_pusher_back.png", + "mesecons_piston_pusher_front_sticky.png" + }, + groups = {not_in_creative_inventory = 1}, + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + diggable = false, + selection_box = piston_pusher_box, + node_box = piston_pusher_box, + on_rotate = piston_rotate_pusher, + drop = "", + sounds = mesecon.node_sound.wood, +}) + + +-- Register pushers as stoppers if they would be seperated from the piston +local function piston_pusher_get_stopper(node, _, stack, stackid) + if (stack[stackid + 1] + and stack[stackid + 1].node.name == get_pistonspec(node.name, "pusher").onname + and stack[stackid + 1].node.param2 == node.param2) + or (stack[stackid - 1] + and stack[stackid - 1].node.name == get_pistonspec(node.name, "pusher").onname + and stack[stackid - 1].node.param2 == node.param2) then + return false + end + 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) + + +-- Register pistons as stoppers if they would be seperated from the stopper +local function piston_get_stopper(node, _, stack, stackid) + local pistonspec = get_pistonspec(node.name, "onname") + local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1) + local pusherpos = vector.add(stack[stackid].pos, dir) + local pushernode = minetest.get_node(pusherpos) + if pistonspec.pusher == pushernode.name then + for _, s in ipairs(stack) do + if vector.equals(s.pos, pusherpos) -- pusher is also to be pushed + and s.node.param2 == node.param2 then + return false + end + end + end + 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) + + +--craft recipes +minetest.register_craft({ + output = "mesecons_pistons:piston_normal_off 2", + recipe = { + {"group:wood", "group:wood", "group:wood"}, + {"mesecons_gamecompat:cobble", "mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:cobble"}, + {"mesecons_gamecompat:cobble", "group:mesecon_conductor_craftable", "mesecons_gamecompat:cobble"}, + } +}) + +minetest.register_craft({ + output = "mesecons_pistons:piston_sticky_off", + recipe = { + {"mesecons_materials:glue"}, + {"mesecons_pistons:piston_normal_off"}, + } +}) + + +-- load legacy code +dofile(minetest.get_modpath("mesecons_pistons").."/legacy.lua") diff --git a/mods/mesecons/mesecons_pistons/legacy.lua b/mods/mesecons/mesecons_pistons/legacy.lua new file mode 100644 index 00000000..0c6dcb33 --- /dev/null +++ b/mods/mesecons/mesecons_pistons/legacy.lua @@ -0,0 +1,48 @@ +local ground_dir = { + [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}, +} + +minetest.register_lbm({ + label = "Upgrade legacy pistons pointing up", + name = "mesecons_pistons:replace_legacy_piston_up", + nodenames = { + "mesecons_pistons:piston_up_normal_off", + "mesecons_pistons:piston_up_normal_on", + "mesecons_pistons:piston_up_pusher_normal", + "mesecons_pistons:piston_up_sticky_off", + "mesecons_pistons:piston_up_sticky_on", + "mesecons_pistons:piston_up_pusher_sticky", + }, + run_at_every_load = false, + action = function(pos, node) + local dir = ground_dir[math.floor(node.param2/4)] + node.param2 = minetest.dir_to_facedir(dir, true) + node.name = node.name:sub(1, 24)..node.name:sub(28) + minetest.swap_node(pos, node) + end, +}) + +minetest.register_lbm({ + label = "Upgrade legacy pistons pointing down", + name = "mesecons_pistons:replace_legacy_piston_down", + nodenames = { + "mesecons_pistons:piston_down_normal_off", + "mesecons_pistons:piston_down_normal_on", + "mesecons_pistons:piston_down_pusher_normal", + "mesecons_pistons:piston_down_sticky_off", + "mesecons_pistons:piston_down_sticky_on", + "mesecons_pistons:piston_down_pusher_sticky", + }, + run_at_every_load = false, + action = function(pos, node) + local dir = vector.multiply(ground_dir[math.floor(node.param2/4)], -1) + node.param2 = minetest.dir_to_facedir(dir, true) + node.name = node.name:sub(1, 24)..node.name:sub(30) + minetest.swap_node(pos, node) + end, +}) diff --git a/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.de.tr b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.de.tr new file mode 100644 index 00000000..b85dd92e --- /dev/null +++ b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.de.tr @@ -0,0 +1,7 @@ +# textdomain: mesecons_pistons +Piston=Kolben +Activated Piston Base=Aktivierter Kolbenkörper +Piston Pusher=Kolbenschieber +Sticky Piston=Haftender Kolben +Activated Sticky Piston Base=Aktivierter haftender Kolbenkörper +Sticky Piston Pusher=Haftender Kolbenschieber diff --git a/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.eo.tr b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.eo.tr new file mode 100644 index 00000000..0eba1cc2 --- /dev/null +++ b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.eo.tr @@ -0,0 +1,9 @@ +# textdomain: mesecons_pistons + +### init.lua ### +Piston=Piŝto +Activated Piston Base=Aktivigita Piŝta Bazo +Piston Pusher=Piŝta Pushero +Sticky Piston=Glueca Piŝto +Activated Sticky Piston Base=Aktivigita Glueca Piŝta Bazo +Sticky Piston Pusher=Glueca Piŝta Puŝilo diff --git a/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.fr.tr b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.fr.tr new file mode 100644 index 00000000..5be2ea32 --- /dev/null +++ b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.fr.tr @@ -0,0 +1,9 @@ +# textdomain: mesecons_pistons + +### init.lua ### +Piston=Piston +Activated Piston Base=Base de piston activé +Piston Pusher=Bras de piston +Sticky Piston=Piston collant +Activated Sticky Piston Base=Base de piston collant activé +Sticky Piston Pusher=Bras de piston collant diff --git a/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.ru.tr b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.ru.tr new file mode 100644 index 00000000..4748e51e --- /dev/null +++ b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.ru.tr @@ -0,0 +1,9 @@ +# textdomain: mesecons_pistons + +### init.lua ### +Piston=Поршень +Activated Piston Base=Основание активированного поршня +Piston Pusher=Толкающая часть поршня +Sticky Piston=Липкий поршень +Activated Sticky Piston Base=Основание активированного липкого поршня +Sticky Piston Pusher=Толкающая часть липкого поршня diff --git a/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.uk.tr b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.uk.tr new file mode 100644 index 00000000..bcd2630e --- /dev/null +++ b/mods/mesecons/mesecons_pistons/locale/mesecons_pistons.uk.tr @@ -0,0 +1,9 @@ +# textdomain: mesecons_pistons + +### init.lua ### +Piston=Поршень +Activated Piston Base=Основа активованого поршня +Piston Pusher=Штовхаюча частина поршня +Sticky Piston=Липкий поршень +Activated Sticky Piston Base=Основа активованого липкого поршня +Sticky Piston Pusher=Штовхаюча частина липкого поршня diff --git a/mods/mesecons/mesecons_pistons/locale/template.txt b/mods/mesecons/mesecons_pistons/locale/template.txt new file mode 100644 index 00000000..05bed8ad --- /dev/null +++ b/mods/mesecons/mesecons_pistons/locale/template.txt @@ -0,0 +1,9 @@ +# textdomain: mesecons_pistons + +### init.lua ### +Piston= +Activated Piston Base= +Piston Pusher= +Sticky Piston= +Activated Sticky Piston Base= +Sticky Piston Pusher= diff --git a/mods/mesecons/mesecons_pistons/mod.conf b/mods/mesecons/mesecons_pistons/mod.conf new file mode 100644 index 00000000..30a73a38 --- /dev/null +++ b/mods/mesecons/mesecons_pistons/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_pistons +depends = mesecons, mesecons_gamecompat, mesecons_mvps diff --git a/mods/mesecons/mesecons_pistons/sounds/piston_extend.ogg b/mods/mesecons/mesecons_pistons/sounds/piston_extend.ogg new file mode 100644 index 00000000..e234ad94 Binary files /dev/null and b/mods/mesecons/mesecons_pistons/sounds/piston_extend.ogg differ diff --git a/mods/mesecons/mesecons_pistons/sounds/piston_retract.ogg b/mods/mesecons/mesecons_pistons/sounds/piston_retract.ogg new file mode 100644 index 00000000..feb9f044 Binary files /dev/null and b/mods/mesecons/mesecons_pistons/sounds/piston_retract.ogg differ diff --git a/mods/mesecons/mesecons_pistons/textures/mesecons_piston_back.png b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_back.png new file mode 100644 index 00000000..2dde41b0 Binary files /dev/null and b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_back.png differ diff --git a/mods/mesecons/mesecons_pistons/textures/mesecons_piston_on_front.png b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_on_front.png new file mode 100644 index 00000000..f7b0f0ca Binary files /dev/null and b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_on_front.png differ diff --git a/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_back.png b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_back.png new file mode 100644 index 00000000..713cd9d3 Binary files /dev/null and b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_back.png differ diff --git a/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front.png b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front.png new file mode 100644 index 00000000..3a09947b Binary files /dev/null and b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front.png differ diff --git a/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front_sticky.png b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front_sticky.png new file mode 100644 index 00000000..686e7857 Binary files /dev/null and b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_front_sticky.png differ diff --git a/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_top.png b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_top.png new file mode 100644 index 00000000..032215be Binary files /dev/null and b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_pusher_top.png differ diff --git a/mods/mesecons/mesecons_pistons/textures/mesecons_piston_top.png b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_top.png new file mode 100644 index 00000000..5b35a96e Binary files /dev/null and b/mods/mesecons/mesecons_pistons/textures/mesecons_piston_top.png differ diff --git a/mods/mesecons/mesecons_powerplant/doc/powerplant/description.html b/mods/mesecons/mesecons_powerplant/doc/powerplant/description.html new file mode 100644 index 00000000..22be4967 --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/doc/powerplant/description.html @@ -0,0 +1,2 @@ +A power plant is a receptor that is always turned on: it provides energy. +It continues to work in an unloaded block. diff --git a/mods/mesecons/mesecons_powerplant/doc/powerplant/preview.png b/mods/mesecons/mesecons_powerplant/doc/powerplant/preview.png new file mode 100644 index 00000000..d64010fe Binary files /dev/null and b/mods/mesecons/mesecons_powerplant/doc/powerplant/preview.png differ diff --git a/mods/mesecons/mesecons_powerplant/doc/powerplant/recipe.png b/mods/mesecons/mesecons_powerplant/doc/powerplant/recipe.png new file mode 100644 index 00000000..94cf08bd Binary files /dev/null and b/mods/mesecons/mesecons_powerplant/doc/powerplant/recipe.png differ diff --git a/mods/mesecons/mesecons_powerplant/init.lua b/mods/mesecons/mesecons_powerplant/init.lua new file mode 100644 index 00000000..28f21b59 --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/init.lua @@ -0,0 +1,35 @@ +-- The POWER_PLANT +-- Just emits power. always. + +local S = minetest.get_translator(minetest.get_current_modname()) + +minetest.register_node("mesecons_powerplant:power_plant", { + drawtype = "plantlike", + visual_scale = 1, + tiles = {"jeija_power_plant.png"}, + inventory_image = "jeija_power_plant.png", + paramtype = "light", + is_ground_content = false, + walkable = false, + groups = {dig_immediate=3, mesecon = 2}, + light_source = minetest.LIGHT_MAX-9, + description=S("Power Plant"), + selection_box = { + type = "fixed", + fixed = {-0.3, -0.5, -0.3, 0.3, -0.5+0.7, 0.3}, + }, + sounds = mesecon.node_sound.leaves, + mesecons = {receptor = { + state = mesecon.state.on + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_craft({ + output = "mesecons_powerplant:power_plant 1", + recipe = { + {"group:mesecon_conductor_craftable"}, + {"group:mesecon_conductor_craftable"}, + {"group:sapling"}, + } +}) diff --git a/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.de.tr b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.de.tr new file mode 100644 index 00000000..8417c6a9 --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_powerplant +Power Plant=Energiepflanze diff --git a/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.eo.tr b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.eo.tr new file mode 100644 index 00000000..8e539c22 --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_powerplant + +### init.lua ### +Power Plant=Elektra Planto diff --git a/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.fr.tr b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.fr.tr new file mode 100644 index 00000000..5098d632 --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_powerplant + +### init.lua ### +Power Plant=Centrale à signal actif \ No newline at end of file diff --git a/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.ru.tr b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.ru.tr new file mode 100644 index 00000000..8d6c21dd --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_powerplant + +### init.lua ### +Power Plant=Энергоцветок diff --git a/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.uk.tr b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.uk.tr new file mode 100644 index 00000000..db6c2972 --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/locale/mesecons_powerplant.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_powerplant + +### init.lua ### +Power Plant=Енергоквітка diff --git a/mods/mesecons/mesecons_powerplant/locale/template.txt b/mods/mesecons/mesecons_powerplant/locale/template.txt new file mode 100644 index 00000000..71eceaf7 --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_powerplant + +### init.lua ### +Power Plant= diff --git a/mods/mesecons/mesecons_powerplant/mod.conf b/mods/mesecons/mesecons_powerplant/mod.conf new file mode 100644 index 00000000..26c580be --- /dev/null +++ b/mods/mesecons/mesecons_powerplant/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_powerplant +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_powerplant/textures/jeija_power_plant.png b/mods/mesecons/mesecons_powerplant/textures/jeija_power_plant.png new file mode 100644 index 00000000..5655c6aa Binary files /dev/null and b/mods/mesecons/mesecons_powerplant/textures/jeija_power_plant.png differ diff --git a/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/description.html b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/description.html new file mode 100644 index 00000000..35e3fc03 --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/description.html @@ -0,0 +1 @@ +This receptor turns on if there's an object above it. An object can be a player, an item, a mob... diff --git a/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/preview.png b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/preview.png new file mode 100644 index 00000000..d95a0ce8 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/preview.png differ diff --git a/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/recipe.png b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/recipe.png new file mode 100644 index 00000000..541d698a Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_stone/recipe.png differ diff --git a/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/description.html b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/description.html new file mode 100644 index 00000000..35e3fc03 --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/description.html @@ -0,0 +1 @@ +This receptor turns on if there's an object above it. An object can be a player, an item, a mob... diff --git a/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/preview.png b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/preview.png new file mode 100644 index 00000000..4fe3d9cf Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/preview.png differ diff --git a/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/recipe.png b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/recipe.png new file mode 100644 index 00000000..923e8d85 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/doc/pressureplate_wood/recipe.png differ diff --git a/mods/mesecons/mesecons_pressureplates/init.lua b/mods/mesecons/mesecons_pressureplates/init.lua new file mode 100644 index 00000000..cc4b10ca --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/init.lua @@ -0,0 +1,155 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +local pp_box_off = { + type = "fixed", + fixed = { -7/16, -8/16, -7/16, 7/16, -7/16, 7/16 }, +} + +local pp_box_on = { + type = "fixed", + fixed = { -7/16, -8/16, -7/16, 7/16, -7.5/16, 7/16 }, +} + +local function obj_touching_plate_pos(obj_ref, plate_pos) + local obj_pos = obj_ref:get_pos() + local props = obj_ref:get_properties() + if not (props and obj_pos and not obj_ref:get_attach()) then + return false + end + + local collisionbox = props.collisionbox + local physical = props.physical + local is_player = obj_ref:is_player() + local luaentity = obj_ref:get_luaentity() + local is_item = luaentity and luaentity.name == "__builtin:item" + if not (collisionbox and physical or is_player or is_item) then + return false + end + + local plate_x_min = plate_pos.x - 7 / 16 + local plate_x_max = plate_pos.x + 7 / 16 + local plate_z_min = plate_pos.z - 7 / 16 + local plate_z_max = plate_pos.z + 7 / 16 + local plate_y_min = plate_pos.y - 8 / 16 + local plate_y_max = plate_pos.y - 6.5 / 16 + + local obj_x_min = obj_pos.x + collisionbox[1] + local obj_x_max = obj_pos.x + collisionbox[4] + local obj_z_min = obj_pos.z + collisionbox[3] + local obj_z_max = obj_pos.z + collisionbox[6] + local obj_y_min = obj_pos.y + collisionbox[2] + local obj_y_max = obj_pos.y + collisionbox[5] + + if + obj_y_min < plate_y_max and + obj_y_max > plate_y_min and + obj_x_min < plate_x_max and + obj_x_max > plate_x_min and + obj_z_min < plate_z_max and + obj_z_max > plate_z_min + then + return true + end + return false +end + +local function pp_on_timer(pos) + 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 basename then return end + + local objs = minetest.get_objects_inside_radius(pos, 1) + local obj_touching = false + for k, obj in pairs(objs) do + if obj_touching_plate_pos(obj, pos) then + obj_touching = true + break + end + end + + if not obj_touching and node.name == basename .. "_on" then + minetest.set_node(pos, {name = basename .. "_off"}) + mesecon.receptor_off(pos, mesecon.rules.pplate) + elseif obj_touching and node.name == basename .. "_off" then + minetest.set_node(pos, {name = basename .. "_on"}) + mesecon.receptor_on(pos, mesecon.rules.pplate ) + end + return true +end + +-- Register a Pressure Plate +-- offstate: name of the pressure plate when inactive +-- onstate: name of the pressure plate when active +-- description: description displayed in the player's inventory +-- tiles_off: textures of the pressure plate when inactive +-- tiles_on: textures of the pressure plate when active +-- image: inventory and wield image of the pressure plate +-- recipe: crafting recipe of the pressure plate +-- groups: groups +-- sounds: sound table + +function mesecon.register_pressure_plate(basename, description, textures_off, textures_on, image_w, image_i, recipe, groups, sounds) + if not groups then + groups = {} + end + local groups_off = table.copy(groups) + local groups_on = table.copy(groups) + groups_on.not_in_creative_inventory = 1 + + mesecon.register_node(basename, { + drawtype = "nodebox", + inventory_image = image_i, + wield_image = image_w, + paramtype = "light", + is_ground_content = false, + description = description, + pressureplate_basename = basename, + on_timer = pp_on_timer, + on_construct = function(pos) + minetest.get_node_timer(pos):start(mesecon.setting("pplate_interval", 0.1)) + end, + sounds = sounds, + },{ + mesecons = {receptor = { state = mesecon.state.off, rules = mesecon.rules.pplate }}, + node_box = pp_box_off, + selection_box = pp_box_off, + groups = groups_off, + tiles = textures_off + },{ + mesecons = {receptor = { state = mesecon.state.on, rules = mesecon.rules.pplate }}, + node_box = pp_box_on, + selection_box = pp_box_on, + groups = groups_on, + tiles = textures_on + }) + + minetest.register_craft({ + output = basename .. "_off", + recipe = recipe, + }) +end + +mesecon.register_pressure_plate( + "mesecons_pressureplates:pressure_plate_wood", + S("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"}, + "jeija_pressure_plate_wood_wield.png", + "jeija_pressure_plate_wood_inv.png", + {{"group:wood", "group:wood"}}, + { choppy = 3, oddly_breakable_by_hand = 3 }, + mesecon.node_sound.wood) + +mesecon.register_pressure_plate( + "mesecons_pressureplates:pressure_plate_stone", + S("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"}, + "jeija_pressure_plate_stone_wield.png", + "jeija_pressure_plate_stone_inv.png", + {{"mesecons_gamecompat:cobble", "mesecons_gamecompat:cobble"}}, + { cracky = 3, oddly_breakable_by_hand = 3 }, + mesecon.node_sound.stone) diff --git a/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.de.tr b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.de.tr new file mode 100644 index 00000000..fd546136 --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.de.tr @@ -0,0 +1,3 @@ +# textdomain: mesecons_pressureplates +Wooden Pressure Plate=Holzdruckplatte +Stone Pressure Plate=Steindruckplatte diff --git a/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.eo.tr b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.eo.tr new file mode 100644 index 00000000..8af30a03 --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.eo.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_pressureplates + +### init.lua ### +Wooden Pressure Plate=Ligna Prema Plato +Stone Pressure Plate=Ŝtona Prema Plato diff --git a/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.fr.tr b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.fr.tr new file mode 100644 index 00000000..23d0c5b6 --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.fr.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_pressureplates + +### init.lua ### +Wooden Pressure Plate=Plaque de pression en bois +Stone Pressure Plate=Plaque de pression en pierre diff --git a/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.ru.tr b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.ru.tr new file mode 100644 index 00000000..f1e26fa6 --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.ru.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_pressureplates + +### init.lua ### +Wooden Pressure Plate=Деревянная нажимная пластина +Stone Pressure Plate=Каменная нажимная пластина diff --git a/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.uk.tr b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.uk.tr new file mode 100644 index 00000000..ad7cd32d --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/locale/mesecons_pressureplates.uk.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_pressureplates + +### init.lua ### +Wooden Pressure Plate=Дерев'яна натискна плита +Stone Pressure Plate=Кам'яна натискна плита diff --git a/mods/mesecons/mesecons_pressureplates/locale/template.txt b/mods/mesecons/mesecons_pressureplates/locale/template.txt new file mode 100644 index 00000000..22413441 --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/locale/template.txt @@ -0,0 +1,5 @@ +# textdomain: mesecons_pressureplates + +### init.lua ### +Wooden Pressure Plate= +Stone Pressure Plate= diff --git a/mods/mesecons/mesecons_pressureplates/mod.conf b/mods/mesecons/mesecons_pressureplates/mod.conf new file mode 100644 index 00000000..cebd8a68 --- /dev/null +++ b/mods/mesecons/mesecons_pressureplates/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_pressureplates +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_inv.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_inv.png new file mode 100644 index 00000000..5f35c843 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_inv.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off.png new file mode 100644 index 00000000..544b1aa8 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off_edges.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off_edges.png new file mode 100644 index 00000000..ad13f5b1 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_off_edges.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on.png new file mode 100644 index 00000000..434b3d83 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on_edges.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on_edges.png new file mode 100644 index 00000000..818c966c Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_on_edges.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_wield.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_wield.png new file mode 100644 index 00000000..5f35c843 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_stone_wield.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_inv.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_inv.png new file mode 100644 index 00000000..5e8109af Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_inv.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off.png new file mode 100644 index 00000000..c9ba34f3 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off_edges.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off_edges.png new file mode 100644 index 00000000..8b101739 Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_off_edges.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on.png new file mode 100644 index 00000000..9ae7cc6d Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on_edges.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on_edges.png new file mode 100644 index 00000000..97cd30ed Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_on_edges.png differ diff --git a/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_wield.png b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_wield.png new file mode 100644 index 00000000..5e8109af Binary files /dev/null and b/mods/mesecons/mesecons_pressureplates/textures/jeija_pressure_plate_wood_wield.png differ diff --git a/mods/mesecons/mesecons_random/doc/ghoststone/description.html b/mods/mesecons/mesecons_random/doc/ghoststone/description.html new file mode 100644 index 00000000..d54ef636 --- /dev/null +++ b/mods/mesecons/mesecons_random/doc/ghoststone/description.html @@ -0,0 +1,2 @@ +Ghoststones disappear when powered, just like Removestones. But in contrast to Removestones, they reappear again when not powered anymore and they are also conductive. +They work in inactive blocks. diff --git a/mods/mesecons/mesecons_random/doc/ghoststone/preview.png b/mods/mesecons/mesecons_random/doc/ghoststone/preview.png new file mode 100644 index 00000000..f3d12574 Binary files /dev/null and b/mods/mesecons/mesecons_random/doc/ghoststone/preview.png differ diff --git a/mods/mesecons/mesecons_random/doc/ghoststone/recipe.png b/mods/mesecons/mesecons_random/doc/ghoststone/recipe.png new file mode 100644 index 00000000..d1ee2013 Binary files /dev/null and b/mods/mesecons/mesecons_random/doc/ghoststone/recipe.png differ diff --git a/mods/mesecons/mesecons_random/doc/removestone/description.html b/mods/mesecons/mesecons_random/doc/removestone/description.html new file mode 100644 index 00000000..ccd3c140 --- /dev/null +++ b/mods/mesecons/mesecons_random/doc/removestone/description.html @@ -0,0 +1,2 @@ +Removestones are probably the simplest effectors possible. They simply disappear when powered. +They work in inactive blocks. diff --git a/mods/mesecons/mesecons_random/doc/removestone/preview.png b/mods/mesecons/mesecons_random/doc/removestone/preview.png new file mode 100644 index 00000000..2941db84 Binary files /dev/null and b/mods/mesecons/mesecons_random/doc/removestone/preview.png differ diff --git a/mods/mesecons/mesecons_random/doc/removestone/recipe.png b/mods/mesecons/mesecons_random/doc/removestone/recipe.png new file mode 100644 index 00000000..ed9dfe4a Binary files /dev/null and b/mods/mesecons/mesecons_random/doc/removestone/recipe.png differ diff --git a/mods/mesecons/mesecons_random/init.lua b/mods/mesecons/mesecons_random/init.lua new file mode 100644 index 00000000..5342fb3b --- /dev/null +++ b/mods/mesecons/mesecons_random/init.lua @@ -0,0 +1,80 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- REMOVESTONE + +minetest.register_node("mesecons_random:removestone", { + tiles = {"jeija_removestone.png"}, + is_ground_content = false, + inventory_image = minetest.inventorycube("jeija_removestone_inv.png"), + groups = {cracky=3}, + description = S("Removestone"), + sounds = mesecon.node_sound.stone, + mesecons = {effector = { + action_on = function (pos, node) + minetest.remove_node(pos) + mesecon.on_dignode(pos, node) + minetest.check_for_falling(vector.add(pos, vector.new(0, 1, 0))) + end + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_craft({ + output = 'mesecons_random:removestone 4', + recipe = { + {"", "mesecons_gamecompat:cobble", ""}, + {"mesecons_gamecompat:cobble", "group:mesecon_conductor_craftable", "mesecons_gamecompat:cobble"}, + {"", "mesecons_gamecompat:cobble", ""}, + } +}) + +-- GHOSTSTONE + +minetest.register_node("mesecons_random:ghoststone", { + description = S("Ghoststone"), + tiles = {"jeija_ghoststone.png"}, + is_ground_content = false, + inventory_image = minetest.inventorycube("jeija_ghoststone_inv.png"), + groups = {cracky=3}, + sounds = mesecon.node_sound.stone, + mesecons = {conductor = { + state = mesecon.state.off, + rules = mesecon.rules.alldirs, + onstate = "mesecons_random:ghoststone_active" + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_random:ghoststone_active", { + drawtype = "airlike", + pointable = false, + walkable = false, + diggable = false, + is_ground_content = false, + sunlight_propagates = true, + paramtype = "light", + drop = "mesecons_random:ghoststone", + mesecons = {conductor = { + state = mesecon.state.on, + rules = mesecon.rules.alldirs, + offstate = "mesecons_random:ghoststone" + }}, + on_construct = function(pos) + -- remove shadow + local shadowpos = vector.add(pos, vector.new(0, 1, 0)) + if (minetest.get_node(shadowpos).name == "air") then + minetest.dig_node(shadowpos) + end + end, + on_blast = mesecon.on_blastnode, +}) + + +minetest.register_craft({ + output = 'mesecons_random:ghoststone 4', + recipe = { + {"mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:cobble", "mesecons_gamecompat:steel_ingot"}, + {"mesecons_gamecompat:cobble", "group:mesecon_conductor_craftable", "mesecons_gamecompat:cobble"}, + {"mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:cobble", "mesecons_gamecompat:steel_ingot"}, + } +}) diff --git a/mods/mesecons/mesecons_random/locale/mesecons_random.de.tr b/mods/mesecons/mesecons_random/locale/mesecons_random.de.tr new file mode 100644 index 00000000..074b9e86 --- /dev/null +++ b/mods/mesecons/mesecons_random/locale/mesecons_random.de.tr @@ -0,0 +1,3 @@ +# textdomain: mesecons_random +Removestone=Verschwindestein +Ghoststone=Geisterstein diff --git a/mods/mesecons/mesecons_random/locale/mesecons_random.eo.tr b/mods/mesecons/mesecons_random/locale/mesecons_random.eo.tr new file mode 100644 index 00000000..ceca5401 --- /dev/null +++ b/mods/mesecons/mesecons_random/locale/mesecons_random.eo.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_random + +### init.lua ### +Removestone=Forigŝtono +Ghoststone=Fantomŝtono diff --git a/mods/mesecons/mesecons_random/locale/mesecons_random.fr.tr b/mods/mesecons/mesecons_random/locale/mesecons_random.fr.tr new file mode 100644 index 00000000..15bdb0ce --- /dev/null +++ b/mods/mesecons/mesecons_random/locale/mesecons_random.fr.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_random + +### init.lua ### +Removestone=Pierre de suppression +Ghoststone=Pierre fantôme diff --git a/mods/mesecons/mesecons_random/locale/mesecons_random.ru.tr b/mods/mesecons/mesecons_random/locale/mesecons_random.ru.tr new file mode 100644 index 00000000..416760b6 --- /dev/null +++ b/mods/mesecons/mesecons_random/locale/mesecons_random.ru.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_random + +### init.lua ### +Removestone=Исчезающий камень +Ghoststone=Призрачный камень diff --git a/mods/mesecons/mesecons_random/locale/mesecons_random.uk.tr b/mods/mesecons/mesecons_random/locale/mesecons_random.uk.tr new file mode 100644 index 00000000..f014b646 --- /dev/null +++ b/mods/mesecons/mesecons_random/locale/mesecons_random.uk.tr @@ -0,0 +1,5 @@ +# textdomain: mesecons_random + +### init.lua ### +Removestone=Зникаючий камінь +Ghoststone=Примарний камінь diff --git a/mods/mesecons/mesecons_random/locale/template.txt b/mods/mesecons/mesecons_random/locale/template.txt new file mode 100644 index 00000000..55a69e8d --- /dev/null +++ b/mods/mesecons/mesecons_random/locale/template.txt @@ -0,0 +1,5 @@ +# textdomain: mesecons_random + +### init.lua ### +Removestone= +Ghoststone= diff --git a/mods/mesecons/mesecons_random/mod.conf b/mods/mesecons/mesecons_random/mod.conf new file mode 100644 index 00000000..af40fbb7 --- /dev/null +++ b/mods/mesecons/mesecons_random/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_random +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_random/textures/jeija_ghoststone.png b/mods/mesecons/mesecons_random/textures/jeija_ghoststone.png new file mode 100644 index 00000000..1f36a41b Binary files /dev/null and b/mods/mesecons/mesecons_random/textures/jeija_ghoststone.png differ diff --git a/mods/mesecons/mesecons_random/textures/jeija_ghoststone_inv.png b/mods/mesecons/mesecons_random/textures/jeija_ghoststone_inv.png new file mode 100644 index 00000000..bfe3a84d Binary files /dev/null and b/mods/mesecons/mesecons_random/textures/jeija_ghoststone_inv.png differ diff --git a/mods/mesecons/mesecons_random/textures/jeija_removestone.png b/mods/mesecons/mesecons_random/textures/jeija_removestone.png new file mode 100644 index 00000000..1f36a41b Binary files /dev/null and b/mods/mesecons/mesecons_random/textures/jeija_removestone.png differ diff --git a/mods/mesecons/mesecons_random/textures/jeija_removestone_inv.png b/mods/mesecons/mesecons_random/textures/jeija_removestone_inv.png new file mode 100644 index 00000000..bfe3a84d Binary files /dev/null and b/mods/mesecons/mesecons_random/textures/jeija_removestone_inv.png differ diff --git a/mods/mesecons/mesecons_receiver/init.lua b/mods/mesecons/mesecons_receiver/init.lua new file mode 100644 index 00000000..6b67fd2d --- /dev/null +++ b/mods/mesecons/mesecons_receiver/init.lua @@ -0,0 +1,268 @@ +local rcvboxes = { + { -3/16, -3/16, -8/16 , 3/16, 3/16 , -13/32 }, -- the smaller bump + { -1/32, -1/32, -3/2 , 1/32, 1/32 , -1/2 }, -- the wire through the block + { -2/32, -1/2 , -.5 , 2/32, 0 , -.5002+3/32 }, -- the vertical wire bit + { -2/32, -1/2 , -7/16+0.002 , 2/32, -14/32, 16/32+0.001 } -- the horizontal wire +} + +local down_rcvboxes = { + {-6/16, -8/16, -6/16, 6/16, -7/16, 6/16}, -- Top plate + {-2/16, -6/16, -2/16, 2/16, -7/16, 2/16}, -- Bump + {-1/16, -8/16, -1/16, 1/16, -24/16, 1/16}, -- Wire through the block + {-1/16, -8/16, 6/16, 1/16, -7/16, 8/16}, -- Plate extension (North) + {-1/16, -8/16, -6/16, 1/16, -7/16, -8/16}, -- Plate extension (South) + {-8/16, -8/16, 1/16, -6/16, -7/16, -1/16}, -- Plate extension (West) + {6/16, -8/16, 1/16, 8/16, -7/16, -1/16}, -- Plate extension (East) +} + +local up_rcvboxes = { + {-6/16, -8/16, -6/16, 6/16, -7/16, 6/16}, -- Top plate + {-2/16, -6/16, -2/16, 2/16, -7/16, 2/16}, -- Bump + {-1/16, -6/16, -1/16, 1/16, 24/16, 1/16}, -- Wire through the block + {-1/16, -8/16, 6/16, 1/16, -7/16, 8/16}, -- Plate extension (North) + {-1/16, -8/16, -6/16, 1/16, -7/16, -8/16}, -- Plate extension (South) + {-8/16, -8/16, 1/16, -6/16, -7/16, -1/16}, -- Plate extension (West) + {6/16, -8/16, 1/16, 8/16, -7/16, -1/16}, -- Plate extension (East) +} + +local receiver_get_rules = mesecon.horiz_rules_getter({ + {x = 0, y = 0, z = 1}, + {x = 0, y = 0, z = -2}, +}) + +local use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or nil + +mesecon.register_node("mesecons_receiver:receiver", { + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + sunlight_propagates = true, + walkable = false, + on_rotate = false, + selection_box = { + type = "fixed", + fixed = { -3/16, -8/16, -8/16, 3/16, 3/16, 8/16 } + }, + node_box = { + type = "fixed", + fixed = rcvboxes + }, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons:wire_00000000_off", + sounds = mesecon.node_sound.default, +}, { + tiles = { + "receiver_top_off.png", + "receiver_bottom_off.png", + "receiver_lr_off.png", + "receiver_lr_off.png", + "receiver_fb_off.png", + "receiver_fb_off.png", + }, + mesecons = {conductor = { + state = mesecon.state.off, + rules = receiver_get_rules, + onstate = "mesecons_receiver:receiver_on" + }} +}, { + tiles = { + "receiver_top_on.png", + "receiver_bottom_on.png", + "receiver_lr_on.png", + "receiver_lr_on.png", + "receiver_fb_on.png", + "receiver_fb_on.png", + }, + mesecons = {conductor = { + state = mesecon.state.on, + rules = receiver_get_rules, + offstate = "mesecons_receiver:receiver_off" + }} +}) + +mesecon.register_node("mesecons_receiver:receiver_up", { + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + sunlight_propagates = true, + walkable = false, + on_rotate = false, + selection_box = { + type = "fixed", + fixed = up_rcvboxes + }, + node_box = { + type = "fixed", + fixed = up_rcvboxes + }, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons:wire_00000000_off", + sounds = mesecon.node_sound.default, + use_texture_alpha = use_texture_alpha, +}, { + tiles = {"mesecons_wire_off.png"}, + mesecons = {conductor = { + state = mesecon.state.off, + rules = {{x=1, y=0, z=0}, + {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=2, z=0}}, + onstate = "mesecons_receiver:receiver_up_on" + }} +}, { + tiles = {"mesecons_wire_on.png"}, + mesecons = {conductor = { + state = mesecon.state.on, + rules = {{x=1, y=0, z=0}, + {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=2, z=0}}, + offstate = "mesecons_receiver:receiver_up_off" + }} +}) + +mesecon.register_node("mesecons_receiver:receiver_down", { + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + sunlight_propagates = true, + walkable = false, + on_rotate = false, + selection_box = { + type = "fixed", + fixed = down_rcvboxes + }, + node_box = { + type = "fixed", + fixed = down_rcvboxes + }, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons:wire_00000000_off", + sounds = mesecon.node_sound.default, + use_texture_alpha = use_texture_alpha, +}, { + tiles = {"mesecons_wire_off.png"}, + mesecons = {conductor = { + state = mesecon.state.off, + rules = {{x=1,y=0, z=0}, + {x=-1,y=0, z=0}, + {x=0, y=0, z=1}, + {x=0, y=0, z=-1}, + {x=0, y=-2,z=0}}, + onstate = "mesecons_receiver:receiver_down_on" + }} +}, { + tiles = {"mesecons_wire_on.png"}, + mesecons = {conductor = { + state = mesecon.state.on, + rules = {{x=1,y=0, z=0}, + {x=-1,y=0, z=0}, + {x=0, y=0, z=1}, + {x=0, y=0, z=-1}, + {x=0, y=-2,z=0}}, + offstate = "mesecons_receiver:receiver_down_off" + }} +}) + +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 + local rcvtype = "mesecons_receiver:receiver_off" + local dir = minetest.facedir_to_dir(param2) + + if dir.x == 1 then + -- No action needed + elseif dir.z == -1 then + rules = mesecon.rotate_rules_left(rules) + elseif dir.x == -1 then + rules = mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) + elseif dir.z == 1 then + rules = mesecon.rotate_rules_right(rules) + elseif dir.y == -1 then + rules = mesecon.rotate_rules_up(rules) + rcvtype = "mesecons_receiver:receiver_up_off" + elseif dir.y == 1 then + rules = mesecon.rotate_rules_down(rules) + rcvtype = "mesecons_receiver:receiver_down_off" + end + local np = { x = pos.x + rules[1].x, + y = pos.y + rules[1].y, + z = pos.z + rules[1].z} + return np, rcvtype +end + +function mesecon.receiver_place(rcpt_pos) + local node = minetest.get_node(rcpt_pos) + local pos, rcvtype = mesecon.receiver_get_pos_from_rcpt(rcpt_pos, node.param2) + local nn = minetest.get_node(pos) + local param2 = minetest.dir_to_facedir(minetest.facedir_to_dir(node.param2)) + + if string.find(nn.name, "mesecons:wire_") ~= nil then + local rcv_node = {name = rcvtype, param2 = param2} + minetest.set_node(pos, rcv_node) + mesecon.on_dignode(pos, nn) + mesecon.on_placenode(pos, rcv_node) + end +end + +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 + local node = {name = "mesecons:wire_00000000_off"} + minetest.set_node(pos, node) + mesecon.on_dignode(pos, nn) + 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) + 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) + end +end) + +minetest.register_on_placenode(function (pos, node) + if string.find(node.name, "mesecons:wire_") ~= nil then + 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}, + {x = 0, y = 2, z = 0}, + {x = 0, y = -2, z = 0}} + local i = 1 + while rules[i] ~= nil do + 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) + end + i = i + 1 + end + end +end) + +function mesecon.buttonlike_onrotate(pos, node, _, _, new_param2) + local new_node = {name = node.name, param1 = node.param1, param2 = new_param2} + minetest.swap_node(pos, new_node) + mesecon.receiver_remove(pos, node) + mesecon.on_dignode(pos, node) + mesecon.on_placenode(pos, new_node) + mesecon.receiver_place(pos) + minetest.check_for_falling(pos) + return true +end diff --git a/mods/mesecons/mesecons_receiver/mod.conf b/mods/mesecons/mesecons_receiver/mod.conf new file mode 100644 index 00000000..3e0fda0c --- /dev/null +++ b/mods/mesecons/mesecons_receiver/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_receiver +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_receiver/textures/receiver_bottom_off.png b/mods/mesecons/mesecons_receiver/textures/receiver_bottom_off.png new file mode 100644 index 00000000..d052bda3 Binary files /dev/null and b/mods/mesecons/mesecons_receiver/textures/receiver_bottom_off.png differ diff --git a/mods/mesecons/mesecons_receiver/textures/receiver_bottom_on.png b/mods/mesecons/mesecons_receiver/textures/receiver_bottom_on.png new file mode 100644 index 00000000..f97c22ba Binary files /dev/null and b/mods/mesecons/mesecons_receiver/textures/receiver_bottom_on.png differ diff --git a/mods/mesecons/mesecons_receiver/textures/receiver_fb_off.png b/mods/mesecons/mesecons_receiver/textures/receiver_fb_off.png new file mode 100644 index 00000000..d052bda3 Binary files /dev/null and b/mods/mesecons/mesecons_receiver/textures/receiver_fb_off.png differ diff --git a/mods/mesecons/mesecons_receiver/textures/receiver_fb_on.png b/mods/mesecons/mesecons_receiver/textures/receiver_fb_on.png new file mode 100644 index 00000000..f97c22ba Binary files /dev/null and b/mods/mesecons/mesecons_receiver/textures/receiver_fb_on.png differ diff --git a/mods/mesecons/mesecons_receiver/textures/receiver_lr_off.png b/mods/mesecons/mesecons_receiver/textures/receiver_lr_off.png new file mode 100644 index 00000000..d052bda3 Binary files /dev/null and b/mods/mesecons/mesecons_receiver/textures/receiver_lr_off.png differ diff --git a/mods/mesecons/mesecons_receiver/textures/receiver_lr_on.png b/mods/mesecons/mesecons_receiver/textures/receiver_lr_on.png new file mode 100644 index 00000000..f97c22ba Binary files /dev/null and b/mods/mesecons/mesecons_receiver/textures/receiver_lr_on.png differ diff --git a/mods/mesecons/mesecons_receiver/textures/receiver_top_off.png b/mods/mesecons/mesecons_receiver/textures/receiver_top_off.png new file mode 100644 index 00000000..d052bda3 Binary files /dev/null and b/mods/mesecons/mesecons_receiver/textures/receiver_top_off.png differ diff --git a/mods/mesecons/mesecons_receiver/textures/receiver_top_on.png b/mods/mesecons/mesecons_receiver/textures/receiver_top_on.png new file mode 100644 index 00000000..f97c22ba Binary files /dev/null and b/mods/mesecons/mesecons_receiver/textures/receiver_top_on.png differ diff --git a/mods/mesecons/mesecons_solarpanel/doc/solarpanel/description.html b/mods/mesecons/mesecons_solarpanel/doc/solarpanel/description.html new file mode 100644 index 00000000..53570cad --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/doc/solarpanel/description.html @@ -0,0 +1,2 @@ +Solar panels are light receptors: they turn on if there is enough light. +They only work in active blocks; in inactive blocks they keep their old state. diff --git a/mods/mesecons/mesecons_solarpanel/doc/solarpanel/preview.png b/mods/mesecons/mesecons_solarpanel/doc/solarpanel/preview.png new file mode 100644 index 00000000..5b3ec68f Binary files /dev/null and b/mods/mesecons/mesecons_solarpanel/doc/solarpanel/preview.png differ diff --git a/mods/mesecons/mesecons_solarpanel/doc/solarpanel/recipe.png b/mods/mesecons/mesecons_solarpanel/doc/solarpanel/recipe.png new file mode 100644 index 00000000..93ec873d Binary files /dev/null and b/mods/mesecons/mesecons_solarpanel/doc/solarpanel/recipe.png differ diff --git a/mods/mesecons/mesecons_solarpanel/init.lua b/mods/mesecons/mesecons_solarpanel/init.lua new file mode 100644 index 00000000..228f7a2a --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/init.lua @@ -0,0 +1,65 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- Solar Panel +mesecon.register_node("mesecons_solarpanel:solar_panel", { + description = S("Solar Panel"), + drawtype = "nodebox", + tiles = {"mesecons_solarpanel.png"}, + inventory_image = "mesecons_solarpanel.png", + wield_image = "mesecons_solarpanel.png", + paramtype = "light", + paramtype2 = "wallmounted", + walkable = false, + is_ground_content = false, + node_box = { + type = "wallmounted", + wall_bottom = {-7/16, -8/16, -7/16, 7/16, -7/16, 7/16}, + wall_top = {-7/16, 7/16, -7/16, 7/16, 8/16, 7/16}, + wall_side = {-8/16, -7/16, -7/16, -7/16, 7/16, 7/16}, + }, + sounds = mesecon.node_sound.glass, + on_blast = mesecon.on_blastnode, +},{ + groups = {dig_immediate = 3}, + mesecons = {receptor = { + state = mesecon.state.off, + rules = mesecon.rules.wallmounted_get + }} +},{ + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + mesecons = {receptor = { + state = mesecon.state.on, + rules = mesecon.rules.wallmounted_get + }}, +}) + +minetest.register_craft({ + output = "mesecons_solarpanel:solar_panel_off", + recipe = { + {"mesecons_materials:silicon", "mesecons_materials:silicon"}, + {"mesecons_materials:silicon", "mesecons_materials:silicon"}, + } +}) + +minetest.register_abm({ + label = "Solar Panel On/Off", + nodenames = { + "mesecons_solarpanel:solar_panel_off", + "mesecons_solarpanel:solar_panel_on" + }, + interval = 1, + chance = 1, + catch_up = false, + action = function(pos, node) + local light = minetest.get_node_light(pos) + if light >= 12 and node.name == "mesecons_solarpanel:solar_panel_off" then + node.name = "mesecons_solarpanel:solar_panel_on" + minetest.swap_node(pos, node) + mesecon.receptor_on(pos, mesecon.rules.wallmounted_get(node)) + elseif light < 12 and node.name == "mesecons_solarpanel:solar_panel_on" then + node.name = "mesecons_solarpanel:solar_panel_off" + minetest.swap_node(pos, node) + mesecon.receptor_off(pos, mesecon.rules.wallmounted_get(node)) + end + end, +}) diff --git a/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.de.tr b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.de.tr new file mode 100644 index 00000000..d5c0c946 --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_solarpanel +Solar Panel=Solarmodul diff --git a/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.eo.tr b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.eo.tr new file mode 100644 index 00000000..cdbf0006 --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_solarpanel + +### init.lua ### +Solar Panel=Suna Panelo diff --git a/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.fr.tr b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.fr.tr new file mode 100644 index 00000000..ed414529 --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_solarpanel + +### init.lua ### +Solar Panel=Détecteur solaire diff --git a/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.ru.tr b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.ru.tr new file mode 100644 index 00000000..7e14ed3c --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_solarpanel + +### init.lua ### +Solar Panel=Солнечная панель diff --git a/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.uk.tr b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.uk.tr new file mode 100644 index 00000000..944fb739 --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/locale/mesecons_solarpanel.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_solarpanel + +### init.lua ### +Solar Panel=Сонячна панель diff --git a/mods/mesecons/mesecons_solarpanel/locale/template.txt b/mods/mesecons/mesecons_solarpanel/locale/template.txt new file mode 100644 index 00000000..bb8464a6 --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_solarpanel + +### init.lua ### +Solar Panel= diff --git a/mods/mesecons/mesecons_solarpanel/mod.conf b/mods/mesecons/mesecons_solarpanel/mod.conf new file mode 100644 index 00000000..ce3f7d73 --- /dev/null +++ b/mods/mesecons/mesecons_solarpanel/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_solarpanel +depends = mesecons, mesecons_gamecompat, mesecons_materials diff --git a/mods/mesecons/mesecons_solarpanel/textures/mesecons_solarpanel.png b/mods/mesecons/mesecons_solarpanel/textures/mesecons_solarpanel.png new file mode 100644 index 00000000..8482ee1f Binary files /dev/null and b/mods/mesecons/mesecons_solarpanel/textures/mesecons_solarpanel.png differ diff --git a/mods/mesecons/mesecons_stickyblocks/init.lua b/mods/mesecons/mesecons_stickyblocks/init.lua new file mode 100644 index 00000000..cf8695f3 --- /dev/null +++ b/mods/mesecons/mesecons_stickyblocks/init.lua @@ -0,0 +1,21 @@ +-- Sticky blocks can be used together with pistons or movestones to push / pull +-- structures that are "glued" together using sticky blocks + +local S = minetest.get_translator(minetest.get_current_modname()) + +-- All sides sticky block +minetest.register_node("mesecons_stickyblocks:sticky_block_all", { + -- TODO: Rename to “All-Faces Sticky Block” when other sticky blocks become available + description = S("Sticky Block"), + tiles = {"mesecons_stickyblocks_sticky.png"}, + is_ground_content = false, + groups = {choppy=3, oddly_breakable_by_hand=2}, + mvps_sticky = function (pos) + local connected = {} + for _, r in ipairs(mesecon.rules.alldirs) do + table.insert(connected, vector.add(pos, r)) + end + return connected + end, + sounds = mesecon.node_sound.wood, +}) diff --git a/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.de.tr b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.de.tr new file mode 100644 index 00000000..25cfd066 --- /dev/null +++ b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_stickyblocks +Sticky Block=Klebeblock diff --git a/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.eo.tr b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.eo.tr new file mode 100644 index 00000000..8ac7f946 --- /dev/null +++ b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_stickyblocks + +### init.lua ### +Sticky Block=Glueca Bloko diff --git a/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.fr.tr b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.fr.tr new file mode 100644 index 00000000..9dc82d74 --- /dev/null +++ b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_stickyblocks + +### init.lua ### +Sticky Block=Bloc collant diff --git a/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.ru.tr b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.ru.tr new file mode 100644 index 00000000..e4846867 --- /dev/null +++ b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_stickyblocks + +### init.lua ### +Sticky Block=Липкий блок diff --git a/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.uk.tr b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.uk.tr new file mode 100644 index 00000000..e4846867 --- /dev/null +++ b/mods/mesecons/mesecons_stickyblocks/locale/mesecons_stickyblocks.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_stickyblocks + +### init.lua ### +Sticky Block=Липкий блок diff --git a/mods/mesecons/mesecons_stickyblocks/locale/template.txt b/mods/mesecons/mesecons_stickyblocks/locale/template.txt new file mode 100644 index 00000000..b96a6973 --- /dev/null +++ b/mods/mesecons/mesecons_stickyblocks/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_stickyblocks + +### init.lua ### +Sticky Block= diff --git a/mods/mesecons/mesecons_stickyblocks/mod.conf b/mods/mesecons/mesecons_stickyblocks/mod.conf new file mode 100644 index 00000000..4aa2ee22 --- /dev/null +++ b/mods/mesecons/mesecons_stickyblocks/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_stickyblocks +depends = mesecons, mesecons_gamecompat, mesecons_mvps diff --git a/mods/mesecons/mesecons_stickyblocks/textures/mesecons_stickyblocks_sticky.png b/mods/mesecons/mesecons_stickyblocks/textures/mesecons_stickyblocks_sticky.png new file mode 100644 index 00000000..3a5f6f12 Binary files /dev/null and b/mods/mesecons/mesecons_stickyblocks/textures/mesecons_stickyblocks_sticky.png differ diff --git a/mods/mesecons/mesecons_switch/doc/switch/description.html b/mods/mesecons/mesecons_switch/doc/switch/description.html new file mode 100644 index 00000000..0c8f6077 --- /dev/null +++ b/mods/mesecons/mesecons_switch/doc/switch/description.html @@ -0,0 +1 @@ +The switch is a receptor. It changes its state when punched. diff --git a/mods/mesecons/mesecons_switch/doc/switch/preview.png b/mods/mesecons/mesecons_switch/doc/switch/preview.png new file mode 100644 index 00000000..c765272a Binary files /dev/null and b/mods/mesecons/mesecons_switch/doc/switch/preview.png differ diff --git a/mods/mesecons/mesecons_switch/doc/switch/recipe.png b/mods/mesecons/mesecons_switch/doc/switch/recipe.png new file mode 100644 index 00000000..15c9b0b3 Binary files /dev/null and b/mods/mesecons/mesecons_switch/doc/switch/recipe.png differ diff --git a/mods/mesecons/mesecons_switch/init.lua b/mods/mesecons/mesecons_switch/init.lua new file mode 100644 index 00000000..a8115de5 --- /dev/null +++ b/mods/mesecons/mesecons_switch/init.lua @@ -0,0 +1,38 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- mesecons_switch + +mesecon.register_node("mesecons_switch:mesecon_switch", { + paramtype2="facedir", + description=S("Switch"), + is_ground_content = false, + sounds = mesecon.node_sound.stone, + on_rightclick = 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 }, true) + end +},{ + groups = {dig_immediate=2}, + tiles = { "mesecons_switch_side.png", "mesecons_switch_side.png", + "mesecons_switch_side.png", "mesecons_switch_side.png", + "mesecons_switch_side.png", "mesecons_switch_off.png"}, + mesecons = {receptor = { state = mesecon.state.off }} +},{ + groups = {dig_immediate=2, not_in_creative_inventory=1}, + tiles = { "mesecons_switch_side.png", "mesecons_switch_side.png", + "mesecons_switch_side.png", "mesecons_switch_side.png", + "mesecons_switch_side.png", "mesecons_switch_on.png"}, + mesecons = {receptor = { state = mesecon.state.on }} +}) + +minetest.register_craft({ + output = "mesecons_switch:mesecon_switch_off 2", + recipe = { + {"mesecons_gamecompat:steel_ingot", "mesecons_gamecompat:cobble", "mesecons_gamecompat:steel_ingot"}, + {"group:mesecon_conductor_craftable","", "group:mesecon_conductor_craftable"}, + } +}) diff --git a/mods/mesecons/mesecons_switch/locale/mesecons_switch.de.tr b/mods/mesecons/mesecons_switch/locale/mesecons_switch.de.tr new file mode 100644 index 00000000..a49a9aca --- /dev/null +++ b/mods/mesecons/mesecons_switch/locale/mesecons_switch.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_switch +Switch=Schalter diff --git a/mods/mesecons/mesecons_switch/locale/mesecons_switch.eo.tr b/mods/mesecons/mesecons_switch/locale/mesecons_switch.eo.tr new file mode 100644 index 00000000..abd93f03 --- /dev/null +++ b/mods/mesecons/mesecons_switch/locale/mesecons_switch.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_switch + +### init.lua ### +Switch=Ŝaltilo diff --git a/mods/mesecons/mesecons_switch/locale/mesecons_switch.fr.tr b/mods/mesecons/mesecons_switch/locale/mesecons_switch.fr.tr new file mode 100644 index 00000000..6c07c640 --- /dev/null +++ b/mods/mesecons/mesecons_switch/locale/mesecons_switch.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_switch + +### init.lua ### +Switch=Commutateur diff --git a/mods/mesecons/mesecons_switch/locale/mesecons_switch.ru.tr b/mods/mesecons/mesecons_switch/locale/mesecons_switch.ru.tr new file mode 100644 index 00000000..8f45ccd9 --- /dev/null +++ b/mods/mesecons/mesecons_switch/locale/mesecons_switch.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_switch + +### init.lua ### +Switch=Выключатель diff --git a/mods/mesecons/mesecons_switch/locale/mesecons_switch.uk.tr b/mods/mesecons/mesecons_switch/locale/mesecons_switch.uk.tr new file mode 100644 index 00000000..9623de3e --- /dev/null +++ b/mods/mesecons/mesecons_switch/locale/mesecons_switch.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_switch + +### init.lua ### +Switch=Перемикач diff --git a/mods/mesecons/mesecons_switch/locale/template.txt b/mods/mesecons/mesecons_switch/locale/template.txt new file mode 100644 index 00000000..c493778b --- /dev/null +++ b/mods/mesecons/mesecons_switch/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_switch + +### init.lua ### +Switch= diff --git a/mods/mesecons/mesecons_switch/mod.conf b/mods/mesecons/mesecons_switch/mod.conf new file mode 100644 index 00000000..f6b642c6 --- /dev/null +++ b/mods/mesecons/mesecons_switch/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_switch +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_switch/sounds/mesecons_switch.ogg b/mods/mesecons/mesecons_switch/sounds/mesecons_switch.ogg new file mode 100644 index 00000000..53d45c18 Binary files /dev/null and b/mods/mesecons/mesecons_switch/sounds/mesecons_switch.ogg differ diff --git a/mods/mesecons/mesecons_switch/textures/mesecons_switch_off.png b/mods/mesecons/mesecons_switch/textures/mesecons_switch_off.png new file mode 100644 index 00000000..1dd77eae Binary files /dev/null and b/mods/mesecons/mesecons_switch/textures/mesecons_switch_off.png differ diff --git a/mods/mesecons/mesecons_switch/textures/mesecons_switch_on.png b/mods/mesecons/mesecons_switch/textures/mesecons_switch_on.png new file mode 100644 index 00000000..bc6bd75c Binary files /dev/null and b/mods/mesecons/mesecons_switch/textures/mesecons_switch_on.png differ diff --git a/mods/mesecons/mesecons_switch/textures/mesecons_switch_side.png b/mods/mesecons/mesecons_switch/textures/mesecons_switch_side.png new file mode 100644 index 00000000..9ffa4f09 Binary files /dev/null and b/mods/mesecons/mesecons_switch/textures/mesecons_switch_side.png differ diff --git a/mods/mesecons/mesecons_torch/doc/torch/description.html b/mods/mesecons/mesecons_torch/doc/torch/description.html new file mode 100644 index 00000000..60a6713e --- /dev/null +++ b/mods/mesecons/mesecons_torch/doc/torch/description.html @@ -0,0 +1,2 @@ +The torch is an inverter, it may take up to 1 second until the signal has passed through. The input is 2 blocks away in the direction of the stick, outputs are around the mesecon glow. +It doesn't work in an inactive block; it just retains its state until the block becomes active. diff --git a/mods/mesecons/mesecons_torch/doc/torch/preview.png b/mods/mesecons/mesecons_torch/doc/torch/preview.png new file mode 100644 index 00000000..edf7194e Binary files /dev/null and b/mods/mesecons/mesecons_torch/doc/torch/preview.png differ diff --git a/mods/mesecons/mesecons_torch/doc/torch/recipe.png b/mods/mesecons/mesecons_torch/doc/torch/recipe.png new file mode 100644 index 00000000..85d586dc Binary files /dev/null and b/mods/mesecons/mesecons_torch/doc/torch/recipe.png differ diff --git a/mods/mesecons/mesecons_torch/init.lua b/mods/mesecons/mesecons_torch/init.lua new file mode 100644 index 00000000..6469d7b7 --- /dev/null +++ b/mods/mesecons/mesecons_torch/init.lua @@ -0,0 +1,130 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +--MESECON TORCHES + +local rotate_torch_rules = function (rules, param2) + if param2 == 5 then + return mesecon.rotate_rules_right(rules) + elseif param2 == 2 then + return mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) --180 degrees + elseif param2 == 4 then + return mesecon.rotate_rules_left(rules) + elseif param2 == 1 then + return mesecon.rotate_rules_down(rules) + elseif param2 == 0 then + return mesecon.rotate_rules_up(rules) + else + return rules + end +end + +local torch_get_output_rules = function(node) + local 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}} + + return rotate_torch_rules(rules, node.param2) +end + +local torch_input_rules_unrotated_horizontal = {vector.new(-2, 0, 0), vector.new(-1, 1, 0)} +local torch_input_rules_unrotated_vertical = {vector.new(-2, 0, 0)} + +local torch_get_input_rules = function(node) + local rules = (node.param2 == 0 or node.param2 == 1) + and torch_input_rules_unrotated_vertical + or torch_input_rules_unrotated_horizontal + + return rotate_torch_rules(rules, node.param2) +end + +minetest.register_craft({ + output = "mesecons_torch:mesecon_torch_on 4", + recipe = { + {"group:mesecon_conductor_craftable"}, + {"group:stick"},} +}) + +local torch_selectionbox = +{ + type = "wallmounted", + wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1}, + wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1}, + wall_side = {-0.5, -0.1, -0.1, -0.5+0.6, 0.1, 0.1}, +} + +minetest.register_node("mesecons_torch:mesecon_torch_off", { + drawtype = "plantlike", + tiles = {"jeija_torches_off.png"}, + inventory_image = "jeija_torches_off.png", + paramtype = "light", + is_ground_content = false, + walkable = false, + paramtype2 = "wallmounted", + selection_box = torch_selectionbox, + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "mesecons_torch:mesecon_torch_on", + sounds = mesecon.node_sound.default, + mesecons = {receptor = { + state = mesecon.state.off, + rules = torch_get_output_rules + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_node("mesecons_torch:mesecon_torch_on", { + drawtype = "plantlike", + tiles = {"jeija_torches_on.png"}, + inventory_image = "jeija_torches_on.png", + wield_image = "jeija_torches_on.png", + paramtype = "light", + is_ground_content = false, + sunlight_propagates = true, + walkable = false, + paramtype2 = "wallmounted", + selection_box = torch_selectionbox, + groups = {dig_immediate=3}, + light_source = minetest.LIGHT_MAX-5, + description = S("Mesecon Torch"), + sounds = mesecon.node_sound.default, + mesecons = {receptor = { + state = mesecon.state.on, + rules = torch_get_output_rules + }}, + on_blast = mesecon.on_blastnode, +}) + +minetest.register_abm({ + nodenames = {"mesecons_torch:mesecon_torch_off","mesecons_torch:mesecon_torch_on"}, + interval = 1, + chance = 1, + action = function(pos, node) + local is_powered = false + for _, rule in ipairs(torch_get_input_rules(node)) do + local src = vector.add(pos, rule) + if mesecon.is_power_on(src) then + is_powered = true + end + end + + 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)) + 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)) + end + end +}) + +-- Param2 Table (Block Attached To) +-- 5 = z-1 +-- 3 = x-1 +-- 4 = z+1 +-- 2 = x+1 +-- 0 = y+1 +-- 1 = y-1 diff --git a/mods/mesecons/mesecons_torch/locale/mesecons_torch.de.tr b/mods/mesecons/mesecons_torch/locale/mesecons_torch.de.tr new file mode 100644 index 00000000..a72a1380 --- /dev/null +++ b/mods/mesecons/mesecons_torch/locale/mesecons_torch.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_torch +Mesecon Torch=Meseconfackel diff --git a/mods/mesecons/mesecons_torch/locale/mesecons_torch.eo.tr b/mods/mesecons/mesecons_torch/locale/mesecons_torch.eo.tr new file mode 100644 index 00000000..393dc4d5 --- /dev/null +++ b/mods/mesecons/mesecons_torch/locale/mesecons_torch.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_torch + +### init.lua ### +Mesecon Torch=Mesekonduktila Torĉo diff --git a/mods/mesecons/mesecons_torch/locale/mesecons_torch.fr.tr b/mods/mesecons/mesecons_torch/locale/mesecons_torch.fr.tr new file mode 100644 index 00000000..50687b3a --- /dev/null +++ b/mods/mesecons/mesecons_torch/locale/mesecons_torch.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_torch + +### init.lua ### +Mesecon Torch=Torche de Mesecon diff --git a/mods/mesecons/mesecons_torch/locale/mesecons_torch.ru.tr b/mods/mesecons/mesecons_torch/locale/mesecons_torch.ru.tr new file mode 100644 index 00000000..d5bceaf3 --- /dev/null +++ b/mods/mesecons/mesecons_torch/locale/mesecons_torch.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_torch + +### init.lua ### +Mesecon Torch=Мезе-факел diff --git a/mods/mesecons/mesecons_torch/locale/mesecons_torch.uk.tr b/mods/mesecons/mesecons_torch/locale/mesecons_torch.uk.tr new file mode 100644 index 00000000..b64578ca --- /dev/null +++ b/mods/mesecons/mesecons_torch/locale/mesecons_torch.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_torch + +### init.lua ### +Mesecon Torch=Месескип diff --git a/mods/mesecons/mesecons_torch/locale/template.txt b/mods/mesecons/mesecons_torch/locale/template.txt new file mode 100644 index 00000000..981e8502 --- /dev/null +++ b/mods/mesecons/mesecons_torch/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_torch + +### init.lua ### +Mesecon Torch= diff --git a/mods/mesecons/mesecons_torch/mod.conf b/mods/mesecons/mesecons_torch/mod.conf new file mode 100644 index 00000000..b631be78 --- /dev/null +++ b/mods/mesecons/mesecons_torch/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_torch +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/mesecons_torch/textures/jeija_torches_off.png b/mods/mesecons/mesecons_torch/textures/jeija_torches_off.png new file mode 100644 index 00000000..92cdce63 Binary files /dev/null and b/mods/mesecons/mesecons_torch/textures/jeija_torches_off.png differ diff --git a/mods/mesecons/mesecons_torch/textures/jeija_torches_on.png b/mods/mesecons/mesecons_torch/textures/jeija_torches_on.png new file mode 100644 index 00000000..7506c8d5 Binary files /dev/null and b/mods/mesecons/mesecons_torch/textures/jeija_torches_on.png differ diff --git a/mods/mesecons/mesecons_walllever/doc/walllever/description.html b/mods/mesecons/mesecons_walllever/doc/walllever/description.html new file mode 100644 index 00000000..ea5a0ed9 --- /dev/null +++ b/mods/mesecons/mesecons_walllever/doc/walllever/description.html @@ -0,0 +1 @@ +A receptor just like a switch, but it can be attached to walls. diff --git a/mods/mesecons/mesecons_walllever/doc/walllever/preview.png b/mods/mesecons/mesecons_walllever/doc/walllever/preview.png new file mode 100644 index 00000000..04819f35 Binary files /dev/null and b/mods/mesecons/mesecons_walllever/doc/walllever/preview.png differ diff --git a/mods/mesecons/mesecons_walllever/doc/walllever/recipe.png b/mods/mesecons/mesecons_walllever/doc/walllever/recipe.png new file mode 100644 index 00000000..8714e029 Binary files /dev/null and b/mods/mesecons/mesecons_walllever/doc/walllever/recipe.png differ diff --git a/mods/mesecons/mesecons_walllever/init.lua b/mods/mesecons/mesecons_walllever/init.lua new file mode 100644 index 00000000..651cd8d5 --- /dev/null +++ b/mods/mesecons/mesecons_walllever/init.lua @@ -0,0 +1,66 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- WALL LEVER +-- Basically a switch that can be attached to a wall +-- Powers the block 2 nodes behind (using a receiver) +mesecon.register_node("mesecons_walllever:wall_lever", { + description = S("Lever"), + drawtype = "mesh", + inventory_image = "jeija_wall_lever_inv.png", + wield_image = "jeija_wall_lever_inv.png", + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + sunlight_propagates = true, + walkable = false, + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, 3/16, 8/16, 8/16, 8/16 }, + }, + sounds = mesecon.node_sound.wood, + on_rightclick = 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 }, true) + end +},{ + tiles = { + "jeija_wall_lever_lever_light_off.png", + "jeija_wall_lever_front.png", + "jeija_wall_lever_front_bump.png", + "jeija_wall_lever_back_edges.png" + }, + mesh="jeija_wall_lever_off.obj", + on_rotate = mesecon.buttonlike_onrotate, + mesecons = {receptor = { + rules = mesecon.rules.buttonlike_get, + state = mesecon.state.off + }}, + groups = {dig_immediate = 2, mesecon_needs_receiver = 1} +},{ + tiles = { + "jeija_wall_lever_lever_light_on.png", + "jeija_wall_lever_front.png", + "jeija_wall_lever_front_bump.png", + "jeija_wall_lever_back_edges.png" + }, + mesh="jeija_wall_lever_on.obj", + on_rotate = false, + 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({ + output = "mesecons_walllever:wall_lever_off 2", + recipe = { + {"group:mesecon_conductor_craftable"}, + {"mesecons_gamecompat:stone"}, + {"group:stick"}, + } +}) diff --git a/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.de.tr b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.de.tr new file mode 100644 index 00000000..d854ff69 --- /dev/null +++ b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_walllever +Lever=Wandschalter diff --git a/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.eo.tr b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.eo.tr new file mode 100644 index 00000000..73d0a9ad --- /dev/null +++ b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_walllever + +### init.lua ### +Lever=Levilo diff --git a/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.fr.tr b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.fr.tr new file mode 100644 index 00000000..48217091 --- /dev/null +++ b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_walllever + +### init.lua ### +Lever=Levier diff --git a/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.ru.tr b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.ru.tr new file mode 100644 index 00000000..b308bea9 --- /dev/null +++ b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_walllever + +### init.lua ### +Lever=Рычаг diff --git a/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.uk.tr b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.uk.tr new file mode 100644 index 00000000..502dbe6d --- /dev/null +++ b/mods/mesecons/mesecons_walllever/locale/mesecons_walllever.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_walllever + +### init.lua ### +Lever=Важіль diff --git a/mods/mesecons/mesecons_walllever/locale/template.txt b/mods/mesecons/mesecons_walllever/locale/template.txt new file mode 100644 index 00000000..505a962e --- /dev/null +++ b/mods/mesecons/mesecons_walllever/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_walllever + +### init.lua ### +Lever= diff --git a/mods/mesecons/mesecons_walllever/mod.conf b/mods/mesecons/mesecons_walllever/mod.conf new file mode 100644 index 00000000..16467d41 --- /dev/null +++ b/mods/mesecons/mesecons_walllever/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_walllever +depends = mesecons, mesecons_gamecompat, mesecons_receiver diff --git a/mods/mesecons/mesecons_walllever/models/jeija_wall_lever_off.obj b/mods/mesecons/mesecons_walllever/models/jeija_wall_lever_off.obj new file mode 100644 index 00000000..334b54bc --- /dev/null +++ b/mods/mesecons/mesecons_walllever/models/jeija_wall_lever_off.obj @@ -0,0 +1,216 @@ +# Blender v2.73 (sub 0) OBJ File: 'mesecons-wall-lever-off.blend' +# www.blender.org +o nodebox-5 +v 0.281250 0.156250 0.312500 +v -0.375000 0.375000 0.375000 +v -0.375000 -0.375000 0.375000 +v 0.343751 0.218750 0.375000 +v 0.343751 -0.218752 0.375000 +v 0.375000 0.375000 0.375000 +v 0.375000 -0.375000 0.375000 +v 0.281250 -0.156250 0.312500 +v -0.062500 -0.055586 0.191789 +v -0.062500 -0.087939 0.312529 +v -0.062500 -0.413939 0.225178 +v -0.062500 -0.381586 0.104437 +v -0.343751 0.218750 0.375000 +v 0.062500 -0.055586 0.191789 +v 0.062500 -0.087939 0.312529 +v -0.343751 -0.218752 0.375000 +v 0.062500 -0.413939 0.225178 +v 0.062500 -0.381586 0.104437 +v 0.375000 -0.375000 0.500000 +v 0.375000 0.375000 0.500000 +v -0.375000 -0.375000 0.500000 +v -0.375000 0.375000 0.500000 +v -0.281250 0.156250 0.312500 +v -0.281250 -0.156250 0.312500 +v -0.250000 0.125000 0.312500 +v -0.250000 -0.125000 0.312500 +v 0.250000 0.125000 0.312500 +v 0.250000 -0.125000 0.312500 +v -0.250000 0.125000 0.250000 +v -0.250000 -0.125000 0.250000 +v 0.250000 0.125000 0.250000 +v 0.250000 -0.125000 0.250000 +v 0.125000 -0.062500 0.187500 +v 0.125000 0.062500 0.187500 +v -0.125000 -0.062500 0.187500 +v -0.125000 0.062500 0.187500 +v 0.062500 -0.031251 0.176992 +v 0.062500 0.031250 0.176992 +v -0.062498 -0.031251 0.176992 +v -0.062498 0.031250 0.176992 +v -0.187500 -0.093750 0.208750 +v 0.187500 0.093750 0.208750 +v 0.187500 -0.093750 0.208750 +v -0.187500 0.093750 0.208750 +v -0.375000 0.375000 0.375000 +v -0.375000 -0.375000 0.375000 +v 0.375000 0.375000 0.375000 +v 0.375000 -0.375000 0.375000 +v 0.375000 -0.375000 0.500000 +v 0.375000 0.375000 0.500000 +v -0.375000 -0.375000 0.500000 +v -0.375000 0.375000 0.500000 +vt 0.312500 0.437500 +vt 0.312500 0.000000 +vt 0.437500 0.000000 +vt 0.437500 0.437500 +vt 0.687500 0.187500 +vt 0.812500 0.187500 +vt 0.812500 0.312500 +vt 0.687500 0.312500 +vt 0.187500 0.437500 +vt 0.062500 0.437500 +vt 0.062500 0.000000 +vt 0.187500 0.000000 +vt 0.875000 0.796875 +vt 0.375000 0.796875 +vt 0.343750 0.765625 +vt 0.906250 0.765625 +vt 0.203125 0.875000 +vt 0.203125 0.625000 +vt 0.234375 0.593750 +vt 0.234375 0.906250 +vt 0.875000 0.890625 +vt 0.906250 0.921875 +vt 0.343750 0.921875 +vt 0.375000 0.890625 +vt 0.109375 0.875000 +vt 0.078125 0.906250 +vt 0.078125 0.593750 +vt 0.109375 0.625000 +vt 0.562500 0.437500 +vt 0.562500 0.000000 +vt 0.218880 0.343823 +vt 0.218880 0.656178 +vt 0.156408 0.718649 +vt 0.156408 0.281350 +vt 0.968592 0.718649 +vt 0.968592 0.281350 +vt 0.999827 0.125174 +vt 0.999827 0.874827 +vt 0.781120 0.656178 +vt 0.843592 0.718649 +vt 0.843592 0.281350 +vt 0.781120 0.343823 +vt 0.843592 0.156350 +vt 0.156408 0.156350 +vt 0.125173 0.000174 +vt 0.874827 0.000174 +vt 0.031408 0.718649 +vt 0.000173 0.874827 +vt 0.000173 0.125174 +vt 0.031408 0.281350 +vt 0.843592 0.843649 +vt 0.874827 0.999827 +vt 0.125173 0.999827 +vt 0.156408 0.843649 +vt 0.250000 0.625000 +vt 0.750000 0.625000 +vt 0.750000 0.687500 +vt 0.250000 0.687500 +vt 0.250000 0.375000 +vt 0.250000 0.312500 +vt 0.750000 0.312500 +vt 0.750000 0.375000 +vt 0.812500 0.375000 +vt 0.812500 0.625000 +vt 0.187500 0.625000 +vt 0.187500 0.375000 +vt 0.625000 0.562500 +vt 0.562500 0.531250 +vt 0.562500 0.468750 +vt 0.625000 0.437500 +vt 0.437500 0.468750 +vt 0.437500 0.531250 +vt 0.375000 0.437500 +vt 0.375000 0.562500 +vt 0.312500 0.406250 +vt 0.687500 0.406250 +vt 0.312500 0.593750 +vt 0.687500 0.593750 +vt 1.000000 0.000000 +vt 1.000000 0.875000 +vt 0.125000 0.875000 +vt 0.125000 0.000000 +vt 0.000000 0.875000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.125000 1.000000 +vn 0.000000 -0.258800 0.965900 +vn 0.000000 -0.965900 -0.258800 +vn 0.000000 0.258800 -0.965900 +vn 0.000000 0.000000 -1.000000 +vn -1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.707100 0.000000 -0.707100 +vn 0.000000 0.707100 -0.707100 +vn 0.000000 -0.707100 -0.707100 +vn -0.707100 0.000000 -0.707100 +vn 0.000000 1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.141100 0.273900 -0.951300 +vn -0.054600 0.137500 -0.989000 +vn -0.054600 -0.137500 -0.989000 +vn -0.141100 -0.273900 -0.951300 +vn 0.054600 -0.137500 -0.989000 +vn 0.054600 0.137500 -0.989000 +vn 0.141100 -0.273900 -0.951300 +vn 0.141100 0.273900 -0.951300 +vn 0.269900 -0.421500 -0.865700 +vn -0.269900 -0.421500 -0.865700 +vn 0.269900 0.421500 -0.865700 +vn -0.269900 0.421500 -0.865700 +vn -0.395600 0.336800 -0.854500 +vn 0.395600 0.336800 -0.854500 +vn 0.395600 -0.336800 -0.854500 +vn -0.395600 -0.336800 -0.854500 +vn 0.000000 -0.000000 1.000000 +g nodebox-5_nodebox-5_lever-light +s off +f 17/1/1 15/2/1 10/3/1 11/4/1 +f 18/5/2 17/6/2 11/7/2 12/8/2 +f 18/9/3 12/10/3 9/11/3 14/12/3 +f 26/13/4 28/14/4 8/15/4 24/16/4 +f 25/17/4 26/18/4 24/19/4 23/20/4 +f 25/21/4 23/22/4 1/23/4 27/24/4 +f 27/25/4 1/26/4 8/27/4 28/28/4 +f 12/29/5 11/4/5 10/3/5 9/30/5 +f 18/9/6 14/12/6 15/2/6 17/1/6 +g nodebox-5_nodebox-5_front +f 8/31/7 1/32/7 4/33/7 5/34/7 +f 13/35/4 16/36/4 3/37/4 2/38/4 +f 1/32/8 23/39/8 13/40/8 4/33/8 +f 8/31/9 5/34/9 16/41/9 24/42/9 +f 24/42/10 16/41/10 13/40/10 23/39/10 +f 16/43/4 5/44/4 7/45/4 3/46/4 +f 4/47/4 6/48/4 7/49/4 5/50/4 +f 13/51/4 2/52/4 6/53/4 4/54/4 +g nodebox-5_nodebox-5_front-bump +f 31/55/11 29/56/11 25/57/11 27/58/11 +f 32/59/12 28/60/12 26/61/12 30/62/12 +f 30/62/5 26/63/5 25/64/5 29/56/5 +f 32/59/6 31/55/6 27/65/6 28/66/6 +s 1 +f 36/67/13 40/68/14 39/69/15 35/70/16 +f 37/71/17 39/69/15 40/68/14 38/72/18 +f 35/70/16 39/69/15 37/71/17 33/73/19 +f 33/73/19 37/71/17 38/72/18 34/74/20 +f 34/74/20 38/72/18 40/68/14 36/67/13 +f 33/73/19 43/75/21 41/76/22 35/70/16 +f 33/73/19 34/74/20 42/77/23 43/75/21 +f 35/70/16 41/76/22 44/78/24 36/67/13 +f 42/77/23 44/78/24 29/56/25 31/55/26 +f 43/75/21 32/59/27 30/62/28 41/76/22 +f 43/75/21 42/77/23 31/55/26 32/59/27 +f 41/76/22 30/62/28 29/56/25 44/78/24 +f 34/74/20 36/67/13 44/78/24 42/77/23 +g nodebox-5_nodebox-5_back-edges +s off +f 19/79/29 20/80/29 22/81/29 21/82/29 +f 7/82/6 6/81/6 20/83/6 19/84/6 +f 3/82/5 21/84/5 22/83/5 2/81/5 +f 48/85/12 49/80/12 51/81/12 46/86/12 +f 47/85/11 45/86/11 52/81/11 50/80/11 diff --git a/mods/mesecons/mesecons_walllever/models/jeija_wall_lever_on.obj b/mods/mesecons/mesecons_walllever/models/jeija_wall_lever_on.obj new file mode 100644 index 00000000..a806be87 --- /dev/null +++ b/mods/mesecons/mesecons_walllever/models/jeija_wall_lever_on.obj @@ -0,0 +1,216 @@ +# Blender v2.73 (sub 0) OBJ File: 'mesecons-wall-lever.blend' +# www.blender.org +o nodebox-5 +v 0.281250 0.156250 0.312500 +v -0.375000 0.375000 0.375000 +v -0.375000 -0.375000 0.375000 +v 0.343751 0.218750 0.375000 +v 0.343751 -0.218752 0.375000 +v 0.375000 0.375000 0.375000 +v 0.375000 -0.375000 0.375000 +v 0.281250 -0.156250 0.312500 +v -0.062500 0.075354 0.315617 +v -0.062500 0.043002 0.194876 +v -0.062500 0.369002 0.107525 +v -0.062500 0.401354 0.228266 +v -0.343751 0.218750 0.375000 +v 0.062500 0.075354 0.315617 +v 0.062500 0.043002 0.194876 +v -0.343751 -0.218752 0.375000 +v 0.062500 0.369002 0.107525 +v 0.062500 0.401354 0.228266 +v 0.375000 -0.375000 0.500000 +v 0.375000 0.375000 0.500000 +v -0.375000 -0.375000 0.500000 +v -0.375000 0.375000 0.500000 +v -0.281250 0.156250 0.312500 +v -0.281250 -0.156250 0.312500 +v -0.250000 0.125000 0.312500 +v -0.250000 -0.125000 0.312500 +v 0.250000 0.125000 0.312500 +v 0.250000 -0.125000 0.312500 +v -0.250000 0.125000 0.250000 +v -0.250000 -0.125000 0.250000 +v 0.250000 0.125000 0.250000 +v 0.250000 -0.125000 0.250000 +v 0.125000 -0.062500 0.187500 +v 0.125000 0.062500 0.187500 +v -0.125000 -0.062500 0.187500 +v -0.125000 0.062500 0.187500 +v 0.062500 -0.031251 0.176992 +v 0.062500 0.031250 0.176992 +v -0.062498 -0.031251 0.176992 +v -0.062498 0.031250 0.176992 +v -0.187500 -0.093750 0.208750 +v 0.187500 0.093750 0.208750 +v 0.187500 -0.093750 0.208750 +v -0.187500 0.093750 0.208750 +v -0.375000 0.375000 0.375000 +v -0.375000 -0.375000 0.375000 +v 0.375000 0.375000 0.375000 +v 0.375000 -0.375000 0.375000 +v 0.375000 -0.375000 0.500000 +v 0.375000 0.375000 0.500000 +v -0.375000 -0.375000 0.500000 +v -0.375000 0.375000 0.500000 +vt 0.312500 0.437500 +vt 0.312500 0.000000 +vt 0.437500 0.000000 +vt 0.437500 0.437500 +vt 0.687500 0.187500 +vt 0.812500 0.187500 +vt 0.812500 0.312500 +vt 0.687500 0.312500 +vt 0.187500 0.437500 +vt 0.062500 0.437500 +vt 0.062500 0.000000 +vt 0.187500 0.000000 +vt 0.875000 0.796875 +vt 0.375000 0.796875 +vt 0.343750 0.765625 +vt 0.906250 0.765625 +vt 0.203125 0.875000 +vt 0.203125 0.625000 +vt 0.234375 0.593750 +vt 0.234375 0.906250 +vt 0.875000 0.890625 +vt 0.906250 0.921875 +vt 0.343750 0.921875 +vt 0.375000 0.890625 +vt 0.109375 0.875000 +vt 0.078125 0.906250 +vt 0.078125 0.593750 +vt 0.109375 0.625000 +vt 0.562500 0.437500 +vt 0.562500 0.000000 +vt 0.218880 0.343823 +vt 0.218880 0.656178 +vt 0.156408 0.718649 +vt 0.156408 0.281350 +vt 0.968592 0.718649 +vt 0.968592 0.281350 +vt 0.999827 0.125174 +vt 0.999827 0.874827 +vt 0.781120 0.656178 +vt 0.843592 0.718649 +vt 0.843592 0.281350 +vt 0.781120 0.343823 +vt 0.843592 0.156350 +vt 0.156408 0.156350 +vt 0.125173 0.000174 +vt 0.874827 0.000174 +vt 0.031408 0.718649 +vt 0.000173 0.874827 +vt 0.000173 0.125174 +vt 0.031408 0.281350 +vt 0.843592 0.843649 +vt 0.874827 0.999827 +vt 0.125173 0.999827 +vt 0.156408 0.843649 +vt 0.250000 0.625000 +vt 0.750000 0.625000 +vt 0.750000 0.687500 +vt 0.250000 0.687500 +vt 0.250000 0.375000 +vt 0.250000 0.312500 +vt 0.750000 0.312500 +vt 0.750000 0.375000 +vt 0.812500 0.375000 +vt 0.812500 0.625000 +vt 0.187500 0.625000 +vt 0.187500 0.375000 +vt 0.625000 0.562500 +vt 0.562500 0.531250 +vt 0.562500 0.468750 +vt 0.625000 0.437500 +vt 0.437500 0.468750 +vt 0.437500 0.531250 +vt 0.375000 0.437500 +vt 0.375000 0.562500 +vt 0.312500 0.406250 +vt 0.687500 0.406250 +vt 0.312500 0.593750 +vt 0.687500 0.593750 +vt 1.000000 0.000000 +vt 1.000000 0.875000 +vt 0.125000 0.875000 +vt 0.125000 0.000000 +vt 0.000000 0.875000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.125000 1.000000 +vn 0.000000 -0.258800 -0.965900 +vn 0.000000 0.965900 -0.258800 +vn 0.000000 0.258800 0.965900 +vn 0.000000 0.000000 -1.000000 +vn -1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.707100 0.000000 -0.707100 +vn 0.000000 0.707100 -0.707100 +vn 0.000000 -0.707100 -0.707100 +vn -0.707100 0.000000 -0.707100 +vn 0.000000 1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.141100 0.273900 -0.951300 +vn -0.054600 0.137500 -0.989000 +vn -0.054600 -0.137500 -0.989000 +vn -0.141100 -0.273900 -0.951300 +vn 0.054600 -0.137500 -0.989000 +vn 0.054600 0.137500 -0.989000 +vn 0.141100 -0.273900 -0.951300 +vn 0.141100 0.273900 -0.951300 +vn 0.269900 -0.421500 -0.865700 +vn -0.269900 -0.421500 -0.865700 +vn 0.269900 0.421500 -0.865700 +vn -0.269900 0.421500 -0.865700 +vn -0.395600 0.336800 -0.854500 +vn 0.395600 0.336800 -0.854500 +vn 0.395600 -0.336800 -0.854500 +vn -0.395600 -0.336800 -0.854500 +vn 0.000000 -0.000000 1.000000 +g nodebox-5_nodebox-5_lever-light +s off +f 17/1/1 15/2/1 10/3/1 11/4/1 +f 18/5/2 17/6/2 11/7/2 12/8/2 +f 18/9/3 12/10/3 9/11/3 14/12/3 +f 26/13/4 28/14/4 8/15/4 24/16/4 +f 25/17/4 26/18/4 24/19/4 23/20/4 +f 25/21/4 23/22/4 1/23/4 27/24/4 +f 27/25/4 1/26/4 8/27/4 28/28/4 +f 12/29/5 11/4/5 10/3/5 9/30/5 +f 18/9/6 14/12/6 15/2/6 17/1/6 +g nodebox-5_nodebox-5_front +f 8/31/7 1/32/7 4/33/7 5/34/7 +f 13/35/4 16/36/4 3/37/4 2/38/4 +f 1/32/8 23/39/8 13/40/8 4/33/8 +f 8/31/9 5/34/9 16/41/9 24/42/9 +f 24/42/10 16/41/10 13/40/10 23/39/10 +f 16/43/4 5/44/4 7/45/4 3/46/4 +f 4/47/4 6/48/4 7/49/4 5/50/4 +f 13/51/4 2/52/4 6/53/4 4/54/4 +g nodebox-5_nodebox-5_front-bump +f 31/55/11 29/56/11 25/57/11 27/58/11 +f 32/59/12 28/60/12 26/61/12 30/62/12 +f 30/62/5 26/63/5 25/64/5 29/56/5 +f 32/59/6 31/55/6 27/65/6 28/66/6 +s 1 +f 36/67/13 40/68/14 39/69/15 35/70/16 +f 37/71/17 39/69/15 40/68/14 38/72/18 +f 35/70/16 39/69/15 37/71/17 33/73/19 +f 33/73/19 37/71/17 38/72/18 34/74/20 +f 34/74/20 38/72/18 40/68/14 36/67/13 +f 33/73/19 43/75/21 41/76/22 35/70/16 +f 33/73/19 34/74/20 42/77/23 43/75/21 +f 35/70/16 41/76/22 44/78/24 36/67/13 +f 42/77/23 44/78/24 29/56/25 31/55/26 +f 43/75/21 32/59/27 30/62/28 41/76/22 +f 43/75/21 42/77/23 31/55/26 32/59/27 +f 41/76/22 30/62/28 29/56/25 44/78/24 +f 34/74/20 36/67/13 44/78/24 42/77/23 +g nodebox-5_nodebox-5_back-edges +s off +f 19/79/29 20/80/29 22/81/29 21/82/29 +f 7/82/6 6/81/6 20/83/6 19/84/6 +f 3/82/5 21/84/5 22/83/5 2/81/5 +f 48/85/12 49/80/12 51/81/12 46/86/12 +f 47/85/11 45/86/11 52/81/11 50/80/11 diff --git a/mods/mesecons/mesecons_walllever/sounds/mesecons_lever.ogg b/mods/mesecons/mesecons_walllever/sounds/mesecons_lever.ogg new file mode 100644 index 00000000..53d45c18 Binary files /dev/null and b/mods/mesecons/mesecons_walllever/sounds/mesecons_lever.ogg differ diff --git a/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_back_edges.png b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_back_edges.png new file mode 100644 index 00000000..edc331fe Binary files /dev/null and b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_back_edges.png differ diff --git a/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_front.png b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_front.png new file mode 100644 index 00000000..c7987ee3 Binary files /dev/null and b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_front.png differ diff --git a/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_front_bump.png b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_front_bump.png new file mode 100644 index 00000000..3b80d7ae Binary files /dev/null and b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_front_bump.png differ diff --git a/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_inv.png b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_inv.png new file mode 100644 index 00000000..f53bd742 Binary files /dev/null and b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_inv.png differ diff --git a/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_lever_light_off.png b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_lever_light_off.png new file mode 100644 index 00000000..3debb2df Binary files /dev/null and b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_lever_light_off.png differ diff --git a/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_lever_light_on.png b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_lever_light_on.png new file mode 100644 index 00000000..746227fd Binary files /dev/null and b/mods/mesecons/mesecons_walllever/textures/jeija_wall_lever_lever_light_on.png differ diff --git a/mods/mesecons/mesecons_wires/doc/mesecon/description.html b/mods/mesecons/mesecons_wires/doc/mesecon/description.html new file mode 100644 index 00000000..b20606bf --- /dev/null +++ b/mods/mesecons/mesecons_wires/doc/mesecon/description.html @@ -0,0 +1 @@ +Mesecons are the wires, use them to connect effectors with receptors. Wiring works through unloaded blocks; they’re loaded when the signal level changes. diff --git a/mods/mesecons/mesecons_wires/doc/mesecon/preview.png b/mods/mesecons/mesecons_wires/doc/mesecon/preview.png new file mode 100644 index 00000000..2c0e5fb0 Binary files /dev/null and b/mods/mesecons/mesecons_wires/doc/mesecon/preview.png differ diff --git a/mods/mesecons/mesecons_wires/doc/mesecon/recipe.png b/mods/mesecons/mesecons_wires/doc/mesecon/recipe.png new file mode 100644 index 00000000..3dfea78c Binary files /dev/null and b/mods/mesecons/mesecons_wires/doc/mesecon/recipe.png differ diff --git a/mods/mesecons/mesecons_wires/init.lua b/mods/mesecons/mesecons_wires/init.lua new file mode 100644 index 00000000..dc1a8ac3 --- /dev/null +++ b/mods/mesecons/mesecons_wires/init.lua @@ -0,0 +1,263 @@ +-- naming scheme: wire:(xp)(zp)(xm)(zm)(xpyp)(zpyp)(xmyp)(zmyp)_on/off +-- where x= x direction, z= z direction, y= y direction, p = +1, m = -1, e.g. xpym = {x=1, y=-1, z=0} +-- The (xp)/(zpyp)/.. statements shall be replaced by either 0 or 1 +-- Where 0 means the wire has no visual connection to that direction and +-- 1 means that the wire visually connects to that other node. + +-- ####################### +-- ## Update wire looks ## +-- ####################### + +local S = minetest.get_translator(minetest.get_current_modname()) + +-- self_pos = pos of any mesecon node, from_pos = pos of conductor to getconnect for +local wire_getconnect = function (from_pos, self_pos) + local node = minetest.get_node(self_pos) + local def = minetest.registered_nodes[node.name] + if def and def.mesecons then + -- rules of node to possibly connect to + local rules + if def.mesecon_wire then + rules = mesecon.rules.default + else + rules = mesecon.get_any_rules(node) + end + + for _, r in ipairs(mesecon.flattenrules(rules)) do + if (vector.equals(vector.add(self_pos, r), from_pos)) then + return true + end + end + end + return false +end + +-- Update this node +local wire_updateconnect = function (pos) + local connections = {} + + for _, r in ipairs(mesecon.rules.default) do + if wire_getconnect(pos, vector.add(pos, r)) then + table.insert(connections, r) + end + end + + local nid = {} + for _, vec in ipairs(connections) do + -- flat component + if vec.x == 1 then nid[0] = "1" end + if vec.z == 1 then nid[1] = "1" end + if vec.x == -1 then nid[2] = "1" end + if vec.z == -1 then nid[3] = "1" end + + -- slopy component + if vec.y == 1 then + if vec.x == 1 then nid[4] = "1" end + if vec.z == 1 then nid[5] = "1" end + if vec.x == -1 then nid[6] = "1" end + if vec.z == -1 then nid[7] = "1" end + end + end + + 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") + + local state_suffix = string.find(minetest.get_node(pos).name, "_off") and "_off" or "_on" + minetest.set_node(pos, {name = "mesecons:wire_"..nodeid..state_suffix}) +end + +local update_on_place_dig = function (pos, node) + -- Update placed node (get_node again as it may have been dug) + do + local nn = minetest.get_node(pos) + local def = minetest.registered_nodes[nn.name] + if def and def.mesecon_wire then + wire_updateconnect(pos) + end + end + + -- Update nodes around it + local rules + local ndef = minetest.registered_nodes[node.name] + if ndef and ndef.mesecon_wire then + rules = mesecon.rules.default + else + rules = mesecon.get_any_rules(node) + end + if (not rules) then return end + + for _, r in ipairs(mesecon.flattenrules(rules)) do + local np = vector.add(pos, r) + local rdef = minetest.registered_nodes[minetest.get_node(np).name] + if rdef and rdef.mesecon_wire then + wire_updateconnect(np) + end + end +end + +mesecon.register_autoconnect_hook("wire", update_on_place_dig) + +-- ############################ +-- ## Wire node registration ## +-- ############################ +-- Nodeboxes: +local box_center = {-1/16, -.5, -1/16, 1/16, -.5+1/16, 1/16} +local box_bump1 = { -2/16, -8/16, -2/16, 2/16, -13/32, 2/16 } + +local nbox_nid = +{ + [0] = {1/16, -.5, -1/16, 8/16, -.5+1/16, 1/16}, -- x positive + [1] = {-1/16, -.5, 1/16, 1/16, -.5+1/16, 8/16}, -- z positive + [2] = {-8/16, -.5, -1/16, -1/16, -.5+1/16, 1/16}, -- x negative + [3] = {-1/16, -.5, -8/16, 1/16, -.5+1/16, -1/16}, -- z negative + + [4] = {.5-1/16, -.5+1/16, -1/16, .5, .4999+1/16, 1/16}, -- x positive up + [5] = {-1/16, -.5+1/16, .5-1/16, 1/16, .4999+1/16, .5}, -- z positive up + [6] = {-.5, -.5+1/16, -1/16, -.5+1/16, .4999+1/16, 1/16}, -- x negative up + [7] = {-1/16, -.5+1/16, -.5, 1/16, .4999+1/16, -.5+1/16} -- z negative up +} + +local tiles_off = { "mesecons_wire_off.png" } +local tiles_on = { "mesecons_wire_on.png" } + +local selectionbox = +{ + type = "fixed", + fixed = {-.5, -.5, -.5, .5, -.5+4/16, .5} +} + +-- go to the next nodeid (ex.: 01000011 --> 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 + + -- 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 + + return i <= 8 +end + +local function register_wires() + 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" + }} + + local meseconspec_on = { conductor = { + rules = rules, + state = mesecon.state.on, + offstate = "mesecons:wire_"..nodeid.."_off" + }} + + local groups_on = {dig_immediate = 3, mesecon_conductor_craftable = 1, + not_in_creative_inventory = 1, not_in_craft_guide = 1} + local groups_off = {dig_immediate = 3, mesecon_conductor_craftable = 1} + if nodeid ~= "00000000" then + groups_off["not_in_creative_inventory"] = 1 + groups_off["not_in_craft_guide"] = 1 + end + + mesecon.register_node(":mesecons:wire_"..nodeid, { + description = S("Mesecon"), + drawtype = "nodebox", + inventory_image = "mesecons_wire_inv.png", + wield_image = "mesecons_wire_inv.png", + paramtype = "light", + paramtype2 = "facedir", + is_ground_content = false, + sunlight_propagates = true, + selection_box = selectionbox, + node_box = nodebox, + walkable = false, + drop = "mesecons:wire_00000000_off", + mesecon_wire = true, + sounds = mesecon.node_sound.default, + on_rotate = false, + }, {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() + +-- ############## +-- ## Crafting ## +-- ############## +-- (Resolve aliases to avoid bug with cooking/fuel recipes.) + +if minetest.registered_aliases["mesecons_gamecompat:mese_crystal_fragment"] then + minetest.register_craft({ + type = "cooking", + output = "mesecons:wire_00000000_off 2", + recipe = minetest.registered_aliases["mesecons_gamecompat:mese_crystal_fragment"], + cooktime = 3, + }) +end + +if minetest.registered_aliases["mesecons_gamecompat:mese_crystal"] then + minetest.register_craft({ + type = "cooking", + output = "mesecons:wire_00000000_off 18", + recipe = minetest.registered_aliases["mesecons_gamecompat:mese_crystal"], + cooktime = 15, + }) +end + +if minetest.registered_aliases["mesecons_gamecompat:mese"] then + minetest.register_craft({ + type = "cooking", + output = "mesecons:wire_00000000_off 162", + recipe = minetest.registered_aliases["mesecons_gamecompat:mese"], + cooktime = 30, + }) +end diff --git a/mods/mesecons/mesecons_wires/locale/mesecons_wires.de.tr b/mods/mesecons/mesecons_wires/locale/mesecons_wires.de.tr new file mode 100644 index 00000000..02970994 --- /dev/null +++ b/mods/mesecons/mesecons_wires/locale/mesecons_wires.de.tr @@ -0,0 +1,2 @@ +# textdomain: mesecons_wires +Mesecon=Mesecon diff --git a/mods/mesecons/mesecons_wires/locale/mesecons_wires.eo.tr b/mods/mesecons/mesecons_wires/locale/mesecons_wires.eo.tr new file mode 100644 index 00000000..9fee95a0 --- /dev/null +++ b/mods/mesecons/mesecons_wires/locale/mesecons_wires.eo.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_wires + +### init.lua ### +Mesecon=Mesekonduktilo diff --git a/mods/mesecons/mesecons_wires/locale/mesecons_wires.fr.tr b/mods/mesecons/mesecons_wires/locale/mesecons_wires.fr.tr new file mode 100644 index 00000000..cc8386c2 --- /dev/null +++ b/mods/mesecons/mesecons_wires/locale/mesecons_wires.fr.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_wires + +### init.lua ### +Mesecon=Mesecon diff --git a/mods/mesecons/mesecons_wires/locale/mesecons_wires.ru.tr b/mods/mesecons/mesecons_wires/locale/mesecons_wires.ru.tr new file mode 100644 index 00000000..dcd5c1ec --- /dev/null +++ b/mods/mesecons/mesecons_wires/locale/mesecons_wires.ru.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_wires + +### init.lua ### +Mesecon=Мезекон diff --git a/mods/mesecons/mesecons_wires/locale/mesecons_wires.uk.tr b/mods/mesecons/mesecons_wires/locale/mesecons_wires.uk.tr new file mode 100644 index 00000000..ed58fa59 --- /dev/null +++ b/mods/mesecons/mesecons_wires/locale/mesecons_wires.uk.tr @@ -0,0 +1,4 @@ +# textdomain: mesecons_wires + +### init.lua ### +Mesecon=Месекон diff --git a/mods/mesecons/mesecons_wires/locale/template.txt b/mods/mesecons/mesecons_wires/locale/template.txt new file mode 100644 index 00000000..82de311c --- /dev/null +++ b/mods/mesecons/mesecons_wires/locale/template.txt @@ -0,0 +1,4 @@ +# textdomain: mesecons_wires + +### init.lua ### +Mesecon= diff --git a/mods/mesecons/mesecons_wires/mod.conf b/mods/mesecons/mesecons_wires/mod.conf new file mode 100644 index 00000000..abbdebe8 --- /dev/null +++ b/mods/mesecons/mesecons_wires/mod.conf @@ -0,0 +1,2 @@ +name = mesecons_wires +depends = mesecons, mesecons_gamecompat diff --git a/mods/mesecons/modpack.conf b/mods/mesecons/modpack.conf new file mode 100644 index 00000000..645a90b8 --- /dev/null +++ b/mods/mesecons/modpack.conf @@ -0,0 +1,6 @@ +name = mesecons +description = Mod that implements a ton of items related to digital circuitry. +min_minetest_version = 5.7.0 +author = Jeija +title = Mesecons +release = 31832 diff --git a/mods/mesecons/screenshot.png b/mods/mesecons/screenshot.png new file mode 100644 index 00000000..aee3934d Binary files /dev/null and b/mods/mesecons/screenshot.png differ diff --git a/mods/mesecons/settingtypes.txt b/mods/mesecons/settingtypes.txt new file mode 100644 index 00000000..455c90a1 --- /dev/null +++ b/mods/mesecons/settingtypes.txt @@ -0,0 +1,67 @@ +[mesecons] + +mesecon.resumetime (Startup delay) int 4 1 10 +mesecon.overheat_max (Device heat limit) int 20 1 100 +mesecon.cooldown_time (Device cooldown time) float 2.0 0.1 10.0 +mesecon.cooldown_granularity (Cooldown step length) float 0.5 0.0 1.0 + + +[mesecons_blinkyplant] + +mesecon.blinky_plant_interval (Plant blinking interval) int 3 1 5 + + +[mesecons_commandblock] + +mesecon.commandblock_param_maxlen (Maximum command parameter length) int 10000 100 1000000 + + +[mesecons_detector] + +mesecon.detector_radius (Player detector scanning radius) int 6 3 16 +mesecon.node_detector_distance_max (Node detector distance limit) int 10 1 16 + + +[mesecons_luacontroller] + +mesecon.luacontroller_string_rep_max (string:rep result length limit) int 64000 1000 1000000 +mesecon.luacontroller_digiline_maxlen (Digiline message size limit) int 50000 1000 1000000 +mesecon.luacontroller_maxevents (Controller execution time limit) int 10000 1000 100000 +mesecon.luacontroller_memsize (Controller memory limit) int 100000 10000 1000000 + +# Use node timer for interrupts (runs in active blocks only). +# IID is ignored and at most one interrupt may be queued if this setting is enabled. +mesecon.luacontroller_lightweight_interrupts (Lightweight interrupts) bool false + +# Behavior of print() inside a luacontroller. By default, this emits a message into actionstream. +# Set it to noop if you wish to disable that behavior. +mesecon.luacontroller_print_behavior (Behavior of print) enum log log,noop + +[mesecons_mvps] + +# In pre-existing world, MVPS may not be labelled with the owner. +# Protection handling for them is configurable. +# - normal: allow legacy MVPS to work in unprotected areas only +# - compat: allow legacy MVPS to work everywhere +# - ignore: allow all MVPS to work everywhere +# - restrict: disallow legacy MVPS +# Note that new unowned (e.g. machine-placed) MVPS are always +# handled as in `normal` mode. +mesecon.mvps_protection_mode (MVPS [movestones, pistons] protection handling) enum compat normal,compat,ignore,restrict + +[mesecons_movestones] + +mesecon.movestone_speed (Speed) int 3 1 10 +mesecon.movestone_max_push (Max push) int 50 1 100 +mesecon.movestone_max_pull (Max pull) int 50 1 100 + + +[mesecons_pistons] + +mesecon.piston_max_push (Max push) int 15 1 100 +mesecon.piston_max_pull (Max pull) int 15 1 100 + + +[mesecons_pressureplates] + +mesecon.pplate_interval (Check interval) float 0.1 0.1 1.0 diff --git a/mods/moremesecons/.github/workflows/luacheck.yml b/mods/moremesecons/.github/workflows/luacheck.yml new file mode 100644 index 00000000..3c99a991 --- /dev/null +++ b/mods/moremesecons/.github/workflows/luacheck.yml @@ -0,0 +1,10 @@ +name: luacheck +on: [push, pull_request] +jobs: + luacheck: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@master + - name: Luacheck + uses: lunarmodules/luacheck@master diff --git a/mods/moremesecons/.gitignore b/mods/moremesecons/.gitignore new file mode 100644 index 00000000..c8d945c1 --- /dev/null +++ b/mods/moremesecons/.gitignore @@ -0,0 +1,7 @@ +## Generic ignorable patterns and files +*~ +debug.txt + +## Eclipse project files & directories +.project +.settings diff --git a/mods/moremesecons/.luacheckrc b/mods/moremesecons/.luacheckrc new file mode 100644 index 00000000..aa5d02ea --- /dev/null +++ b/mods/moremesecons/.luacheckrc @@ -0,0 +1,9 @@ +read_globals = { + -- Defined by Minetest + "minetest", "vector", "PseudoRandom", "VoxelArea", "table", + + -- Mods + "digiline", "default", "creative", +} +globals = {"moremesecons", "mesecon"} +ignore = {"212", "631", "422", "432"} diff --git a/mods/moremesecons/LICENSE.txt b/mods/moremesecons/LICENSE.txt new file mode 100644 index 00000000..52d13511 --- /dev/null +++ b/mods/moremesecons/LICENSE.txt @@ -0,0 +1,374 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + diff --git a/mods/moremesecons/README.md b/mods/moremesecons/README.md new file mode 100644 index 00000000..f58e8171 --- /dev/null +++ b/mods/moremesecons/README.md @@ -0,0 +1,50 @@ +# MoreMesecons + +Based on Mesecons by Jeija
+By @paly2 and @HybridDog
+With the participation of @LeMagnesium (bugfix), @Ataron (textures), @JAPP (texture). + +Dependencies: [Mesecons](https://github.com/Jeija/minetest-mod-mesecons/)
+Optional dependencies: [digilines](https://github.com/minetest-mods/digilines) + +MoreMesecons is a mod for minetest which adds some mesecons items. + +[Here](http://github.com/minetest-mods/MoreMesecons/wiki)'s the wiki ! + +## New items + +* `Adjustable Blinky plant` : Like a mesecons blinky plant, but... adjustable. Right-click to change the interval. +* `Adjustable Player Detector` : Like a mesecons player detector, but you can change its detection radius by right-click. +* `Craftable Command Block` : A command block with just some commands accepted. The admin can change the accepted command (first line of the init.lua), default "tell". Only "@nearest" can be used in the commands, and the admin can change the maximum distance of "@nearest" (default 8 blocks). +* `Conductor Signal Changer` : Like a diode which can be activated by sending a signal on its pin "F", and deactivated by sending a signal on its pin "O". +* `Dual Delayer` : If it receives a mesecons signal, port 1 turns on immediatly and port 2 turns on 0.4 seconds later. At the end of the signal, port 2 turns off immediatly and port 1 turns off 0.4 secondes later. For example, this is useful for double extenders. +* `Entity Detector` : You can use it to detect an entity. You can choose the entity to detect by right-click (use itemstring, for example "mobs:rat". To detect a dropped item, write "__builtin:item". To detect a specific dropped item, write its itemstring (for example "default:cobble")). +* `Igniter` : This node is a lighter that ignites its adjacent flammable nodes (including TNT). +* `Injector Controller` : This node is useful to activate/deactivate a pipeworks filter injector : it sends a blinky signal. +* `Jammer` : If turned on, this node stops mesecons in a radius of 10 nodes. +* `LuaBlock`: This block allows its owner to execute any Lua code in the global environment when turned on. Using it requires the server privilege. +* `Luacontroller Template Tool` : This tool is very useful to manipulate templates with luacontrollers. Just click with it on a luacontroller, then you'll see a formspec. +* `Player Killer` : This block kills the nearest player (with a maximal distance of 8 blocks by default) (if this player isn't its owner) when it receives a mesecons signal. +* `Sayer` : This node sends a message to every players inside a radius of 8 nodes. +* `Signal Changer` : If it receives a signal on its pin "F", it turns on. If it receives a signal on its pin "O", it turns off. Note : an inverted signal is sended at the other end of the arrow. +* `Switch Torch` : It connects just like Mesecons Torch. If it receives a signal, it turns on, and if it receives a second signal, it turns off. +* `Teleporter` : If you place one teleporter, it teleports the nearest player on itself when it receives a mesecons signal. If you place two teleporters on the same axis, when one receives a mesecons signal, it teleports the nearest player on the second (with a maximal distance of 50 nodes by default). The player teleporter must be inside a radius of 25 nodes. +* `Time Gate` : If it receives a mesecons signal, whatever its duration, a mesecons signal is send with a fixed duration. You can change it in the formspec by right-clicking on the gate. +* `Wireless` : Place 2 (or more) wireless somewhere. Change their channel by right-click. If you send a signal to a wireless, every wireless wich have the same channel will send the signal. Compatible with digiline mod. +* `Wireless Jammer` : If it receives a mesecons signal, it deactivates all wireless (receptors) in a radius of 15 nodes. + +## Settings + +You can set the settings by using the Minetest GUI ("Settings" tab -> Advanced settings -> Mods -> MoreMesecons). + +## The Sayer and the Speech Dispatcher + +[Speech Dispatcher project](http://freecode.com/projects/speech-dispatcher) + +The Sayer item is able to speak on your speakers using the speech dispatcher, under these conditions: +1. The moremesecons_sayer mod is present in your trusted_mods setting +2. You are playing in singleplayer. +3. You are using a POSIX-compliant system and a sh-compatible shell (such as bash, dash, zsh...). Microsoft Windows is NOT POSIX-compliant. +4. The speech dispatcher is installed on your system. + +The mod is able to detect issues 1, 2, and 4 by itself and then disable the speech dispatcher ; however, if you are using a non-POSIX-compliant system, the mod will crash on startup and you will need to disable the speech dispatcher manually (Settings tab -> Advanced settings -> Mods -> MoreMesecons -> Sayer -> Use the Speech Dispatcher). diff --git a/mods/moremesecons/description.txt b/mods/moremesecons/description.txt new file mode 100644 index 00000000..4172a16d --- /dev/null +++ b/mods/moremesecons/description.txt @@ -0,0 +1 @@ +Adds more Mesecons items. diff --git a/mods/moremesecons/modpack.conf b/mods/moremesecons/modpack.conf new file mode 100644 index 00000000..a12eb501 --- /dev/null +++ b/mods/moremesecons/modpack.conf @@ -0,0 +1,5 @@ +release = 32037 +author = Palige +name = moremesecons +description = Adds more Mesecons items. +title = MoreMesecons diff --git a/mods/moremesecons/modpack.txt b/mods/moremesecons/modpack.txt new file mode 100644 index 00000000..33d91f57 --- /dev/null +++ b/mods/moremesecons/modpack.txt @@ -0,0 +1 @@ +The presence of this file indicates that the current folder is a modpack. \ No newline at end of file diff --git a/mods/moremesecons/moremesecons_adjustable_blinkyplant/init.lua b/mods/moremesecons/moremesecons_adjustable_blinkyplant/init.lua new file mode 100644 index 00000000..66c5e9d8 --- /dev/null +++ b/mods/moremesecons/moremesecons_adjustable_blinkyplant/init.lua @@ -0,0 +1,66 @@ +local toggle_timer = function (pos, restart) + local timer = minetest.get_node_timer(pos) + if timer:is_started() + and not restart then + timer:stop() + else + local interval = tonumber(minetest.get_meta(pos):get_string("interval")) or 1 + if interval < moremesecons.setting("adjustable_blinky_plant", "min_interval", 0.5) then + interval = moremesecons.setting("adjustable_blinky_plant", "min_interval", 0.5) + end + timer:start(interval) + end +end + +local on_timer = function(pos) + if mesecon.flipstate(pos, minetest.get_node(pos)) == "on" then + mesecon.receptor_on(pos) + else + mesecon.receptor_off(pos) + end + toggle_timer(pos, false) +end + +mesecon.register_node("moremesecons_adjustable_blinkyplant:adjustable_blinky_plant", { + description="Adjustable Blinky Plant", + drawtype = "plantlike", + inventory_image = "moremesecons_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_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("interval", "1") + meta:set_string("formspec", "field[interval;interval;${interval}]") + toggle_timer(pos, true) + end, + on_receive_fields = function(pos, _, fields, player) + local interval = tonumber(fields.interval) + if interval + and not minetest.is_protected(pos, player:get_player_name()) then + minetest.get_meta(pos):set_string("interval", interval) + toggle_timer(pos, true) + end + end, +},{ + tiles = {"moremesecons_blinky_plant_off.png"}, + groups = {dig_immediate=3}, + mesecons = {receptor = { state = mesecon.state.off }} +},{ + tiles = {"moremesecons_blinky_plant_off.png^moremesecons_blinky_plant_on.png"}, + groups = {dig_immediate=3, not_in_creative_inventory=1}, + sunlight_propagates = true, + mesecons = {receptor = { state = mesecon.state.on }}, +}) + + +minetest.register_craft({ + output = "moremesecons_adjustable_blinkyplant:adjustable_blinky_plant_off 1", + recipe = { {"mesecons_blinkyplant:blinky_plant_off"}, + {"default:mese_crystal_fragment"},} +}) diff --git a/mods/moremesecons/moremesecons_adjustable_blinkyplant/mod.conf b/mods/moremesecons/moremesecons_adjustable_blinkyplant/mod.conf new file mode 100644 index 00000000..1fe52b05 --- /dev/null +++ b/mods/moremesecons/moremesecons_adjustable_blinkyplant/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_adjustable_blinkyplant +depends = mesecons,moremesecons_utils,default +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_adjustable_blinkyplant/textures/moremesecons_blinky_plant_off.png b/mods/moremesecons/moremesecons_adjustable_blinkyplant/textures/moremesecons_blinky_plant_off.png new file mode 100644 index 00000000..e36f3a10 Binary files /dev/null and b/mods/moremesecons/moremesecons_adjustable_blinkyplant/textures/moremesecons_blinky_plant_off.png differ diff --git a/mods/moremesecons/moremesecons_adjustable_blinkyplant/textures/moremesecons_blinky_plant_on.png b/mods/moremesecons/moremesecons_adjustable_blinkyplant/textures/moremesecons_blinky_plant_on.png new file mode 100644 index 00000000..8f157d1f Binary files /dev/null and b/mods/moremesecons/moremesecons_adjustable_blinkyplant/textures/moremesecons_blinky_plant_on.png differ diff --git a/mods/moremesecons/moremesecons_adjustable_player_detector/init.lua b/mods/moremesecons/moremesecons_adjustable_player_detector/init.lua new file mode 100644 index 00000000..3753f0f2 --- /dev/null +++ b/mods/moremesecons/moremesecons_adjustable_player_detector/init.lua @@ -0,0 +1,160 @@ +-- Adjustable Player Detector +-- Detects players in a certain radius +-- The radius can be changes by right-click (by default 6) + +local MAX_RADIUS = moremesecons.setting("adjustable_player_detector", "max_radius", 16, 0) + +local function make_formspec(meta) + meta:set_string("formspec", "size[9,5]" .. + "field[0.3, 0;9,2;scanname;Comma-separated list of the names of players to scan for (empty for any):;${scanname}]".. + "field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]".. + "field[0.3,3;4,2;radius;Detection radius:;${radius}]".. + "button_exit[3.5,3.5;2,3;;Save]") +end + +local function object_detector_make_formspec(pos) + make_formspec(minetest.get_meta(pos)) +end + +local function object_detector_on_receive_fields(pos, _, fields, player) + if not fields.scanname + or not fields.digiline_channel + or minetest.is_protected(pos, player:get_player_name()) then + return + end + + local meta = minetest.get_meta(pos) + meta:set_string("scanname", fields.scanname) + meta:set_string("digiline_channel", fields.digiline_channel) + local r = tonumber(fields.radius) + if r then + meta:set_int("radius", r) + end +end + +-- returns true if player was found, false if not +local object_detector_scan = function (pos) + local meta = minetest.get_meta(pos) + local scanname = meta:get_string("scanname") + local scan_all = scanname == "" + local scan_names = scanname:split(',') + local radius = math.min(meta:get_int("radius"), MAX_RADIUS) + if radius <= 0 then + radius = 6 + end + for _,obj in pairs(minetest.get_objects_inside_radius(pos, radius)) do + local isname = obj:get_player_name() -- "" is returned if it is not a player; "" ~= nil! + if isname ~= "" then + if scan_all then + return true, isname + end + for _, name in ipairs(scan_names) do + if isname == name then + return true, isname + end + end + end + end + return false +end + +-- set player name when receiving a digiline signal on a specific channel +local object_detector_digiline = { + effector = { + action = function (pos, node, channel, msg) + local meta = minetest.get_meta(pos) + local active_channel = meta:get_string("digiline_channel") + if channel ~= active_channel then + return + end + if type(msg) == "string" then + meta:set_string("scanname", msg) + make_formspec(meta) + elseif type(msg) == "table" then + if msg.radius then + local r = tonumber(msg.radius) + if r then + meta:set_int("radius", tonumber(msg.radius)) + make_formspec(meta) + end + end + if type(msg.scanname) == "string" then + meta:set_string("scanname", msg.scanname) + make_formspec(meta) + end + if msg.command == "get" then + local found, name = object_detector_scan(pos) + if not found then + name = "" + end + digiline:receptor_send(pos, digiline.rules.default, channel, name) + end + end + end, + }, + receptor = {} +} + +minetest.register_node("moremesecons_adjustable_player_detector:player_detector_off", { + tiles = {"default_steel_block.png", "default_steel_block.png", "moremesecons_player_detector_off.png"}, + paramtype = "light", + walkable = true, + groups = {cracky=3}, + description="Adjustable Player Detector", + mesecons = {receptor = { + state = mesecon.state.off, + rules = mesecon.rules.pplate + }}, + on_construct = object_detector_make_formspec, + on_receive_fields = object_detector_on_receive_fields, + sounds = default.node_sound_stone_defaults(), + digiline = object_detector_digiline +}) + +minetest.register_node("moremesecons_adjustable_player_detector:player_detector_on", { + tiles = {"default_steel_block.png", "default_steel_block.png", "moremesecons_player_detector_on.png"}, + paramtype = "light", + walkable = true, + groups = {cracky=3,not_in_creative_inventory=1}, + drop = 'moremesecons_adjustable_player_detector:player_detector_off', + mesecons = {receptor = { + state = mesecon.state.on, + rules = mesecon.rules.pplate + }}, + on_construct = object_detector_make_formspec, + on_receive_fields = object_detector_on_receive_fields, + sounds = default.node_sound_stone_defaults(), + digiline = object_detector_digiline +}) + +minetest.register_craft({ + output = 'moremesecons_adjustable_player_detector:player_detector_off', + recipe = { + {"mesecons_detector:object_detector_off"}, + {"default:mese_crystal_fragment"} + } +}) + +minetest.register_abm({ + nodenames = {"moremesecons_adjustable_player_detector:player_detector_off"}, + interval = 1.0, + chance = 1, + action = function(pos) + if object_detector_scan(pos) then + minetest.swap_node(pos, {name = "moremesecons_adjustable_player_detector:player_detector_on"}) + mesecon.receptor_on(pos, mesecon.rules.pplate) + end + end, +}) + +minetest.register_abm({ + nodenames = {"moremesecons_adjustable_player_detector:player_detector_on"}, + interval = 1.0, + chance = 1, + action = function(pos) + if not object_detector_scan(pos) then + minetest.swap_node(pos, {name = "moremesecons_adjustable_player_detector:player_detector_off"}) + mesecon.receptor_off(pos, mesecon.rules.pplate) + end + end, +}) diff --git a/mods/moremesecons/moremesecons_adjustable_player_detector/mod.conf b/mods/moremesecons/moremesecons_adjustable_player_detector/mod.conf new file mode 100644 index 00000000..feafaa8d --- /dev/null +++ b/mods/moremesecons/moremesecons_adjustable_player_detector/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_adjustable_player_detector +depends = mesecons,moremesecons_utils,default +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_adjustable_player_detector/textures/moremesecons_player_detector_off.png b/mods/moremesecons/moremesecons_adjustable_player_detector/textures/moremesecons_player_detector_off.png new file mode 100644 index 00000000..47bb37b1 Binary files /dev/null and b/mods/moremesecons/moremesecons_adjustable_player_detector/textures/moremesecons_player_detector_off.png differ diff --git a/mods/moremesecons/moremesecons_adjustable_player_detector/textures/moremesecons_player_detector_on.png b/mods/moremesecons/moremesecons_adjustable_player_detector/textures/moremesecons_player_detector_on.png new file mode 100644 index 00000000..a73a43dc Binary files /dev/null and b/mods/moremesecons/moremesecons_adjustable_player_detector/textures/moremesecons_player_detector_on.png differ diff --git a/mods/moremesecons/moremesecons_commandblock/init.lua b/mods/moremesecons/moremesecons_commandblock/init.lua new file mode 100644 index 00000000..da1eca4f --- /dev/null +++ b/mods/moremesecons/moremesecons_commandblock/init.lua @@ -0,0 +1,180 @@ +local strip_color_codes = minetest.settings:get_bool("strip_color_codes", false) + +local function initialize_data(meta) + local NEAREST_MAX_DISTANCE = moremesecons.setting("commandblock", "nearest_max_distance", 8, 1) + + local commands = meta:get_string("commands") + meta:set_string("formspec", + "size[9,5]" .. + "textarea[0.5,0.5;8.5,4;commands;Commands;"..minetest.formspec_escape(commands).."]" .. + "label[1,3.8;@nearest is replaced by the nearest player name ("..tostring(NEAREST_MAX_DISTANCE).." nodes max for the nearest distance)".."]" .. + "button_exit[3.3,4.5;2,1;submit;Submit]") + local owner = meta:get_string("owner") + if owner == "" then + owner = "not owned" + else + owner = "owned by " .. owner + end + meta:set_string("infotext", "Command Block\n" .. + "(" .. owner .. ")\n" .. + "Commands: "..commands) +end + +local function construct(pos) + local meta = minetest.get_meta(pos) + + meta:set_string("commands", "tell @nearest Commandblock unconfigured") + + meta:set_string("owner", "") + + initialize_data(meta) +end + +local function after_place(pos, placer) + if placer then + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + initialize_data(meta) + end +end + +local function receive_fields(pos, _, fields, player) + if not fields.submit then + return + end + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + if owner ~= "" + and player:get_player_name() ~= owner then + return + end + if strip_color_codes then + meta:set_string("commands", minetest.strip_colors(fields.commands)) + else + meta:set_string("commands", fields.commands) + end + + initialize_data(meta) +end + +local function resolve_commands(commands, pos) + local nearest = "" + local min_distance = math.huge + local players = minetest.get_connected_players() + for _, player in pairs(players) do + local distance = vector.distance(pos, player:get_pos()) + if distance < min_distance then + min_distance = distance + nearest = player:get_player_name() + end + end + local new_commands = commands:gsub("@nearest", nearest) + return new_commands, min_distance, new_commands ~= commands +end + +local function commandblock_action_on(pos, node) + local NEAREST_MAX_DISTANCE = moremesecons.setting("commandblock", "nearest_max_distance", 8, 1) + + local accepted_commands = {} + do + local commands_str = moremesecons.setting("commandblock", "authorized_commands", "tell") + for command in string.gmatch(commands_str, "([^ ]+)") do + accepted_commands[command] = true + end + end + + if node.name ~= "moremesecons_commandblock:commandblock_off" then + return + end + + minetest.swap_node(pos, {name = "moremesecons_commandblock:commandblock_on"}) + + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + if owner == "" then + return + end + + local commands, distance, nearest_in_commands = resolve_commands(meta:get_string("commands"), pos) + if distance > NEAREST_MAX_DISTANCE and nearest_in_commands then + minetest.chat_send_player(owner, "The nearest player is too far to use his name in the commands of a craftable command block.") + return + end + for _, command in pairs(commands:split("\n")) do + local pos = command:find(" ") + local cmd, param = command, "" + if pos then + cmd = command:sub(1, pos - 1) + param = command:sub(pos + 1) + end + local cmddef = minetest.chatcommands[cmd] + if not accepted_commands[cmd] and next(accepted_commands) then + minetest.chat_send_player(owner, "You can not execute the command "..cmd.." with a craftable command block ! This event will be reported.") + minetest.log("action", "Player "..owner.." tryed to execute an unauthorized command with a craftable command block.") + return + end + if not cmddef then + minetest.chat_send_player(owner, "The command "..cmd.." does not exist") + return + end + local has_privs, missing_privs = minetest.check_player_privs(owner, cmddef.privs) + if not has_privs then + minetest.chat_send_player(owner, "You don't have permission " + .."to run "..cmd + .." (missing privileges: " + ..table.concat(missing_privs, ", ")..")") + return + end + cmddef.func(owner, param) + end +end + +local function commandblock_action_off(pos, node) + if node.name == "moremesecons_commandblock:commandblock_on" then + minetest.swap_node(pos, {name = "moremesecons_commandblock:commandblock_off"}) + end +end + +local function can_dig(pos, player) + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + return owner == "" or owner == player:get_player_name() +end + +minetest.register_node("moremesecons_commandblock:commandblock_off", { + description = "Craftable Command Block", + tiles = {"moremesecons_commandblock_off.png"}, + groups = {cracky=2, mesecon_effector_off=1}, + on_construct = construct, + after_place_node = after_place, + on_receive_fields = receive_fields, + can_dig = can_dig, + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + action_on = commandblock_action_on + }} +}) + +minetest.register_node("moremesecons_commandblock:commandblock_on", { + tiles = {"moremesecons_commandblock_on.png"}, + groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1}, + light_source = 10, + drop = "moremesecons_commandblock:commandblock_off", + on_construct = construct, + after_place_node = after_place, + on_receive_fields = receive_fields, + can_dig = can_dig, + sounds = default.node_sound_stone_defaults(), + mesecons = {effector = { + action_off = commandblock_action_off + }} +}) + +minetest.register_craft({ + output = "moremesecons_commandblock:commandblock_off", + recipe = { + {"group:mesecon_conductor_craftable","default:mese_crystal","group:mesecon_conductor_craftable"}, + {"default:mese_crystal","group:mesecon_conductor_craftable","default:mese_crystal"}, + {"group:mesecon_conductor_craftable","default:mese_crystal","group:mesecon_conductor_craftable"} + } +}) diff --git a/mods/moremesecons/moremesecons_commandblock/mod.conf b/mods/moremesecons/moremesecons_commandblock/mod.conf new file mode 100644 index 00000000..88db0725 --- /dev/null +++ b/mods/moremesecons/moremesecons_commandblock/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_commandblock +depends = mesecons,moremesecons_utils,default +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_commandblock/textures/moremesecons_commandblock_off.png b/mods/moremesecons/moremesecons_commandblock/textures/moremesecons_commandblock_off.png new file mode 100644 index 00000000..dd8ed9dd Binary files /dev/null and b/mods/moremesecons/moremesecons_commandblock/textures/moremesecons_commandblock_off.png differ diff --git a/mods/moremesecons/moremesecons_commandblock/textures/moremesecons_commandblock_on.png b/mods/moremesecons/moremesecons_commandblock/textures/moremesecons_commandblock_on.png new file mode 100644 index 00000000..05095ab6 Binary files /dev/null and b/mods/moremesecons/moremesecons_commandblock/textures/moremesecons_commandblock_on.png differ diff --git a/mods/moremesecons/moremesecons_conductor_signalchanger/init.lua b/mods/moremesecons/moremesecons_conductor_signalchanger/init.lua new file mode 100644 index 00000000..fc47e51a --- /dev/null +++ b/mods/moremesecons/moremesecons_conductor_signalchanger/init.lua @@ -0,0 +1,81 @@ +local nodebox = { + type = "fixed", + fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }}, +} + +local function signalchanger_get_output_rules(node) + local rules = {{x=-1, y=0, z=0}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local function signalchanger_get_input_rules(node) + local rules = {{x=0, y=0, z=-1, name="input_on"}, {x=0, y=0, z=1, name="input_off"}, {x=1, y=0, z=0, name="input_signal"}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local update = function(pos, node, link, newstate) + local meta = minetest.get_meta(pos) + meta:set_int(link.name, newstate == "on" and 1 or 0) + local input_on = meta:get_int("input_on") == 1 + local input_off = meta:get_int("input_off") == 1 + local input_signal = meta:get_int("input_signal") == 1 + + if input_on then + minetest.swap_node(pos, {name = "moremesecons_conductor_signalchanger:conductor_signalchanger_on", param2 = node.param2}) + elseif input_off then + mesecon.receptor_off(pos, signalchanger_get_output_rules(node)) + minetest.swap_node(pos, {name = "moremesecons_conductor_signalchanger:conductor_signalchanger_off", param2 = node.param2}) + end + + if input_signal and minetest.get_node(pos).name == "moremesecons_conductor_signalchanger:conductor_signalchanger_on" then -- Note : we must use "minetest.get_node(pos)" and not "node" because the node may have been changed + mesecon.receptor_on(pos, signalchanger_get_output_rules(node)) + else + mesecon.receptor_off(pos, signalchanger_get_output_rules(node)) + end +end + +mesecon.register_node("moremesecons_conductor_signalchanger:conductor_signalchanger", { + description = "Conductor Signal Changer", + inventory_image = "moremesecons_conductor_signalchanger_off.png", + groups = {dig_immediate = 2}, + paramtype = "light", + paramtype2 = "facedir", + drawtype = "nodebox", + selection_box = nodebox, + node_box = nodebox, +},{ + groups = {dig_immediate = 2}, + mesecons = { + receptor = { + rules = signalchanger_get_output_rules + }, + effector = { + rules = signalchanger_get_input_rules, + action_change = update + }, + }, + tiles = {"moremesecons_conductor_signalchanger_off.png"}, +},{ + groups = {dig_immediate = 2, not_in_creative_inventory = 1}, + mesecons = { + receptor = { + rules = signalchanger_get_output_rules, + }, + effector = { + rules = signalchanger_get_input_rules, + action_change = update, + }, + }, + tiles = {"moremesecons_conductor_signalchanger_on.png"}, +}) + +minetest.register_craft({ + output = "moremesecons_conductor_signalchanger:conductor_signalchanger_off", + recipe = {{"group:mesecon_conductor_craftable","moremesecons_signalchanger:signalchanger_off"}} +}) diff --git a/mods/moremesecons/moremesecons_conductor_signalchanger/mod.conf b/mods/moremesecons/moremesecons_conductor_signalchanger/mod.conf new file mode 100644 index 00000000..975942a2 --- /dev/null +++ b/mods/moremesecons/moremesecons_conductor_signalchanger/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_conductor_signalchanger +depends = mesecons +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_conductor_signalchanger/textures/moremesecons_conductor_signalchanger_off.png b/mods/moremesecons/moremesecons_conductor_signalchanger/textures/moremesecons_conductor_signalchanger_off.png new file mode 100644 index 00000000..02232192 Binary files /dev/null and b/mods/moremesecons/moremesecons_conductor_signalchanger/textures/moremesecons_conductor_signalchanger_off.png differ diff --git a/mods/moremesecons/moremesecons_conductor_signalchanger/textures/moremesecons_conductor_signalchanger_on.png b/mods/moremesecons/moremesecons_conductor_signalchanger/textures/moremesecons_conductor_signalchanger_on.png new file mode 100644 index 00000000..58279361 Binary files /dev/null and b/mods/moremesecons/moremesecons_conductor_signalchanger/textures/moremesecons_conductor_signalchanger_on.png differ diff --git a/mods/moremesecons/moremesecons_dual_delayer/init.lua b/mods/moremesecons/moremesecons_dual_delayer/init.lua new file mode 100644 index 00000000..6cfb9d42 --- /dev/null +++ b/mods/moremesecons/moremesecons_dual_delayer/init.lua @@ -0,0 +1,100 @@ +local function dual_delayer_get_input_rules(node) + local rules = {{x=1, y=0, z=0}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local function dual_delayer_get_output_rules(node) + local rules = {{x=0, y=0, z=1}, {x=0, y=0, z=-1}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local dual_delayer_activate = function(pos, node) + mesecon.receptor_on(pos, {dual_delayer_get_output_rules(node)[1]}) -- Turn on the port 1 + minetest.swap_node(pos, {name = "moremesecons_dual_delayer:dual_delayer_10", param2 = node.param2}) + minetest.after(0.4, function() + mesecon.receptor_on(pos, {dual_delayer_get_output_rules(node)[2]}) -- Turn on the port 2 + minetest.swap_node(pos, {name = "moremesecons_dual_delayer:dual_delayer_11", param2 = node.param2}) + end) +end + +local dual_delayer_deactivate = function(pos, node, link) + mesecon.receptor_off(pos, {dual_delayer_get_output_rules(node)[2]}) -- Turn off the port 2 + minetest.swap_node(pos, {name = "moremesecons_dual_delayer:dual_delayer_10", param2 = node.param2}) + minetest.after(0.4, function() + mesecon.receptor_off(pos, {dual_delayer_get_output_rules(node)[1]}) -- Turn off the port 1 + minetest.swap_node(pos, {name = "moremesecons_dual_delayer:dual_delayer_00", param2 = node.param2}) + end) +end + + +for n,i in pairs({{0,0},{1,0},{1,1}}) do + local i1,i2 = unpack(i) + + local groups = {dig_immediate = 2} + if n ~= 1 then + groups.not_in_creative_inventory = 1 + end + + local top_texture = "^moremesecons_dual_delayer_overlay.png^[makealpha:255,126,126" + if i1 == i2 then + if i1 == 0 then + top_texture = "mesecons_wire_off.png"..top_texture + else + top_texture = "mesecons_wire_on.png"..top_texture + end + else + local pre = "mesecons_wire_off.png^[lowpart:50:mesecons_wire_on.png^[transformR" + if i1 == 0 then + pre = pre.. 90 + else + pre = pre.. 270 + end + top_texture = pre..top_texture + end + + local use_texture_alpha + if minetest.features.use_texture_alpha_string_modes then + use_texture_alpha = "opaque" + end + minetest.register_node("moremesecons_dual_delayer:dual_delayer_"..i1 ..i2, { + description = "Dual Delayer", + drop = "moremesecons_dual_delayer:dual_delayer_00", + inventory_image = top_texture, + wield_image = top_texture, + paramtype = "light", + paramtype2 = "facedir", + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = {{-6/16, -8/16, -8/16, 6/16, -7/16, 1/16 }, + {-8/16, -8/16, 1/16, -6/16, -7/16, -1/16}, + {8/16, -8/16, -1/16, 6/16, -7/16, 1/16}} + }, + groups = groups, + tiles = {top_texture, "moremesecons_dual_delayer_bottom.png", "moremesecons_dual_delayer_side_left.png", "moremesecons_dual_delayer_side_right.png", "moremesecons_dual_delayer_ends.png", "moremesecons_dual_delayer_ends.png"}, + use_texture_alpha = use_texture_alpha, + mesecons = { + receptor = { + state = mesecon.state.off, + rules = dual_delayer_get_output_rules + }, + effector = { + rules = dual_delayer_get_input_rules, + action_on = dual_delayer_activate, + action_off = dual_delayer_deactivate + } + } + }) +end + +minetest.register_craft({ + type = "shapeless", + output = "moremesecons_dual_delayer:dual_delayer_00 2", + recipe = {"mesecons_delayer:delayer_off_1", "mesecons_delayer:delayer_off_1"} +}) diff --git a/mods/moremesecons/moremesecons_dual_delayer/mod.conf b/mods/moremesecons/moremesecons_dual_delayer/mod.conf new file mode 100644 index 00000000..3926831d --- /dev/null +++ b/mods/moremesecons/moremesecons_dual_delayer/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_dual_delayer +depends = mesecons +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_bottom.png b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_bottom.png new file mode 100644 index 00000000..4cdb641e Binary files /dev/null and b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_bottom.png differ diff --git a/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_ends.png b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_ends.png new file mode 100644 index 00000000..c1f47d3f Binary files /dev/null and b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_ends.png differ diff --git a/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_overlay.png b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_overlay.png new file mode 100644 index 00000000..97423891 Binary files /dev/null and b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_overlay.png differ diff --git a/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_side_left.png b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_side_left.png new file mode 100644 index 00000000..46bb7939 Binary files /dev/null and b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_side_left.png differ diff --git a/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_side_right.png b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_side_right.png new file mode 100644 index 00000000..5e9cc8db Binary files /dev/null and b/mods/moremesecons/moremesecons_dual_delayer/textures/moremesecons_dual_delayer_side_right.png differ diff --git a/mods/moremesecons/moremesecons_entity_detector/init.lua b/mods/moremesecons/moremesecons_entity_detector/init.lua new file mode 100644 index 00000000..57783f91 --- /dev/null +++ b/mods/moremesecons/moremesecons_entity_detector/init.lua @@ -0,0 +1,138 @@ +-- Entity detector +-- Detects entitys in a certain radius +-- The radius can be changes by right-click (by default 6) + +local MAX_RADIUS = moremesecons.setting("entity_detector", "max_radius", 16, 0) + +local function make_formspec(meta) + meta:set_string("formspec", "size[9,5]" .. + "field[0.3, 0;9,2;scanname;Comma-separated list of the names (itemstring) of entities to scan for (empty for any):;${scanname}]".. + "field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]".. + "field[0.3,3;2,2;radius;Detection radius:;${radius}]".. + "button_exit[3.5,3.5;2,3;;Save]") +end + +local function object_detector_make_formspec(pos) + make_formspec(minetest.get_meta(pos)) +end + +local function object_detector_on_receive_fields(pos, _, fields, player) + if not fields.scanname + or not fields.digiline_channel + or minetest.is_protected(pos, player:get_player_name()) then + return + end + + local meta = minetest.get_meta(pos) + meta:set_string("scanname", fields.scanname) + meta:set_string("digiline_channel", fields.digiline_channel) + local r = tonumber(fields.radius) + if r then + meta:set_int("radius", math.min(r, MAX_RADIUS)) + end +end + +-- returns true if entity was found, false if not +local object_detector_scan = function (pos) + local meta = minetest.get_meta(pos) + local scanname = meta:get_string("scanname") + local scan_all = scanname == "" + local scan_names = scanname:split(',') + local radius = math.min(tonumber(meta:get("radius")) or 6, MAX_RADIUS) + for _,obj in pairs(minetest.get_objects_inside_radius(pos, radius)) do + local luaentity = obj:get_luaentity() + if luaentity then + if scan_all then + return true + end + local isname = luaentity.name + for _, name in ipairs(scan_names) do + if isname == name or (isname == "__builtin:item" and luaentity.itemstring == name) then + return true + end + end + end + end + return false +end + +-- set entity name when receiving a digiline signal on a specific channel +local object_detector_digiline = { + effector = { + action = function (pos, node, channel, msg) + local meta = minetest.get_meta(pos) + local active_channel = meta:get_string("digiline_channel") + if channel ~= active_channel or type(msg) ~= "string" then + return + end + meta:set_string("scanname", msg) + if meta:get_string("formspec") ~= "" then + make_formspec(meta) + end + end, + } +} + +minetest.register_node("moremesecons_entity_detector:entity_detector_off", { + tiles = {"default_steel_block.png", "default_steel_block.png", "moremesecons_entity_detector_off.png"}, + paramtype = "light", + walkable = true, + groups = {cracky=3}, + description="Entity Detector", + mesecons = {receptor = { + state = mesecon.state.off, + rules = mesecon.rules.pplate + }}, + on_construct = object_detector_make_formspec, + on_receive_fields = object_detector_on_receive_fields, + sounds = default.node_sound_stone_defaults(), + digiline = object_detector_digiline +}) + +minetest.register_node("moremesecons_entity_detector:entity_detector_on", { + tiles = {"default_steel_block.png", "default_steel_block.png", "moremesecons_entity_detector_on.png"}, + paramtype = "light", + walkable = true, + groups = {cracky=3,not_in_creative_inventory=1}, + drop = 'moremesecons_entity_detector:entity_detector_off', + mesecons = {receptor = { + state = mesecon.state.on, + rules = mesecon.rules.pplate + }}, + on_construct = object_detector_make_formspec, + on_receive_fields = object_detector_on_receive_fields, + sounds = default.node_sound_stone_defaults(), + digiline = object_detector_digiline +}) + +minetest.register_craft({ + output = 'moremesecons_entity_detector:entity_detector_off', + recipe = { + {"default:mese_crystal_fragment"}, + {"mesecons_detector:object_detector_off"} + } +}) + +minetest.register_abm({ + nodenames = {"moremesecons_entity_detector:entity_detector_off"}, + interval = 1.0, + chance = 1, + action = function(pos) + if object_detector_scan(pos) then + minetest.swap_node(pos, {name = "moremesecons_entity_detector:entity_detector_on"}) + mesecon.receptor_on(pos, mesecon.rules.pplate) + end + end, +}) + +minetest.register_abm({ + nodenames = {"moremesecons_entity_detector:entity_detector_on"}, + interval = 1.0, + chance = 1, + action = function(pos) + if not object_detector_scan(pos) then + minetest.swap_node(pos, {name = "moremesecons_entity_detector:entity_detector_off"}) + mesecon.receptor_off(pos, mesecon.rules.pplate) + end + end, +}) diff --git a/mods/moremesecons/moremesecons_entity_detector/mod.conf b/mods/moremesecons/moremesecons_entity_detector/mod.conf new file mode 100644 index 00000000..4a111a41 --- /dev/null +++ b/mods/moremesecons/moremesecons_entity_detector/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_entity_detector +depends = mesecons,moremesecons_utils,default +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_entity_detector/textures/moremesecons_entity_detector_off.png b/mods/moremesecons/moremesecons_entity_detector/textures/moremesecons_entity_detector_off.png new file mode 100644 index 00000000..0e96bc5e Binary files /dev/null and b/mods/moremesecons/moremesecons_entity_detector/textures/moremesecons_entity_detector_off.png differ diff --git a/mods/moremesecons/moremesecons_entity_detector/textures/moremesecons_entity_detector_on.png b/mods/moremesecons/moremesecons_entity_detector/textures/moremesecons_entity_detector_on.png new file mode 100644 index 00000000..fa4aceb8 Binary files /dev/null and b/mods/moremesecons/moremesecons_entity_detector/textures/moremesecons_entity_detector_on.png differ diff --git a/mods/moremesecons/moremesecons_igniter/init.lua b/mods/moremesecons/moremesecons_igniter/init.lua new file mode 100644 index 00000000..82cbbdf7 --- /dev/null +++ b/mods/moremesecons/moremesecons_igniter/init.lua @@ -0,0 +1,48 @@ +local function add_back_igniter(pos) + local name = minetest.get_node(pos).name + + if name == "moremesecons_igniter:igniter" then + -- this should not happen + minetest.log("error", "[moremesecons_igniter] igniter is already back") + return + end + + if name == "ignore" then + -- in case of unloaded chunk + minetest.get_voxel_manip():read_from_map(pos, pos) + name = minetest.get_node(pos).name + end + + if name == "air" + or name == "fire:basic_flame" then + minetest.set_node(pos, {name="moremesecons_igniter:igniter"}) + else + -- drop it as item if something took place there in the 0.8 seconds + pos.y = pos.y+1 + minetest.add_item(pos, "moremesecons_igniter:igniter") + pos.y = pos.y-1 + end +end + +local function igniter_on(pos) + minetest.set_node(pos, {name="fire:basic_flame"}) + minetest.after(0.8, add_back_igniter, pos) +end + +minetest.register_node("moremesecons_igniter:igniter", { + description = "Igniter", + paramtype = "light", + tiles = {"moremesecons_igniter.png"}, + groups = {cracky=3}, + mesecons = { + effector = { + action_on = igniter_on + }} +}) + + +minetest.register_craft({ + output = "moremesecons_igniter:igniter", + recipe = { {"default:torch"}, + {"default:mese_crystal_fragment"},} +}) diff --git a/mods/moremesecons/moremesecons_igniter/mod.conf b/mods/moremesecons/moremesecons_igniter/mod.conf new file mode 100644 index 00000000..3245b92e --- /dev/null +++ b/mods/moremesecons/moremesecons_igniter/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_igniter +depends = mesecons,fire +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_igniter/textures/moremesecons_igniter.png b/mods/moremesecons/moremesecons_igniter/textures/moremesecons_igniter.png new file mode 100644 index 00000000..b3fce67c Binary files /dev/null and b/mods/moremesecons/moremesecons_igniter/textures/moremesecons_igniter.png differ diff --git a/mods/moremesecons/moremesecons_induction_transmitter/init.lua b/mods/moremesecons/moremesecons_induction_transmitter/init.lua new file mode 100644 index 00000000..cca1e4c2 --- /dev/null +++ b/mods/moremesecons/moremesecons_induction_transmitter/init.lua @@ -0,0 +1,100 @@ +local function induction_transmitter_get_input_rules(node) + -- All horizontal rules, except the output + local rules = { + {x=-1,y=0,z=0}, + {x=1,y=0,z=0}, + {x=0,y=0,z=-1}, + {x=0,y=0,z=1} + } + for i, r in ipairs(rules) do + if vector.equals(r, minetest.facedir_to_dir(node.param2)) then + table.remove(rules, i) + end + end + return rules +end + +local function induction_transmitter_get_output_rules(node) + return {vector.multiply(minetest.facedir_to_dir(node.param2), 2)} +end + +local function act(pos, node, state) + minetest.swap_node(pos, {name = "moremesecons_induction_transmitter:induction_transmitter_"..state, param2 = node.param2}) + + local dir = minetest.facedir_to_dir(node.param2) + local target_pos = vector.add(pos, vector.multiply(dir, 2)) + local target_node = minetest.get_node(target_pos) + if mesecon.is_effector(target_node.name) then + -- Switch on an aside node, so it sends a signal to the target node + local aside_rule = mesecon.effector_get_rules(target_node)[1] + if not aside_rule then + return + end + mesecon["receptor_"..state](vector.add(target_pos, aside_rule), {vector.multiply(aside_rule, -1)}) + elseif mesecon.is_conductor(target_node.name) then + -- Switch on the conductor itself + mesecon["receptor_"..state](target_pos, mesecon.conductor_get_rules(target_node)) + end +end + +mesecon.register_node("moremesecons_induction_transmitter:induction_transmitter", { + description = "Induction Transmitter", + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + node_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, 0.125, 0.5, 0.5, 0.5}, + {-0.375, -0.375, -0.1875, 0.375, 0.375, 0.125}, + {-0.25, -0.25, -0.5, 0.25, 0.25, -0.1875}, + } + }, + selection_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, 0.125, 0.5, 0.5, 0.5}, + {-0.375, -0.375, -0.1875, 0.375, 0.375, 0.125}, + {-0.25, -0.25, -0.5, 0.25, 0.25, -0.1875}, + }, + }, +}, { + tiles = {"default_mese_block.png"}, + groups = {cracky = 3}, + mesecons = { + receptor = { + state = mesecon.state.off, + rules = induction_transmitter_get_output_rules + }, + effector = { + rules = induction_transmitter_get_input_rules, + action_on = function(pos, node) + act(pos, node, "on") + end + } + } +}, { + light_source = 5, + tiles = {"default_mese_block.png^[brighten"}, + groups = {cracky = 3, not_in_creative_inventory = 1}, + mesecons = { + receptor = { + state = mesecon.state.on, + rules = induction_transmitter_get_output_rules + }, + effector = { + rules = induction_transmitter_get_input_rules, + action_off = function(pos, node) + act(pos, node, "off") + end + } + } +}) + +minetest.register_craft({ + output = "moremesecons_induction_transmitter:induction_transmitter_off", + recipe = { + {"default:mese_crystal_fragment", "mesecons_torch:mesecon_torch_on", "default:mese_crystal_fragment"}, + {"", "default:mese_crystal_fragment", ""} + } +}) diff --git a/mods/moremesecons/moremesecons_induction_transmitter/mod.conf b/mods/moremesecons/moremesecons_induction_transmitter/mod.conf new file mode 100644 index 00000000..fb6bef5b --- /dev/null +++ b/mods/moremesecons/moremesecons_induction_transmitter/mod.conf @@ -0,0 +1,2 @@ +name = moremesecons_induction_transmitter +depends = mesecons,mesecons_torch,default diff --git a/mods/moremesecons/moremesecons_injector_controller/init.lua b/mods/moremesecons/moremesecons_injector_controller/init.lua new file mode 100644 index 00000000..5be9f07d --- /dev/null +++ b/mods/moremesecons/moremesecons_injector_controller/init.lua @@ -0,0 +1,84 @@ +local injector_controller_get_output_rules = function(node) + local rules = {{x = 0, y = 0, z = 1}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local injector_controller_get_input_rules = function(node) + local rules = {{x = 0, y = 0, z = -1}, + {x = 1, y = 0, z = 0}, + {x = -1, y = 0, z = 0}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local start_timer = function(pos) + local timer = minetest.get_node_timer(pos) + timer:start(1) +end +local stop_timer = function(pos, node) + local timer = minetest.get_node_timer(pos) + timer:stop() + mesecon.receptor_off(pos, injector_controller_get_output_rules(node)) + minetest.swap_node(pos, {name="moremesecons_injector_controller:injector_controller_off", param2=node.param2}) +end + +local on_timer = function(pos) + local node = minetest.get_node(pos) + if(mesecon.flipstate(pos, node) == "on") then + mesecon.receptor_on(pos, injector_controller_get_output_rules(node)) + else + mesecon.receptor_off(pos, injector_controller_get_output_rules(node)) + end + start_timer(pos) +end + +mesecon.register_node("moremesecons_injector_controller:injector_controller", { + description="Injector Controller", + drawtype = "nodebox", + inventory_image = "moremesecons_injector_controller_off.png", + paramtype = "light", + paramtype2 = "facedir", + node_box = { + type = "fixed", + fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }}, + }, + on_timer = on_timer, +},{ + tiles = {"moremesecons_injector_controller_off.png", "moremesecons_injector_controller_side.png", "moremesecons_injector_controller_side.png"}, + groups = {dig_immediate=2}, + mesecons = { + receptor = { + state = mesecon.state.off, + rules = injector_controller_get_output_rules + }, + effector = { + rules = injector_controller_get_input_rules, + action_on = start_timer, + action_off = stop_timer, + } + } +},{ + tiles = {"moremesecons_injector_controller_on.png", "moremesecons_injector_controller_side.png", "moremesecons_injector_controller_side.png"}, + groups = {dig_immediate=2, not_in_creative_inventory=1}, + mesecons = { + receptor = { + state = mesecon.state.on, + rules = injector_controller_get_output_rules + }, + effector = { + rules = injector_controller_get_input_rules, + action_off = stop_timer, + action_on = start_timer, + } + } +}) + +minetest.register_craft({ + output = "moremesecons_injector_controller:injector_controller_off", + recipe = {{"mesecons_blinkyplant:blinky_plant_off","mesecons_gates:and_off"}} +}) diff --git a/mods/moremesecons/moremesecons_injector_controller/mod.conf b/mods/moremesecons/moremesecons_injector_controller/mod.conf new file mode 100644 index 00000000..d396545c --- /dev/null +++ b/mods/moremesecons/moremesecons_injector_controller/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_injector_controller +depends = mesecons +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_off.png b/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_off.png new file mode 100644 index 00000000..ecc5d59b Binary files /dev/null and b/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_off.png differ diff --git a/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_on.png b/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_on.png new file mode 100644 index 00000000..820e6afc Binary files /dev/null and b/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_on.png differ diff --git a/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_side.png b/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_side.png new file mode 100644 index 00000000..6f7bbc6e Binary files /dev/null and b/mods/moremesecons/moremesecons_injector_controller/textures/moremesecons_injector_controller_side.png differ diff --git a/mods/moremesecons/moremesecons_jammer/init.lua b/mods/moremesecons/moremesecons_jammer/init.lua new file mode 100644 index 00000000..1e4e3f16 --- /dev/null +++ b/mods/moremesecons/moremesecons_jammer/init.lua @@ -0,0 +1,133 @@ +-- see wireless jammer +local storage = minetest.get_mod_storage() + +local jammers = moremesecons.load_MapDataStorage_legacy(storage, "jammers_v2", + "jammers") + +local function update_mod_storage() + storage:set_string("jammers_v2", jammers:serialize()) +end + +local function add_jammer(pos) + if jammers:getAt(pos) then + return + end + jammers:setAt(pos, true) + update_mod_storage() +end + +local function remove_jammer(pos) + jammers:removeAt(pos) + update_mod_storage() +end + +local function is_jammed(pos) + local JAMMER_MAX_DISTANCE = moremesecons.setting("jammer", "max_distance", 10, 1) + + local minp = vector.subtract(pos, JAMMER_MAX_DISTANCE) + local maxp = vector.add(pos, JAMMER_MAX_DISTANCE) + for p in jammers:iter(minp, maxp) do + local d = vector.subtract(pos, p) + if d.x ^ 2 + d.y ^ 2 + d.z ^ 2 <= JAMMER_MAX_DISTANCE^2 then + return true + end + end + return false +end + +minetest.after(0, function() -- After loading all mods, override some functions + local jammed + + local actual_node_get = mesecon.get_node_force + local function temp_node_get(pos, ...) + local node = actual_node_get(pos, ...) + if jammed == nil + and node then + jammed = is_jammed(pos) + end + return node + end + + local actual_is_conductor_off = mesecon.is_conductor_off + local function temp_is_conductor_off(...) + if jammed then + -- go to the next elseif, there's is_effector + return + end + local v = actual_is_conductor_off(...) + if v then + -- it continues to the next frontier + jammed = nil + end + return v + end + + local actual_is_effector = mesecon.is_effector + local function temp_is_effector(...) + local abort_here = jammed + -- the last elseif before continuing, jammed needs to be nil then + jammed = nil + if abort_here then + return + end + return actual_is_effector(...) + end + + local actual_turnon = mesecon.turnon + function mesecon.turnon(...) + --set those to the temporary functions + mesecon.get_node_force = temp_node_get + mesecon.is_conductor_off = temp_is_conductor_off + mesecon.is_effector = temp_is_effector + + actual_turnon(...) + + mesecon.get_node_force = actual_node_get + mesecon.is_conductor_off = actual_is_conductor_off + mesecon.is_effector = actual_is_effector + + -- safety + jammed = nil + end +end) + +mesecon.register_node("moremesecons_jammer:jammer", { + description = "Mesecons Jammer", + paramtype = "light", +},{ + tiles = {"moremesecons_jammer_off.png"}, + groups = {dig_immediate=2}, + mesecons = {effector = { + action_on = function(pos) + add_jammer(pos) + minetest.sound_play("moremesecons_jammer", {pos = pos}) + minetest.swap_node(pos, {name="moremesecons_jammer:jammer_on"}) + end + }}, +},{ + tiles = {"moremesecons_jammer_on.png"}, + groups = {dig_immediate=2, not_in_creative_inventory=1}, + mesecons = {effector = { + action_off = function(pos) + remove_jammer(pos) + minetest.swap_node(pos, {name="moremesecons_jammer:jammer_off"}) + end + }}, + on_destruct = remove_jammer, + on_construct = add_jammer, +}) + +minetest.register_craft({ + output = "moremesecons_jammer:jammer_off", + recipe = {{"group:mesecon_conductor_craftable", "default:mese", "group:mesecon_conductor_craftable"}, + {"", "moremesecons_wireless:jammer_off", ""}} +}) + +if moremesecons.setting("jammer", "enable_lbm", false) then + minetest.register_lbm({ + name = "moremesecons_jammer:add_jammer", + nodenames = {"moremesecons_jammer:jammer_on"}, + run_at_every_load = true, + action = add_jammer + }) +end diff --git a/mods/moremesecons/moremesecons_jammer/mod.conf b/mods/moremesecons/moremesecons_jammer/mod.conf new file mode 100644 index 00000000..01cabddb --- /dev/null +++ b/mods/moremesecons/moremesecons_jammer/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_jammer +depends = mesecons,moremesecons_utils +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_jammer/sounds/moremesecons_jammer.ogg b/mods/moremesecons/moremesecons_jammer/sounds/moremesecons_jammer.ogg new file mode 100644 index 00000000..930b0b40 Binary files /dev/null and b/mods/moremesecons/moremesecons_jammer/sounds/moremesecons_jammer.ogg differ diff --git a/mods/moremesecons/moremesecons_jammer/textures/moremesecons_jammer_off.png b/mods/moremesecons/moremesecons_jammer/textures/moremesecons_jammer_off.png new file mode 100644 index 00000000..77e8205d Binary files /dev/null and b/mods/moremesecons/moremesecons_jammer/textures/moremesecons_jammer_off.png differ diff --git a/mods/moremesecons/moremesecons_jammer/textures/moremesecons_jammer_on.png b/mods/moremesecons/moremesecons_jammer/textures/moremesecons_jammer_on.png new file mode 100644 index 00000000..cafccdea Binary files /dev/null and b/mods/moremesecons/moremesecons_jammer/textures/moremesecons_jammer_on.png differ diff --git a/mods/moremesecons/moremesecons_luablock/init.lua b/mods/moremesecons/moremesecons_luablock/init.lua new file mode 100644 index 00000000..24bc7eed --- /dev/null +++ b/mods/moremesecons/moremesecons_luablock/init.lua @@ -0,0 +1,160 @@ +local storage = minetest.get_mod_storage() +local pos_data = moremesecons.get_storage_data(storage, "pos_data") + +local function set_data(pos, code, owner) + local data = { + code = code, + owner = owner + } + moremesecons.set_data_to_pos(pos_data, pos, data) +end + +local function check_data(pos, code, owner) + local stored_data = moremesecons.get_data_from_pos(pos_data, pos) + if not stored_data then + return false + end + if code ~= stored_data.code + or owner ~= stored_data.owner then + return false + end + return true +end + + +local function make_formspec(meta, pos) + local code = minetest.formspec_escape(meta:get_string("code")) + local errmsg = minetest.formspec_escape(meta:get_string("errmsg")) + meta:set_string("formspec", + "size[10,8;]" .. + "textarea[0.5,0.5;9.5,7;code;Code;"..code.."]" .. + "label[0.1,7;"..errmsg.."]" .. + "button_exit[4,7.5;2,1;submit;Submit]") +end + +minetest.register_node("moremesecons_luablock:luablock", { + description = "Lua Block", + tiles = {"moremesecons_luablock.png"}, + groups = {cracky = 2}, + on_place = function(itemstack, placer, pointed_thing) + local under = pointed_thing.under + local node = minetest.get_node(under) + local udef = minetest.registered_nodes[node.name] + if udef and udef.on_rightclick and + not (placer and placer:get_player_control().sneak) then + return udef.on_rightclick(under, node, placer, itemstack, + pointed_thing) or itemstack + end + + local pos + if minetest.registered_items[minetest.get_node(under).name].buildable_to then + pos = under + else + pos = pointed_thing.above + end + + local name = placer:get_player_name() + if minetest.is_protected(pos, name) and + not minetest.check_player_privs(name, {protection_bypass = true}) then + minetest.record_protection_violation(pos, name) + return itemstack + end + if not minetest.check_player_privs(name, {server = true}) then + minetest.chat_send_player(name, "You can't use a LuaBlock without the server privilege.") + return itemstack + end + + local node_def = minetest.registered_nodes[minetest.get_node(pos).name] + if not node_def or not node_def.buildable_to then + return itemstack + end + + minetest.set_node(pos, {name = "moremesecons_luablock:luablock"}) + + local meta = minetest.get_meta(pos) + meta:set_string("owner", name) + meta:set_string("infotext", "LuaBlock owned by " .. name) + make_formspec(meta, pos) + + if not (creative and creative.is_enabled_for + and creative.is_enabled_for(placer:get_player_name())) then + itemstack:take_item() + end + return itemstack + end, + on_receive_fields = function(pos, form_name, fields, sender) + if not fields.submit then + return + end + local name = sender:get_player_name() + local meta = minetest.get_meta(pos) + if name ~= meta:get_string("owner") then + minetest.chat_send_player(name, "You don't own this LuaBlock.") + return + end + if not minetest.check_player_privs(name, {server = true}) then + minetest.chat_send_player(name, "You can't use a LuaBlock without the server privilege.") + return + end + + meta:set_string("code", fields.code) + set_data(pos, fields.code, name) + make_formspec(meta, pos) + end, + can_dig = function(pos, player) + local meta = minetest.get_meta(pos) + return meta:get_string("owner") == player:get_player_name() + end, + on_destruct = function(pos) + moremesecons.remove_data_from_pos(pos_data, pos) + end, + mesecons = {effector = { + action_on = function(npos, node) + local meta = minetest.get_meta(npos) + local code = meta:get_string("code") + local owner = meta:get_string("owner") + if code == "" then + return + end + if not check_data(npos, code, owner) then + minetest.log("warning", "[moremesecons_luablock] Metadata of LuaBlock at pos "..minetest.pos_to_string(npos).." does not match its mod storage data!") + return + end + + local env = {} + for k, v in pairs(_G) do + env[k] = v + end + env.pos = table.copy(npos) + env.mem = minetest.deserialize(meta:get_string("mem")) or {} + + local func, err_syntax + if _VERSION == "Lua 5.1" then + func, err_syntax = loadstring(code) + if func then + setfenv(func, env) + end + else + func, err_syntax = load(code, nil, "t", env) + end + if not func then + meta:set_string("errmsg", err_syntax) + make_formspec(meta, npos) + return + end + + local good, err_runtime = pcall(func) + + if not good then + meta:set_string("errmsg", err_runtime) + make_formspec(meta, npos) + return + end + + meta:set_string("mem", minetest.serialize(env.mem)) + + meta:set_string("errmsg", "") + make_formspec(meta, npos) + end + }} +}) diff --git a/mods/moremesecons/moremesecons_luablock/mod.conf b/mods/moremesecons/moremesecons_luablock/mod.conf new file mode 100644 index 00000000..3f553948 --- /dev/null +++ b/mods/moremesecons/moremesecons_luablock/mod.conf @@ -0,0 +1,2 @@ +name = moremesecons_luablock +depends = mesecons,moremesecons_utils diff --git a/mods/moremesecons/moremesecons_luablock/textures/moremesecons_luablock.png b/mods/moremesecons/moremesecons_luablock/textures/moremesecons_luablock.png new file mode 100644 index 00000000..4dafb12f Binary files /dev/null and b/mods/moremesecons/moremesecons_luablock/textures/moremesecons_luablock.png differ diff --git a/mods/moremesecons/moremesecons_luacontroller_tool/init.lua b/mods/moremesecons/moremesecons_luacontroller_tool/init.lua new file mode 100644 index 00000000..54b6cb01 --- /dev/null +++ b/mods/moremesecons/moremesecons_luacontroller_tool/init.lua @@ -0,0 +1,357 @@ +local templates = {MoreMesecons = { + logic = [[-- AND +port.a = pin.b and pin.c +-- OR +port.a = pin.b or pin.c +-- NOT +port.a = not pin.b +-- NAND +port.a = not (pin.b and pin.c) +-- NOR +port.a = not (pin.b or pin.c) +-- XOR +port.a = pin.b ~= pin.c +-- XNOR / NXOR +port.a = pin.b == pin.c]], + + digilinesth = [[digiline_send(channel, msg) +if event.type == "digiline" then + print(event.channel) + print(event.msg) +end]], + + clock = [[number_of_oscillations = 0 -- 0 for infinity +interval = 1 +input_port = "A" +output_port = "C" + +if event.type == "on" and event.pin.name == input_port and not mem.running then + if not mem.counter then + mem.counter = 0 + end + mem.running = true + port[string.lower(output_port)] = true + interrupt(interval) + mem.counter = mem.counter + 1 +elseif event.type == "off" and event.pin.name == input_port and mem.running and number_of_oscillations == 0 then + mem.running = false + mem.counter = 0 +elseif event.type == "interrupt" then + if not port[string.lower(output_port)] and mem.running then + port[string.lower(output_port)] = true + interrupt(interval) + mem.counter = mem.counter + 1 + else + port[string.lower(output_port)] = false + if mem.counter < number_of_oscillations or number_of_oscillations == 0 and mem.running then + interrupt(interval) + else + mem.running = false + mem.counter = 0 + end + end +end]], + + counter = [[counter_limit = 5 +output_time = 0.5 +input_port = "A" +output_port = "C" + +if event.type == "on" and event.pin.name == input_port then + if not mem.counter then + mem.counter = 0 + end + mem.counter = mem.counter + 1 + if mem.counter >= counter_limit then + port[string.lower(output_port)] = true + interrupt(output_time) + mem.counter = 0 + end +elseif event.type == "interrupt" then + port[string.lower(output_port)] = false +end]] +}} + + +local file_path = minetest.get_worldpath().."/MoreMesecons_lctt" + +-- load templates from a compressed file +do + local templates_file = io.open(file_path, "rb") + if templates_file then + local templates_raw = templates_file:read("*all") + io.close(templates_file) + if templates_raw + and templates_raw ~= "" then + local data = minetest.deserialize(minetest.decompress(templates_raw)) + for name,t in pairs(data) do + templates[name] = t + end + end + end +end + +-- the save function +local function save_to_file() + local templates_file = io.open(file_path, "w") + if not templates_file then + minetest.log("error", "[MoreMesecons] Could not open file for saving!") + return + end + local player_templates = table.copy(templates) + player_templates.MoreMesecons = nil + templates_file:write(minetest.compress(minetest.serialize(player_templates))) + io.close(templates_file) +end + +-- save doesn't save more than every 10s to disallow spamming +local saving +local function save() + if saving then + return + end + saving = true + minetest.after(16, function() + save_to_file() + saving = false + end) +end + +minetest.register_on_shutdown(function() + if saving then + save_to_file() + end +end) + + +-- used for the dropdown formspec element +local function fill_formspec_dropdown_list(t, selected) + local it,num = {},1 + for i in pairs(t) do + it[num] = i + num = num+1 + end + num = num-1 + table.sort(it) + local txt = "" + local selected_id + for i = 1,num do + local t = it[i] + if not selected_id + and t == selected then + selected_id = i + end + txt = txt..t -- add available indices + if i ~= num then + txt = txt.."," + end + end + return txt..";"..(selected_id or 1).."]" + --spec = string.sub(spec, 1, -2) +end + +local pdata = {} + +local function get_selection_formspec(pname, selected_template) + -- templates might be removed by someone while changing sth in formspec + local pl_templates = templates[pname] + if not pl_templates then + pname = next(templates) + pl_templates = templates[pname] + end + + local template_code = pl_templates[selected_template] + if not template_code then + selected_template = next(pl_templates) + template_code = pl_templates[selected_template] + end + + local spec = "size[10,10]".. + + -- show available players, field player_name, current player name is the selected one + "dropdown[0,0;5;player_name;".. + fill_formspec_dropdown_list(templates, pname).. + + -- show templates of pname + "dropdown[5,0;5;template_name;".. + fill_formspec_dropdown_list(pl_templates, selected_template).. + + -- show selected template + "textarea[0,1;10.5,8.5;template_code;template code:;"..minetest.formspec_escape(template_code).."]".. + + -- save name + "field[5,9.5;5,0;save_name;savename;"..selected_template.."]".. + + "button[0,10;2,0;button;set]".. + + "button[2,10;2,0;button;add]".. + + "button[5,10;2,0;button;save]" + + return spec +end + +-- tests if the node is a luacontroller +local function is_luacontroller(pos) + if not pos then + return false + end + return string.match(minetest.get_node(pos).name, "mesecons_luacontroller:luacontroller%d%d%d%d") +end + +-- do not localize the function directly here to support possible overwritten luacontrollers +local luac_def = minetest.registered_nodes["mesecons_luacontroller:luacontroller0000"] +local function set_luacontroller_code(pos, code, sender) + luac_def.on_receive_fields(pos, nil, {code=code, program=""}, sender) +end + +minetest.register_tool("moremesecons_luacontroller_tool:lctt", { + description = "luacontroller template tool", + inventory_image = "moremesecons_luacontroller_tool.png", + + on_use = function(_, player, pt) + if not player + or not pt then + return + end + + local pname = player:get_player_name() + local pos = pt.under + if not is_luacontroller(pos) then + minetest.chat_send_player(pname, "You can use the luacontroller template tool only on luacontroller nodes.") + return + end + + pdata[pname] = { + pos = pos, + player_name = pname, + template_name = pdata[pname] and pdata[pname].template_name or next(templates[pname] or templates[next(templates)]), + } + minetest.show_formspec(pname, "moremesecons:luacontroller_tool", get_selection_formspec(pdata[pname].player_name, pdata[pname].template_name)) + end, +}) + +--[[ Luacontroller reset_meta function, by Jeija +local function reset_meta(pos, code, errmsg) + local meta = minetest.get_meta(pos) + meta:set_string("code", code) + code = minetest.formspec_escape(code or "") + errmsg = minetest.formspec_escape(errmsg or "") + meta:set_string("formspec", "size[10,8]".. + "background[-0.2,-0.25;10.4,8.75;jeija_luac_background.png]".. + "textarea[0.2,0.6;10.2,5;code;;"..code.."]".. + "image_button[3.75,6;2.5,1;jeija_luac_runbutton.png;program;]".. + "image_button_exit[9.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]".. + "label[0.1,5;"..errmsg.."]") + meta:set_int("heat", 0) + meta:set_int("luac_id", math.random(1, 65535)) +end--]] + +-- used to avoid possibly crashes +local function get_code_or_nil(pname, player_name, template_name) + local player_templates = templates[player_name] + if not player_templates then + minetest.chat_send_player(pname, "error: "..player_name.." doesn't have templates now") + return + end + local code = player_templates[template_name] + if not code then + minetest.chat_send_player(pname, "error: "..template_name.." doesn't exist now") + return + end + return code +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "moremesecons:luacontroller_tool" + or fields.quit + or not player then + return + end + + --minetest.chat_send_all(dump(fields)) + + local pname = player:get_player_name() + + if fields.player_name + and fields.player_name ~= pdata[pname].player_name then + -- show available templates of that player + minetest.show_formspec(pname, "moremesecons:luacontroller_tool", + get_selection_formspec(fields.player_name, pdata[pname].template_name) + ) + pdata[pname].player_name = fields.player_name + return + end + + if fields.template_name + and fields.template_name ~= pdata[pname].template_name then + -- show selected template of that player + minetest.show_formspec(pname, "moremesecons:luacontroller_tool", + get_selection_formspec(pdata[pname].player_name, fields.template_name) + ) + pdata[pname].template_name = fields.template_name + return + end + + local pos = pdata[pname].pos + if not is_luacontroller(pos) then + -- this can happen + return + end + + local meta = minetest.get_meta(pos) + + if fields.button == "set" then + -- replace the code of the luacontroller with the template + local code = get_code_or_nil(pname, fields.player_name, fields.template_name) + if code then + set_luacontroller_code(pos, code, player) + minetest.chat_send_player(pname, "code set to template at "..minetest.pos_to_string(pos)) + end + return + end + + if fields.button == "add" then + -- add the template to the end of the code of the luacontroller + local code = get_code_or_nil(pname, fields.player_name, fields.template_name) + if code then + set_luacontroller_code(pos, meta:get_string("code").."\r"..code, player) + minetest.chat_send_player(pname, "code added to luacontroller at "..minetest.pos_to_string(pos)) + end + return + end + + if fields.button == "save" then + -- save the template, when you try to change others' templates, yours become changed + local savename = fields.template_name + if fields.save_name + and fields.save_name ~= "" + and fields.save_name ~= savename then + savename = minetest.formspec_escape(fields.save_name) + end + local code = fields.template_code + if not code then + minetest.chat_send_player(pname, "error: template code missing") + return + end + templates[pname] = templates[pname] or {} + if code == "" then + templates[pname][savename] = nil + if not next(templates[pname]) then + templates[pname] = nil + end + minetest.chat_send_player(pname, "template removed") + save() + return + end + code = minetest.formspec_escape(code) + if templates[pname][savename] == code then + minetest.chat_send_player(pname, "template not saved because it didn't change") + return + end + templates[pname][savename] = code + save() + minetest.chat_send_player(pname, "template "..pname.."/"..savename.." saved") + return + end +end) diff --git a/mods/moremesecons/moremesecons_luacontroller_tool/mod.conf b/mods/moremesecons/moremesecons_luacontroller_tool/mod.conf new file mode 100644 index 00000000..3cac5a52 --- /dev/null +++ b/mods/moremesecons/moremesecons_luacontroller_tool/mod.conf @@ -0,0 +1,2 @@ +name = moremesecons_luacontroller_tool +depends = mesecons,mesecons_luacontroller,moremesecons_utils diff --git a/mods/moremesecons/moremesecons_luacontroller_tool/textures/moremesecons_luacontroller_tool.png b/mods/moremesecons/moremesecons_luacontroller_tool/textures/moremesecons_luacontroller_tool.png new file mode 100644 index 00000000..ec0154db Binary files /dev/null and b/mods/moremesecons/moremesecons_luacontroller_tool/textures/moremesecons_luacontroller_tool.png differ diff --git a/mods/moremesecons/moremesecons_mesechest/init.lua b/mods/moremesecons/moremesecons_mesechest/init.lua new file mode 100644 index 00000000..2fe26cda --- /dev/null +++ b/mods/moremesecons/moremesecons_mesechest/init.lua @@ -0,0 +1,120 @@ +local function mesechest_get_output_rules(node) + local rules = {{x=-1, y=0, z=0}, + {x=0, y=0, z=-1}, + {x=0, y=0, z=1}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +-- default.chest.register_chest() doesn't allow to register most of the callbacks we need +-- we have to override the chest node we registered again +default.chest.register_chest("moremesecons_mesechest:mesechest", { + description = "Mese Chest", + tiles = { + "default_chest_top.png^[colorize:#d8e002:70", + "default_chest_top.png^[colorize:#d8e002:70", + "default_chest_side.png^[colorize:#d8e002:70", + "default_chest_side.png^[colorize:#d8e002:70", + "default_chest_front.png^[colorize:#d8e002:70", + "default_chest_inside.png^[colorize:#d8e002:70" + }, + sounds = default.node_sound_wood_defaults(), + sound_open = "default_chest_open", + sound_close = "default_chest_close", + groups = {choppy = 2, oddly_breakable_by_hand = 2}, + mesecons = { + receptor = { + rules = mesechest_get_output_rules + } + } +}) + +default.chest.register_chest("moremesecons_mesechest:mesechest_locked", { + description = "Locked Mese Chest", + tiles = { + "default_chest_top.png^[colorize:#d8e002:70", + "default_chest_top.png^[colorize:#d8e002:70", + "default_chest_side.png^[colorize:#d8e002:70", + "default_chest_side.png^[colorize:#d8e002:70", + "default_chest_lock.png^[colorize:#d8e002:70", + "default_chest_inside.png^[colorize:#d8e002:70" + }, + sounds = default.node_sound_wood_defaults(), + sound_open = "default_chest_open", + sound_close = "default_chest_close", + groups = {choppy = 2, oddly_breakable_by_hand = 2}, + protected = true, + mesecons = { + receptor = { + rules = mesechest_get_output_rules + } + } +}) + +local moremesecons_chests = {} + +for _, chest in ipairs({"moremesecons_mesechest:mesechest", "moremesecons_mesechest:mesechest_locked", + "moremesecons_mesechest:mesechest_open", "moremesecons_mesechest:mesechest_locked_open"}) do + local old_def = minetest.registered_nodes[chest] + + local old_on_metadata_inventory_put = old_def.on_metadata_inventory_put + local old_on_metadata_inventory_take = old_def.on_metadata_inventory_take + local old_on_rightclick = old_def.on_rightclick + + local override = {} + override.on_metadata_inventory_put = function(pos, ...) + old_on_metadata_inventory_put(pos, ...) + mesecon.receptor_on(pos, {mesechest_get_output_rules(minetest.get_node(pos))[2]}) + minetest.after(1, function(pos) + mesecon.receptor_off(pos, {mesechest_get_output_rules(minetest.get_node(pos))[2]}) + end, pos) + end + override.on_metadata_inventory_take = function(pos, ...) + old_on_metadata_inventory_take(pos, ...) + mesecon.receptor_on(pos, {mesechest_get_output_rules(minetest.get_node(pos))[3]}) + minetest.after(1, function(pos) + mesecon.receptor_off(pos, {mesechest_get_output_rules(minetest.get_node(pos))[3]}) + end, pos) + end + override.on_rightclick = function(pos, node, clicker, ...) + if old_on_rightclick(pos, node, clicker, ...) == nil then + mesecon.receptor_on(pos, {mesechest_get_output_rules(node)[1]}) + end + end + + minetest.override_item(chest, override) + moremesecons_chests[chest] = true +end + +-- if the chest is getting closed, turn the signal off +-- luacheck: ignore 122 +local old_lid_close = default.chest.chest_lid_close +function default.chest.chest_lid_close(pn) + local pos = default.chest.open_chests[pn].pos + -- old_lid_close will return true if the chest won't be closed + if old_lid_close(pn) then + return true + end + local node = minetest.get_node(pos) + if moremesecons_chests[node.name] then + mesecon.receptor_off(pos, {mesechest_get_output_rules(node)[1]}) + end +end + +minetest.register_craft({ + output = "moremesecons_mesechest:mesechest", + recipe = {{"group:mesecon_conductor_craftable", "default:chest", "group:mesecon_conductor_craftable"}} +}) + +minetest.register_craft({ + output = "moremesecons_mesechest:mesechest_locked", + recipe = {{"group:mesecon_conductor_craftable", "default:chest_locked", "group:mesecon_conductor_craftable"}} +}) + +-- Legacy +minetest.register_alias("default:mesechest", "moremesecons_mesechest:mesechest") +minetest.register_alias("mesechest", "moremesecons_mesechest:mesechest") +minetest.register_alias("default:mesechest_locked", "moremesecons_mesechest:mesechest") +minetest.register_alias("mesechest_locked", "moremesecons_mesechest:mesechest_locked") diff --git a/mods/moremesecons/moremesecons_mesechest/mod.conf b/mods/moremesecons/moremesecons_mesechest/mod.conf new file mode 100644 index 00000000..fdb396f4 --- /dev/null +++ b/mods/moremesecons/moremesecons_mesechest/mod.conf @@ -0,0 +1,2 @@ +name = moremesecons_mesechest +depends = default,mesecons diff --git a/mods/moremesecons/moremesecons_playerkiller/init.lua b/mods/moremesecons/moremesecons_playerkiller/init.lua new file mode 100644 index 00000000..dea28daa --- /dev/null +++ b/mods/moremesecons/moremesecons_playerkiller/init.lua @@ -0,0 +1,62 @@ +local kill_nearest_player = function(pos) + local MAX_DISTANCE = moremesecons.setting("playerkiller", "max_distance", 8, 1) + + -- Search the nearest player + local nearest + local min_distance = MAX_DISTANCE + for _, player in pairs(minetest.get_connected_players()) do + local distance = vector.distance(pos, player:getpos()) + if distance < min_distance then + min_distance = distance + nearest = player + end + end + + if not nearest then + -- no nearby player + return + end + + local owner = minetest.get_meta(pos):get_string("owner") + if not owner then + -- maybe some mod placed it + return + end + + if owner == nearest:get_player_name() then + -- don't kill the owner ! + return + end + + -- And kill him + nearest:set_hp(0) + minetest.log("action", "Player "..owner.." kills player "..nearest:get_player_name().." using a MoreMesecons Player Killer.") +end + +minetest.register_craft({ + output = "moremesecons_playerkiller:playerkiller", + recipe = { {"","default:mese",""}, + {"default:apple","mesecons_detector:object_detector_off","default:apple"}, + {"","default:apple",""}} +}) + +minetest.register_node("moremesecons_playerkiller:playerkiller", { + description = "Player Killer", + tiles = {"moremesecons_playerkiller_top.png", "moremesecons_playerkiller_top.png", "moremesecons_playerkiller_side.png"}, + paramtype = "light", + walkable = true, + groups = {cracky=3}, + mesecons = {effector = { + state = mesecon.state.off, + action_on = kill_nearest_player + }}, + after_place_node = function(pos, placer) + if not placer then + return + end + local meta = minetest.get_meta(pos) + meta:set_string("owner", placer:get_player_name()) + meta:set_string("infotext", "PlayerKiller owned by " .. meta:get_string("owner")) + end, + sounds = default.node_sound_stone_defaults(), +}) diff --git a/mods/moremesecons/moremesecons_playerkiller/mod.conf b/mods/moremesecons/moremesecons_playerkiller/mod.conf new file mode 100644 index 00000000..c5827de1 --- /dev/null +++ b/mods/moremesecons/moremesecons_playerkiller/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_playerkiller +depends = mesecons,mesecons_materials,moremesecons_utils,default +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_playerkiller/textures/moremesecons_playerkiller_side.png b/mods/moremesecons/moremesecons_playerkiller/textures/moremesecons_playerkiller_side.png new file mode 100644 index 00000000..77f28720 Binary files /dev/null and b/mods/moremesecons/moremesecons_playerkiller/textures/moremesecons_playerkiller_side.png differ diff --git a/mods/moremesecons/moremesecons_playerkiller/textures/moremesecons_playerkiller_top.png b/mods/moremesecons/moremesecons_playerkiller/textures/moremesecons_playerkiller_top.png new file mode 100644 index 00000000..a61d3445 Binary files /dev/null and b/mods/moremesecons/moremesecons_playerkiller/textures/moremesecons_playerkiller_top.png differ diff --git a/mods/moremesecons/moremesecons_sayer/init.lua b/mods/moremesecons/moremesecons_sayer/init.lua new file mode 100644 index 00000000..f5d0bad8 --- /dev/null +++ b/mods/moremesecons/moremesecons_sayer/init.lua @@ -0,0 +1,123 @@ +local use_speech_dispatcher = moremesecons.setting("sayer", "use_speech_dispatcher", true) + +local popen, execute = io.popen, os.execute +if use_speech_dispatcher then + if not minetest.is_singleplayer() then + minetest.log("warning", "[moremesecons_sayer] use_speech_dispatcher = true, but the speech dispatcher can only be used in singleplayer") + use_speech_dispatcher = false + else + local ie = {} + if minetest.request_insecure_environment then + ie = minetest.request_insecure_environment() + end + if not ie then + minetest.log("warning", "[moremesecons_sayer] This mod needs access to insecure functions in order to use the speech dispatcher. Please add the moremesecons_sayer mod to your secure.trusted_mods settings or disable the speech dispatcher.") + use_speech_dispatcher = false + else + popen = ie.io.popen + execute = ie.os.execute + end + end + + if use_speech_dispatcher then + if popen("if hash spd-say 2>/dev/null; then printf yes; fi"):read("*all") ~= "yes" then + minetest.log("warning", "[moremesecons_sayer] use_speech_dispatcher = true, but it seems the speech dispatcher isn't installed on your system") + use_speech_dispatcher = false + end + end +end + +local sayer_activate +if use_speech_dispatcher then + minetest.log("info", "[moremesecons_sayer] using speech dispatcher") + local tab = { + "spd-say", + nil, + "" + } + local language = minetest.settings:get("language") or "en" + if language ~= "en" then + tab[3] = "-l "..language + end + + function sayer_activate(pos) + local MAX_DISTANCE = moremesecons.setting("sayer", "max_distance", 8, 1) ^ 2 + + local text = minetest.get_meta(pos):get_string("text") + if text == "" then + -- nothing to say + return + end + if string.find(text, '"') then + text = "So, singleplayer, you want to use me to execute commands? Writing quotes is not allowed!" + end + tab[2] = '"'..text..'"' + local ppos = minetest.get_player_by_name("singleplayer"):getpos() + ppos.y = ppos.y+1.625 -- camera position (without bobbing) + -- that here's just 1 volume means that it's mono + local volume = math.floor(-100*( + 1-MAX_DISTANCE/vector.distance(pos, ppos)^2 + +0.5)) + if volume <= -100 then + -- nothing to hear + return + end + if volume > 0 then + --volume = "+"..math.min(100, volume) + -- volume bigger 0 somehow isn't louder, it rather tries to scream + volume = "+"..math.min(100, math.floor(volume/(MAX_DISTANCE-1)+0.5)) + end + if volume == 0 then + tab[4] = nil + else + tab[4] = "-i "..volume + end + execute(table.concat(tab, " ")) + end +else + function sayer_activate(pos) + local MAX_DISTANCE = moremesecons.setting("sayer", "max_distance", 8, 1) + + local tab = { + "Sayer at pos", + nil, + "says : "..minetest.get_meta(pos):get_string("text") + } + for _,player in pairs(minetest.get_connected_players()) do + if vector.distance(pos, player:getpos()) <= MAX_DISTANCE then + tab[2] = minetest.pos_to_string(pos) + minetest.chat_send_player(player:get_player_name(), table.concat(tab, " ")) + end + end + end +end + +minetest.register_node("moremesecons_sayer:sayer", { + description = "sayer", + tiles = {"mesecons_noteblock.png", "default_wood.png"}, + drawtype = "nodebox", + paramtype = "light", + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5}, + }, + groups = {dig_immediate = 2}, + on_construct = function(pos) + minetest.get_meta(pos):set_string("formspec", "field[text;text;${text}]") + end, + on_receive_fields = function(pos, _, fields, player) + if fields.text + and not minetest.is_protected(pos, player:get_player_name()) then + minetest.get_meta(pos):set_string("text", fields.text) + end + end, + mesecons = {effector = { + action_on = sayer_activate + }} +}) + +minetest.register_craft({ + output = "moremesecons_sayer:sayer 2", + recipe = {{"mesecons_luacontroller:luacontroller0000", "mesecons_noteblock:noteblock"}, + {"group:wood", "group:wood"}} +}) diff --git a/mods/moremesecons/moremesecons_sayer/mod.conf b/mods/moremesecons/moremesecons_sayer/mod.conf new file mode 100644 index 00000000..7e7fdc1d --- /dev/null +++ b/mods/moremesecons/moremesecons_sayer/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_sayer +depends = mesecons,mesecons_noteblock,moremesecons_utils,default +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_signalchanger/init.lua b/mods/moremesecons/moremesecons_signalchanger/init.lua new file mode 100644 index 00000000..0de35264 --- /dev/null +++ b/mods/moremesecons/moremesecons_signalchanger/init.lua @@ -0,0 +1,81 @@ +local nodebox = { + type = "fixed", + fixed = {{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }}, +} + +local function signalchanger_get_output_rules(node) + local rules = {{x=-1, y=0, z=0}, + {x=1, y=0, z=0}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local function signalchanger_get_input_rules(node) + local rules = {{x=0, y=0, z=-1, name="input_on"}, {x=0, y=0, z=1, name="input_off"}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local update = function(pos, node, link, newstate) + local meta = minetest.get_meta(pos) + meta:set_int(link.name, newstate == "on" and 1 or 0) + local input_on = meta:get_int("input_on") == 1 + local input_off = meta:get_int("input_off") == 1 + if input_on then + mesecon.receptor_on(pos, {signalchanger_get_output_rules(node)[1]}) + mesecon.receptor_off(pos, {signalchanger_get_output_rules(node)[2]}) + minetest.swap_node(pos, {name = "moremesecons_signalchanger:signalchanger_on", param2 = node.param2}) + elseif input_off then + mesecon.receptor_off(pos, {signalchanger_get_output_rules(node)[1]}) + mesecon.receptor_on(pos, {signalchanger_get_output_rules(node)[2]}) + minetest.swap_node(pos, {name = "moremesecons_signalchanger:signalchanger_off", param2 = node.param2}) + end +end + +mesecon.register_node("moremesecons_signalchanger:signalchanger", { + description = "Signal Changer", + inventory_image = "moremesecons_signalchanger_off.png", + groups = {dig_immediate = 2}, + paramtype = "light", + paramtype2 = "facedir", + drawtype = "nodebox", + selection_box = nodebox, + node_box = nodebox, +},{ + groups = {dig_immediate = 2}, + mesecons = { + receptor = { + rules = signalchanger_get_output_rules + }, + effector = { + rules = signalchanger_get_input_rules, + action_change = update + }, + }, + tiles = {"moremesecons_signalchanger_off.png"}, + on_construct = function(pos) + local node = minetest.get_node(pos) + mesecon.receptor_on(pos, {signalchanger_get_output_rules(node)[2]}) + end +},{ + groups = {dig_immediate = 2, not_in_creative_inventory = 1}, + mesecons = { + receptor = { + rules = signalchanger_get_output_rules, + }, + effector = { + rules = signalchanger_get_input_rules, + action_change = update, + }, + }, + tiles = {"moremesecons_signalchanger_on.png"}, +}) + +minetest.register_craft({ + output = "moremesecons_signalchanger:signalchanger_off", + recipe = {{"group:mesecon_conductor_craftable","moremesecons_switchtorch:switchtorch_off","group:mesecon_conductor_craftable"}} +}) diff --git a/mods/moremesecons/moremesecons_signalchanger/mod.conf b/mods/moremesecons/moremesecons_signalchanger/mod.conf new file mode 100644 index 00000000..852e30f0 --- /dev/null +++ b/mods/moremesecons/moremesecons_signalchanger/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_signalchanger +depends = mesecons +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_signalchanger/textures/moremesecons_signalchanger_off.png b/mods/moremesecons/moremesecons_signalchanger/textures/moremesecons_signalchanger_off.png new file mode 100644 index 00000000..df7a8cdd Binary files /dev/null and b/mods/moremesecons/moremesecons_signalchanger/textures/moremesecons_signalchanger_off.png differ diff --git a/mods/moremesecons/moremesecons_signalchanger/textures/moremesecons_signalchanger_on.png b/mods/moremesecons/moremesecons_signalchanger/textures/moremesecons_signalchanger_on.png new file mode 100644 index 00000000..5b94536f Binary files /dev/null and b/mods/moremesecons/moremesecons_signalchanger/textures/moremesecons_signalchanger_on.png differ diff --git a/mods/moremesecons/moremesecons_switchtorch/init.lua b/mods/moremesecons/moremesecons_switchtorch/init.lua new file mode 100644 index 00000000..2001f037 --- /dev/null +++ b/mods/moremesecons/moremesecons_switchtorch/init.lua @@ -0,0 +1,129 @@ +local rotate_torch_rules = function (rules, param2) + if param2 == 5 then + return mesecon.rotate_rules_right(rules) + elseif param2 == 2 then + return mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules)) --180 degrees + elseif param2 == 4 then + return mesecon.rotate_rules_left(rules) + elseif param2 == 1 then + return mesecon.rotate_rules_down(rules) + elseif param2 == 0 then + return mesecon.rotate_rules_up(rules) + else + return rules + end +end + +local output_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 torch_get_output_rules = function(node) + return rotate_torch_rules(output_rules, node.param2) +end + +local input_rules = { + {x = -2, y = 0, z = 0}, + {x = -1, y = 1, z = 0} +} +local torch_get_input_rules = function(node) + return rotate_torch_rules(input_rules, node.param2) +end + +minetest.register_craft({ + output = "moremesecons_switchtorch:switchtorch_off 4", + recipe = { + {"default:stick"}, + {"group:mesecon_conductor_craftable"}, + } +}) + +local torch_selectionbox = +{ + type = "wallmounted", + wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1}, + wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1}, + wall_side = {-0.5, -0.1, -0.1, -0.5+0.6, 0.1, 0.1}, +} + +minetest.register_node("moremesecons_switchtorch:switchtorch_off", { + description = "Switch Torch", + inventory_image = "moremesecons_switchtorch_on.png", + wield_image = "moremesecons_switchtorch_on.png", + drawtype = "torchlike", + tiles = {"moremesecons_switchtorch_off.png", "moremesecons_switchtorch_off_ceiling.png", "moremesecons_switchtorch_off_side.png"}, + paramtype = "light", + walkable = false, + paramtype2 = "wallmounted", + selection_box = torch_selectionbox, + groups = {dig_immediate = 3}, + mesecons = {receptor = { + state = mesecon.state.off, + rules = torch_get_output_rules + }}, + + on_construct = function(pos)-- For EndPower + minetest.get_meta(pos):set_int("EndPower", 1) -- 1 for true, 0 for false + end +}) + +minetest.register_node("moremesecons_switchtorch:switchtorch_on", { + drawtype = "torchlike", + tiles = {"moremesecons_switchtorch_on.png", "moremesecons_switchtorch_on_ceiling.png", "moremesecons_switchtorch_on_side.png"}, + paramtype = "light", + sunlight_propagates = true, + walkable = false, + paramtype2 = "wallmounted", + selection_box = torch_selectionbox, + groups = {dig_immediate=3, not_in_creative_inventory = 1}, + drop = "moremesecons_switchtorch:switchtorch_off", + light_source = 9, + mesecons = {receptor = { + state = mesecon.state.on, + rules = torch_get_output_rules + }}, +}) + +minetest.register_abm({ + nodenames = {"moremesecons_switchtorch:switchtorch_off","moremesecons_switchtorch:switchtorch_on"}, + interval = 1, + chance = 1, + action = function(pos, node) + local is_powered = false + for _, rule in ipairs(torch_get_input_rules(node)) do + local src = vector.add(pos, rule) + if mesecon.is_power_on(src) then + is_powered = true + break + end + end + + local meta = minetest.get_meta(pos) + if meta:get_int("EndPower") == 0 == is_powered then + return + end + if not is_powered then + meta:set_int("EndPower", 1) + return + end + if node.name == "moremesecons_switchtorch:switchtorch_on" then + minetest.swap_node(pos, {name = "moremesecons_switchtorch:switchtorch_off", param2 = node.param2}) + mesecon.receptor_off(pos, torch_get_output_rules(node)) + elseif node.name == "moremesecons_switchtorch:switchtorch_off" then + minetest.swap_node(pos, {name = "moremesecons_switchtorch:switchtorch_on", param2 = node.param2}) + mesecon.receptor_on(pos, torch_get_output_rules(node)) + end + meta:set_int("EndPower", 0) + end +}) + +-- Param2 Table (Block Attached To) +-- 5 = z-1 +-- 3 = x-1 +-- 4 = z+1 +-- 2 = x+1 +-- 0 = y+1 +-- 1 = y-1 diff --git a/mods/moremesecons/moremesecons_switchtorch/mod.conf b/mods/moremesecons/moremesecons_switchtorch/mod.conf new file mode 100644 index 00000000..f13be84c --- /dev/null +++ b/mods/moremesecons/moremesecons_switchtorch/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_switchtorch +depends = mesecons +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off.png b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off.png new file mode 100644 index 00000000..c37a6767 Binary files /dev/null and b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off.png differ diff --git a/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off_ceiling.png b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off_ceiling.png new file mode 100644 index 00000000..d768644b Binary files /dev/null and b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off_ceiling.png differ diff --git a/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off_side.png b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off_side.png new file mode 100644 index 00000000..1d7effee Binary files /dev/null and b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_off_side.png differ diff --git a/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on.png b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on.png new file mode 100644 index 00000000..a8a21f24 Binary files /dev/null and b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on.png differ diff --git a/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on_ceiling.png b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on_ceiling.png new file mode 100644 index 00000000..6501c624 Binary files /dev/null and b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on_ceiling.png differ diff --git a/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on_side.png b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on_side.png new file mode 100644 index 00000000..ddf6936a Binary files /dev/null and b/mods/moremesecons/moremesecons_switchtorch/textures/moremesecons_switchtorch_on_side.png differ diff --git a/mods/moremesecons/moremesecons_teleporter/init.lua b/mods/moremesecons/moremesecons_teleporter/init.lua new file mode 100644 index 00000000..df1d03ca --- /dev/null +++ b/mods/moremesecons/moremesecons_teleporter/init.lua @@ -0,0 +1,108 @@ +local storage = minetest.get_mod_storage() + +local teleporters = minetest.deserialize(storage:get_string("teleporters")) or {} +local teleporters_rids = moremesecons.load_MapDataStorage_legacy(storage, + "teleporters_rids_v2", "teleporters_rids") + +local function update_mod_storage() + storage:set_string("teleporters", minetest.serialize(teleporters)) + storage:set_string("teleporters_rids_v2", teleporters_rids:serialize()) +end + + +local function register(pos) + if not teleporters_rids:getAt(pos) then + table.insert(teleporters, pos) + teleporters_rids:setAt(pos, #teleporters) + update_mod_storage() + end +end + +local function teleport_nearest(pos) + local MAX_TELEPORTATION_DISTANCE = moremesecons.setting("teleporter", "max_t2t_distance", 50, 1) + local MAX_PLAYER_DISTANCE = moremesecons.setting("teleporter", "max_p2t_distance", 25, 1) + + -- Search for the nearest player + local nearest = nil + local min_distance_player = MAX_PLAYER_DISTANCE + local players = minetest.get_connected_players() + for _, player in pairs(players) do + local distance = vector.distance(pos, player:getpos()) + if distance <= min_distance_player then + min_distance_player = distance + nearest = player + end + end + + if not nearest then + -- If there is no nearest player (maybe too far away...) + return + end + + -- Search for the corresponding teleporter and teleport + if not minetest.registered_nodes["moremesecons_teleporter:teleporter"] then return end + + local newpos = {} + local min_distance = MAX_TELEPORTATION_DISTANCE + for i = 1, #teleporters do + if minetest.get_node(teleporters[i]).name == "moremesecons_teleporter:teleporter" then + local tel_pos + if teleporters[i].y == pos.y and teleporters[i].x == pos.x and teleporters[i].z ~= pos.z then + tel_pos = {x=teleporters[i].x, y=teleporters[i].y+1, z=teleporters[i].z} + elseif teleporters[i].z == pos.z and teleporters[i].x == pos.x and teleporters[i].y ~= pos.y then + tel_pos = {x=teleporters[i].x, y=teleporters[i].y+1, z=teleporters[i].z} + elseif teleporters[i].z == pos.z and teleporters[i].y == pos.y and teleporters[i].x ~= pos.x then + tel_pos = {x=teleporters[i].x, y=teleporters[i].y+1, z=teleporters[i].z} + end + + if tel_pos then + local distance = vector.distance(tel_pos, pos) + if distance <= min_distance then + min_distance = distance + newpos = tel_pos + end + end + end + end + if not newpos.x then + newpos = {x=pos.x, y=pos.y+1, z=pos.z} -- If newpos doesn't exist, teleport on the current teleporter + end + + nearest:moveto(newpos) + minetest.log("action", "Player "..nearest:get_player_name().." was teleported using a MoreMesecons Teleporter.") +end + +minetest.register_craft({ + output = "moremesecons_teleporter:teleporter 2", + recipe = {{"default:diamond","default:stick","default:mese"}} +}) +minetest.register_node("moremesecons_teleporter:teleporter", { + tiles = {"moremesecons_teleporter.png"}, + paramtype = "light", + walkable = true, + groups = {cracky=3}, + description="Teleporter", + mesecons = {effector = { + state = mesecon.state.off, + action_on = teleport_nearest + }}, + sounds = default.node_sound_stone_defaults(), + on_construct = register, + on_destruct = function(pos) + local RID = teleporters_rids:getAt(pos) + if RID then + table.remove(teleporters, RID) + teleporters_rids:removeAt(pos) + update_mod_storage() + end + end, +}) + +if moremesecons.setting("teleporter", "enable_lbm", false) then + minetest.register_lbm({ + name = "moremesecons_teleporter:add_teleporter", + nodenames = {"moremesecons_teleporter:teleporter"}, + run_at_every_load = true, + action = register + }) +end diff --git a/mods/moremesecons/moremesecons_teleporter/mod.conf b/mods/moremesecons/moremesecons_teleporter/mod.conf new file mode 100644 index 00000000..03d2446a --- /dev/null +++ b/mods/moremesecons/moremesecons_teleporter/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_teleporter +depends = mesecons,moremesecons_utils,default +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_teleporter/textures/moremesecons_teleporter.png b/mods/moremesecons/moremesecons_teleporter/textures/moremesecons_teleporter.png new file mode 100644 index 00000000..cd9140a3 Binary files /dev/null and b/mods/moremesecons/moremesecons_teleporter/textures/moremesecons_teleporter.png differ diff --git a/mods/moremesecons/moremesecons_timegate/init.lua b/mods/moremesecons/moremesecons_timegate/init.lua new file mode 100644 index 00000000..2920a90d --- /dev/null +++ b/mods/moremesecons/moremesecons_timegate/init.lua @@ -0,0 +1,136 @@ +local timegate_get_output_rules = function(node) + local rules = {{x = 0, y = 0, z = 1}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +local timegate_get_input_rules = function(node) + local rules = {{x = 0, y = 0, z = -1}} + for _ = 0, node.param2 do + rules = mesecon.rotate_rules_left(rules) + end + return rules +end + +-- Functions that are called after the delay time + +local function timegate_activate(pos, node) + -- using a meta string allows writing the time in hexadecimals + local time = tonumber(minetest.get_meta(pos):get_string("time")) + if not time then + return + end + node.name = "moremesecons_timegate:timegate_on" + minetest.swap_node(pos, node) + mesecon.receptor_on(pos) + minetest.after(time, function() + local node = minetest.get_node(pos) + if node.name == "moremesecons_timegate:timegate_on" then + mesecon.receptor_off(pos) + node.name = "moremesecons_timegate:timegate_off" + minetest.swap_node(pos, node) + end + end) +end + +local boxes = {{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab + + { -2/16, -7/16, -4/16, 2/16, -26/64, -3/16 }, -- the jeweled "on" indicator + { -3/16, -7/16, -3/16, 3/16, -26/64, -2/16 }, + { -4/16, -7/16, -2/16, 4/16, -26/64, 2/16 }, + { -3/16, -7/16, 2/16, 3/16, -26/64, 3/16 }, + { -2/16, -7/16, 3/16, 2/16, -26/64, 4/16 }, + + { -6/16, -7/16, -6/16, -4/16, -27/64, -4/16 }, -- the timer indicator + { -8/16, -8/16, -1/16, -6/16, -7/16, 1/16 }, -- the two wire stubs + { 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }} + +local use_texture_alpha +if minetest.features.use_texture_alpha_string_modes then + use_texture_alpha = "opaque" +end +mesecon.register_node("moremesecons_timegate:timegate", { + description = "Time Gate", + drawtype = "nodebox", + inventory_image = "moremesecons_timegate_off.png", + wield_image = "moremesecons_timegate_off.png", + walkable = true, + selection_box = { + type = "fixed", + fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 }, + }, + node_box = { + type = "fixed", + fixed = boxes + }, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + is_ground_content = true, + sounds = default.node_sound_stone_defaults(), + on_construct = function(pos) + minetest.get_meta(pos):set_string("formspec", "field[time;time;${time}]") + end, + on_receive_fields = function(pos, _, fields, player) + if fields.time + and not minetest.is_protected(pos, player:get_player_name()) then + minetest.get_meta(pos):set_string("time", fields.time) + end + end +},{ + tiles = { + "moremesecons_timegate_off.png", + "moremesecons_timegate_bottom.png", + "moremesecons_timegate_ends_off.png", + "moremesecons_timegate_ends_off.png", + "moremesecons_timegate_sides_off.png", + "moremesecons_timegate_sides_off.png" + }, + use_texture_alpha = use_texture_alpha, + groups = {bendy=2,snappy=1,dig_immediate=2}, + mesecons = { + receptor = + { + state = mesecon.state.off, + rules = timegate_get_output_rules + }, + effector = + { + rules = timegate_get_input_rules, + action_on = timegate_activate + } + }, +},{ + tiles = { + "moremesecons_timegate_on.png", + "moremesecons_timegate_bottom.png", + "moremesecons_timegate_ends_on.png", + "moremesecons_timegate_ends_on.png", + "moremesecons_timegate_sides_on.png", + "moremesecons_timegate_sides_on.png" + }, + use_texture_alpha = use_texture_alpha, + groups = {bendy=2,snappy=1,dig_immediate=2, not_in_creative_inventory=1}, + mesecons = { + receptor = { + state = mesecon.state.on, + rules = timegate_get_output_rules + }, + effector = { + rules = timegate_get_input_rules, + } + }, +}) + +minetest.register_craft({ + output = "moremesecons_timegate:timegate_off 2", + recipe = { + {"group:mesecon_conductor_craftable", "mesecons_delayer:delayer_off_1", "group:mesecon_conductor_craftable"}, + {"default:wood","default:wood", "default:wood"}, + } +}) + +minetest.register_alias("moremesecons_temporarygate:temporarygate_off", "moremesecons_timegate:timegate_off") +minetest.register_alias("moremesecons_temporarygate:temporarygate_on", "moremesecons_timegate:timegate_on") diff --git a/mods/moremesecons/moremesecons_timegate/mod.conf b/mods/moremesecons/moremesecons_timegate/mod.conf new file mode 100644 index 00000000..d916d204 --- /dev/null +++ b/mods/moremesecons/moremesecons_timegate/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_timegate +depends = mesecons,default +optional_depends = craft_guide diff --git a/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_bottom.png b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_bottom.png new file mode 100644 index 00000000..5f2b67a0 Binary files /dev/null and b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_bottom.png differ diff --git a/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_ends_off.png b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_ends_off.png new file mode 100644 index 00000000..f8c8b1c2 Binary files /dev/null and b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_ends_off.png differ diff --git a/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_ends_on.png b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_ends_on.png new file mode 100644 index 00000000..953fde3f Binary files /dev/null and b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_ends_on.png differ diff --git a/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_off.png b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_off.png new file mode 100644 index 00000000..d0f1ebde Binary files /dev/null and b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_off.png differ diff --git a/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_on.png b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_on.png new file mode 100644 index 00000000..7c019352 Binary files /dev/null and b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_on.png differ diff --git a/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_sides_off.png b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_sides_off.png new file mode 100644 index 00000000..cae207cd Binary files /dev/null and b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_sides_off.png differ diff --git a/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_sides_on.png b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_sides_on.png new file mode 100644 index 00000000..9647a019 Binary files /dev/null and b/mods/moremesecons/moremesecons_timegate/textures/moremesecons_timegate_sides_on.png differ diff --git a/mods/moremesecons/moremesecons_utils/init.lua b/mods/moremesecons/moremesecons_utils/init.lua new file mode 100644 index 00000000..a6cbcc2b --- /dev/null +++ b/mods/moremesecons/moremesecons_utils/init.lua @@ -0,0 +1,381 @@ +moremesecons = {} + +function moremesecons.setting(modname, settingname, default, min) + local setting = "moremesecons_" .. modname .. "." .. settingname + + if type(default) == "boolean" then + local ret = minetest.settings:get_bool(setting) + if ret == nil then + ret = default + end + return ret + elseif type(default) == "string" then + return minetest.settings:get(setting) or default + elseif type(default) == "number" then + local ret = tonumber(minetest.settings:get(setting)) or default + if not ret then + minetest.log("warning", "[moremesecons_"..modname.."]: setting '"..setting.."' must be a number. Set to default value ("..tostring(default)..").") + ret = default + elseif ret ~= ret then -- NaN + minetest.log("warning", "[moremesecons_"..modname.."]: setting '"..setting.."' is NaN. Set to default value ("..tostring(default)..").") + ret = default + end + if min and ret < min then + minetest.log("warning", "[moremesecons_"..modname.."]: setting '"..setting.."' is under minimum value "..tostring(min)..". Set to minimum value ("..tostring(min)..").") + ret = min + end + return ret + end +end + +-- Storage helpers + +function moremesecons.get_storage_data(storage, name) + return { + tab = minetest.deserialize(storage:get_string(name)) or {}, + name = name, + storage = storage + } +end + +function moremesecons.set_data_to_pos(sto, pos, data) + sto.tab[minetest.hash_node_position(pos)] = data + sto.storage:set_string(sto.name, minetest.serialize(sto.tab)) +end + +function moremesecons.get_data_from_pos(sto, pos) + return sto.tab[minetest.hash_node_position(pos)] +end + +function moremesecons.remove_data_from_pos(sto, pos) + sto.tab[minetest.hash_node_position(pos)] = nil + sto.storage:set_string(sto.name, minetest.serialize(sto.tab)) +end + +-- Some additional vector helpers + +-- The same as minetest.hash_node_position; I copied it to ensure backwards +-- compatibility and used hexadecimal number notation +local function node_position_key(pos) + return (pos.z + 0x8000) * 0x10000 * 0x10000 + + (pos.y + 0x8000) * 0x10000 + + pos.x + 0x8000 +end + +local MapDataStorage = {} +setmetatable(MapDataStorage, {__call = function() + local obj = {} + setmetatable(obj, MapDataStorage) + return obj +end}) +MapDataStorage.__index = { + getAt = function(self, pos) + return self[node_position_key(pos)] + end, + setAt = function(self, pos, data) + -- If x, y or z is omitted, the key corresponds to a position outside + -- of the map (hopefully), so it can be used to skip lines and planes + local vi_z = (pos.z + 0x8000) * 0x10000 * 0x10000 + local vi_zy = vi_z + (pos.y + 0x8000) * 0x10000 + local vi = vi_zy + pos.x + 0x8000 + local is_new = self[vi] == nil + self[vi] = data + if is_new then + self[vi_z] = (self[vi_z] or 0) + 1 + self[vi_zy] = (self[vi_zy] or 0) + 1 + end + end, + setAtI = function(self, vi, data) + local vi_zy = vi - vi % 0x10000 + local vi_z = vi - vi % (0x10000 * 0x10000) + local is_new = self[vi] == nil + self[vi] = data + if is_new then + self[vi_z] = (self[vi_z] or 0) + 1 + self[vi_zy] = (self[vi_zy] or 0) + 1 + end + end, + removeAt = function(self, pos) + local vi_z = (pos.z + 0x8000) * 0x10000 * 0x10000 + local vi_zy = vi_z + (pos.y + 0x8000) * 0x10000 + local vi = vi_zy + pos.x + 0x8000 + if self[vi] == nil then + -- Nothing to remove + return + end + self[vi] = nil + -- Update existence information for the xy plane and x line + self[vi_z] = self[vi_z] - 1 + if self[vi_z] == 0 then + self[vi_z] = nil + self[vi_zy] = nil + return + end + self[vi_zy] = self[vi_zy] - 1 + if self[vi_zy] == 0 then + self[vi_zy] = nil + end + end, + iter = function(self, pos1, pos2) + local ystride = 0x10000 + local zstride = 0x10000 * 0x10000 + + -- Skip z values where no data can be found + pos1 = vector.new(pos1) + local vi_z = (pos1.z + 0x8000) * 0x10000 * 0x10000 + while not self[vi_z] do + pos1.z = pos1.z + 1 + vi_z = vi_z + zstride + if pos1.z > pos2.z then + -- There are no values to iterate through + return function() return end + end + end + -- Skipping y values is not yet implemented and may require much code + + local xrange = pos2.x - pos1.x + 1 + local yrange = pos2.y - pos1.y + 1 + local zrange = pos2.z - pos1.z + 1 + + -- x-only and y-only parts of the vector index of pos1 + local vi_y = (pos1.y + 0x8000) * 0x10000 + local vi_x = pos1.x + 0x8000 + + local y = 0 + local z = 0 + + local vi = node_position_key(pos1) + local pos = vector.new(pos1) + local nextaction = vi + xrange + pos.x = pos.x - 1 + vi = vi - 1 + local function iterfunc() + -- continue along x until it needs to jump + vi = vi + 1 + pos.x = pos.x + 1 + if vi ~= nextaction then + local v = self[vi] + if v == nil then + -- No data here + return iterfunc() + end + -- The returned position must not be changed + return pos, v + end + + -- Reset x position + vi = vi - xrange + -- Go along y until pos2.y is exceeded + while true do + y = y + 1 + pos.y = pos.y + 1 + -- Set vi to index(pos1.x, pos1.y + y, pos1.z + z) + vi = vi + ystride + if y == yrange then + break + end + if self[vi - vi_x] then + nextaction = vi + xrange + + vi = vi - 1 + pos.x = pos1.x - 1 + return iterfunc() + end + -- Nothing along this x line, so increase y again + end + + -- Go back along y + vi = vi - yrange * ystride + y = 0 + pos.y = pos1.y + -- Go along z until pos2.z is exceeded + while true do + z = z + 1 + pos.z = pos.z + 1 + vi = vi + zstride + if z == zrange then + -- Cuboid finished, return nil + return + end + if self[vi - vi_x - vi_y] then + y = 0 + nextaction = vi + xrange + + vi = vi - 1 + pos.x = pos1.x - 1 + return iterfunc() + end + -- Nothing in this xy plane, so increase z again + end + end + return iterfunc + end, + iterAll = function(self) + local previous_vi = nil + local function iterfunc() + local vi, v = next(self, previous_vi) + previous_vi = vi + if not vi then + return + end + local z = math.floor(vi / (0x10000 * 0x10000)) + vi = vi - z * 0x10000 * 0x10000 + local y = math.floor(vi / 0x10000) + if y == 0 or z == 0 then + -- The index does not refer to a position inside the map + return iterfunc() + end + local x = vi - y * 0x10000 - 0x8000 + y = y - 0x8000 + z = z - 0x8000 + return {x=x, y=y, z=z}, v + end + return iterfunc + end, + serialize = function(self) + local indices = {} + local values = {} + local i = 1 + for pos, v in self:iterAll() do + local vi = node_position_key(pos) + -- Convert the double reversible to a string; + -- minetest.serialize does not (yet) do this + indices[i] = ("%.17g"):format(vi) + values[i] = v + end + return minetest.serialize({ + version = "MapDataStorage_v1", + indices = "return {" .. table.concat(indices, ",") .. "}", + values = minetest.serialize(values), + }) + end, +} +MapDataStorage.deserialize = function(txtdata) + local data = minetest.deserialize(txtdata) + if data.version ~= "MapDataStorage_v1" then + minetest.log("error", "Unknown MapDataStorage version: " .. + data.version) + end + -- I assume that minetest.deserialize correctly deserializes the indices, + -- which are in the %a format + local indices = minetest.deserialize(data.indices) + local values = minetest.deserialize(data.values) + if not indices or not values then + return MapDataStorage() + end + data = MapDataStorage() + for i = 1,#indices do + local vi = indices[i] + local v = values[i] + data:setAtI(vi, v) + end + return data +end +moremesecons.MapDataStorage = MapDataStorage + + +-- Legacy + +-- vector_extras there: https://github.com/HybridDog/vector_extras +-- Creates a MapDataStorage object from old vector_extras generated table +function moremesecons.load_old_data_from_pos(t) + local data = MapDataStorage() + for z, yxv in pairs(t) do + for y, xv in pairs(yxv) do + for x, v in pairs(xv) do + data:setAt({x=x, y=y, z=z}, v) + end + end + end + return data +end + +function moremesecons.load_old_dfp_storage(modstorage, name) + local data = minetest.deserialize(modstorage:get_string(name)) + if not data then + return + end + return moremesecons.load_old_data_from_pos(data) +end + +function moremesecons.load_MapDataStorage_legacy(modstorage, name, oldname) + local t_old = moremesecons.load_old_dfp_storage(modstorage, oldname) + local t + if t_old and t_old ~= "" then + t = t_old + modstorage:set_string(name, t:serialize()) + modstorage:set_string(oldname, nil) + return t + end + t = modstorage:get_string(name) + if t and t ~= "" then + return MapDataStorage.deserialize(t) + end + return MapDataStorage() +end + + + +--[[ +-- This testing code shows an example usage of the MapDataStorage code +local function do_test() + print("Test if iter returns correct positions when a lot is set") + local data = MapDataStorage() + local k = 0 + for x = -5, 3 do + for y = -5, 3 do + for z = -5, 3 do + k = k + 1 + data:setAt({x=x, y=y, z=z}, k) + end + end + end + local expected_positions = {} + for z = -4, 2 do + for y = -4, 2 do + for x = -4, 2 do + expected_positions[#expected_positions+1] = {x=x, y=y, z=z} + end + end + end + local i = 0 + for pos in data:iter({x=-4, y=-4, z=-4}, {x=2, y=2, z=2}) do + i = i + 1 + assert(vector.equals(pos, expected_positions[i])) + end + + print("Test if iter works correctly on a corner") + local found = false + for pos in data:iter({x=-8, y=-7, z=-80}, {x=-5, y=-5, z=-5}) do + assert(not found) + found = true + assert(vector.equals(pos, {x=-5, y=-5, z=-5})) + end + assert(found) + + print("Test if iter finds all corners") + local expected_positions = {} + local k = 1 + for _, z in ipairs({-9, -6}) do + for _, y in ipairs({-9, -6}) do + for _, x in ipairs({-8, -6}) do + local pos = {x=x, y=y, z=z} + expected_positions[#expected_positions+1] = pos + data:setAt(pos, k) + k = k + 1 + end + end + end + local i = 1 + for pos, v in data:iter({x=-8, y=-9, z=-9}, {x=-6, y=-6, z=-6}) do + assert(v == i) + assert(vector.equals(pos, expected_positions[i])) + i = i + 1 + --~ print("found " .. minetest.pos_to_string(pos)) + end + assert(i == 8 + 1, "Not enough or too many corners found") + + --~ data:iterAll() +end +do_test() +--]] diff --git a/mods/moremesecons/moremesecons_utils/mod.conf b/mods/moremesecons/moremesecons_utils/mod.conf new file mode 100644 index 00000000..d317b408 --- /dev/null +++ b/mods/moremesecons/moremesecons_utils/mod.conf @@ -0,0 +1,2 @@ +name = moremesecons_utils +description = Various helping functions for moremesecons diff --git a/mods/moremesecons/moremesecons_wireless/init.lua b/mods/moremesecons/moremesecons_wireless/init.lua new file mode 100644 index 00000000..9c887dfa --- /dev/null +++ b/mods/moremesecons/moremesecons_wireless/init.lua @@ -0,0 +1,500 @@ +local storage = minetest.get_mod_storage() + +-- Names wireless_meta, and jammers were used in old versions of this mod. +-- There is legacy code at the end of this file to migrate the mod storage. +local wireless = minetest.deserialize(storage:get_string("networks")) or {} +local wireless_meta = moremesecons.get_storage_data(storage, "wireless_meta_2") +local jammers = moremesecons.get_storage_data(storage, "jammers_2") + +local function update_mod_storage() + storage:set_string("networks", minetest.serialize(wireless)) +end + +local wireless_effector_off +local function remove_wireless(pos) + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls then + return + end + + if not wls.owner or wls.owner == "" then + moremesecons.remove_data_from_pos(wireless_meta, pos) + return + end + + if not wireless[wls.owner] or not next(wireless[wls.owner]) then + wireless[wls.owner] = nil + moremesecons.remove_data_from_pos(wireless_meta, pos) + return + end + + if not wls.channel or wls.channel == "" then + moremesecons.remove_data_from_pos(wireless_meta, pos) + return + end + + local network = wireless[wls.owner][wls.channel] + + if network.sources[wls.id] then + wireless_effector_off(pos) + end + + moremesecons.remove_data_from_pos(wireless_meta, pos) + + network.members[wls.id] = nil + if not next(network.members) then + wireless[wls.owner][wls.channel] = nil + if not next(wireless[wls.owner]) then + wireless[wls.owner] = nil + end + end + update_mod_storage() +end + +local function set_owner(pos, owner) + if not owner or owner == "" then + return + end + + remove_wireless(pos) + + local meta = minetest.get_meta(pos) + if meta then + meta:set_string("owner", owner) + end + + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) or {} + wls.owner = owner + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + + if not wireless[owner] then + wireless[owner] = {} + end + + if meta then + meta:set_string("infotext", "Wireless owned by " .. owner .. " on " .. ((wls.channel and wls.channel ~= "") and "channel " .. wls.channel or "undefined channel")) + end +end + +local wireless_receptor_on +local wireless_receptor_off +local wireless_effector_on +local function set_channel(pos, channel) + if not channel or channel == "" then + return + end + + local meta = minetest.get_meta(pos) + + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls or wls.owner == "" then + return + end + + if wls.id then + remove_wireless(pos) + end + + if meta then + meta:set_string("channel", channel) + end + wls.channel = channel + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + + if not wireless[wls.owner] then + wireless[wls.owner] = {} + end + if not wireless[wls.owner][channel] then + wireless[wls.owner][channel] = { + members = {}, + sources = {} + } + end + + -- Find the first free ID + local id = 1 + while wireless[wls.owner][channel].members[id] do + id = id + 1 + end + wls.id = id + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + + local network = wireless[wls.owner][channel] + + network.members[id] = pos + + if meta then + meta:set_int("id", id) + end + + update_mod_storage() + + if meta then + meta:set_string("infotext", "Wireless owned by " .. wls.owner .. " on channel " .. channel) + end + + if wls.effector then + wireless_effector_on(pos) + elseif next(network.sources) then + wireless_receptor_on(pos, id, network, false) + else + wireless_receptor_off(pos, id, network, false) + end +end + +local function register_wireless(pos) + local meta = minetest.get_meta(pos) + local owner = meta:get_string("owner") + if owner == "" then + return + end + remove_wireless(pos) + + set_owner(pos, owner) + + local channel = meta:get_string("channel") + if channel ~= "" then + set_channel(pos, channel) + end +end + +local function check_wireless_exists(pos) + local nn = minetest.get_node(pos).name + if nn:sub(1, 30) == "moremesecons_wireless:wireless" then + return true + elseif nn ~= "ignore" then + -- Defer the remove_wireless() call so it doesn't interfere + -- with pairs(). + minetest.after(0, remove_wireless, pos) + return false + end +end + +function wireless_receptor_on(pos, id, network, check) + if check == false or check_wireless_exists(pos) then + minetest.swap_node(pos, {name = "moremesecons_wireless:wireless_on"}) + if not network.sources[id] then + mesecon.receptor_on(pos) + end + end +end + +function wireless_receptor_off(pos, id, network, check) + if check == false or check_wireless_exists(pos) then + minetest.swap_node(pos, {name = "moremesecons_wireless:wireless_off"}) + mesecon.receptor_off(pos) + end +end + +local function activate_network(owner, channel) + local network = wireless[owner][channel] + for i, wl_pos in pairs(network.members) do + wireless_receptor_on(wl_pos, i, network) + end +end + +local function deactivate_network(owner, channel) + local network = wireless[owner][channel] + for i, wl_pos in pairs(network.members) do + wireless_receptor_off(wl_pos, i, network) + end +end + +local is_jammed +function wireless_effector_on(pos) + if is_jammed(pos) then + -- jamming doesn't disallow receiving signals, only sending them + return + end + + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls then + return + end + + wls.effector = true + + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + + if wls.owner == "" or not wireless[wls.owner] or wls.channel == "" or not wireless[wls.owner][wls.channel] then + return + end + + local network = wireless[wls.owner][wls.channel] + network.sources[wls.id] = true + activate_network(wls.owner, wls.channel) + + update_mod_storage() +end + +function wireless_effector_off(pos) + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls then + return + end + + wls.effector = nil + moremesecons.set_data_to_pos(wireless_meta, pos, wls) + + if wls.owner == "" or not wireless[wls.owner] or wls.channel == "" or not wireless[wls.owner][wls.channel] then + return + end + + local network = wireless[wls.owner][wls.channel] + network.sources[wls.id] = nil + if not next(network.sources) then + deactivate_network(wls.owner, wls.channel) + else + -- There is another source in the network. Turn this wireless into + -- a receptor. + mesecon.receptor_on(pos) + end + + update_mod_storage() +end + +-- This table is required to prevent a message from being sent in loop between wireless nodes +local sending_digilines = {} + +local function on_digiline_receive(pos, node, channel, msg) + if is_jammed(pos) then + return + end + + local wls = moremesecons.get_data_from_pos(wireless_meta, pos) + if not wls then + return + end + + if wls.owner == "" or not wireless[wls.owner] or channel == "" or not wireless[wls.owner][wls.channel] then + return + end + + local pos_hash = minetest.hash_node_position(pos) + if sending_digilines[pos_hash] then + return + end + + sending_digilines[pos_hash] = true + for i, wl_pos in pairs(wireless[wls.owner][wls.channel].members) do + if i ~= wls.id then + digiline:receptor_send(wl_pos, digiline.rules.default, channel, msg) + end + end + sending_digilines[pos_hash] = nil +end + +mesecon.register_node("moremesecons_wireless:wireless", { + paramtype = "light", + paramtype2 = "facedir", + description = "Wireless", + digiline = { + receptor = {}, + effector = { + action = on_digiline_receive + }, + }, + sounds = default.node_sound_stone_defaults(), + on_construct = function(pos) + minetest.get_meta(pos):set_string("formspec", "field[channel;channel;${channel}]") + end, + on_destruct = function(pos) + remove_wireless(pos) + mesecon.receptor_off(pos) + end, + after_place_node = function(pos, placer) + set_owner(pos, placer:get_player_name()) + end, + on_receive_fields = function(pos, _, fields, player) + local meta = minetest.get_meta(pos) + local playername = player:get_player_name() + + local owner = meta:get_string("owner") + if not owner or owner == "" then + -- Old wireless + if not minetest.is_protected(pos, playername) then + set_owner(pos, playername) + else + return + end + end + + if playername == owner then + set_channel(pos, fields.channel) + end + end, +}, { + tiles = {"moremesecons_wireless_off.png"}, + groups = {cracky=3}, + mesecons = {effector = { + action_on = wireless_effector_on + }}, +}, { + tiles = {"moremesecons_wireless_on.png"}, + groups = {cracky=3, not_in_creative_inventory=1}, + mesecons = {effector = { + action_off = wireless_effector_off + }}, +}) + +minetest.register_alias("moremesecons_wireless:wireless", "moremesecons_wireless:wireless_off") + +minetest.register_craft({ + output = "moremesecons_wireless:wireless_off 2", + recipe = { + {"group:mesecon_conductor_craftable", "", "group:mesecon_conductor_craftable"}, + {"", "mesecons_torch:mesecon_torch_on", ""}, + {"group:mesecon_conductor_craftable", "", "group:mesecon_conductor_craftable"}, + } +}) + +local function remove_jammer(pos) + moremesecons.remove_data_from_pos(jammers, pos) +end + +local function add_jammer(pos) + remove_jammer(pos) + moremesecons.set_data_to_pos(jammers, pos, true) +end + +function is_jammed(pos) + local JAMMER_MAX_DISTANCE = moremesecons.setting("wireless", "jammer_max_distance", 15, 1) + local JAMMER_MAX_DISTANCE_SQUARE = JAMMER_MAX_DISTANCE^2 -- Cache this result + + for pos_hash, _ in pairs(jammers.tab) do + local j_pos = minetest.get_position_from_hash(pos_hash) + -- Fast comparisons first + if math.abs(pos.x - j_pos.x) <= JAMMER_MAX_DISTANCE and + math.abs(pos.y - j_pos.y) <= JAMMER_MAX_DISTANCE and + math.abs(pos.z - j_pos.z) <= JAMMER_MAX_DISTANCE and + (pos.x - j_pos.x)^2 + (pos.y - j_pos.y)^2 + (pos.z - j_pos.z)^2 <= JAMMER_MAX_DISTANCE_SQUARE then + return true + end + end + + return false +end + +if moremesecons.setting("wireless", "enable_jammer", true) then + mesecon.register_node("moremesecons_wireless:jammer", { + description = "Wireless Jammer", + paramtype = "light", + drawtype = "nodebox", + },{ + tiles = {"mesecons_wire_off.png^moremesecons_jammer_top.png", "moremesecons_jammer_bottom.png", "mesecons_wire_off.png^moremesecons_jammer_side_off.png"}, + node_box = { + type = "fixed", + fixed = { + -- connection + {-1/16, -0.5, -0.5, 1/16, -7/16, 0.5}, + {-0.5, -0.5, -1/16, 0.5, -7/16, 1/16}, + + --stabilization + {-1/16, -7/16, -1/16, 1/16, -6/16, 1/16}, + + -- fields + {-7/16, -6/16, -7/16, 7/16, -4/16, 7/16}, + {-5/16, -4/16, -5/16, 5/16, -3/16, 5/16}, + {-3/16, -3/16, -3/16, 3/16, -2/16, 3/16}, + {-1/16, -2/16, -1/16, 1/16, -1/16, 1/16}, + }, + }, + groups = {dig_immediate=2}, + mesecons = {effector = { + rules = mesecon.rules.flat, + action_on = function(pos) + add_jammer(pos) + minetest.swap_node(pos, {name="moremesecons_wireless:jammer_on"}) + end + }} + },{ + tiles = {"mesecons_wire_on.png^moremesecons_jammer_top.png", "moremesecons_jammer_bottom.png", "mesecons_wire_on.png^moremesecons_jammer_side_on.png"}, + node_box = { + type = "fixed", + fixed = { + -- connection + {-1/16, -0.5, -0.5, 1/16, -7/16, 0.5}, + {-0.5, -0.5, -1/16, 0.5, -7/16, 1/16}, + + --stabilization + {-1/16, -7/16, -1/16, 1/16, 5/16, 1/16}, + + -- fields + {-7/16, -6/16, -7/16, 7/16, -4/16, 7/16}, + {-5/16, -3/16, -5/16, 5/16, -1/16, 5/16}, + {-3/16, 0, -3/16, 3/16, 2/16, 3/16}, + {-1/16, 3/16, -1/16, 1/16, 5/16, 1/16}, + }, + }, + groups = {dig_immediate=2, not_in_creative_inventory=1}, + mesecons = {effector = { + rules = mesecon.rules.flat, + action_off = function(pos) + remove_jammer(pos) + minetest.swap_node(pos, {name="moremesecons_wireless:jammer_off"}) + end + }}, + on_destruct = remove_jammer, + on_construct = add_jammer, + }) + + minetest.register_craft({ + output = "moremesecons_wireless:jammer_off", + recipe = { + {"moremesecons_wireless:wireless", "mesecons_torch:mesecon_torch_on", "moremesecons_wireless:wireless"} + } + }) +end + +if moremesecons.setting("wireless", "enable_lbm", false) then + minetest.register_lbm({ + name = "moremesecons_wireless:add_jammer", + nodenames = {"moremesecons_wireless:jammer_on"}, + run_at_every_load = true, + action = add_jammer + }) + + minetest.register_lbm({ + name = "moremesecons_wireless:add_wireless", + nodenames = {"moremesecons_wireless:wireless"}, + run_at_every_load = true, + action = register_wireless + }) +end + +-- Legacy +if storage:get_string("wireless_meta_2") == "" then + local wireless_meta_1 = minetest.deserialize(storage:get_string("wireless_meta")) + if not wireless_meta_1 then + return + end + + minetest.log("action", "[moremesecons_wireless] Migrating mod storage data...") + local jammers_1 = minetest.deserialize(storage:get_string("jammers")) + + local get = function(t, pos) + -- FIXME: this does not test explicitly for false, + -- but channel is never false + return t[pos.z] and t[pos.z][pos.y] and t[pos.z][pos.y][pos.x] + end + + for z, data_z in pairs(wireless_meta_1.owners) do + for y, data_y in pairs(data_z) do + for x, owner in pairs(data_y) do + local pos = {x = x, y = y, z = z} + set_owner(pos, owner) + set_channel(pos, get(wireless_meta_1.channels, pos)) + end + end + end + + for z, data_z in pairs(jammers_1) do + for y, data_y in pairs(data_z) do + for x, jammer in pairs(data_y) do + local pos = {x = x, y = y, z = z} + moremesecons.set_data_to_pos(jammers, pos, jammer) + end + end + end + minetest.log("action", "[moremesecons_wireless] Done!") +end diff --git a/mods/moremesecons/moremesecons_wireless/mod.conf b/mods/moremesecons/moremesecons_wireless/mod.conf new file mode 100644 index 00000000..f632a1be --- /dev/null +++ b/mods/moremesecons/moremesecons_wireless/mod.conf @@ -0,0 +1,3 @@ +name = moremesecons_wireless +depends = mesecons,moremesecons_utils,default +optional_depends = digilines,craft_guide diff --git a/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_bottom.png b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_bottom.png new file mode 100644 index 00000000..8df74806 Binary files /dev/null and b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_bottom.png differ diff --git a/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_side_off.png b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_side_off.png new file mode 100644 index 00000000..0c1fe1d3 Binary files /dev/null and b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_side_off.png differ diff --git a/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_side_on.png b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_side_on.png new file mode 100644 index 00000000..4d54e2ce Binary files /dev/null and b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_side_on.png differ diff --git a/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_top.png b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_top.png new file mode 100644 index 00000000..0adf8024 Binary files /dev/null and b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_jammer_top.png differ diff --git a/mods/moremesecons/moremesecons_wireless/textures/moremesecons_wireless_off.png b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_wireless_off.png new file mode 100644 index 00000000..fe639716 Binary files /dev/null and b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_wireless_off.png differ diff --git a/mods/moremesecons/moremesecons_wireless/textures/moremesecons_wireless_on.png b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_wireless_on.png new file mode 100644 index 00000000..27f8f9ce Binary files /dev/null and b/mods/moremesecons/moremesecons_wireless/textures/moremesecons_wireless_on.png differ diff --git a/mods/moremesecons/settingtypes.txt b/mods/moremesecons/settingtypes.txt new file mode 100644 index 00000000..ee7379fb --- /dev/null +++ b/mods/moremesecons/settingtypes.txt @@ -0,0 +1,85 @@ +[Adjustable Blinky Plant] + +# Minimal interval authorized. Any lower will be set to it. +moremesecons_adjustable_blinky_plant.min_interval (Minimum Interval) float 0.5 + +[Adjustable Player Detector] + +moremesecons_adjustable_player_detector.max_radius (Maximum adjustable player detector radius) float 16 0 + +[Craftable Commandblock] + +# Space-separated list of authorized commands +# Empty to authorize all +moremesecons_commandblock.authorized_commands (Authorized commands) string tell + +# Maximum distance of the @nearest player +# Any value less than or equal to 0 will be changed to 1 and a NaN value will be changed to the default value +moremesecons_commandblock.nearest_max_distance (Nearest player maximum distance) float 8 + +[Entity Detector] + +moremesecons_entity_detector.max_radius (Maximum entity detector radius) float 16 0 + +[Signal Jammer] + +# Jammer action range +# Any value less than or equal to 0 will be changed to 1 and a NaN value will be changed to the default value +moremesecons_jammer.max_distance (Jammer action range) float 10 + +# Whether to enable the registration LBM. +# The registration LBM will recover the jammer database if the moremesecons_jammer +# mod storage has been removed, and will create that mod storage after an update +# from an older version which did not use it. +moremesecons_jammer.enable_lbm (Enable Registration LBM) bool false + +[Player Killer] + +# Player Killer action range +# Any value less than or equal to 0 will be changed to 1 and a NaN value will be changed to the default value +moremesecons_playerkiller.max_distance (Player Killer action range) float 8 + +[Sayer] + +# Whether to use the Speech Dispatcher +# It will work only if: +# * moremesecons_sayer is present in your trusted_mods setting +# * you are playing in singleplayer +# * the speech-dispatcher is installed on your system +# * you are using a POSIX-compliant system and a sh-compatible shell (such as bash, dash, zsh...) +moremesecons_sayer.use_speech_dispatcher (Use the Speech Dispatcher) bool true + +# Sayer range +# Any value less than or equal to 0 will be changed to 1 and a NaN value will be changed to the default value +moremesecons_sayer.max_distance (Range) float 8 + +[Teleporter] + +# Maximum Teleporter To Teleporter distance +# Any value less than or equal to 0 will be changed to 1 and a NaN value will be changed to the default value +moremesecons_teleporter.max_t2t_distance (Maximum Teleporter To Teleporter distance) float 50 + +# Maximum Player To Teleporter distance +# Any value less than or equal to 0 will be set to 1 +moremesecons_teleporter.max_p2t_distance (Maximum Player To Teleporter distance) float 25 + +# Whether to enable the registration LBM. +# The registration LBM will recover a teleporter network if the moremesecons_teleporter +# mod storage has been removed, and will create that mod storage after an update +# from an older version which did not use it. +moremesecons_teleporter.enable_lbm (Enable Registration LBM) bool false + +[Wireless] + +# Whether to enable the wireless jammer node +moremesecons_wireless.enable_jammer (Enable wireless jammer) bool true + +# Wireless Jammer action range +# Any value less than or equal to 0 will be changed to 1 and a NaN value will be changed to the default value +moremesecons_wireless.jammer_max_distance (Wireless Jammer action range) float 15 + +# Whether to enable the registration LBM. +# The registration LBM will recover a wireless network if the moremesecons_wireless +# mod storage has been removed, and will create that mod storage after an update +# from an older version which did not use it. +moremesecons_wireless.enable_lbm (Enable Registration LBM) bool false diff --git a/mods/redef/settingtypes.txt b/mods/redef/settingtypes.txt index 19d384f2..e2eed8c5 100644 --- a/mods/redef/settingtypes.txt +++ b/mods/redef/settingtypes.txt @@ -59,4 +59,4 @@ redef_aligned_textures (Use world-aligned textures) bool true # Fixes: # # https://github.com/minetest-mods/moreblocks/issues/138 -redef_proper_rotation (Properly rotate shaped nodes) bool true +redef_proper_rotation (Properly rotate shaped nodes) bool false