Add transistors

This commit is contained in:
Desour 2021-04-08 18:24:31 +02:00
parent f5c3f798be
commit b79f21f8f3
9 changed files with 501 additions and 0 deletions

View File

@ -0,0 +1,499 @@
local node_box = {
type = "fixed",
fixed = {
{-8/16, -8/16, -8/16, 8/16, -7/16, 8/16},
},
}
local function rotate_rules(node, rules)
for rotations = 0, node.param2 - 1 do
rules = mesecon.rotate_rules_left(rules)
end
return rules
end
local function get_switcher_inputrules(node)
return rotate_rules(node, {{x = 0, y = 0, z = -1}, {x = 1, y = 0, z = 0},
{x = -1, y = 0, z = 0}})
end
local function get_conductorrules(node)
return rotate_rules(node, {{x = 1, y = 0, z = 0}, {x = -1, y = 0, z = 0}})
end
local function get_dir_to_switcher(node)
return rotate_rules(node, {{x = 0, y = 0, z = -1}})[1]
end
local function get_dir_to_switched(node)
return rotate_rules(node, {{x = 0, y = 0, z = 1}})[1]
end
local is_transistor_node = {
["mesecons_transistors:normally_open_contact_open"] = true,
["mesecons_transistors:normally_open_contact_closed_off" ] = true,
["mesecons_transistors:normally_open_contact_closed_on" ] = true,
["mesecons_transistors:normally_closed_contact_open" ] = true,
["mesecons_transistors:normally_closed_contact_closed_off"] = true,
["mesecons_transistors:normally_closed_contact_closed_on"] = true,
}
local function handle_overheat(pos, node)
local conductor_pos = vector.add(pos, get_dir_to_switched(node))
local conductor_node = mesecon.get_node_force(conductor_pos)
if not conductor_node or conductor_node.param2 ~= node.param2 or
not is_transistor_node[conductor_node.name] then
minetest.remove_node(pos)
mesecon.on_dignode(pos, node)
return
end
minetest.remove_node(pos)
minetest.remove_node(conductor_pos)
mesecon.on_dignode(pos, node)
mesecon.on_dignode(conductor_pos, conductor_node)
minetest.add_item(conductor_pos, minetest.registered_nodes[conductor_node.name].drop)
end
local function switcher_on(pos, node)
if mesecon.do_overheat(pos) then
handle_overheat(pos, node)
return
end
node.name = "mesecons_transistors:switcher_on"
minetest.swap_node(pos, node)
local dir = get_dir_to_switched(node)
local switched_pos = vector.add(pos, dir)
local switched_node = mesecon.get_node_force(switched_pos)
if not switched_node then
return
end
local old_switched_node = {name = switched_node.name, param1 = switched_node.param1,
param2 = switched_node.param2}
if switched_node.name == "mesecons_transistors:normally_open_contact_open" then
switched_node.name = "mesecons_transistors:normally_open_contact_closed_off"
elseif switched_node.name == "mesecons_transistors:normally_closed_contact_closed_off" or
switched_node.name == "mesecons_transistors:normally_closed_contact_closed_on" then
switched_node.name = "mesecons_transistors:normally_closed_contact_open"
else
minetest.log("info", "invalid mesecons_transistors:swicher was triggered at "
.. minetest.pos_to_string(pos) .. ", node at front is " .. switched_node.name)
return
end
if old_switched_node.param2 ~= node.param2 then
minetest.log("info", "invalid mesecons_transistors:swicher was triggered at "
.. minetest.pos_to_string(pos) .. ", node at front is from another switcher")
return
end
minetest.swap_node(switched_pos, switched_node)
mesecon.on_dignode(switched_pos, old_switched_node)
mesecon.on_placenode(switched_pos, switched_node)
end
local function switcher_off(pos, node)
if mesecon.do_overheat(pos) then
handle_overheat(pos, node)
return
end
node.name = "mesecons_transistors:switcher_off"
minetest.swap_node(pos, node)
local dir = get_dir_to_switched(node)
local switched_pos = vector.add(pos, dir)
local switched_node = mesecon.get_node_force(switched_pos)
if not switched_node then
return
end
local old_switched_node = {name = switched_node.name, param1 = switched_node.param1,
param2 = switched_node.param2}
if switched_node.name == "mesecons_transistors:normally_open_contact_closed_off" or
switched_node.name == "mesecons_transistors:normally_open_contact_closed_on" then
switched_node.name = "mesecons_transistors:normally_open_contact_open"
elseif switched_node.name == "mesecons_transistors:normally_closed_contact_open" then
switched_node.name = "mesecons_transistors:normally_closed_contact_closed_off"
else
minetest.log("info", "invalid mesecons_transistors:swicher was triggered at "
.. minetest.pos_to_string(pos) .. ", node at front is " .. switched_node.name)
return
end
if old_switched_node.param2 ~= node.param2 then
minetest.log("info", "invalid mesecons_transistors:swicher was triggered at "
.. minetest.pos_to_string(pos) .. ", node at front is from another switcher")
return
end
minetest.swap_node(switched_pos, switched_node)
mesecon.on_dignode(switched_pos, old_switched_node)
mesecon.on_placenode(switched_pos, switched_node)
end
local function do_nothing()
-- nothing
end
-- returns a fuction for on_place
-- does pretty much the same as minetest.item_place, but also places the switcher
local function get_on_place_callback(is_nc)
return function(itemstack, placer, pointed_thing)
-- Call on_rightclick if the pointed node defines it
if pointed_thing.type == "node" and placer and
not placer:get_player_control().sneak then
local n = minetest.get_node(pointed_thing.under)
local nn = n.name
if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].on_rightclick then
return minetest.registered_nodes[nn].on_rightclick(pointed_thing.under, n,
placer, itemstack, pointed_thing) or itemstack
end
end
if pointed_thing.type ~= "node" then
return itemstack
end
local nodename = is_nc and "mesecons_transistors:normally_closed_contact_closed_off" or
"mesecons_transistors:normally_open_contact_open"
local under = pointed_thing.under
local oldnode_under = minetest.get_node_or_nil(under)
local above = pointed_thing.above
local oldnode_above = minetest.get_node_or_nil(above)
local playername = placer and placer:get_player_name() or ""
local log = playername ~= "" and minetest.log or do_nothing
if not oldnode_under or not oldnode_above then
log("info", playername .. " tried to place"
.. " node in unloaded position " .. minetest.pos_to_string(above))
return itemstack
end
local olddef_under = minetest.registered_nodes[oldnode_under.name]
olddef_under = olddef_under or minetest.nodedef_default
local olddef_above = minetest.registered_nodes[oldnode_above.name]
olddef_above = olddef_above or minetest.nodedef_default
if not olddef_above.buildable_to and not olddef_under.buildable_to then
log("info", playername .. " tried to place node in invalid position " ..
minetest.pos_to_string(above) .. ", replacing " ..
oldnode_above.name)
return itemstack
end
-- Place above pointed node
local place_to = vector.new(above)
local oldnode = oldnode_above
-- If node under is buildable_to, place into it instead (eg. snow)
if olddef_under.buildable_to then
log("info", "node under is buildable to")
place_to = vector.new(under)
oldnode = oldnode_under
end
local newnode = {name = nodename, param1 = 0, param2 = 0}
-- Calculate direction
local placer_pos = placer and placer:get_pos()
if placer_pos then
local dir = vector.subtract(above, placer_pos)
newnode.param2 = minetest.dir_to_facedir(dir)
log("info", "facedir: " .. newnode.param2)
end
-- pos for switcher
local switcher_dir = get_dir_to_switcher(newnode)
local switcher_pos = vector.add(place_to, switcher_dir)
local switcher_name = "mesecons_transistors:switcher_off"
local switcher_node = {name = switcher_name, param1 = 0, param2 = newnode.param2}
local switcher_pointed_thing = {type = "node", above = vector.add(above, switcher_dir),
under = vector.add(under, switcher_dir)}
-- check if switcher pos is loaded and buildable to
local switcher_oldnode = minetest.get_node_or_nil(switcher_pos)
if not oldnode_under or not oldnode_above then
log("info", playername .. " tried to place node in unloaded position " ..
minetest.pos_to_string(switcher_pos))
return itemstack
end
local switcher_oldnode_def = minetest.registered_nodes[switcher_oldnode.name]
switcher_oldnode_def = switcher_oldnode_def or minetest.nodedef_default
if not switcher_oldnode_def.buildable_to then
log("info", playername .. " tried to place node in invalid position " ..
minetest.pos_to_string(switcher_pos) .. ", replacing " ..
switcher_oldnode.name)
return itemstack
end
-- check protection
if minetest.is_protected(place_to, playername) then
log("action", playername .. " tried to place " .. nodename ..
" at protected position " .. minetest.pos_to_string(place_to))
minetest.record_protection_violation(place_to, playername)
return itemstack
end
if minetest.is_protected(switcher_pos, playername) then
log("action", playername .. " tried to place " .. switcher_name ..
" at protected position " .. minetest.pos_to_string(switcher_pos))
minetest.record_protection_violation(switcher_pos, playername)
return itemstack
end
log("action", playername .. " places node " .. nodename .. " at " ..
minetest.pos_to_string(place_to))
-- Add nodes and update
minetest.set_node(place_to, newnode)
minetest.set_node(switcher_pos, switcher_node)
-- Play sound if it was done by a player
if playername ~= "" then
local sounds = default.node_sound_stone_defaults()
minetest.sound_play(sounds.place, {
pos = place_to,
exclude_player = playername,
}, true)
end
local take_item = true
-- Run script hook
for _, callback in ipairs(core.registered_on_placenodes) do
-- Deepcopy pos, node and pointed_thing because callback can modify them
local place_to_copy = vector.new(place_to)
local newnode_copy = {name = newnode.name, param1 = newnode.param1, param2 = newnode.param2}
local oldnode_copy = {name = oldnode.name, param1 = oldnode.param1, param2 = oldnode.param2}
local pointed_thing_copy = {type = "node", above = vector.new(above), under = vector.new(under)}
if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
take_item = false
end
end
for _, callback in ipairs(core.registered_on_placenodes) do
-- Deepcopy pos, node and pointed_thing because callback can modify them
local place_to_copy = vector.new(switcher_pos)
local newnode_copy = {name = switcher_node.name, param1 = switcher_node.param1, param2 = switcher_node.param2}
local oldnode_copy = {name = switcher_oldnode.name, param1 = switcher_oldnode.param1, param2 = switcher_oldnode.param2}
local pointed_thing_copy = {type = "node", above = vector.new(switcher_pointed_thing.above),
under = vector.new(switcher_pointed_thing.under)}
if callback(place_to_copy, newnode_copy, placer, oldnode_copy, itemstack, pointed_thing_copy) then
take_item = false
end
end
if take_item then
itemstack:take_item()
end
return itemstack
end
end
local function transistor_after_dig_node(pos, oldnode, _, _)
local switcher_pos = vector.add(pos, get_dir_to_switcher(oldnode))
local old_switcher_node = mesecon.get_node_force(switcher_pos)
if not old_switcher_node or old_switcher_node.param2 ~= oldnode.param2 or
(old_switcher_node.name ~= "mesecons_transistors:switcher_off" and
old_switcher_node.name ~= "mesecons_transistors:switcher_on") then
return
end
minetest.remove_node(switcher_pos)
mesecon.do_cooldown(switcher_pos)
mesecon.on_dignode(pos, old_switcher_node)
end
local function switcher_on_dig(pos, node, digger)
local conductor_pos = vector.add(pos, get_dir_to_switched(node))
local conductor_node = mesecon.get_node_force(conductor_pos)
if not conductor_node or conductor_node.param2 ~= node.param2 or
not is_transistor_node[conductor_node.name] then
return false
end
return minetest.node_dig(conductor_pos, conductor_node, digger)
end
local function generate_tiles(is_nc, is_closed, is_on)
local tiles = {
"jeija_microcontroller_bottom.png^mesecons_transistors_basepattern.png"..
"^(mesecons_wire_off.png^[mask:mesecons_transistors_wire_mask.png)"..
"^mesecons_transistors_no_open.png",
"jeija_microcontroller_bottom.png",
"jeija_microcontroller_bottom.png^jeija_gate_side_output_off.png",
"jeija_microcontroller_bottom.png^jeija_gate_side_output_off.png",
"jeija_microcontroller_bottom.png",
"jeija_microcontroller_bottom.png^jeija_gate_side_output_off.png",
}
-- conductor wire
local is_on_str = is_on and "on" or "off"
tiles[1] = tiles[1] .. "^(mesecons_wire_" .. is_on_str ..
".png^[mask:mesecons_transistors_wire_mask.png)"
tiles[3] = tiles[3] .. "^jeija_gate_side_output_" .. is_on_str .. ".png"
tiles[4] = tiles[4] .. "^jeija_gate_side_output_" .. is_on_str .. ".png"
-- effector wire and closed/opened stuff
tiles[1] = tiles[1] .. "^mesecons_transistors_" .. (is_nc and "nc" or "no")
.. "_" .. (is_closed and "closed" or "open") .. ".png"
tiles[6] = tiles[6] .. "^jeija_gate_side_output_" ..
(is_nc == is_closed and "off" or "on") .. ".png"
return tiles
end
mesecon.register_node("mesecons_transistors:switcher", {
description = "You hacker you!",
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
drawtype = "nodebox",
node_box = node_box,
sounds = default.node_sound_stone_defaults(),
groups = {dig_immediate = 2, not_in_creative_inventory = 1, overheat = 1},
drop = "",
on_dig = switcher_on_dig,
on_rotate = false,
}, {
tiles = {
"jeija_microcontroller_bottom.png"..
"^(mesecons_wire_off.png^[mask:mesecons_transistors_switcher_mask.png)",
"jeija_microcontroller_bottom.png",
"jeija_microcontroller_bottom.png",
"jeija_microcontroller_bottom.png",
"jeija_microcontroller_bottom.png^jeija_gate_side_output_off.png",
"jeija_microcontroller_bottom.png",
},
mesecons = {effector = {
rules = get_switcher_inputrules,
action_on = switcher_on,
}},
}, {
tiles = {
"jeija_microcontroller_bottom.png"..
"^(mesecons_wire_on.png^[mask:mesecons_transistors_switcher_mask.png)",
"jeija_microcontroller_bottom.png",
"jeija_microcontroller_bottom.png",
"jeija_microcontroller_bottom.png",
"jeija_microcontroller_bottom.png^jeija_gate_side_output_on.png",
"jeija_microcontroller_bottom.png",
},
mesecons = {effector = {
rules = get_switcher_inputrules,
action_off = switcher_off,
}}
})
minetest.register_node("mesecons_transistors:normally_open_contact_open", {
description = "N/O contact",
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
drawtype = "nodebox",
node_box = node_box,
node_placement_prediction = "",
sounds = default.node_sound_stone_defaults(),
groups = {dig_immediate = 2},
tiles = generate_tiles(false, false, false),
mesecons = {receptor = { -- pseudo-receptor to keep wires connected
state = mesecon.state.off,
rules = get_conductorrules,
}},
on_place = get_on_place_callback(false),
after_dig_node = transistor_after_dig_node,
on_rotate = false,
on_blast = mesecon.on_blastnode,
})
mesecon.register_node("mesecons_transistors:normally_open_contact_closed", {
description = "N/O contact (You hacker you!)",
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
drawtype = "nodebox",
drop = "mesecons_transistors:normally_open_contact_open",
node_box = node_box,
sounds = default.node_sound_stone_defaults(),
groups = {dig_immediate = 2, not_in_creative_inventory = 1},
after_dig_node = transistor_after_dig_node,
on_rotate = false,
}, {
tiles = generate_tiles(false, true, false),
mesecons = {conductor = {
state = mesecon.state.off,
onstate = "mesecons_transistors:normally_open_contact_closed_on",
rules = get_conductorrules,
}},
}, {
tiles = generate_tiles(false, true, true),
mesecons = {conductor = {
state = mesecon.state.on,
offstate = "mesecons_transistors:normally_open_contact_closed_off",
rules = get_conductorrules,
}},
})
minetest.register_node("mesecons_transistors:normally_closed_contact_open", {
description = "N/C contact (You hacker you!)",
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
drawtype = "nodebox",
drop = "mesecons_transistors:normally_closed_contact_closed_off",
node_box = node_box,
sounds = default.node_sound_stone_defaults(),
groups = {dig_immediate = 2, not_in_creative_inventory = 1},
tiles = generate_tiles(true, false, false),
mesecons = {receptor = { -- pseudo-receptor to keep wires connected
state = mesecon.state.off,
rules = get_conductorrules,
}},
after_dig_node = transistor_after_dig_node,
on_rotate = false,
on_blast = mesecon.on_blastnode,
})
mesecon.register_node("mesecons_transistors:normally_closed_contact_closed", {
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
drawtype = "nodebox",
drop = "mesecons_transistors:normally_closed_contact_closed_off",
node_box = node_box,
sounds = default.node_sound_stone_defaults(),
after_dig_node = transistor_after_dig_node,
on_rotate = false,
}, {
description = "N/C contact",
node_placement_prediction = "",
groups = {dig_immediate = 2},
tiles = generate_tiles(true, true, false),
mesecons = {conductor = {
state = mesecon.state.off,
onstate = "mesecons_transistors:normally_closed_contact_closed_on",
rules = get_conductorrules,
}},
on_place = get_on_place_callback(true),
}, {
description = "N/C contact (You hacker you!)",
groups = {dig_immediate = 2, not_in_creative_inventory = 1},
tiles = generate_tiles(true, true, true),
mesecons = {conductor = {
state = mesecon.state.on,
offstate = "mesecons_transistors:normally_closed_contact_closed_off",
rules = get_conductorrules,
}},
})
mesecon.register_mvps_stopper("mesecons_transistors:switcher_on")
mesecon.register_mvps_stopper("mesecons_transistors:switcher_off")
mesecon.register_mvps_stopper("mesecons_transistors:normally_open_contact_open")
mesecon.register_mvps_stopper("mesecons_transistors:normally_open_contact_closed_off")
mesecon.register_mvps_stopper("mesecons_transistors:normally_open_contact_closed_on")
mesecon.register_mvps_stopper("mesecons_transistors:normally_closed_contact_open")
mesecon.register_mvps_stopper("mesecons_transistors:normally_closed_contact_closed_off")
mesecon.register_mvps_stopper("mesecons_transistors:normally_closed_contact_closed_on")

View File

@ -0,0 +1,2 @@
name = mesecons_transistors
depends = mesecons, default, mesecons_gates, mesecons_mvps

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB