Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add access cards #88

Merged
merged 7 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 254 additions & 0 deletions access_card.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
local FORMSPEC_NAME = "scifi_nodes:access_card_configure"

local function create_id()
local template = "xxxxxx"
return string.gsub(template, '[x]', function ()
return string.format('%x', math.random(0, 0xf))
end)
end

local function get_door_access_table(meta)
local str = meta:get_string("access")
if str == "" then
-- no config
return {}
else
return minetest.deserialize(str) or {}
end
end

local function set_door_access_table(meta, at)
if next(at) then
meta:set_string("access", minetest.serialize(at))
else
meta:set_string("access", "")
end
end

function scifi_nodes.door_check_access_card(node_pos, itemstack, player)
local node_meta = minetest.get_meta(node_pos)
local access_table = get_door_access_table(node_meta)
if not next(access_table) then
-- access not restricted
return true
end

local playername = player:get_player_name()

if itemstack:get_name() ~= "scifi_nodes:access_card" then
minetest.chat_send_player(playername, minetest.colorize("#ff0000", "Access denied: no access card detected!"))
minetest.sound_play("scifi_nodes_scanner_refused", { pos = node_pos, max_hear_distance = 10 })
return false
end

local item_meta = itemstack:get_meta()
local id = item_meta:get_string("id")
if id == "" then
minetest.chat_send_player(playername, minetest.colorize("#ff0000", "Access denied: unconfigured access card"))
minetest.sound_play("scifi_nodes_scanner_refused", { pos = node_pos, max_hear_distance = 10 })
return false
end

if not access_table[id] then
minetest.chat_send_player(playername, minetest.colorize("#ff0000", "Access denied: invalid access card"))
minetest.sound_play("scifi_nodes_scanner_refused", { pos = node_pos, max_hear_distance = 10 })
return false
end

minetest.sound_play("scifi_nodes_scanner_granted", { pos = node_pos, max_hear_distance = 10 })
return true
end

-- using a card against a door toggles the access to it
local function on_use(itemstack, player, pointed_thing)
local playername = player:get_player_name()
local pos = pointed_thing.under

if not pos then
-- nothing selected
return
end

if minetest.is_protected(pos, playername) then
-- protected
return
end

local node = minetest.get_node(pos)
local node_def = minetest.registered_nodes[node.name]
if not node_def.groups or not node_def.groups.scifi_nodes_door then
-- incompatible node
return
end

local item_meta = itemstack:get_meta()
local card_id = item_meta:get_string("id")
if card_id == "" then
minetest.chat_send_player(playername, "Access card is unconfigured")
return
end
local card_name = item_meta:get_string("name")

local node_meta = minetest.get_meta(pos)
local access_table = get_door_access_table(node_meta)

if access_table[card_id] then
-- remove access
access_table[card_id] = nil
minetest.chat_send_player(playername, "Revoked access to card-id '" .. card_id .. "'")
minetest.sound_play("scifi_nodes_scanner_refused", { pos = pos, max_hear_distance = 10 })
else
-- grant access
access_table[card_id] = card_name
minetest.chat_send_player(playername, "Granted access to card-id '" .. card_id .. "'")
minetest.sound_play("scifi_nodes_scanner_granted", { pos = pos, max_hear_distance = 10 })
end

local msg = ""
if next(access_table) then
msg = msg .. "Current registered cards: "
for id, name in pairs(access_table) do
msg = msg .. "Name: '" .. name .. "' ID: '" .. id .. "' / "
end
else
-- access table is empty
msg = "No access-card left in access-table, door is free to use"
end
minetest.chat_send_player(playername, msg)

-- set new access table
set_door_access_table(node_meta, access_table)
end

local function configure_access_card(meta, name)
local id = meta:get_string("id")
if id == "" then
-- set new id
id = create_id()
meta:set_string("id", id)
end

meta:set_string("name", name)
meta:set_string("description", "Access card '" .. name .. "' (id: '" .. id .. "')")
end

-- right-click with a card for rename/configuration
local function on_secondary_use(itemstack, player, pointed_thing)
local meta = itemstack:get_meta()
if meta:get_string("id") == "" then
-- initial configuration
configure_access_card(meta, "")
end
local name = meta:get_string("name")

minetest.show_formspec(player:get_player_name(), FORMSPEC_NAME, [[
size[10,1.4]
real_coordinates[true]
field[0.1,0.4;7,0.8;name;Name;]] .. minetest.formspec_escape(name) .. [[]
button_exit[7.3,0.4;2.5,0.8;save;Save]
]])

return itemstack
end

minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= FORMSPEC_NAME then
-- wrong formspec
return false
end

if not fields.save and not fields.key_enter_field then
-- quit
return true
end

local itemstack = player:get_wielded_item()
if itemstack:get_name() ~= "scifi_nodes:access_card" then
-- invalid item
return true
end

