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 isn’t 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 wasn’t 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 isn’t 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 isn’t 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 wasn’t 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 isn’t 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 wasn’t 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 wasn’t 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 wasn’t 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")