parent
974fb22aa2
commit
1da67202db
|
@ -29,9 +29,57 @@ end
|
|||
|
||||
local function comparator_turnon(params)
|
||||
local rules = comparator_get_output_rules(params.node)
|
||||
mesecon.receptor_on(params.pos, rules)
|
||||
if params.lower_voltage then
|
||||
-- nur den eigenen Strom rausnehmen
|
||||
-- output verfolgen, solange er kleiner wird und auf 0 setzen
|
||||
|
||||
-- Call turnoff on all linking positions
|
||||
for _, rule in ipairs(mesecon.flattenrules(rules)) do
|
||||
local np = vector.add(params.pos, rule)
|
||||
local rulenames = mesecon.rules_link_rule_all(params.pos, rule)
|
||||
for _, rulename in ipairs(rulenames) do
|
||||
comparator_removevoltage(np, rulename, params.old_voltage)
|
||||
end
|
||||
end
|
||||
end
|
||||
mesecon.receptor_on(params.pos, rules, params.voltage)
|
||||
end
|
||||
|
||||
function comparator_removevoltage(pos, link, voltage)
|
||||
local frontiers = {{pos = pos, link = link}}
|
||||
local signals = {}
|
||||
local rec_on = {}
|
||||
|
||||
local cur_vol = voltage+1
|
||||
minetest.log("action", mesecon.postostring(pos) .. "-->" .. "comparator_removevoltage" .. " v="..cur_vol)
|
||||
|
||||
local depth = 1
|
||||
while frontiers[1] do
|
||||
local f = table.remove(frontiers, 1)
|
||||
local node = mesecon.get_node_force(f.pos)
|
||||
|
||||
if node and mesecon.is_conductor_on(node, f.link) then
|
||||
local meta = minetest.get_meta(f.pos)
|
||||
|
||||
local tmp_vol = (meta:get_string("mesecon_voltage")~="" and meta:get_int("mesecon_voltage") or 15)
|
||||
|
||||
if tmp_vol<cur_vol and tmp_vol>=1 then
|
||||
--solange spannung niedriger wird
|
||||
cur_vol = tmp_vol
|
||||
meta:set_int("mesecon_voltage", 0)
|
||||
local rules = mesecon.conductor_get_rules(node)
|
||||
for _, r in pairs(mesecon.rule2meta(f.link, rules)) do
|
||||
local np = vector.add(f.pos, r)
|
||||
-- check neighbors
|
||||
for _, l in pairs(mesecon.rules_link_rule_all(f.pos, r)) do
|
||||
table.insert(frontiers, {pos = np, link = l})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
depth = depth + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function comparator_turnoff(params)
|
||||
local rules = comparator_get_output_rules(params.node)
|
||||
|
@ -41,14 +89,16 @@ end
|
|||
|
||||
-- Functions that set the correct node type an schedule a turnon/off
|
||||
|
||||
local function comparator_activate(pos, node)
|
||||
local function comparator_activate(pos, node, voltage, lower_voltage, old_voltage)
|
||||
minetest.log("action", mesecon.postostring(pos) .. "-->" .. "comparator_activate" .. " v="..voltage .. " lv=" .. tostring(lower_voltage))
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
minetest.swap_node(pos, { name = def.comparator_onstate, param2 = node.param2 })
|
||||
minetest.after(0.1, comparator_turnon , {pos = pos, node = node})
|
||||
minetest.after(0.1, comparator_turnon , {pos = pos, node = node, voltage = voltage, lower_voltage=lower_voltage, old_voltage=old_voltage})
|
||||
end
|
||||
|
||||
|
||||
local function comparator_deactivate(pos, node)
|
||||
minetest.log("action", mesecon.postostring(pos) .. "-->" .. "comparator_deactivate " .. mesecon.postostring(pos))
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
minetest.swap_node(pos, { name = def.comparator_offstate, param2 = node.param2 })
|
||||
minetest.after(0.1, comparator_turnoff, {pos = pos, node = node})
|
||||
|
@ -57,72 +107,166 @@ end
|
|||
|
||||
-- weather pos has an inventory that contains at least one item
|
||||
local function container_inventory_nonempty(pos)
|
||||
-- https://minecraft.fandom.com/wiki/Redstone_Comparator#Measure_block_state
|
||||
-- signal strength = floor(1 + ((sum of all slots' fullnesses) / (number of slots in container)) × 14)
|
||||
-- fullness of a slot = number of items in slot / max stack size for this type of item
|
||||
|
||||
|
||||
|
||||
local invnode = minetest.get_node(pos)
|
||||
local invnodedef = minetest.registered_nodes[invnode.name]
|
||||
-- Ignore stale nodes
|
||||
if not invnodedef then return false end
|
||||
if not invnodedef then return 0 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
|
||||
if not invnodedef.groups.container then return 0 end
|
||||
|
||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||
if not inv then return false end
|
||||
if not inv then return 0 end
|
||||
|
||||
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "container_inventory_nonempty.inv= " .. mesecon.tabletostring(inv:get_lists()))
|
||||
|
||||
local item_count = 0
|
||||
local inv_space = 0
|
||||
|
||||
|
||||
for listname, _ in pairs(inv:get_lists()) do
|
||||
if not inv:is_empty(listname) then return true end
|
||||
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "container_inventory_nonempty.inv.size= " .. inv:get_size(listname))
|
||||
|
||||
local stack = inv:get_stack(listname, 1)
|
||||
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "container_inventory_nonempty.inv.stack1= " .. mesecon.tabletostring(stack))
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "container_inventory_nonempty.inv.stack1.max= " .. stack:get_stack_max())
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "container_inventory_nonempty.inv.stack1.count= " .. stack:get_count())
|
||||
|
||||
local st_size = inv:get_size(listname)
|
||||
inv_space = inv_space + (64 * st_size)
|
||||
for i = 1,st_size do
|
||||
local stack = inv:get_stack(listname, i)
|
||||
item_count = item_count + (stack:get_count() * 64 / stack:get_stack_max())
|
||||
end
|
||||
--if not inv:is_empty(listname) then return true, 15 end
|
||||
end
|
||||
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "container_inventory_nonempty.inv_space= " .. inv_space)
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "container_inventory_nonempty.item_count= " .. item_count)
|
||||
|
||||
if item_count>0 then
|
||||
local voltage = math.floor(1 + (item_count/inv_space*14))
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "container_inventory_nonempty.voltage= " .. voltage)
|
||||
return voltage
|
||||
end
|
||||
|
||||
return false
|
||||
return 0
|
||||
end
|
||||
|
||||
-- weather pos has an constant signal output for the comparator
|
||||
local function static_signal_output(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local g = minetest.get_item_group(node.name, "comparator_signal")
|
||||
return g > 0
|
||||
return g
|
||||
end
|
||||
|
||||
-- whether the comparator should be on according to its inputs
|
||||
local function comparator_desired_on(pos, node)
|
||||
local my_input_rules = comparator_get_input_rules(node);
|
||||
local back_rule = my_input_rules[1]
|
||||
local state
|
||||
local voltage = 0
|
||||
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)
|
||||
local _, vo_back = mesecon.is_power_on(back_pos)
|
||||
|
||||
local vo_coin = container_inventory_nonempty(back_pos)
|
||||
|
||||
local vo_sso = static_signal_output(back_pos)
|
||||
|
||||
voltage = math.max(vo_back, vo_coin, vo_sso)
|
||||
end
|
||||
|
||||
-- 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
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "comparator_desired_on1.voltage= " .. voltage .. "state="..tostring(state))
|
||||
|
||||
-- if back input is off, we don't need to check side inputs
|
||||
if voltage<1 then return false, 0 end
|
||||
|
||||
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
|
||||
local side_voltage = 0
|
||||
for ri = 2,3 do
|
||||
if my_input_rules[ri] then
|
||||
side_state = mesecon.is_power_on(vector.add(pos, my_input_rules[ri]))
|
||||
local _, s_voltage = mesecon.is_power_on(vector.add(pos, my_input_rules[ri]))
|
||||
side_voltage = math.max(side_voltage, s_voltage)
|
||||
end
|
||||
if side_state then break end
|
||||
end
|
||||
-- state is known to be true
|
||||
return not side_state
|
||||
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "comparator_desired_on2.voltage= " .. voltage .. "state="..tostring(state))
|
||||
|
||||
if mode == "comp" then
|
||||
-- Comparators in comparison mode
|
||||
if side_voltage > voltage then
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "comparator_desired_on3.voltage= " .. voltage .. "state="..tostring(state))
|
||||
return false, 0
|
||||
else
|
||||
--minetest.log("action", mesecon.postostring(pos) .. "-->" .. "comparator_desired_on4.voltage= " .. voltage .. "state="..tostring(state))
|
||||
return true, voltage
|
||||
end
|
||||
end
|
||||
|
||||
-- comparator in subtraction mode
|
||||
voltage = math.max(voltage-side_voltage, 0)
|
||||
if voltage>0 then
|
||||
return true, voltage
|
||||
else
|
||||
return false, 0
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Compare signal strength
|
||||
|
||||
Comparators in comparison mode.
|
||||
|
||||
A redstone comparator in comparison mode (front torch down and unpowered) compares its rear input to its two side inputs.
|
||||
If either side input is greater than the rear input, the comparator output turns off. If neither side input is greater than
|
||||
the rear input, the comparator outputs the same signal strength as its rear input.
|
||||
|
||||
The formula for calculating the output signal strength is as follows:
|
||||
|
||||
output = rear × [left ≤ rear AND right ≤ rear]
|
||||
|
||||
|
||||
Subtract signal strength
|
||||
|
||||
A redstone comparator in subtraction mode (front torch up and powered) subtracts the signal strength of the higher side input from the signal strength of the rear input.
|
||||
|
||||
output = max(rear − max(left, right), 0)
|
||||
|
||||
For example: if the signal strength is 6 at the left input, 7 at the right input and 4 at the rear, the output signal has a strength of max(4 − max(6, 7), 0) = max(4−7, 0) = max(−3, 0) = 0.
|
||||
|
||||
If the signal strength is 9 at the rear, 2 at the right input and 5 at the left input, the output signal has a strength of max(9 − max(2, 5), 0) = max(9−5, 0) = 4.
|
||||
|
||||
|
||||
|
||||
|
||||
--]]
|
||||
-- update comparator state, if needed
|
||||
local function update_self(pos, node)
|
||||
node = node or minetest.get_node(pos)
|
||||
local old_state = mesecon.is_receptor_on(node.name)
|
||||
local new_state = comparator_desired_on(pos, node)
|
||||
if new_state ~= old_state then
|
||||
local meta = minetest.get_meta(pos)
|
||||
local old_voltage = old_state and (meta:get_string("mesecon_voltage")~="" and meta:get_int("mesecon_voltage") or 15) or 0
|
||||
|
||||
local new_state, new_voltage = comparator_desired_on(pos, node)
|
||||
|
||||
if (new_state ~= old_state) or (old_voltage~=new_voltage) then
|
||||
minetest.log("action", mesecon.postostring(pos) .. "-->" .. "update_self.ov=" .. old_voltage .. " nv="..new_voltage.." os="..tostring(old_state).." ns="..tostring(new_state))
|
||||
|
||||
if old_voltage~=new_voltage then meta:set_int("mesecon_voltage", new_voltage) end
|
||||
if new_state then
|
||||
comparator_activate(pos, node)
|
||||
comparator_activate(pos, node, new_voltage, (new_voltage<old_voltage), old_voltage)
|
||||
else
|
||||
comparator_deactivate(pos, node)
|
||||
end
|
||||
|
|
|
@ -112,7 +112,10 @@ mesecon.queue:add_function("receptor_off", function (pos, rules)
|
|||
for _, rec in pairs(rec_on) do
|
||||
--rules??? -> mesecon.receptor_get_rules(node)
|
||||
local node = mesecon.get_node_force(rec)
|
||||
mesecon.receptor_on(rec, mesecon.receptor_get_rules(node))
|
||||
|
||||
local meta = minetest.get_meta(rec)
|
||||
local voltage = meta:get_string("mesecon_voltage")~="" and meta:get_int("mesecon_voltage") or 15
|
||||
mesecon.receptor_on(rec, mesecon.receptor_get_rules(node), voltage)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -373,9 +373,11 @@ end
|
|||
function mesecon.is_power_on(pos, rulename)
|
||||
local node = get_node_force(pos)
|
||||
if node and (mesecon.is_conductor_on(node, rulename) or is_receptor_on(node.name)) then
|
||||
return true
|
||||
local meta = minetest.get_meta(pos)
|
||||
voltage = meta:get_string("mesecon_voltage")~="" and meta:get_int("mesecon_voltage") or 15
|
||||
return true, voltage
|
||||
end
|
||||
return false
|
||||
return false, 0
|
||||
end
|
||||
|
||||
function mesecon.is_power_off(pos, rulename)
|
||||
|
@ -416,14 +418,15 @@ function mesecon.turnon(pos, link, voltage)
|
|||
|
||||
local old_v = (mesecon.is_conductor_off(node, f.link) and 0 or meta:get_int("mesecon_voltage"))
|
||||
|
||||
|
||||
local v = math.max(f.voltage, old_v)
|
||||
--wenn spannung geändert
|
||||
--wenn gleiche spannung, aber muss ausgeschalten werden
|
||||
--if v~=old_v or (v<1 and mesecon.is_conductor_on(node, f.link)) or (meta:get_int("mesecon_voltage")<0) then
|
||||
if v~=old_v or (v<1 and mesecon.is_conductor_on(node, f.link)) then
|
||||
--minetest.log("action", f.pos.x .. "/" .. f.pos.y .. "/" .. f.pos.z .. "-->" .. "turnon.f.voltage="..f.voltage.."<-->"..v)
|
||||
|
||||
if v>0 or (v<1 and mesecon.is_conductor_on(node, f.link)) then
|
||||
--if v>0 or (v<1 and mesecon.is_conductor_on(node, f.link)) or (meta:get_int("mesecon_voltage")<0) then
|
||||
if v>=1 or (v<1 and mesecon.is_conductor_on(node, f.link)) then
|
||||
-- Call turnon on neighbors
|
||||
for _, r in pairs(mesecon.rule2meta(f.link, rules)) do
|
||||
local np = vector.add(f.pos, r)
|
||||
|
|
Loading…
Reference in New Issue