2024-12-10 02:34:33 +01:00

510 lines
18 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local TRIGGER_MODE_SENDER = 0
local TRIGGER_MODE_RECEIVER = 1
local TRIGGER_MODE_SIGNAL_TYPE = 2
local TRIGGER_MODE_RECEIVER_TYPE = 3
local TRIGGER_MODE_RESET = 4
local TRIGGER_MODE_INFO = 5
local TRIGGER_MODE_MAX = 5
local S = minetest.get_translator("lzr_laser")
local trigger_tool_crosshairs = {}
local selected_senders = {}
minetest.register_tool("lzr_laser:block_state_toggler", {
description = S("Block State Toggler"),
_tt_help = S("Turns blocks on or off"),
inventory_image = "lzr_laser_emitter_toggler.png",
groups = { editor_tool = 1 },
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local uname = user:get_player_name()
local state = lzr_gamestate.get_state()
if state ~= lzr_gamestate.EDITOR and state ~= lzr_gamestate.DEV then
minetest.chat_send_player(uname, S("This tool only works in the level editor or development mode."))
return itemstack
end
local pos = pointed_thing.under
local node = minetest.get_node(pos)
local def = minetest.registered_nodes[node.name]
if def._lzr_on_toggle then
def._lzr_on_toggle(pos, node)
end
return itemstack
end,
})
minetest.register_tool("lzr_laser:color_changer", {
description = S("Color Changer"),
_tt_help = S("Changes block color"),
inventory_image = "lzr_laser_color_changer.png",
groups = { editor_tool = 1 },
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local state = lzr_gamestate.get_state()
local uname = user:get_player_name()
if state ~= lzr_gamestate.EDITOR and state ~= lzr_gamestate.DEV then
minetest.chat_send_player(uname, S("This tool only works in the level editor or development mode."))
return itemstack
end
local pos = pointed_thing.under
local node = minetest.get_node(pos)
local def = minetest.registered_nodes[node.name]
if def._lzr_next_color then
node.name = def._lzr_next_color
minetest.swap_node(pos, node)
minetest.sound_play({name="lzr_laser_change_color", gain=0.4}, {pos=pos}, true)
local minpos, maxpos = lzr_world.get_level_bounds()
if state == lzr_gamestate.EDITOR then
lzr_laser.full_laser_update(minpos, maxpos)
end
end
return itemstack
end,
on_place = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local state = lzr_gamestate.get_state()
local uname = user:get_player_name()
if state ~= lzr_gamestate.EDITOR and state ~= lzr_gamestate.DEV then
minetest.chat_send_player(uname, S("This tool only works in the level editor or development mode."))
return itemstack
end
local pos = pointed_thing.under
local node = minetest.get_node(pos)
local def = minetest.registered_nodes[node.name]
if def._lzr_prev_color then
node.name = def._lzr_prev_color
minetest.swap_node(pos, node)
minetest.sound_play({name="lzr_laser_change_color", gain=0.4}, {pos=pos}, true)
local minpos, maxpos = lzr_world.get_level_bounds()
if state == lzr_gamestate.EDITOR then
lzr_laser.full_laser_update(minpos, maxpos)
end
end
return itemstack
end,
})
minetest.register_tool("lzr_laser:screw_changer", {
description = S("Screw Changer"),
_tt_help = S("Cycles through screw types for blocks"),
inventory_image = "lzr_laser_screw_changer.png",
groups = { editor_tool = 1 },
pointabilities = {
nodes = {
["group:skull"] = true,
},
},
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local state = lzr_gamestate.get_state()
local uname = user:get_player_name()
if state ~= lzr_gamestate.EDITOR and state ~= lzr_gamestate.DEV then
minetest.chat_send_player(uname, S("This tool only works in the level editor or development mode."))
return itemstack
end
local pos = pointed_thing.under
local node = minetest.get_node(pos)
if minetest.get_item_group(node.name, "laser_block") == 0 then
return itemstack
end
local def = minetest.registered_nodes[node.name]
local next_node
-- Takable node
if minetest.get_item_group(node.name, "takable") ~= 0 then
if def._lzr_fixed then
next_node = def._lzr_fixed
end
-- Rotatable node
elseif minetest.get_item_group(node.name, "rotatable") == 1 then
if def._lzr_takable then
next_node = def._lzr_takable
elseif def._lzr_fixed then
next_node = def._lzr_fixed
end
-- Fixed node
else
if def._lzr_rotatable then
next_node = def._lzr_rotatable
elseif def._lzr_takable then
next_node = def._lzr_takable
end
end
if next_node then
node.name = next_node
minetest.swap_node(pos, node)
minetest.sound_play({name="lzr_laser_change_screw", gain=0.4}, {pos=pos}, true)
end
return itemstack
end,
on_place = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local state = lzr_gamestate.get_state()
local uname = user:get_player_name()
if state ~= lzr_gamestate.EDITOR and state ~= lzr_gamestate.DEV then
minetest.chat_send_player(uname, S("This tool only works in the level editor or development mode."))
return itemstack
end
local pos = pointed_thing.under
local node = minetest.get_node(pos)
if minetest.get_item_group(node.name, "laser_block") == 0 then
return itemstack
end
local def = minetest.registered_nodes[node.name]
local next_node
-- Takable node
if minetest.get_item_group(node.name, "takable") ~= 0 then
if def._lzr_rotatable then
next_node = def._lzr_rotatable
elseif def._lzr_fixed then
next_node = def._lzr_fixed
end
-- Rotatable node
elseif minetest.get_item_group(node.name, "rotatable") == 1 then
if def._lzr_fixed then
next_node = def._lzr_fixed
elseif def._lzr_takable then
next_node = def._lzr_takable
end
-- Fixed node
else
if def._lzr_takable then
next_node = def._lzr_takable
elseif def._lzr_rotatable then
next_node = def._lzr_rotatable
end
end
if next_node then
node.name = next_node
minetest.swap_node(pos, node)
minetest.sound_play({name="lzr_laser_change_screw", gain=0.4}, {pos=pos}, true)
end
return itemstack
end,
})
local trigger_tool_modeinfo = {
[TRIGGER_MODE_SENDER] = {
img = "lzr_laser_trigger_tool_sender.png",
name = S("Sender Mode"),
description = S("Punch node to select a sender to add receivers to in Receiver Mode"),
},
[TRIGGER_MODE_RECEIVER] = {
img = "lzr_laser_trigger_tool_receiver.png",
name = S("Receiver Mode"),
description = S("Punch node to add a node as a receiver to the list of receivers of the selected sender from Sender Mode"),
},
[TRIGGER_MODE_SIGNAL_TYPE] = {
img = "lzr_laser_trigger_tool_signal_type.png",
name = S("Signal Type Mode"),
description = S("Punch sender node to change its signal type"),
},
[TRIGGER_MODE_RECEIVER_TYPE] = {
img = "lzr_laser_trigger_tool_receiver_type.png",
name = S("Receiver Type Mode"),
description = S("Punch receiver node to change its receiver type"),
},
[TRIGGER_MODE_RESET] = {
img = "lzr_laser_trigger_tool_reset.png",
name = S("Reset Mode"),
description = S("Punch sender or receiver to remove all its trigger information"),
},
[TRIGGER_MODE_INFO] = {
img = "lzr_laser_trigger_tool_info.png",
name = S("Info Mode"),
description = S("Punch node to expose its current trigger relations"),
},
}
local function construct_trigger_tool_description(mode)
local MODE_COLOR = "#fff020"
local HELP_COLOR = "#ffd0d0"
--~ Tool in level editor to change triggers
return S("Trigger Tool").."\n"..
minetest.colorize(MODE_COLOR, trigger_tool_modeinfo[mode].name).."\n"..
minetest.colorize(HELP_COLOR, trigger_tool_modeinfo[mode].description).."\n"..
minetest.colorize(HELP_COLOR, S("Place to change mode"))
end
local function add_sender_crosshair(player, pos)
local id = player:hud_add({
type = "image_waypoint",
text = "lzr_laser_particle_crosshair.png^[opacity:200",
offset = { x = 0, y = 0 },
scale = { x = 8, y = 8 },
z_index = -295,
world_pos = pos,
})
if id then
trigger_tool_crosshairs[player:get_player_name()] = {
time = 0,
id = id,
}
end
end
minetest.register_tool("lzr_laser:trigger_tool", {
description = construct_trigger_tool_description(TRIGGER_MODE_SENDER),
short_description = S("Trigger Tool"),
-- This tool handles its tooltip extension itself
_tt_ignore = true,
inventory_image = "lzr_laser_trigger_tool_sender.png",
groups = { editor_tool = 1 },
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local uname = user:get_player_name()
if lzr_gamestate.get_state() ~= lzr_gamestate.EDITOR then
minetest.chat_send_player(uname, S("This tool only works in the level editor."))
return itemstack
end
local pos = pointed_thing.under
local minpos, maxpos = lzr_world.get_level_bounds()
if not vector.in_area(pos, minpos, maxpos) then
minetest.chat_send_player(uname, S("This node is outside the level area."))
return itemstack
end
local node = minetest.get_node(pos)
if minetest.get_item_group(node.name, "sender") == 0 and minetest.get_item_group(node.name, "receiver") == 0 then
minetest.chat_send_player(uname, S("This node is neither a sender nor a receiver."))
return itemstack
end
local imeta = itemstack:get_meta()
local nmeta = minetest.get_meta(pos)
local mode = imeta:get_int("mode")
if mode == TRIGGER_MODE_SENDER then
if minetest.get_item_group(node.name, "sender") == 0 then
minetest.chat_send_player(uname, S("This node isnt a sender."))
return itemstack
end
local meta = minetest.get_meta(pos)
local trigger_id = meta:get_string("trigger_id")
if not lzr_triggers.trigger_exists(trigger_id) then
minetest.chat_send_player(uname, S("ERROR: This node wasnt initialized as a trigger!"))
return itemstack
end
selected_senders[uname] = trigger_id
-- Show crosshair at position
if trigger_tool_crosshairs[uname] then
user:hud_change(trigger_tool_crosshairs[uname].id, "world_pos", pos)
else
add_sender_crosshair(user, pos)
end
minetest.chat_send_player(uname, S("Now setting receivers for sender: @1", trigger_id))
elseif mode == TRIGGER_MODE_RECEIVER then
if minetest.get_item_group(node.name, "receiver") == 0 then
minetest.chat_send_player(uname, S("This node isnt a receiver."))
return itemstack
end
local current_sender_str = selected_senders[uname] or ""
local current_sender_pos = minetest.string_to_pos(current_sender_str)
if not current_sender_pos then
minetest.chat_send_player(uname, S("Select a sender in Sender Mode first!"))
return itemstack
end
local meta = minetest.get_meta(current_sender_pos)
local sender_id = meta:get_string("trigger_id")
if not lzr_triggers.trigger_exists(sender_id) then
minetest.chat_send_player(uname, S("The selected sender no longer exists."))
selected_senders[uname] = nil
if trigger_tool_crosshairs[uname] then
user:hud_remove(trigger_tool_crosshairs[uname].id)
trigger_tool_crosshairs[uname] = nil
end
return itemstack
end
local receiver_id = minetest.pos_to_string(pos)
local added = lzr_triggers.add_signal(sender_id, receiver_id)
if added then
minetest.chat_send_player(uname, S("Added signal from sender @1 to receiver @2.", sender_id, receiver_id))
else
minetest.chat_send_player(uname, S("This receiver was already added to the receiver list of the sender at @1.", sender_id))
end
lzr_laser.show_trigger_info(sender_id, user, true)
elseif mode == TRIGGER_MODE_SIGNAL_TYPE then
if minetest.get_item_group(node.name, "sender") == 0 then
minetest.chat_send_player(uname, S("This node isnt a sender."))
return itemstack
end
local meta = minetest.get_meta(pos)
local trigger_id = meta:get_string("trigger_id")
if not lzr_triggers.trigger_exists(trigger_id) then
minetest.chat_send_player(uname, S("ERROR: This node wasnt initialized as a trigger!"))
return itemstack
end
local trigger = lzr_triggers.get_trigger(trigger_id)
local signal_type = trigger.signal_type or 0
signal_type = signal_type + 1
if signal_type > lzr_triggers.MAX_SIGNAL_TYPE then
signal_type = 0
end
lzr_triggers.set_trigger_signal_type(trigger_id, signal_type)
--~ @1: short signal type name, @2: long signal type description
local signal_description = S("@1 (@2)", lzr_triggers.SIGNAL_TYPE_NAMES[signal_type], lzr_triggers.SIGNAL_TYPE_DESCRIPTIONS[signal_type])
if not signal_description then
signal_description = tostring(signal_type)
end
lzr_laser.show_trigger_info(trigger_id, user, true)
minetest.chat_send_player(uname, S("Signal type of sender @1 changed to @2.", trigger_id, signal_description))
elseif mode == TRIGGER_MODE_RECEIVER_TYPE then
if minetest.get_item_group(node.name, "receiver") == 0 then
minetest.chat_send_player(uname, S("This node isnt a receiver."))
return itemstack
end
local meta = minetest.get_meta(pos)
local trigger_id = meta:get_string("trigger_id")
if not lzr_triggers.trigger_exists(trigger_id) then
minetest.chat_send_player(uname, S("ERROR: This node wasnt initialized as a trigger!"))
return itemstack
end
local trigger = lzr_triggers.get_trigger(trigger_id)
local receiver_type = trigger.receiver_type or 0
receiver_type = receiver_type + 1
if receiver_type > lzr_triggers.MAX_RECEIVER_TYPE then
receiver_type = 0
end
lzr_triggers.set_trigger_receiver_type(trigger_id, receiver_type)
--~ @1: short receiver type name, @2: long receiver type description
local receiver_type_description = S("@1 (@2)", lzr_triggers.RECEIVER_TYPE_NAMES[receiver_type], lzr_triggers.RECEIVER_TYPE_DESCRIPTIONS[receiver_type])
if not receiver_type_description then
receiver_type_description = tostring(receiver_type)
end
lzr_laser.show_trigger_info(trigger_id, user, true)
minetest.chat_send_player(uname, S("Receiver type of receiver @1 changed to @2.", trigger_id, receiver_type_description))
elseif mode == TRIGGER_MODE_RESET then
local meta = minetest.get_meta(pos)
local trigger_id = meta:get_string("trigger_id")
if not lzr_triggers.trigger_exists(trigger_id) then
minetest.chat_send_player(uname, S("ERROR: This node wasnt initialized as a trigger!"))
return itemstack
end
lzr_triggers.set_signals(trigger_id, {})
lzr_triggers.set_trigger_signal_type(trigger_id, 0)
lzr_triggers.set_trigger_receiver_type(trigger_id, 0)
--~ Node was reset at @1.
minetest.chat_send_player(uname, S("Reset node at @1.", minetest.pos_to_string(pos)))
elseif mode == TRIGGER_MODE_INFO then
local meta = minetest.get_meta(pos)
local trigger_id = meta:get_string("trigger_id")
if not lzr_triggers.trigger_exists(trigger_id) then
minetest.chat_send_player(uname, S("ERROR: This node wasnt initialized as a trigger!"))
return itemstack
end
local send_to, receive_from, send_to_str, receive_from_str
local is_sender = minetest.get_item_group(node.name, "sender") ~= 0
local is_receiver = minetest.get_item_group(node.name, "receiver") ~= 0
if is_sender then
send_to = lzr_triggers.get_receivers(trigger_id)
if #send_to > 0 then
local send_to_concat = {}
for s=1, #send_to do
table.insert(send_to_concat, send_to[s])
end
--~ list separator
send_to_str = table.concat(send_to_concat, S(", "))
end
end
if is_receiver then
receive_from = lzr_triggers.get_senders(trigger_id)
if #receive_from > 0 then
local receive_from_concat = {}
for r=1, #receive_from do
table.insert(receive_from_concat, receive_from[r])
end
receive_from_str = table.concat(receive_from_concat, S(", "))
end
end
if send_to_str then
minetest.chat_send_player(uname, S("This node sends to: @1", send_to_str))
end
if receive_from_str then
minetest.chat_send_player(uname, S("This node receives from: @1", receive_from_str))
end
if is_sender and is_receiver and not send_to_str and not receive_from_str then
minetest.chat_send_player(uname, S("This node is a sender and receiver. It neither sends nor receives signals."))
elseif is_receiver and not receive_from_str then
minetest.chat_send_player(uname, S("This node is a receiver. It does not receive signals."))
elseif is_sender and not send_to_str then
minetest.chat_send_player(uname, S("This node is a sender. It does not send signals."))
end
lzr_laser.show_trigger_info(trigger_id, user, true)
end
return itemstack
end,
on_place = function(itemstack, user, pointed_thing)
local imeta = itemstack:get_meta()
local mode = imeta:get_int("mode")
mode = (mode + 1) % (TRIGGER_MODE_MAX+1)
imeta:set_int("mode", mode)
imeta:set_string("description", construct_trigger_tool_description(mode))
imeta:set_string("inventory_image", trigger_tool_modeinfo[mode].img)
local modename = trigger_tool_modeinfo[mode].name
local uname = user:get_player_name()
--~ Trigger tool was set to the new mode @1
minetest.chat_send_player(uname, S("Tool set to @1!", modename))
return itemstack
end,
})
local timer = 0
local CROSSHAIR_STEP = 0.5
local CROSSHAIR_TIME_MAX = 1.0
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer < CROSSHAIR_STEP then
return
end
timer = 0
local players = minetest.get_connected_players()
for p=1, #players do
local player = players[p]
local pname = player:get_player_name()
local wield = player:get_wielded_item()
local ttc = trigger_tool_crosshairs[pname]
if wield:get_name() == "lzr_laser:trigger_tool" then
if not ttc then
local sid = selected_senders[pname]
local spos = minetest.string_to_pos(sid)
if spos then
add_sender_crosshair(player, spos)
end
end
else
if ttc then
ttc.time = ttc.time + dtime + CROSSHAIR_STEP
if ttc.time > CROSSHAIR_TIME_MAX then
player:hud_remove(ttc.id)
trigger_tool_crosshairs[pname] = nil
end
end
end
end
end)
minetest.register_on_leaveplayer(function(player)
trigger_tool_crosshairs[player:get_player_name()] = nil
selected_senders[player:get_player_name()] = nil
end)
-- The Block State Toggler replaces the Emitter Toggler
minetest.register_alias("lzr_laser:emit_toggler", "lzr_laser:block_state_toggler")