510 lines
18 KiB
Lua
510 lines
18 KiB
Lua
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")
|
||
|