local meta = itemstack:get_meta()
configure_access_card(meta, fields.name or "")
player:set_wielded_item(itemstack)
end)

minetest.register_craftitem("scifi_nodes:access_card", {
description = "Access card (unconfigured)",
inventory_image = "scifi_nodes_access_card.png",
palette = "unifieddyes_palette_extended.png",
stack_max = 1,
paramtype2 = "color",
on_use = on_use,
on_secondary_use = on_secondary_use,
groups = {
ud_param2_colorable = 1
}
})

-- initial recipe
minetest.register_craft({
output = "scifi_nodes:access_card",
recipe = {
{"scifi_nodes:white2", "", ""},
{"scifi_nodes:white_pad", "", ""},
{"scifi_nodes:white2", "", ""}
}
})

-- copy recipe
minetest.register_craft({
output = "scifi_nodes:access_card",
recipe = {
{"scifi_nodes:access_card", "scifi_nodes:white_pad", ""},
{"", "", ""},
{"", "", ""}
}
})

minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
if itemstack:get_name() ~= "scifi_nodes:access_card" then
return
end

local original
local index
for i = 1, #old_craft_grid do
if old_craft_grid[i]:get_name() == "scifi_nodes:access_card" then
original = old_craft_grid[i]
index = i
break
end
end
if not original then
return
end

-- copy metadata
local src_meta = original:get_meta()
local dst_meta = itemstack:get_meta()
local copy_fields = {"id", "name", "description"}
for _, fieldname in ipairs(copy_fields) do
dst_meta:set_string(fieldname, src_meta:get_string(fieldname))
end

if old_craft_grid[2]:get_name() == "scifi_nodes:white_pad" then
-- keep original item if the copy-recipe is used
craft_inv:set_stack("craft", index, original)
end
end)

if minetest.get_modpath("unifieddyes") then
-- add colored crafts
unifieddyes.register_color_craft({
output = "scifi_nodes:access_card",
palette = "extended",
neutral_node = "scifi_nodes:access_card",
recipe = {
"NEUTRAL_NODE",
"MAIN_DYE"
},
type = "shapeless"
})

end
20 changes: 12 additions & 8 deletions doors.lua
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,18 @@ for _, current_door in ipairs(doors) do

local adjacent = minetest.get_node({x=x, y=y, z=z})
if adjacent.name == target_opposite then
minetest.set_node({x=x, y=y, z=z}, {name=target, param2 = adjacent.param2})
minetest.set_node({x=x, y=y+1, z=z}, {name=target_top, param2 = adjacent.param2})
minetest.swap_node({x=x, y=y, z=z}, {name=target, param2 = adjacent.param2})
minetest.swap_node({x=x, y=y+1, z=z}, {name=target_top, param2 = adjacent.param2})
end
end

end

local function open_door(pos, node)
local function open_door(pos, node, player, itemstack)
if not scifi_nodes.door_check_access_card(pos, itemstack, player) then
return
end

-- play sound
minetest.sound_play(sound,{
max_hear_distance = 16,
Expand All @@ -165,8 +169,8 @@ for _, current_door in ipairs(doors) do

local timer = minetest.get_node_timer(pos)

minetest.set_node(pos, {name=opened, param2=node.param2})
minetest.set_node({x=pos.x,y=pos.y+1,z=pos.z}, {name=opened_top, param2=node.param2})
minetest.swap_node(pos, {name=opened, param2=node.param2})
minetest.swap_node({x=pos.x,y=pos.y+1,z=pos.z}, {name=opened_top, param2=node.param2})

change_adjacent(opened, pos, node)

Expand All @@ -188,8 +192,8 @@ for _, current_door in ipairs(doors) do

local node = minetest.get_node(pos)

minetest.set_node(pos, {name=closed, param2=node.param2})
minetest.set_node({x=pos.x,y=pos.y+1,z=pos.z}, {name=closed_top, param2=node.param2})
minetest.swap_node(pos, {name=closed, param2=node.param2})
minetest.swap_node({x=pos.x,y=pos.y+1,z=pos.z}, {name=closed_top, param2=node.param2})

change_adjacent(closed, pos, node)
end
Expand Down Expand Up @@ -242,7 +246,7 @@ for _, current_door in ipairs(doors) do
paramtype2 = "facedir",
groups = {
cracky = 3,
oddly_breakable_by_hand = 1,
dig_generic = 3,
scifi_nodes_door = 1,
door = 1
},
Expand Down
1 change: 1 addition & 0 deletions init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ end
dofile(MP.."/plants.lua")
dofile(MP.."/models.lua")
dofile(MP.."/nodes.lua")
dofile(MP.."/access_card.lua")
dofile(MP.."/doors.lua")
dofile(MP.."/switch.lua")
dofile(MP.."/protected_switch.lua")
Expand Down
Binary file added textures/scifi_nodes_access_card.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.