add mesecons mods

This commit is contained in:
N-Nachtigal 2025-07-26 18:53:34 +02:00
parent 71a53fbef8
commit 9861939223
721 changed files with 19937 additions and 1 deletions

View file

@ -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

7
mods/moremesecons/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
## Generic ignorable patterns and files
*~
debug.txt
## Eclipse project files & directories
.project
.settings

View file

@ -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"}

View file

@ -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.

View file

@ -0,0 +1,50 @@
# MoreMesecons
Based on Mesecons by Jeija <br/>
By @paly2 and @HybridDog <br/>
With the participation of @LeMagnesium (bugfix), @Ataron (textures), @JAPP (texture).
Dependencies: [Mesecons](https://github.com/Jeija/minetest-mod-mesecons/) <br/>
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).

View file

@ -0,0 +1 @@
Adds more Mesecons items.

View file

@ -0,0 +1,5 @@
release = 32037
author = Palige
name = moremesecons
description = Adds more Mesecons items.
title = MoreMesecons

View file

@ -0,0 +1 @@
The presence of this file indicates that the current folder is a modpack.

View file

@ -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"},}
})

View file

@ -0,0 +1,3 @@
name = moremesecons_adjustable_blinkyplant
depends = mesecons,moremesecons_utils,default
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

View file

@ -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,
})

View file

@ -0,0 +1,3 @@
name = moremesecons_adjustable_player_detector
depends = mesecons,moremesecons_utils,default
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

View file

@ -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"}
}
})

View file

@ -0,0 +1,3 @@
name = moremesecons_commandblock
depends = mesecons,moremesecons_utils,default
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

View file

@ -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"}}
})

View file

@ -0,0 +1,3 @@
name = moremesecons_conductor_signalchanger
depends = mesecons
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

View file

@ -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"}
})

View file

@ -0,0 +1,3 @@
name = moremesecons_dual_delayer
depends = mesecons
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

View file

@ -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,
})

View file

@ -0,0 +1,3 @@
name = moremesecons_entity_detector
depends = mesecons,moremesecons_utils,default
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

View file

@ -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"},}
})

View file

@ -0,0 +1,3 @@
name = moremesecons_igniter
depends = mesecons,fire
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

View file

@ -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", ""}
}
})

View file

@ -0,0 +1,2 @@
name = moremesecons_induction_transmitter
depends = mesecons,mesecons_torch,default

View file

@ -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"}}
})

View file

@ -0,0 +1,3 @@
name = moremesecons_injector_controller
depends = mesecons
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

View file

@ -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

View file

@ -0,0 +1,3 @@
name = moremesecons_jammer
depends = mesecons,moremesecons_utils
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

View file

@ -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
}}
})

View file

@ -0,0 +1,2 @@
name = moremesecons_luablock
depends = mesecons,moremesecons_utils

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -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)

View file

@ -0,0 +1,2 @@
name = moremesecons_luacontroller_tool
depends = mesecons,mesecons_luacontroller,moremesecons_utils

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

View file

@ -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")

View file

@ -0,0 +1,2 @@
name = moremesecons_mesechest
depends = default,mesecons

View file

@ -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(),
})

View file

@ -0,0 +1,3 @@
name = moremesecons_playerkiller
depends = mesecons,mesecons_materials,moremesecons_utils,default
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

View file

@ -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"}}
})

View file

@ -0,0 +1,3 @@
name = moremesecons_sayer
depends = mesecons,mesecons_noteblock,moremesecons_utils,default
optional_depends = craft_guide

View file

@ -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"}}
})

View file

@ -0,0 +1,3 @@
name = moremesecons_signalchanger
depends = mesecons
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

View file

@ -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

View file

@ -0,0 +1,3 @@
name = moremesecons_switchtorch
depends = mesecons
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

View file

@ -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

View file

@ -0,0 +1,3 @@
name = moremesecons_teleporter
depends = mesecons,moremesecons_utils,default
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

View file

@ -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")

View file

@ -0,0 +1,3 @@
name = moremesecons_timegate
depends = mesecons,default
optional_depends = craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

View file

@ -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()
--]]

View file

@ -0,0 +1,2 @@
name = moremesecons_utils
description = Various helping functions for moremesecons

View file

@ -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

View file

@ -0,0 +1,3 @@
name = moremesecons_wireless
depends = mesecons,moremesecons_utils,default
optional_depends = digilines,craft_guide

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

View file

@ -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