Mineclonia/mods/ITEMS/REDSTONE/mcl_comparators/init.lua

359 lines
11 KiB
Lua
Raw Normal View History

local S = minetest.get_translator("mcl_comparators")
2017-08-28 01:51:21 +02:00
-- Functions that get the input/output rules of the comparator
local comparator_get_output_rules = function(node)
local rules = {{x = -1, y = 0, z = 0, spread=true}}
2017-08-28 01:51:21 +02:00
for i = 0, node.param2 do
rules = mesecon.rotate_rules_left(rules)
2017-08-28 01:51:21 +02:00
end
return rules
end
local comparator_get_input_rules = function(node)
local rules = {
-- we rely on this order in update_self below
{x = 1, y = 0, z = 0}, -- back
{x = 0, y = 0, z = -1}, -- side
{x = 0, y = 0, z = 1}, -- side
}
for i = 0, node.param2 do
rules = mesecon.rotate_rules_left(rules)
2017-08-28 01:51:21 +02:00
end
return rules
end
-- Functions that are called after the delay time
local comparator_turnon = function(params)
local rules = comparator_get_output_rules(params.node)
mesecon.receptor_on(params.pos, rules)
2017-08-28 01:51:21 +02:00
end
local comparator_turnoff = function(params)
local rules = comparator_get_output_rules(params.node)
mesecon.receptor_off(params.pos, rules)
2017-08-28 01:51:21 +02:00
end
-- Functions that set the correct node type an schedule a turnon/off
local comparator_activate = function(pos, node)
local def = minetest.registered_nodes[node.name]
minetest.swap_node(pos, { name = def.comparator_onstate, param2 = node.param2 })
2017-08-28 01:51:21 +02:00
minetest.after(0.1, comparator_turnon , {pos = pos, node = node})
end
local comparator_deactivate = function(pos, node)
local def = minetest.registered_nodes[node.name]
minetest.swap_node(pos, { name = def.comparator_offstate, param2 = node.param2 })
2017-08-28 01:51:21 +02:00
minetest.after(0.1, comparator_turnoff, {pos = pos, node = node})
end
-- weather pos has an inventory that contains at least one item
2017-08-28 01:51:21 +02:00
local container_inventory_nonempty = function(pos)
local invnode = minetest.get_node(pos)
local invnodedef = minetest.registered_nodes[invnode.name]
-- Ignore stale nodes
if not invnodedef then return false end
-- Only accept containers. When a container is dug, it's inventory
-- seems to stay. and we don't want to accept the inventory of an air
-- block
if not invnodedef.groups.container then return false end
local inv = minetest.get_inventory({type="node", pos=pos})
if not inv then return false end
for listname, _ in pairs(inv:get_lists()) do
if not inv:is_empty(listname) then return true end
end
return false
end
-- weather pos has an constant signal output for the comparator
local static_signal_output = function(pos)
local node = minetest.get_node(pos)
local g = minetest.get_item_group(node.name, "comparator_signal")
return g > 0
end
2017-08-28 01:51:21 +02:00
-- whether the comparator should be on according to its inputs
local comparator_desired_on = function(pos, node)
local my_input_rules = comparator_get_input_rules(node);
local back_rule = my_input_rules[1]
local state
if back_rule then
local back_pos = vector.add(pos, back_rule)
state = mesecon.is_power_on(back_pos) or container_inventory_nonempty(back_pos) or static_signal_output(back_pos)
end
2017-08-28 01:51:21 +02:00
-- if back input if off, we don't need to check side inputs
if not state then return false end
-- without power levels, side inputs have no influence on output in compare
-- mode
local mode = minetest.registered_nodes[node.name].comparator_mode
if mode == "comp" then return state end
-- subtract mode, subtract max(side_inputs) from back input
local side_state = false
for ri = 2,3 do
if my_input_rules[ri] then
side_state = mesecon.is_power_on(vector.add(pos, my_input_rules[ri]))
end
2017-08-28 01:51:21 +02:00
if side_state then break end
end
-- state is known to be true
return not side_state
end
-- update comparator state, if needed
local update_self = function(pos, node)
node = node or minetest.get_node(pos)
local old_state = mesecon.is_receptor_on(node.name)
2017-08-28 01:51:21 +02:00
local new_state = comparator_desired_on(pos, node)
if new_state ~= old_state then
if new_state then
comparator_activate(pos, node)
else
comparator_deactivate(pos, node)
end
end
end
-- compute tile depending on state and mode
local get_tiles = function(state, mode)
local top = "mcl_comparators_"..state..".png^"..
"mcl_comparators_"..mode..".png"
local sides = "mcl_comparators_sides_"..state..".png^"..
"mcl_comparators_sides_"..mode..".png"
local ends = "mcl_comparators_ends_"..state..".png^"..
"mcl_comparators_ends_"..mode..".png"
2017-08-28 01:51:21 +02:00
return {
top, "mcl_stairs_stone_slab_top.png",
sides, sides.."^[transformFX",
ends, ends,
}
end
-- Given one mode, get the other mode
local flipmode = function(mode)
if mode == "comp" then return "sub"
elseif mode == "sub" then return "comp"
end
end
local make_rightclick_handler = function(state, mode)
local newnodename =
"mcl_comparators:comparator_"..state.."_"..flipmode(mode)
2019-02-08 21:59:01 +01:00
return function (pos, node, clicker)
local protname = clicker:get_player_name()
if minetest.is_protected(pos, protname) then
minetest.record_protection_violation(pos, protname)
return
end
minetest.swap_node(pos, {name = newnodename, param2 = node.param2 })
2017-08-28 01:51:21 +02:00
end
end
-- Register the 2 (states) x 2 (modes) comparators
local icon = "mcl_comparators_item.png"
2017-08-28 01:51:21 +02:00
local node_boxes = {
comp = {
{ -8/16, -8/16, -8/16,
8/16, -6/16, 8/16 }, -- the main slab
{ -1/16, -6/16, 6/16,
1/16, -4/16, 4/16 }, -- front torch
{ -4/16, -6/16, -5/16,
-2/16, -1/16, -3/16 }, -- left back torch
{ 2/16, -6/16, -5/16,
4/16, -1/16, -3/16 }, -- right back torch
},
sub = {
{ -8/16, -8/16, -8/16,
8/16, -6/16, 8/16 }, -- the main slab
{ -1/16, -6/16, 6/16,
1/16, -3/16, 4/16 }, -- front torch (active)
{ -4/16, -6/16, -5/16,
-2/16, -1/16, -3/16 }, -- left back torch
{ 2/16, -6/16, -5/16,
4/16, -1/16, -3/16 }, -- right back torch
},
}
local collision_box = {
type = "fixed",
fixed = { -8/16, -8/16, -8/16, 8/16, -6/16, 8/16 },
}
local state_strs = {
[ mesecon.state.on ] = "on",
[ mesecon.state.off ] = "off",
}
local groups = {
dig_immediate = 3,
dig_by_water = 1,
destroy_by_lava_flow = 1,
dig_by_piston = 1,
attached_node = 1,
}
2017-12-05 14:09:39 +01:00
local on_rotate
if minetest.get_modpath("screwdriver") then
on_rotate = screwdriver.disallow
end
2017-08-28 01:51:21 +02:00
for _, mode in pairs{"comp", "sub"} do
for _, state in pairs{mesecon.state.on, mesecon.state.off} do
local state_str = state_strs[state]
local nodename =
"mcl_comparators:comparator_"..state_strs[state].."_"..mode
2017-08-28 01:51:21 +02:00
-- Help
local longdesc, usagehelp, use_help
if state_strs[state] == "off" and mode == "comp" then
longdesc = S("Redstone comparators are multi-purpose redstone components.").."\n"..
S("They can transmit a redstone signal, detect whether a block contains any items and compare multiple signals.")
usagehelp = S("A redstone comparator has 1 main input, 2 side inputs and 1 output. The output is in arrow direction, the main input is in the opposite direction. The other 2 sides are the side inputs.").."\n"..
S("The main input can powered in 2 ways: First, it can be powered directly by redstone power like any other component. Second, it is powered if, and only if a container (like a chest) is placed in front of it and the container contains at least one item.").."\n"..
2019-03-16 02:00:48 +01:00
S("The side inputs are only powered by normal redstone power. The redstone comparator can operate in two modes: Transmission mode and subtraction mode. It starts in transmission mode and the mode can be changed by using the block.").."\n\n"..
S("Transmission mode:\nThe front torch is unlit and lowered. The output is powered if, and only if the main input is powered. The two side inputs are ignored.").."\n"..
S("Subtraction mode:\nThe front torch is lit. The output is powered if, and only if the main input is powered and none of the side inputs is powered.")
else
use_help = false
end
2017-08-28 01:51:21 +02:00
local nodedef = {
description = S("Redstone Comparator"),
2017-08-28 01:51:21 +02:00
inventory_image = icon,
wield_image = icon,
_doc_items_create_entry = use_help,
2017-08-28 01:51:21 +02:00
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
drawtype = "nodebox",
tiles = get_tiles(state_strs[state], mode),
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
wield_image = "mcl_comparators_off.png",
2017-08-28 01:51:21 +02:00
walkable = true,
selection_box = collision_box,
collision_box = collision_box,
node_box = {
type = "fixed",
fixed = node_boxes[mode],
},
groups = groups,
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = false,
is_ground_content = false,
drop = 'mcl_comparators:comparator_off_comp',
2017-08-28 01:51:21 +02:00
on_construct = update_self,
on_rightclick =
make_rightclick_handler(state_strs[state], mode),
comparator_mode = mode,
comparator_onstate = "mcl_comparators:comparator_on_"..mode,
comparator_offstate = "mcl_comparators:comparator_off_"..mode,
2017-08-28 01:51:21 +02:00
sounds = mcl_sounds.node_sound_stone_defaults(),
mesecons = {
receptor = {
state = state,
rules = comparator_get_output_rules,
},
effector = {
rules = comparator_get_input_rules,
action_change = update_self,
}
2017-12-05 14:09:39 +01:00
},
on_rotate = on_rotate,
2017-08-28 01:51:21 +02:00
}
if mode == "comp" and state == mesecon.state.off then
-- This is the prototype
nodedef._doc_items_create_entry = true
else
nodedef.groups = table.copy(nodedef.groups)
nodedef.groups.not_in_creative_inventory = 1
local extra_desc = {}
if mode == "sub" or state == mesecon.state.on then
nodedef.inventory_image = nil
2017-08-28 01:51:21 +02:00
end
local desc = nodedef.description
if mode ~= "sub" and state == mesecon.state.on then
desc = S("Redstone Comparator (Powered)")
elseif mode == "sub" and state ~= mesecon.state.on then
desc = S("Redstone Comparator (Subtract)")
elseif mode == "sub" and state == mesecon.state.on then
desc = S("Redstone Comparator (Subtract, Powered)")
2017-08-28 01:51:21 +02:00
end
nodedef.description = desc
2017-08-28 01:51:21 +02:00
end
minetest.register_node(nodename, nodedef)
end
end
-- Register recipies
local rstorch = "mesecons_torch:mesecon_torch_on"
local quartz = "mcl_nether:quartz"
local stone = "mcl_core:stone"
minetest.register_craft({
output = "mcl_comparators:comparator_off_comp",
2017-08-28 01:51:21 +02:00
recipe = {
{ "", rstorch, "" },
{ rstorch, quartz, rstorch },
{ stone, stone, stone },
}
})
-- Register active block handlers
minetest.register_abm({
label = "Comparator signal input check (comparator is off)",
2017-08-28 01:51:21 +02:00
nodenames = {
"mcl_comparators:comparator_off_comp",
"mcl_comparators:comparator_off_sub",
2017-08-28 01:51:21 +02:00
},
neighbors = {"group:container", "group:comparator_signal"},
2017-08-28 01:51:21 +02:00
interval = 1,
chance = 1,
action = update_self,
})
minetest.register_abm({
label = "Comparator signal input check (comparator is on)",
2017-08-28 01:51:21 +02:00
nodenames = {
"mcl_comparators:comparator_on_comp",
"mcl_comparators:comparator_on_sub",
2017-08-28 01:51:21 +02:00
},
-- needs to run regardless of neighbors to make sure we detect when a
-- container is dug
interval = 1,
chance = 1,
action = update_self,
})
-- Add entry aliases for the Help
if minetest.get_modpath("doc") then
doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
"nodes", "mcl_comparators:comparator_off_sub")
doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
"nodes", "mcl_comparators:comparator_on_comp")
doc.add_entry_alias("nodes", "mcl_comparators:comparator_off_comp",
"nodes", "mcl_comparators:comparator_on_sub")
2017-08-28 01:51:21 +02:00
end