From 80a9df48451eb97c9d3ea489c269b272902952e9 Mon Sep 17 00:00:00 2001 From: Henry Behrendt Date: Thu, 16 Sep 2021 08:29:00 +0200 Subject: [PATCH] voltage for redstone - wires has voltage from 0 to 15 (lower by one for every step) - wiring-rules - comparator read content from chest, hopper, jukebox, group "comparator_signal" (cauldrons, cake, ...) --- mods/ITEMS/REDSTONE/mcl_comparators/init.lua | 220 ++++++++-- mods/ITEMS/REDSTONE/mcl_comparators/mod.conf | 2 +- mods/ITEMS/REDSTONE/mesecons/actionqueue.lua | 7 + mods/ITEMS/REDSTONE/mesecons/init.lua | 57 ++- mods/ITEMS/REDSTONE/mesecons/internal.lua | 239 +++++++---- mods/ITEMS/REDSTONE/mesecons/services.lua | 85 +++- mods/ITEMS/REDSTONE/mesecons/util.lua | 74 ++++ mods/ITEMS/REDSTONE/mesecons_button/init.lua | 9 +- mods/ITEMS/REDSTONE/mesecons_delayer/init.lua | 12 +- .../REDSTONE/mesecons_pressureplates/init.lua | 16 +- mods/ITEMS/REDSTONE/mesecons_torch/init.lua | 5 +- .../REDSTONE/mesecons_walllever/init.lua | 10 +- mods/ITEMS/REDSTONE/mesecons_wires/init.lua | 381 ++++++++++++++++-- 13 files changed, 942 insertions(+), 175 deletions(-) diff --git a/mods/ITEMS/REDSTONE/mcl_comparators/init.lua b/mods/ITEMS/REDSTONE/mcl_comparators/init.lua index 3517e09cb..246576781 100644 --- a/mods/ITEMS/REDSTONE/mcl_comparators/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_comparators/init.lua @@ -29,9 +29,49 @@ 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 cur_vol = voltage+1 + local frontiers = {{pos = pos, link = link, voltage=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=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, voltage=cur_vol}) + end + end + end + end + depth = depth + 1 + end +end local function comparator_turnoff(params) local rules = comparator_get_output_rules(params.node) @@ -41,10 +81,10 @@ 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) 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 @@ -56,73 +96,180 @@ end -- weather pos has an inventory that contains at least one item -local function container_inventory_nonempty(pos) +local function container_inventory_nonempty(pos, rule) + -- 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, 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 + if not invnodedef.groups.container then + if minetest.get_item_group(invnode.name, "opaque") == 1 and rule then + --found opaque block -> check next block + local backback_pos = vector.add(pos, rule) + local bb_voltage, _ = container_inventory_nonempty(backback_pos, nil) + return bb_voltage, true + else + return 0, false + end end - return false + local inv = minetest.get_inventory({type="node", pos=pos}) + if not inv then return 0, false end + + if invnode.name=="mcl_jukebox:jukebox" then + if not inv:is_empty("main") then + -- Jukebox contains a disc: Stop music and remove disc + local record = inv:get_stack("main", 1) + if mcl_jukebox.registered_records[record:get_name()] then + local ident = mcl_jukebox.registered_records[record:get_name()][3] + local t = { + id_13 = 1, + id_cat = 2, + id_blocks = 3, + id_chirp = 4, + id_far = 5, + id_mall = 6, + id_mellohi = 7, + id_stal = 8, + id_strad = 9, + id_ward = 10, + id_11 = 11, + id_wait = 12, + id_Pigstep = 13, + } + local vol = t["id_"..ident] + if vol then return vol, false end + end + end + else + local item_count = 0 + local inv_space = 0 + + + for listname, _ in pairs(inv:get_lists()) do + + + local stack = inv:get_stack(listname, 1) + + 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 + + if item_count>0 then + local voltage = math.floor(1 + (item_count/inv_space*14)) + return voltage, false + end + end + return 0, false 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_powered(pos, back_rule) + local vo_coin, spread = container_inventory_nonempty(back_pos, back_rule) + local vo_sso = static_signal_output(back_pos) + if vo_coin>=1 and spread and vo_back<15 then + --container through opaque block and block is powerd less than 15 -> ignore powered block + vo_back=0 + end + 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 + -- if back input is off, we don't need to check side inputs + if voltage<1 then return false, 0 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 + 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])) + for _, l in pairs(mesecon.rules_link_rule_all_inverted(pos, my_input_rules[ri])) do + local _, s_voltage = mesecon.is_power_on(vector.add(pos, my_input_rules[ri])) + side_voltage = math.max(side_voltage, s_voltage) + end + end - if side_state then break end end - -- state is known to be true - return not side_state + local mode = minetest.registered_nodes[node.name].comparator_mode + if mode == "comp" then + -- Comparators in comparison mode + if side_voltage > voltage then + return false, 0 + else + 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 + 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 mesecon.receptor_get_rules(node) + local node = mesecon.get_node_force(rec) + 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 end end) -function mesecon.receptor_off(pos, rules) - mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules) +function mesecon.receptor_off(pos, rules, opaquespread) + mesecon.queue:add_action(pos, "receptor_off", {rules, opaquespread}, nil, rules) +end + +mesecon.queue:add_function("conductor_off", function (pos, rules) + rules = rules or mesecon.rules.default + local node = mesecon.get_node_force(pos) + for _, rule in ipairs(mesecon.flattenrules(rules)) do + mesecon.vm_begin() + mesecon.changesignal(pos, node, rule, mesecon.state.off, 2) + local res, rec_on = mesecon.turnoff(pos, rule) + if (res) then + mesecon.vm_commit() + else + mesecon.vm_abort() + for _, rec in pairs(rec_on) do + local node = mesecon.get_node_force(rec) + 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 +end) + +function mesecon.conductor_off(pos, rules) + mesecon.queue:add_action(pos, "conductor_off", {rules}, nil, rules) end --Services like turnoff receptor on dignode and so on diff --git a/mods/ITEMS/REDSTONE/mesecons/internal.lua b/mods/ITEMS/REDSTONE/mesecons/internal.lua index dbe3ebe12..9f9974ee8 100644 --- a/mods/ITEMS/REDSTONE/mesecons/internal.lua +++ b/mods/ITEMS/REDSTONE/mesecons/internal.lua @@ -47,6 +47,12 @@ -- mesecon.rotate_rules_down(rules) -- These functions return rules that have been rotated in the specific direction +-- mesecon.turnon(pos, link, voltage) +-- mesecon.turnoff(pos, link) + + +local rs_tick = 0.05 + local equals = vector.equals local get_node_force = mesecon.get_node_force local invertRule = mesecon.invertRule @@ -149,6 +155,12 @@ local function receptor_get_rules(node) end mesecon.receptor_get_rules = receptor_get_rules +function mesecon.is_receptor_opaquespread(nodename) + local receptor = mesecon.get_receptor(nodename) + return receptor and receptor.opaquespread +end + + -- Effectors -- Nodes that can be powered by mesecons function mesecon.is_effector_on(nodename) @@ -204,14 +216,14 @@ mesecon.queue:add_function("activate", function (pos, rulename) end end) -function mesecon.activate(pos, node, rulename, depth) +function mesecon.activate(pos, node, rulename, depth, time) if rulename == nil then for _,rule in pairs(mesecon.effector_get_rules(node)) do - mesecon.activate(pos, node, rule, depth + 1) + mesecon.activate(pos, node, rule, depth + 1, time) end return end - mesecon.queue:add_action(pos, "activate", {rulename}, nil, rulename, 1 / depth) + mesecon.queue:add_action(pos, "activate", {rulename}, time, rulename, 1 / depth) end @@ -227,14 +239,14 @@ mesecon.queue:add_function("deactivate", function (pos, rulename) end end) -function mesecon.deactivate(pos, node, rulename, depth) +function mesecon.deactivate(pos, node, rulename, depth, time) if rulename == nil then for _,rule in pairs(mesecon.effector_get_rules(node)) do - mesecon.deactivate(pos, node, rule, depth + 1) + mesecon.deactivate(pos, node, rule, depth + 1, time) end return end - mesecon.queue:add_action(pos, "deactivate", {rulename}, nil, rulename, 1 / depth) + mesecon.queue:add_action(pos, "deactivate", {rulename}, time, rulename, 1 / depth) end @@ -250,10 +262,10 @@ mesecon.queue:add_function("change", function (pos, rulename, changetype) end end) -function mesecon.changesignal(pos, node, rulename, newstate, depth) +function mesecon.changesignal(pos, node, rulename, newstate, depth, time) if rulename == nil then for _,rule in pairs(mesecon.effector_get_rules(node)) do - mesecon.changesignal(pos, node, rule, newstate, depth + 1) + mesecon.changesignal(pos, node, rule, newstate, depth + 1, time) end return end @@ -261,7 +273,7 @@ function mesecon.changesignal(pos, node, rulename, newstate, depth) -- Include "change" in overwritecheck so that it cannot be overwritten -- by "active" / "deactivate" that will be called upon the node at the same time. local overwritecheck = {"change", rulename} - mesecon.queue:add_action(pos, "change", {rulename, newstate}, nil, overwritecheck, 1 / depth) + mesecon.queue:add_action(pos, "change", {rulename, newstate}, time, overwritecheck, 1 / depth) end -- Conductors @@ -283,7 +295,6 @@ function mesecon.is_conductor_on(node, rulename) return mesecon.get_bit(binstate, bit) end end - return false end @@ -366,9 +377,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) @@ -379,35 +392,83 @@ function mesecon.is_power_off(pos, rulename) return false end --- Turn off an equipotential section starting at `pos`, which outputs in the direction of `link`. +-- Turn on an equipotential section starting at `pos`, which outputs in the direction of `link`. -- Breadth-first search. Map is abstracted away in a voxelmanip. -- Follow all all conductor paths replacing conductors that were already -- looked at, activating / changing all effectors along the way. -function mesecon.turnon(pos, link) - local frontiers = {{pos = pos, link = link}} +function mesecon.turnon(pos, link, voltage) + voltage = voltage or 15 + local pn = get_node_force(pos) + local frontiers = {{pos = pos, link = link, voltage = voltage}} local depth = 1 while frontiers[1] do local f = table.remove(frontiers, 1) local node = get_node_force(f.pos) - if node and mesecon.is_conductor_off(node, f.link) then - local rules = mesecon.conductor_get_rules(node) - - -- Call turnon on neighbors - for _, r in pairs(mesecon.rule2meta(f.link, rules)) do - local np = vector.add(f.pos, r) - for _, l in pairs(mesecon.rules_link_rule_all(f.pos, r)) do - insert(frontiers, {pos = np, link = l}) + if node and mesecon.is_conductor(node.name) and (f.link.spread==nil and true or f.link.spread) then + --neue spannung berechnen + local meta = minetest.get_meta(f.pos) + 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)) then + if v>=1 or (v<1 and mesecon.is_conductor_on(node, f.link)) then + -- Call turnon on neighbors + local rules = mesecon.conductor_get_rules(node) + for _, r in pairs(mesecon.rule2meta(f.link, rules)) do + local np = vector.add(f.pos, r) + for _, l in pairs(mesecon.rules_link_rule_all(f.pos, r)) do + --aktuelle spannung an nachbarn übergeben + --wenn nachbar wire -> v-1 sonst v + local nnode = get_node_force(np) + if mesecon.is_conductor(nnode.name) then + insert(frontiers, {pos = np, link = l, voltage=v-1 ,source=f.pos}) + else + insert(frontiers, {pos = np, link = l, voltage=v ,source=f.pos}) + end + end + end + end + --spannung setzen + if v<1 then + -- ich bin aus + if mesecon.is_conductor_on(node, f.link) then + mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link)) + end + meta:set_int("mesecon_voltage", 0) + else + if mesecon.is_conductor_off(node, f.link) then + mesecon.swap_node_force(f.pos, mesecon.get_conductor_on(node, f.link)) + end + meta:set_int("mesecon_voltage", v) + end + f.voltage = (v<1 and 0 or v) + else + if v<1 then + --ausschalten + if mesecon.is_conductor_on(node, f.link) then + mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link)) + end + else + --mesecon.swap_node_force(f.pos, mesecon.get_conductor_on(node, f.link)) end end - - mesecon.swap_node_force(f.pos, mesecon.get_conductor_on(node, f.link)) + f.link.opaquespread=false elseif mesecon.is_effector(node.name) then - mesecon.changesignal(f.pos, node, f.link, mesecon.state.on, depth) - if mesecon.is_effector_off(node.name) then + if f.voltage<1 then + --ausschalten + --if mesecon.is_effector_on(node.name) then + mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth) + mesecon.deactivate(f.pos, node, f.link, depth) + --end + else + --einschalten + mesecon.changesignal(f.pos, node, f.link, mesecon.state.on, depth) mesecon.activate(f.pos, node, f.link, depth) end + if minetest.get_item_group(node.name, "opaque") ~= 1 then f.link.opaquespread=false end end if node and f.link.spread and minetest.get_item_group(node.name, "opaque") == 1 then -- Call turnon on neighbors @@ -416,12 +477,11 @@ function mesecon.turnon(pos, link) local np = vector.add(f.pos, r) for _, l in pairs(mesecon.rules_link_rule_all(f.pos, r)) do local nlink = copy(l) - nlink.spread = false - insert(frontiers, {pos = np, link = nlink}) + if not (f.link.opaquespread and mesecon.is_conductor(mesecon.get_node_force(np).name)) then nlink.spread = false end + insert(frontiers, {pos = np, link = nlink, voltage=f.voltage}) end end end - depth = depth + 1 end end @@ -443,8 +503,11 @@ end -- depth = indicates order in which signals wire fired, higher is later -- } function mesecon.turnoff(pos, link) + --muss alle receptor_on zurückliefern + -- komplett durchgehen, nicht abbrechen local frontiers = {{pos = pos, link = link}} local signals = {} + local rec_on = {} local depth = 1 while frontiers[1] do @@ -455,13 +518,12 @@ function mesecon.turnoff(pos, link) 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 if an onstate receptor is connected. If that is the case, -- abort this turnoff process by returning false. `receptor_off` will -- discard all the changes that we made in the voxelmanip: for _, l in pairs(mesecon.rules_link_rule_all_inverted(f.pos, r)) do if is_receptor_on(get_node_force(np).name) then - return false + insert(rec_on, np) end end @@ -469,9 +531,17 @@ function mesecon.turnoff(pos, link) for _, l in pairs(mesecon.rules_link_rule_all(f.pos, r)) do insert(frontiers, {pos = np, link = l}) end + end mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link)) + local meta = minetest.get_meta(f.pos) + --if mesecon.is_conductor_on(node, f.link) then + --spannung neu rechnen + --else + --erstmal spannung überall auf 0 -> wird im anschluss von den receptoren ausgehend wieder gesetzt + meta:set_int("mesecon_voltage", 0) + --end elseif mesecon.is_effector(node.name) then insert(signals, { pos = f.pos, @@ -486,35 +556,55 @@ function mesecon.turnoff(pos, link) -- Warning: A LOT of nodes need to be looked at for this to work local fpos = f.pos for _, r in pairs(mesecon.rule2meta(f.link, mesecon.rules.mcl_alldirs_spread)) do - local np = {x=fpos.x+r.x, y=fpos.y+r.y, z=fpos.z+r.z} + local np = vector.add(f.pos, r) local n = get_node_force(np) - if n and is_receptor_on(n.name) then + if n and is_receptor_on(n.name) and mesecon.get_receptor(n.name).opaquespread then local receptorrules = receptor_get_rules(n) for _, rr in pairs(receptorrules) do if rr.spread and equals(invertRule(rr), r) then - return false + insert(rec_on, np) + --return false end end end + if n and mesecon.is_effector(n.name) then + insert(signals, { + pos = np, + node = n, + link = r, + depth = depth + }) + end + if mesecon.is_conductor_on(n) and f.link.opaquespread then + insert(frontiers, {pos = np, link = r}) + end for _, l in pairs(mesecon.rules_link_rule_all(fpos, r)) do - local nlink = copy(l) - nlink.spread = false - insert(frontiers, {pos = np, link = nlink}) + local lp = vector.add(np, l) + local ln = get_node_force(lp) + if mesecon.is_effector(ln.name) then + local nlink = copy(l) + if not f.link.opaquespread then nlink.spread = false end + insert(frontiers, {pos = np, link = nlink}) + end end end end - depth = depth + 1 end - for _, sig in pairs(signals) do - mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth) - if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then - mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth) + if not next(rec_on) then + --nur, wenn kein receptor_on gefunden + for _, sig in pairs(signals) do + mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth) + if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then + mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth) + end end - end - return true + return true, rec_on + else + return false, rec_on + end end -- Get all linking inputrules of inputnode (effector or conductor) that is connected to @@ -565,12 +655,12 @@ end function mesecon.is_powered(pos, rule, depth, sourcepos, home_pos) if depth == nil then depth = 0 end if depth > 1 then - return false, false + return false, false, 0, false, false end local node = get_node_force(pos) local rules = mesecon.get_any_inputrules(node) if not rules then - return false, false + return false, false, 0, false, false end if not home_pos then home_pos = pos @@ -581,61 +671,74 @@ function mesecon.is_powered(pos, rule, depth, sourcepos, home_pos) sourcepos = {} end - local function power_walk(pos, home_pos, sourcepos, rulenames, rule, depth) + local function power_walk(pos, home_pos, sourcepos, rulenames, rule, depth, voltage, fc, os) local spread = false + local cond = fc for _, rname in pairs(rulenames) do local np = vector.add(pos, rname) local nn = get_node_force(np) - if (mesecon.is_conductor_on (nn, invertRule(rname)) - or is_receptor_on (nn.name)) then + if (mesecon.is_conductor_on (nn, invertRule(rname)) or is_receptor_on (nn.name)) then if not equals(home_pos, np) then local rulez = mesecon.get_any_outputrules(nn) - local spread_tmp = false for r=1, #rulez do if equals(invertRule(rname), rulez[r]) then - if rulez[r].spread then - spread_tmp = true + --has output connected to me + local spread_tmp = rulez[r].spread + if depth == 0 or spread_tmp then + + local meta = minetest.get_meta(np) + + local nvol = meta:get_string("mesecon_voltage")~="" and meta:get_int("mesecon_voltage") or 15 + if nvol>voltage then + voltage = nvol + cond = mesecon.is_conductor(nn.name) + end + os = os or mesecon.is_receptor_opaquespread(nn.name) + np.opaquespread=mesecon.is_receptor_opaquespread(nn.name) + insert(sourcepos, np) + if spread_tmp then spread = true end end end end - if depth == 0 or spread_tmp then - insert(sourcepos, np) - if spread_tmp then - spread = true - end - end end + --elseif depth == 0 and minetest.get_item_group(nn.name, "opaque") == 1 and not pos.conductor then elseif depth == 0 and minetest.get_item_group(nn.name, "opaque") == 1 then - local more_sourcepos = mesecon.is_powered(np, nil, depth + 1, sourcepos, home_pos) - if more_sourcepos and #more_sourcepos > 0 then + local more_sourcepos, more_spread, more_voltage, more_cond, more_os = mesecon.is_powered(np, nil, depth + 1, sourcepos, home_pos, os) + if more_sourcepos and #more_sourcepos > 0 and more_voltage>=1 and (not pos.conductor or more_os) then mesecon.mergetable(sourcepos, more_sourcepos) + if more_voltage>voltage then + voltage = more_voltage + cond = more_cond + os=more_os + end end end end - return sourcepos, spread + return sourcepos, spread, voltage, cond, os end + local v = 0 + local fromConductor = false local spread = false + local opaquespread = false if not rule then for _, rule in pairs(mesecon.flattenrules(rules)) do local spread_temp local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule) - sourcepos, spread_temp = power_walk(pos, home_pos, sourcepos, rulenames, rule, depth) + if next(rulenames) ~= nil then sourcepos, spread_temp, v, fromConductor, opaquespread = power_walk(pos, home_pos, sourcepos, rulenames, rule, depth, v, fromConductor, opaquespread) end if spread_temp then spread = true end end else local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule) - sourcepos, spread = power_walk(pos, home_pos, sourcepos, rulenames, rule, depth) + sourcepos, spread, v, fromConductor, opaquespread = power_walk(pos, home_pos, sourcepos, rulenames, rule, depth, v, opaquespread) end -- Return FALSE if not powered, return list of sources if is powered - if (#sourcepos == 0) then - return false, false + return false, false, 0, false, false else - return sourcepos, spread + return sourcepos, spread, v, fromConductor, opaquespread end end - diff --git a/mods/ITEMS/REDSTONE/mesecons/services.lua b/mods/ITEMS/REDSTONE/mesecons/services.lua index 7d1fce2d8..cf3dfdc8d 100644 --- a/mods/ITEMS/REDSTONE/mesecons/services.lua +++ b/mods/ITEMS/REDSTONE/mesecons/services.lua @@ -1,3 +1,12 @@ +--function mesecon.on_placenode(pos, node) +--function mesecon.on_dignode(pos, node) +--function mesecon.on_blastnode(pos, node) +--function mesecon.do_overheat(pos) +--function mesecon.do_cooldown(pos) +--function mesecon.get_heat(pos) +--function mesecon.move_hot_nodes(moved_nodes) + + -- Dig and place services function mesecon.on_placenode(pos, node) @@ -11,15 +20,21 @@ function mesecon.on_placenode(pos, node) -- Conductors: Send turnon signal when powered or replace by respective offstate conductor -- if placed conductor is an onstate one if mesecon.is_conductor(node.name) then - local sources = mesecon.is_powered(pos) - if sources then + node = mesecon.get_node_force(pos) + pos.conductor=true + local sources, _, voltage, fromConductor = mesecon.is_powered(pos) + if sources and voltage>=1 then + voltage = fromConductor and voltage-1 or voltage + local meta = minetest.get_meta(pos) + meta:set_int("mesecon_voltage", voltage) -- also call receptor_on if itself is powered already, so that neighboring -- conductors will be activated (when pushing an on-conductor with a piston) for _, s in ipairs(sources) do local rule = vector.subtract(pos, s) - mesecon.turnon(pos, rule) + local nnode = mesecon.get_node_force(s) + mesecon.turnon(pos, rule, voltage) end - mesecon.receptor_on (pos, mesecon.conductor_get_rules(node)) + mesecon.receptor_on (pos, mesecon.conductor_get_rules(node), voltage-1) elseif mesecon.is_conductor_on(node) then minetest.swap_node(pos, {name = mesecon.get_conductor_off(node)}) end @@ -52,29 +67,50 @@ function mesecon.on_placenode(pos, node) end if minetest.get_item_group(node.name, "opaque") == 1 then - local neighbors = mesecon.mcl_get_neighbors(pos) - local is_powered, direct_source = mesecon.is_powered(pos) + local is_powered, direct_source, voltage, _, opaquespread = mesecon.is_powered(pos) if is_powered and direct_source then - for n=1, #neighbors do - local npos = neighbors[n].pos - local nnode = minetest.get_node(npos) - if mesecon.is_conductor_off(nnode) then - mesecon.receptor_on(npos, mesecon.conductor_get_rules(nnode)) - -- Redstone torch is a special case and must be ignored - elseif mesecon.is_effector_on(nnode.name) and minetest.get_item_group(nnode.name, "redstone_torch") == 0 then - mesecon.changesignal(npos, nnode, neighbors[n].link, mesecon.state.on, 1) - mesecon.activate(npos, nnode, neighbors[n].link, 1) + if opaquespread then + mesecon.receptor_on(pos, nil, voltage) + else + local neighbors = mesecon.mcl_get_neighbors(pos) + for n=1, #neighbors do + local npos = neighbors[n].pos + local nnode = minetest.get_node(npos) + if mesecon.is_conductor_off(nnode) and opaquespread then + + -- Redstone torch is a special case and must be ignored + elseif mesecon.is_effector_off(nnode.name) and minetest.get_item_group(nnode.name, "redstone_torch") == 0 then + mesecon.changesignal(npos, nnode, neighbors[n].link, mesecon.state.on, 1) + mesecon.activate(npos, nnode, neighbors[n].link, 1) + elseif mesecon.is_effector(nnode.name) and minetest.get_item_group(nnode.name, "redstone_torch") == 0 then + --eigen funktion für comparator schreiben + if voltage<1 then + --if mesecon.is_effector_on(node.name) then + --mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth) + --mesecon.deactivate(f.pos, node, f.link, depth) + + mesecon.changesignal(npos, nnode, neighbors[n].link, mesecon.state.on, 1) + mesecon.deactivate(npos, nnode, neighbors[n].link, 1) + --end + else + mesecon.changesignal(npos, nnode, neighbors[n].link, mesecon.state.on, 1) + mesecon.activate(npos, nnode, neighbors[n].link, 1) + end + end end end end end end -function mesecon.on_dignode(pos, node) - if mesecon.is_conductor_on(node) then - mesecon.receptor_off(pos, mesecon.conductor_get_rules(node)) - elseif mesecon.is_receptor_on(node.name) then - mesecon.receptor_off(pos, mesecon.receptor_get_rules(node)) +function mesecon.on_dignode(pos, node, direct_dig) + local regnode = minetest.registered_nodes[node.name] + if (regnode and regnode.mesecons and not regnode.on_destruct) or not direct_dig then + if mesecon.is_conductor_on(node) then + mesecon.conductor_off(pos, mesecon.conductor_get_rules(node)) + elseif mesecon.is_receptor_on(node.name) then + mesecon.receptor_off(pos, mesecon.receptor_get_rules(node), mesecon.is_receptor_opaquespread(node.name)) + end end if minetest.get_item_group(node.name, "opaque") == 1 then --local sources = mesecon.is_powered(pos) @@ -84,7 +120,7 @@ function mesecon.on_dignode(pos, node) local nlink = neighbors[n].link local nnode = minetest.get_node(npos) if mesecon.is_conductor_on(nnode) then - mesecon.receptor_off(npos, mesecon.conductor_get_rules(nnode)) + mesecon.conductor_off(npos, mesecon.conductor_get_rules(nnode)) -- Disable neighbor effectors unless they are in a special ignore group elseif mesecon.is_effector_on(nnode.name) and mesecon.is_powered(npos) == false and minetest.get_item_group(nnode.name, "mesecon_ignore_opaque_dig") == 0 then mesecon.changesignal(npos, nnode, nlink, mesecon.state.off, 1) @@ -102,8 +138,13 @@ function mesecon.on_blastnode(pos, node) return minetest.get_node_drops(node.name, "") end +function mesecon.reg_on_dignode(pos, node) + mesecon.on_dignode(pos, node, true) +end + + minetest.register_on_placenode(mesecon.on_placenode) -minetest.register_on_dignode(mesecon.on_dignode) +minetest.register_on_dignode(mesecon.reg_on_dignode) -- Overheating service for fast circuits local OVERHEAT_MAX = mesecon.setting("overheat_max", 8) diff --git a/mods/ITEMS/REDSTONE/mesecons/util.lua b/mods/ITEMS/REDSTONE/mesecons/util.lua index b6602526a..17ed17df2 100644 --- a/mods/ITEMS/REDSTONE/mesecons/util.lua +++ b/mods/ITEMS/REDSTONE/mesecons/util.lua @@ -1,3 +1,42 @@ +--[[ +function mesecon.move_node(pos, newpos) +function mesecon.rotate_rules_right(rules) +function mesecon.rotate_rules_left(rules) +function mesecon.rotate_rules_down(rules) +function mesecon.rotate_rules_up(rules) +function mesecon.flattenrules(allrules) +function mesecon.rule2bit(findrule, allrules) +function mesecon.rule2metaindex(findrule, allrules) +function mesecon.rule2meta(findrule, allrules) +function mesecon.mcl_get_neighbors(pos) +function mesecon.dec2bin(n) +function mesecon.getstate(nodename, states) +function mesecon.getbinstate(nodename, states) +function mesecon.get_bit(binary,bit) +function mesecon.set_bit(binary,bit,value) +function mesecon.invertRule(r) +function mesecon.tablecopy(table) -- deep table copy +function mesecon.cmpAny(t1, t2) +function mesecon.mergetable(source, dest) +function mesecon.register_node(name, spec_common, spec_off, spec_on) +function mesecon.flipstate(pos, node) +function mesecon.file2table(filename) +function mesecon.table2file(filename, table) +function mesecon.vm_begin() +function mesecon.vm_commit() +function mesecon.vm_abort() +function mesecon.vm_get_node(pos) +function mesecon.vm_swap_node(pos, name) +function mesecon.get_node_force(pos) +function mesecon.swap_node_force(pos, name) +function mesecon.register_autoconnect_hook(name, fct) +function mesecon.execute_autoconnect_hooks_now(pos, node) +function mesecon.execute_autoconnect_hooks_queue(pos, node) + +function mesecon.tab2str(tbl) +function mesecon.pos2str(pos) +--]] + function mesecon.move_node(pos, newpos) local node = minetest.get_node(pos) local meta = minetest.get_meta(pos):to_table() @@ -254,6 +293,13 @@ function mesecon.register_node(name, spec_common, spec_off, spec_on) spec_off.__mesecon_state = "off" spec_on = mesecon.mergetable(spec_common, spec_on); + if spec_on.mesecons and (spec_on.mesecons.receptor or spec_on.mesecons.conductor) then + spec_on.on_destruct = spec_on.on_destruct or + function(pos, oldnode) + local node = minetest.get_node(pos) + mesecon.on_dignode(pos, node) + end + end spec_off = mesecon.mergetable(spec_common, spec_off); minetest.register_node(name .. "_on", spec_on) @@ -459,3 +505,31 @@ function mesecon.execute_autoconnect_hooks_queue(pos, node) mesecon.queue:add_action(pos, "autoconnect_hook_"..name, {node}) end end + + +function mesecon.tab2str(tbl) + if type(tbl) ~= "table" then + return tostring(tbl) + else + local tmp = "" + for k,v in pairs(tbl) do + if tmp ~="" then tmp = tmp .. " / " end + tmp = tmp .. tostring(k).."=" .. (type(v) == "table" and ("{"..mesecon.tabletostring(v).."}") or tostring(v)) + end + return tmp + end +end + +function mesecon.pos21tr(pos) + return pos.x .. "/" .. pos.y .. "/" .. pos.z +end + +function mesecon.rules_sub(source_rules, sub) + local t = {} + for i = 1, #sub do t[mesecon.postostring(sub[i])] = true end + local res = mesecon.tablecopy(source_rules) + for i = #res, 1, -1 do + if t[mesecon.postostring(res[i])] then table.remove(res, i) end + end + return res +end diff --git a/mods/ITEMS/REDSTONE/mesecons_button/init.lua b/mods/ITEMS/REDSTONE/mesecons_button/init.lua index 2812b2758..112f7a704 100644 --- a/mods/ITEMS/REDSTONE/mesecons_button/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_button/init.lua @@ -139,6 +139,7 @@ function mesecon.register_button(basename, description, texture, recipeitem, sou mesecons = {receptor = { state = mesecon.state.off, rules = button_get_output_rules, + opaquespread = true, }}, _mcl_button_basename = basename, _mcl_button_timer = button_timer, @@ -165,7 +166,8 @@ function mesecon.register_button(basename, description, texture, recipeitem, sou sounds = sounds, mesecons = {receptor = { state = mesecon.state.on, - rules = button_get_output_rules + rules = button_get_output_rules, + opaquespread = true, }}, _mcl_button_basename = basename, _mcl_button_timer = button_timer, @@ -193,7 +195,10 @@ function mesecon.register_button(basename, description, texture, recipeitem, sou mesecon.receptor_off(pos, button_get_output_rules(node)) end end, - + on_destruct = function(pos, oldnode) + local node = minetest.get_node(pos) + mesecon.on_dignode(pos, node) + end, _mcl_blast_resistance = 0.5, _mcl_hardness = 0.5, }) diff --git a/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua b/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua index fc12c0a36..69c10fb3d 100644 --- a/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua @@ -290,6 +290,7 @@ for i = 1, 4 do receptor = { state = mesecon.state.off, rules = delayer_get_output_rules, + opaquespread = true, }, effector = { rules = delayer_get_input_rules, @@ -359,6 +360,7 @@ for i = 1, 4 do receptor = { state = mesecon.state.on, rules = delayer_get_output_rules, + opaquespread = true, }, effector = { rules = delayer_get_input_rules, @@ -366,6 +368,10 @@ for i = 1, 4 do }, }, on_rotate = on_rotate, + on_destruct = function(pos, oldnode) + local node = minetest.get_node(pos) + mesecon.on_dignode(pos, node) + end, }) end @@ -417,7 +423,8 @@ minetest.register_node("mesecons_delayer:delayer_off_locked", { receptor = { state = mesecon.state.off, - rules = delayer_get_output_rules + rules = delayer_get_output_rules, + opaquespread = true, }, effector = { @@ -472,7 +479,8 @@ minetest.register_node("mesecons_delayer:delayer_on_locked", { receptor = { state = mesecon.state.on, - rules = delayer_get_output_rules + rules = delayer_get_output_rules, + opaquespread = true, }, effector = { diff --git a/mods/ITEMS/REDSTONE/mesecons_pressureplates/init.lua b/mods/ITEMS/REDSTONE/mesecons_pressureplates/init.lua index c0894224c..f1ee0f795 100644 --- a/mods/ITEMS/REDSTONE/mesecons_pressureplates/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_pressureplates/init.lua @@ -133,7 +133,13 @@ function mesecon.register_pressure_plate(basename, description, textures_off, te groups = groups_off, tiles = textures_off, - mesecons = {receptor = { state = mesecon.state.off, rules = mesecon.rules.pplate }}, + mesecons = { + receptor = { + state = mesecon.state.off, + rules = mesecon.rules.pplate, + opaquespread = true, + } + }, _doc_items_longdesc = longdesc, _tt_help = tt, },{ @@ -143,7 +149,13 @@ function mesecon.register_pressure_plate(basename, description, textures_off, te tiles = textures_on, description = "", - mesecons = {receptor = { state = mesecon.state.on, rules = mesecon.rules.pplate }}, + mesecons = { + receptor = { + state = mesecon.state.on, + rules = mesecon.rules.pplate, + opaquespread = true, + } + }, _doc_items_create_entry = false, }) diff --git a/mods/ITEMS/REDSTONE/mesecons_torch/init.lua b/mods/ITEMS/REDSTONE/mesecons_torch/init.lua index e49b843cc..c2955b1ed 100644 --- a/mods/ITEMS/REDSTONE/mesecons_torch/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_torch/init.lua @@ -136,6 +136,7 @@ local off_override = { receptor = { state = mesecon.state.off, rules = torch_get_output_rules, + opaquespread = true, }, effector = { state = mesecon.state.on, @@ -184,11 +185,13 @@ local on_override = { on_destruct = function(pos, oldnode) local node = minetest.get_node(pos) torch_action_on(pos, node) + mesecon.on_dignode(pos, node) end, mesecons = { receptor = { state = mesecon.state.on, - rules = torch_get_output_rules + rules = torch_get_output_rules, + opaquespread = true, }, effector = { state = mesecon.state.off, diff --git a/mods/ITEMS/REDSTONE/mesecons_walllever/init.lua b/mods/ITEMS/REDSTONE/mesecons_walllever/init.lua index c251587d5..18e887a86 100644 --- a/mods/ITEMS/REDSTONE/mesecons_walllever/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_walllever/init.lua @@ -125,7 +125,8 @@ minetest.register_node("mesecons_walllever:wall_lever_off", { sounds = mcl_sounds.node_sound_stone_defaults(), mesecons = {receptor = { rules = lever_get_output_rules, - state = mesecon.state.off + state = mesecon.state.off, + opaquespread = true, }}, on_rotate = on_rotate, _mcl_blast_resistance = 0.5, @@ -158,8 +159,13 @@ minetest.register_node("mesecons_walllever:wall_lever_on", { sounds = mcl_sounds.node_sound_stone_defaults(), mesecons = {receptor = { rules = lever_get_output_rules, - state = mesecon.state.on + state = mesecon.state.on, + opaquespread = true, }}, + on_destruct = function(pos, oldnode) + local node = minetest.get_node(pos) + mesecon.on_dignode(pos, node) + end, on_rotate = on_rotate, _mcl_blast_resistance = 0.5, _mcl_hardness = 0.5, diff --git a/mods/ITEMS/REDSTONE/mesecons_wires/init.lua b/mods/ITEMS/REDSTONE/mesecons_wires/init.lua index 0f2febc44..e5e92ba07 100644 --- a/mods/ITEMS/REDSTONE/mesecons_wires/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_wires/init.lua @@ -1,4 +1,4 @@ --- naming scheme: wire:(xp)(zp)(xm)(zm)(xpyp)(zpyp)(xmyp)(zmyp)_on/off +-- naming scheme: wire:(xp)(zp)(xm)(zm)(xpyp)(zpyp)(xmyp)(zmyp)(xpym)(zpym)(xmym)(zmym)_on/off -- where x= x direction, z= z direction, y= y direction, p = +1, m = -1, e.g. xpym = {x=1, y=-1, z=0} -- The (xp)/(zpyp)/.. statements shall be replaced by either 0 or 1 -- Where 0 means the wire has no visual connection to that direction and @@ -10,28 +10,28 @@ local S = minetest.get_translator(minetest.get_current_modname()) -- ## Update wire looks ## -- ####################### -local wire_rules = -{{x=-1, y= 0, z= 0, spread=true}, - {x= 1, y= 0, z= 0, spread=true}, - {x= 0, y=-1, z= 0, spread=true}, - {x= 0, y= 1, z= 0, spread=true}, - {x= 0, y= 0, z=-1, spread=true}, - {x= 0, y= 0, z= 1, spread=true}, +local wire_rules = { + {x= 1, y= 0, z= 0, spread=true}, --xp + {x= 0, y= 0, z= 1, spread=true}, --zp + {x=-1, y= 0, z= 0, spread=true}, --xm + {x= 0, y= 0, z=-1, spread=true}, --zm + {x= 1, y= 1, z= 0}, --xpyp + {x= 0, y= 1, z= 1}, --zpyp + {x=-1, y= 1, z= 0}, --xmyp + {x= 0, y= 1, z=-1}, --zmyp + {x= 1, y=-1, z= 0}, --xpym + {x= 0, y=-1, z= 1}, --zpym + {x=-1, y=-1, z= 0}, --xmym + {x= 0, y=-1, z=-1}, --zmym + {x= 0, y=-1, z= 0, spread=true}, --ym (always) +} - {x= 1, y= 1, z= 0}, - {x= 1, y=-1, z= 0}, - {x=-1, y= 1, z= 0}, - {x=-1, y=-1, z= 0}, - {x= 0, y= 1, z= 1}, - {x= 0, y=-1, z= 1}, - {x= 0, y= 1, z=-1}, - {x= 0, y=-1, z=-1}} -- self_pos = pos of any mesecon node, from_pos = pos of conductor to getconnect for -local function wire_getconnect(from_pos, self_pos) +local function wire_getconnect(from_pos, self_pos, from_rule) local node = minetest.get_node(self_pos) if minetest.registered_nodes[node.name] - and minetest.registered_nodes[node.name].mesecons then + and minetest.registered_nodes[node.name].mesecons or minetest.get_item_group(node.name, "opaque") == 1 then -- rules of node to possibly connect to local rules if (minetest.registered_nodes[node.name].mesecon_wire) then @@ -42,19 +42,90 @@ local function wire_getconnect(from_pos, self_pos) for _, r in ipairs(mesecon.flattenrules(rules)) do if (vector.equals(vector.add(self_pos, r), from_pos)) then - return true + -- no upper-connect with opaqu block above me + if from_rule.y==1 then + local ufnode = mesecon.get_node_force(vector.add(from_pos, {x=0, y=1, z=0})) + if minetest.get_item_group(ufnode.name, "opaque") == 1 then return false, 1 end + end + if from_rule.y==-1 then + local nfnode = mesecon.get_node_force(vector.add(from_pos, {x=from_rule.x, y=0, z=from_rule.z})) + if minetest.get_item_group(nfnode.name, "opaque") == 1 then return false, 2 end + end + + -- receptor -> always + if mesecon.is_receptor(node.name) then return true, 3 end + -- conductor -> always + if mesecon.is_conductor(node.name) then return true, 4 end + + if from_rule.x==1 or from_rule.x==-1 then + local xpmnode = mesecon.get_node_force(vector.add(from_pos, {x=from_rule.x, y=0, z=0})) + --check blocks z=+-1 + local zmnode = mesecon.get_node_force(vector.add(from_pos, {x=0, y=0, z=-1})) + if (mesecon.is_receptor(zmnode.name) or mesecon.is_conductor(zmnode.name)) and not (minetest.get_item_group(xpmnode.name, "opaque") == 1) then return false, 5 end + if minetest.get_item_group(zmnode.name, "opaque") == 1 then + --check upper + local zmypnode = mesecon.get_node_force(vector.add(from_pos, {x=0, y= 1, z=-1})) + if mesecon.is_conductor(zmypnode.name) then return false, 6 end + elseif zmnode.name=="air" then + --check lower + local zmymnode = mesecon.get_node_force(vector.add(from_pos, {x=0, y=-1, z=-1})) + if mesecon.is_conductor(zmymnode.name) then return false, 7 end + end + + local zpnode = mesecon.get_node_force(vector.add(from_pos, {x=0, y=0, z= 1})) + if (mesecon.is_receptor(zpnode.name) or mesecon.is_conductor(zpnode.name)) and not (minetest.get_item_group(xpmnode.name, "opaque") == 1) then return false, 8 end + if minetest.get_item_group(zpnode.name, "opaque") == 1 then + --check upper + local zpypnode = mesecon.get_node_force(vector.add(from_pos, {x=0, y=1, z= 1})) + if mesecon.is_conductor(zpypnode.name) then return false, 9 end + elseif zpnode.name=="air" then + --check lower + local zpymnode = mesecon.get_node_force(vector.add(from_pos, {x=0, y=-1, z= 1})) + if mesecon.is_conductor(zpymnode.name) then return false, 10 end + end + end + + if from_rule.z==1 or from_rule.z==-1 then + local zpmnode = mesecon.get_node_force(vector.add(from_pos, {x=0, y=0, z=from_rule.z})) + --check blocks x=+-1 + local xmnode = mesecon.get_node_force(vector.add(from_pos, {x=-1, y=0, z=0})) + if (mesecon.is_receptor(xmnode.name) or mesecon.is_conductor(xmnode.name)) and not (minetest.get_item_group(zpmnode.name, "opaque") == 1) then return false, 12 end + if minetest.get_item_group(xmnode.name, "opaque") == 1 then + --check upper + local xmypnode = mesecon.get_node_force(vector.add(from_pos, {x=-1, y=1, z=0})) + if mesecon.is_conductor(xmypnode.name) then return false, 13 end + elseif xmnode.name=="air" then + --check lower + local xmymnode = mesecon.get_node_force(vector.add(from_pos, {x=-1, y=-1, z= 0})) + if mesecon.is_conductor(xmymnode.name) then return false, 14 end + end + + local xpnode = mesecon.get_node_force(vector.add(from_pos, {x= 1, y=0, z=0})) + if (mesecon.is_receptor(xpnode.name) or mesecon.is_conductor(xpnode.name)) and not (minetest.get_item_group(zpmnode.name, "opaque") == 1) then return false, 15 end + if minetest.get_item_group(xpnode.name, "opaque") == 1 then + --check upper + local xpypnode = mesecon.get_node_force(vector.add(from_pos, {x= 1, y=1, z=0})) + if mesecon.is_conductor(xpypnode.name) then return false, 16 end + elseif xpnode.name=="air" then + --check lower + local xpymnode = mesecon.get_node_force(vector.add(from_pos, {x=1, y=-1, z= 0})) + if mesecon.is_conductor(xpymnode.name) then return false, 17 end + end + end + return true, 0 end end end - return false + return false, -1 end -- Update this node local function wire_updateconnect(pos) local connections = {} - + --check all rules for _, r in ipairs(wire_rules) do - if wire_getconnect(pos, vector.add(pos, r)) then + local res, val = wire_getconnect(pos, vector.add(pos, r), r) + if res then table.insert(connections, r) end end @@ -73,14 +144,25 @@ local function wire_updateconnect(pos) if vec.z == 1 then nid[5] = "1" end if vec.x == -1 then nid[6] = "1" end if vec.z == -1 then nid[7] = "1" end + elseif vec.y == -1 then + if vec.x == 1 then nid[ 8] = "1" end + if vec.z == 1 then nid[ 9] = "1" end + if vec.x == -1 then nid[10] = "1" end + if vec.z == -1 then nid[11] = "1" end + end end - local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0") - ..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0") + local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[ 2] or "0")..(nid[ 3] or "0") + ..(nid[4] or "0")..(nid[5] or "0")..(nid[ 6] or "0")..(nid[ 7] or "0") + ..(nid[8] or "0")..(nid[9] or "0")..(nid[10] or "0")..(nid[11] or "0") local state_suffix = string.find(minetest.get_node(pos).name, "_off") and "_off" or "_on" - minetest.set_node(pos, {name = "mesecons:wire_"..nodeid..state_suffix}) + local orules = mesecon.get_any_inputrules(mesecon.get_node_force(pos)) + mesecon.swap_node_force(pos, "mesecons:wire_"..nodeid..state_suffix) + local nrules = mesecon.get_any_inputrules(mesecon.get_node_force(pos)) + local res = mesecon.rules_sub(orules, nrules) + return res end local function update_on_place_dig(pos, node) @@ -103,9 +185,13 @@ local function update_on_place_dig(pos, node) for _, r in ipairs(mesecon.flattenrules(rules)) do local np = vector.add(pos, r) - if minetest.registered_nodes[minetest.get_node(np).name] - and minetest.registered_nodes[minetest.get_node(np).name].mesecon_wire then - wire_updateconnect(np) + local nnode = minetest.get_node(np).name + if minetest.registered_nodes[nnode] and minetest.registered_nodes[nnode].mesecon_wire then + local abandoned_rules = wire_updateconnect(np) + if next(abandoned_rules) ~= nil then + mesecon.conductor_off(np, abandoned_rules) + mesecon.conductor_off(np, mesecon.conductor_get_rules(minetest.get_node(np))) + end end end end @@ -161,7 +247,7 @@ local function register_wires() while true do -- Create group specifiction and nodeid string (see note above for details) local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[2] or "0")..(nid[3] or "0") - ..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0") + ..(nid[4] or "0")..(nid[5] or "0")..(nid[6] or "0")..(nid[7] or "0") -- Calculate nodebox local nodebox = {type = "fixed", fixed={box_center}} @@ -206,13 +292,13 @@ local function register_wires() local ratio_off = 128 local ratio_on = 192 local crossing_off = "(redstone_redstone_dust_dot.png^redstone_redstone_dust_line0.png^(redstone_redstone_dust_line1.png^[transformR90))^[colorize:#FF0000:"..ratio_off - local crossing_on = "(redstone_redstone_dust_dot.png^redstone_redstone_dust_line0.png^(redstone_redstone_dust_line1.png^[transformR90))^[colorize:#FF0000:"..ratio_on + local crossing_on = "(redstone_redstone_dust_dot.png^redstone_redstone_dust_line0.png^(redstone_redstone_dust_line1.png^[transformR90))^[colorize:#FF0000:"..ratio_on local straight0_off = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_off - local straight0_on = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_on + local straight0_on = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_on local straight1_off = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_off - local straight1_on = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_on + local straight1_on = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_on local dot_off = "redstone_redstone_dust_dot.png^[colorize:#FF0000:"..ratio_off - local dot_on = "redstone_redstone_dust_dot.png^[colorize:#FF0000:"..ratio_on + local dot_on = "redstone_redstone_dust_dot.png^[colorize:#FF0000:"..ratio_on local tiles_off, tiles_on @@ -286,8 +372,237 @@ S("Read the help entries on the other redstone components to learn how redstone if (nid_inc(nid) == false) then return end end end +-- register the old nodes -> alias? register_wires() + +---------------------------------------------------- + +-- go to the next nodeid (ex.: 01000011 --> 01000100) +local function nid_inc2() end +function nid_inc2(nid) + local i = 0 + while nid[i-1] ~= 1 do + nid[i] = (nid[i] ~= 1) and 1 or 0 + i = i + 1 + end + + -- BUT: Skip impossible nodeids: + if ( + (nid[0] == 0 and nid[4] == 1) or (nid[0] == 0 and nid[ 8] == 1) or (nid[4] == 1 and nid[ 8] == 1) or + (nid[1] == 0 and nid[5] == 1) or (nid[1] == 0 and nid[ 9] == 1) or (nid[5] == 1 and nid[ 9] == 1) or + (nid[2] == 0 and nid[6] == 1) or (nid[2] == 0 and nid[10] == 1) or (nid[6] == 1 and nid[10] == 1) or + (nid[3] == 0 and nid[7] == 1) or (nid[3] == 0 and nid[11] == 1) or (nid[7] == 1 and nid[11] == 1) + ) then + return nid_inc2(nid) + end + + return i <= 12 +end + + +local function register_wires2() + local nid = {} + while true do + -- Create group specifiction and nodeid string (see note above for details) + local nodeid = (nid[0] or "0")..(nid[1] or "0")..(nid[ 2] or "0")..(nid[ 3] or "0") + ..(nid[4] or "0")..(nid[5] or "0")..(nid[ 6] or "0")..(nid[ 7] or "0") + ..(nid[8] or "0")..(nid[9] or "0")..(nid[10] or "0")..(nid[11] or "0") + + -- Calculate nodebox, ignore 8 to 11 + local nodebox = {type = "fixed", fixed={box_center}} + for i=0,7 do + if nid[i] == 1 then + table.insert(nodebox.fixed, nbox_nid[i]) + end + end + + -- Add bump to nodebox if curved + if (nid[0] == 1 and nid[1] == 1) or (nid[1] == 1 and nid[2] == 1) + or (nid[2] == 1 and nid[3] == 1) or (nid[3] == 1 and nid[0] == 1) then + table.insert(nodebox.fixed, box_bump1) + end + + -- If nothing to connect to, still make a nodebox of a straight wire + --if nodeid == "00000000" then + if nodeid:sub(1,8) == "00000000" then + nodebox.fixed = {-8/16, -.5, -1/16, 8/16, -.5+1/16, 1/16} + end + --rules berechnen, nur nötige verwenden + local nrules = {} + for i=0,11 do + if nid[i]==1 then + table.insert(nrules,wire_rules[i+1]) + end + end + table.insert(nrules,wire_rules[12+1]) --ym (always) + +--[[ +00100000 + + +-- naming scheme: wire:(xp)(zp)(xm)(zm)(xpyp)(zpyp)(xmyp)(zmyp)_on/off + + +komplett flat +11110000 + + {x= 1, y= 0, z= 0, spread=true}, --xp 0 x + {x= 0, y= 0, z= 1, spread=true}, --zp 1 - + {x=-1, y= 0, z= 0, spread=true}, --xm 2 x + {x= 0, y= 0, z=-1, spread=true}, --zm 3 + + +{x= 0, y=-1, z= 0, spread=true}, --unten (immer) + + + + {x= 1, y= 1, z= 0}, --xpyp 4 + {x= 0, y= 1, z= 1}, --zpyp 5 + {x=-1, y= 1, z= 0}, --xmyp 6 + {x= 0, y= 1, z=-1}, --zmyp 7 + + {x= 1, y=-1, z= 0}, --xpym 8 + {x= 0, y=-1, z= 1}, --zpym 9 + {x=-1, y=-1, z= 0}, --xmym 10 + {x= 0, y=-1, z=-1}, --zmym 11 + +0,4, 8 +1,5, 9 +2,6,10 +3,7,11 +--]] + +--[[ + {x= 1, y= 0, z= 0, spread=true}, --xp + {x= 0, y= 0, z= 1, spread=true}, --zp + {x=-1, y= 0, z= 0, spread=true}, --xm + {x= 0, y= 0, z=-1, spread=true}, --zm + {x= 1, y= 1, z= 0}, --xpyp + {x= 0, y= 1, z= 1}, --zpyp + {x=-1, y= 1, z= 0}, --xmyp + {x= 0, y= 1, z=-1}, --zmyp + {x= 1, y=-1, z= 0}, --xpym + {x= 0, y=-1, z= 1}, --zpym + {x=-1, y=-1, z= 0}, --xmym + {x= 0, y=-1, z=-1}} --zmym + {x= 0, y=-1, z= 0, spread=true}, --ym (always) + +--]] + + local meseconspec_off = { conductor = { + --rules = wire_rules, + rules = nrules, + state = mesecon.state.off, + onstate = "mesecons:wire_"..nodeid.."_on" + }} + + local meseconspec_on = { conductor = { + --rules = wire_rules, + rules = nrules, + state = mesecon.state.on, + offstate = "mesecons:wire_"..nodeid.."_off" + }} + + local groups_on = {dig_immediate = 3, mesecon_conductor_craftable = 1, + not_in_creative_inventory = 1, attached_node = 1, dig_by_water = 1,destroy_by_lava_flow=1, dig_by_piston = 1} + local groups_off = {dig_immediate = 3, mesecon_conductor_craftable = 1, + attached_node = 1, dig_by_water = 1,destroy_by_lava_flow=1, dig_by_piston = 1, craftitem = 1} + --if nodeid ~= "00000000" then + if nodeid:sub(1,8) ~= "00000000" then + groups_off["not_in_creative_inventory"] = 1 + end + + -- Wire textures + local ratio_off = 128 + local ratio_on = 192 + local crossing_off = "(redstone_redstone_dust_dot.png^redstone_redstone_dust_line0.png^(redstone_redstone_dust_line1.png^[transformR90))^[colorize:#FF0000:"..ratio_off + local crossing_on = "(redstone_redstone_dust_dot.png^redstone_redstone_dust_line0.png^(redstone_redstone_dust_line1.png^[transformR90))^[colorize:#FF0000:"..ratio_on + local straight0_off = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_off + local straight0_on = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_on + local straight1_off = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_off + local straight1_on = "redstone_redstone_dust_line0.png^[colorize:#FF0000:"..ratio_on + local dot_off = "redstone_redstone_dust_dot.png^[colorize:#FF0000:"..ratio_off + local dot_on = "redstone_redstone_dust_dot.png^[colorize:#FF0000:"..ratio_on + + local tiles_off, tiles_on + + local wirehelp, tt, longdesc, usagehelp, img, desc_off, desc_on + if nodeid:sub(1,8) == "00000000" then + -- Non-connected redstone wire + nodebox.fixed = {-8/16, -.5, -8/16, 8/16, -.5+1/64, 8/16} + -- “Dot” texture + tiles_off = { dot_off, dot_off, "blank.png", "blank.png", "blank.png", "blank.png" } + tiles_on = { dot_on, dot_on, "blank.png", "blank.png", "blank.png", "blank.png" } + + tt = S("Transmits redstone power, powers mechanisms") + longdesc = S("Redstone is a versatile conductive mineral which transmits redstone power. It can be placed on the ground as a trail.").."\n".. + S("A redstone trail can be in two states: Powered or not powered. A powered redstone trail will power (and thus activate) adjacent redstone components.").."\n".. + S("Redstone power can be received from various redstone components, such as a block of redstone or a button. Redstone power is used to activate numerous mechanisms, such as redstone lamps or pistons.") + usagehelp = S("Place redstone on the ground to build a redstone trail. The trails will connect to each other automatically and it can also go over hills.").."\n\n".. + +S("Read the help entries on the other redstone components to learn how redstone components interact.") + img = "redstone_redstone_dust.png" + desc_off = S("Redstone") + desc_on = S("Powered Redstone Spot (@1)", nodeid) + else + -- Connected redstone wire + table.insert(nodebox, box_center) + tiles_off = { crossing_off, crossing_off, straight0_off, straight1_off, straight0_off, straight1_off } + tiles_on = { crossing_on, crossing_on, straight0_on, straight1_on, straight0_on, straight1_on } + wirehelp = false + desc_off = S("Redstone Trail (@1)", nodeid) + desc_on = S("Powered Redstone Trail (@1)", nodeid) + end + + mesecon.register_node(":mesecons:wire_"..nodeid, { + drawtype = "nodebox", + paramtype = "light", + use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true, + sunlight_propagates = true, + selection_box = selectionbox, + node_box = nodebox, + walkable = false, + drop = "mesecons:wire_00000000_off", + sounds = mcl_sounds.node_sound_defaults(), + is_ground_content = false, + mesecon_wire = true + },{ + description = desc_off, + inventory_image = img, + wield_image = img, + _tt_help = tt, + _doc_items_create_entry = wirehelp, + _doc_items_longdesc = longdesc, + _doc_items_usagehelp = usagehelp, + tiles = tiles_off, + mesecons = meseconspec_off, + groups = groups_off, + },{ + description = desc_on, + _doc_items_create_entry = false, + tiles = tiles_on, + mesecons = meseconspec_on, + groups = groups_on + }) + + -- Add Help entry aliases for e.g. making it identifiable by the lookup tool [doc_identifier] + if minetest.get_modpath("doc") then + if nodeid:sub(1,8) ~= "00000000" then + doc.add_entry_alias("nodes", "mesecons:wire_000000000000_off", "nodes", "mesecons:wire_"..nodeid.."_off") + end + doc.add_entry_alias("nodes", "mesecons:wire_000000000000_off", "nodes", "mesecons:wire_"..nodeid.."_on") + end + + if (nid_inc2(nid) == false) then return end + end +end + +register_wires2() + +---------------------------------------------------- + + minetest.register_alias("mesecons:redstone", "mesecons:wire_00000000_off") minetest.register_craft({