commit 53466eed17794533dc95d728c454f6fbe8be7375 Author: rainer Date: Thu Feb 12 12:21:21 2026 +0100 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/handlers.lua b/handlers.lua new file mode 100644 index 0000000..4b38171 --- /dev/null +++ b/handlers.lua @@ -0,0 +1,205 @@ +-- 5. FORMSPEC HANDLER +minetest.register_on_player_receive_fields(function(player, formname, fields) + local name = player:get_player_name() + + -- --- ADMIN PANEL --- + if formname:sub(1, 18) == "smart_light:admin_" then + local pos_str = formname:sub(19) + local pos = minetest.string_to_pos(pos_str) + local meta = minetest.get_meta(pos) + local area = meta:get_string("area_id") + + if fields.chan_list then + local evt = minetest.explode_textlist_event(fields.chan_list) + if evt.type == "CHG" or evt.type == "DCL" then meta:set_int("selected_chan_idx", evt.index) end + end + + if fields.save_admin and fields.new_area ~= "" then + meta:set_string("area_id", fields.new_area) + smart_light.registry.areas[fields.new_area] = smart_light.registry.areas[fields.new_area] or { channels = {} } + smart_light.save() + minetest.show_formspec(name, formname, smart_light.get_admin_fs(fields.new_area)) + end + + if fields.del_chan then + local idx = meta:get_int("selected_chan_idx") + if idx > 0 then + local channels = {} + if smart_light.registry.areas[area] then + for c_id, _ in pairs(smart_light.registry.areas[area].channels) do table.insert(channels, c_id) end + table.sort(channels) + end + local target = channels[idx] + if target then + local c_data = smart_light.registry.areas[area].channels[target] + -- Lampen Reset + for p_str, _ in pairs(c_data.nodes or {}) do + local l_pos = minetest.string_to_pos(p_str) + local l_node = minetest.get_node(l_pos) + local original = smart_light.shadow_to_original[l_node.name] or l_node.name + minetest.swap_node(l_pos, {name = original, param2 = l_node.param2}) + local l_meta = minetest.get_meta(l_pos) + l_meta:set_string("sl_area", "") + l_meta:set_string("sl_chan", "") + end + -- Schalter Reset + for s_str, _ in pairs(c_data.switches or {}) do + local s_pos = minetest.string_to_pos(s_str) + minetest.swap_node(s_pos, {name = "smart_light:switch"}) + local s_meta = minetest.get_meta(s_pos) + s_meta:set_string("sl_area", "") + s_meta:set_string("sl_chan", "") + s_meta:set_string("infotext", "") + end + smart_light.registry.areas[area].channels[target] = nil + smart_light.save() + meta:set_int("selected_chan_idx", 0) + minetest.show_formspec(name, formname, smart_light.get_admin_fs(area)) + end + end + end + end + + -- --- SCHALTER PROGRAMMIERER (REBOOTED) --- + if formname:sub(1, 20) == "smart_light:prog_sw_" then + local pos_str = formname:sub(21) + local pos = minetest.string_to_pos(pos_str) + if not pos then return end + + if fields.save_switch then + local area, chan = fields.area_sel, fields.chan_sel + if area == "-- Bitte wählen --" or chan == "-- Bitte wählen --" then + minetest.chat_send_player(name, "FEHLER: Bitte Area UND Kanal auswählen!") + return + end + + local meta = minetest.get_meta(pos) + meta:set_string("sl_area", area) + meta:set_string("sl_chan", chan) + meta:set_string("infotext", "Schalter: " .. area .. ":" .. chan) + + if smart_light.registry.areas[area] and smart_light.registry.areas[area].channels[chan] then + smart_light.registry.areas[area].channels[chan].switches = smart_light.registry.areas[area].channels[chan].switches or {} + smart_light.registry.areas[area].channels[chan].switches[pos_str] = true + smart_light.save() + local level = smart_light.registry.areas[area].channels[chan].last_level or "max" + smart_light.update_switch_visuals(area, chan, level) + minetest.chat_send_player(name, "Schalter gespeichert!") + end + return + end + + if fields.area_sel and fields.area_sel ~= "-- Bitte wählen --" then + minetest.get_meta(pos):set_string("sl_area", fields.area_sel) + minetest.registered_tools["smart_light:programmer"].on_place(player:get_wielded_item(), player, {type="node", under=pos}) + end + end + + -- --- LICHT PROGRAMMIERER --- + if formname:sub(1, 17) == "smart_light:prog_" and formname:sub(1, 20) ~= "smart_light:prog_sw_" then + if fields.save then + local pos_str = formname:sub(18) + local pos = minetest.string_to_pos(pos_str) + local area, chan = fields.area_sel, fields.chan_in + if not area or area == "-- Bitte wählen --" or chan == "" then return end + + minetest.get_meta(pos):set_string("sl_area", area) + minetest.get_meta(pos):set_string("sl_chan", chan) + + local item = player:get_wielded_item() + local t_meta = item:get_meta() + t_meta:set_string("last_area", area) + t_meta:set_string("last_channel", chan) + t_meta:set_string("description", "Programmer Area: " .. area .. "\nChannel: " .. chan) + player:set_wielded_item(item) + + smart_light.registry.areas[area] = smart_light.registry.areas[area] or { channels = {} } + smart_light.registry.areas[area].channels[chan] = smart_light.registry.areas[area].channels[chan] or { nodes = {}, last_level = "max", brightness = "max" } + smart_light.registry.areas[area].channels[chan].nodes[pos_str] = true + smart_light.save() + minetest.chat_send_player(name, "Licht registriert!") + end + end + + -- --- HAUPTMENÜ (PANEL) --- + if formname:sub(1, 17) == "smart_light:main_" then + local pos_str = formname:sub(18) + local pos = minetest.string_to_pos(pos_str) + local area = minetest.get_meta(pos):get_string("area_id") + + if fields.all_off then + for c,_ in pairs(smart_light.registry.areas[area].channels) do smart_light.switch_channel(area, c, "off") end + minetest.registered_nodes["smart_light:controller"].on_rightclick(pos, nil, player) + elseif fields.all_on then + for c,_ in pairs(smart_light.registry.areas[area].channels) do smart_light.switch_channel(area, c, "on") end + minetest.registered_nodes["smart_light:controller"].on_rightclick(pos, nil, player) + else + for k, _ in pairs(fields) do + local cid = k:match("^chan_(.+)$") + if cid then + local count = smart_light.get_count(area, cid) + local status = smart_light.get_status_text(area, cid) + local last_lvl = smart_light.registry.areas[area].channels[cid].last_level or "max" + + local subfs = "size[4,5.5]label[0.5,0.2;Channel: " .. cid .. "]" .. + "label[0.5,0.7;Anzahl Leuchten: " .. count .. "]" .. + "label[0.5,1.2;Status: " .. status .. "]" .. + "label[0.5,1.7;Dimmlevel: " .. last_lvl .. "]" .. + "button[0.5,2.5;1.5,0.8;sub_"..cid.."_on;An]" .. + "button[2.2,2.5;1.0,0.8;sub_"..cid.."_up;D+]" .. + "button[0.5,3.5;1.5,0.8;sub_"..cid.."_off;Aus]" .. + "button[2.2,3.5;1.0,0.8;sub_"..cid.."_down;D-]" .. + "button[0.5,4.7;3,0.6;back;Zurück]" + minetest.show_formspec(name, "smart_light:sub_" .. pos_str, subfs) + return + end + end + end + end + + -- --- SUB-MENÜ --- + if formname:sub(1, 16) == "smart_light:sub_" then + local pos_str = formname:sub(17) + local pos = minetest.string_to_pos(pos_str) + local meta = minetest.get_meta(pos) + local area = meta:get_string("area_id") + if area == "" then area = meta:get_string("sl_area") end + + for k, _ in pairs(fields) do + local cid, action = k:match("^sub_(.+)_([%a%d]+)$") + if cid and action then + smart_light.switch_channel(area, cid, action) + local count = smart_light.get_count(area, cid) + local status = smart_light.get_status_text(area, cid) + local last_lvl = smart_light.registry.areas[area].channels[cid].last_level or "max" + + local subfs = "size[4,5.5]label[0.5,0.2;Channel: " .. cid .. "]" .. + "label[0.5,0.7;Anzahl Leuchten: " .. count .. "]" .. + "label[0.5,1.2;Status: " .. status .. "]" .. + "label[0.5,1.7;Dimmlevel: " .. last_lvl .. "]" .. + "button[0.5,2.5;1.5,0.8;sub_"..cid.."_on;An]" .. + "button[2.2,2.5;1.0,0.8;sub_"..cid.."_up;D+]" .. + "button[0.5,3.5;1.5,0.8;sub_"..cid.."_off;Aus]" .. + "button[2.2,3.5;1.0,0.8;sub_"..cid.."_down;D-]" .. + "button[0.5,4.7;3,0.6;back;Zurück]" + minetest.show_formspec(name, formname, subfs) + return + end + end + if fields.back or fields.exit then + if minetest.get_node(pos).name == "smart_light:controller" then + minetest.registered_nodes["smart_light:controller"].on_rightclick(pos, nil, player) + else minetest.close_formspec(name, formname) end + end + end + + -- --- PANEL SETUP --- + if formname:sub(1, 18) == "smart_light:setup_" then + if fields.set_area and fields.area_id ~= "" then + local pos = minetest.string_to_pos(formname:sub(19)) + minetest.get_meta(pos):set_string("area_id", fields.area_id) + smart_light.registry.areas[fields.area_id] = smart_light.registry.areas[fields.area_id] or { channels = {} } + smart_light.save() + end + end +end) diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..0964901 --- /dev/null +++ b/init.lua @@ -0,0 +1,151 @@ +smart_light = {} +local storage = minetest.get_mod_storage() + +-- Datenstruktur laden +local data = storage:get_string("registry") +smart_light.registry = data ~= "" and minetest.deserialize(data) or { areas = {} } + +smart_light.shadow_to_original = {} +smart_light.original_to_shadows = {} + +-- Definition der Stufen für die Dimm-Logik +smart_light.LEVEL_ORDER = {"off", "low", "mid", "high", "max"} + +function smart_light.save() + storage:set_string("registry", minetest.serialize(smart_light.registry)) +end + +-- Hilfsfunktion: Status-Text (AN/AUS) für UI +function smart_light.get_status_text(area, chan) + if not smart_light.registry.areas[area] or not smart_light.registry.areas[area].channels[chan] then + return "AUS" + end + local level = smart_light.registry.areas[area].channels[chan].last_level or "max" + return (level == "off") and "AUS" or "AN" +end + +-- Hilfsfunktion: Zählt Lichter in einem Channel +function smart_light.get_count(area, chan) + if not smart_light.registry.areas[area] or not smart_light.registry.areas[area].channels[chan] then + return 0 + end + local count = 0 + local target = smart_light.registry.areas[area].channels[chan].nodes or {} + for _ in pairs(target) do + count = count + 1 + end + return count +end + +-- Hilfsfunktion: Entfernt ein Licht aus der Registry +function smart_light.unregister_light(pos, area, chan) + local pos_str = minetest.pos_to_string(pos) + if smart_light.registry.areas[area] and smart_light.registry.areas[area].channels[chan] then + if smart_light.registry.areas[area].channels[chan].nodes then + smart_light.registry.areas[area].channels[chan].nodes[pos_str] = nil + if next(smart_light.registry.areas[area].channels[chan].nodes) == nil then + smart_light.registry.areas[area].channels[chan] = nil + end + smart_light.save() + end + end +end + +-- Hilfsfunktion: Schalter-Visuals aktualisieren +function smart_light.update_switch_visuals(area, chan, level) + if not smart_light.registry.areas[area] or not smart_light.registry.areas[area].channels[chan] then return end + local chan_data = smart_light.registry.areas[area].channels[chan] + if not chan_data.switches then return end + + local node_name = (level == "off") and "smart_light:switch" or "smart_light:switch_active" + + for pos_str, _ in pairs(chan_data.switches) do + local pos = minetest.string_to_pos(pos_str) + local node = minetest.get_node(pos) + if node.name:sub(1, 18) == "smart_light:switch" then + minetest.swap_node(pos, {name = node_name, param2 = node.param2}) + end + end +end + +-- Hilfsfunktion: Admin-Formspec +function smart_light.get_admin_fs(area, selected_idx) + local channels = {} + if smart_light.registry.areas[area] and smart_light.registry.areas[area].channels then + for c_id, _ in pairs(smart_light.registry.areas[area].channels) do + table.insert(channels, c_id) + end + table.sort(channels) + end + local list_str = "" + for _, c_id in ipairs(channels) do + list_str = list_str .. c_id .. " (" .. smart_light.get_count(area, c_id) .. ")," + end + return "size[6,7]label[0.5,0.2;Panel Verwaltung ("..area..")]" .. + "field[0.8,1.2;5,1;new_area;Area-ID ändern;"..area.."]" .. + "textlist[0.5,2.5;5,3;chan_list;"..list_str..";"..(selected_idx or "")..";false]" .. + "button[0.5,6;2.5,1;del_chan;Channel löschen]" .. + "button_exit[3.5,6;2,1;save_admin;Speichern]" +end + +-- Hilfsfunktion: Schaltlogik (RECALL FIXED) +function smart_light.switch_channel(area_id, channel_id, action) + local area = smart_light.registry.areas[area_id] + if not area or not area.channels or not area.channels[channel_id] then return end + + local chan_data = area.channels[channel_id] + + -- Korrekte Initialisierung der Datenstruktur + if not chan_data.nodes then + local old_nodes = table.copy(chan_data) + area.channels[channel_id] = { nodes = old_nodes, last_level = "max", brightness = "max" } + chan_data = area.channels[channel_id] + end + + -- Helligkeits-Gedächtnis sicherstellen + if not chan_data.brightness or chan_data.brightness == "off" then + chan_data.brightness = "max" + end + + local target_level + + if action == "off" then + target_level = "off" + -- Wir speichern target_level NICHT in brightness, um das Gedächtnis zu behalten + elseif action == "on" then + target_level = chan_data.brightness + elseif action == "up" or action == "down" then + local cur = chan_data.brightness + local idx = 1 + for i, v in ipairs(smart_light.LEVEL_ORDER) do if v == cur then idx = i end end + if action == "up" then idx = math.min(idx + 1, 5) else idx = math.max(idx - 1, 2) end + target_level = smart_light.LEVEL_ORDER[idx] + chan_data.brightness = target_level -- Neues Gedächtnis speichern + end + + -- Aktuellen Status für das UI speichern + chan_data.last_level = target_level + + -- Physisches Umschalten + for pos_str, _ in pairs(chan_data.nodes) do + local pos = minetest.string_to_pos(pos_str) + local node = minetest.get_node(pos) + local original = smart_light.shadow_to_original[node.name] or node.name + local shadows = smart_light.original_to_shadows[original] + if shadows and shadows[target_level] then + minetest.swap_node(pos, {name = shadows[target_level], param2 = node.param2}) + end + end + + smart_light.update_switch_visuals(area_id, channel_id, target_level) + smart_light.save() +end + +-- Dateien laden +local path = minetest.get_modpath("smart_light") +dofile(path .. "/nodes.lua") +dofile(path .. "/tools.lua") +dofile(path .. "/panel.lua") +dofile(path .. "/handlers.lua") +dofile(path .. "/switch.lua") +dofile(path .. "/overrides.lua") diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..00b2838 --- /dev/null +++ b/mod.conf @@ -0,0 +1,6 @@ +name = smart_light +description = Steuerung und Dimmen von Lichtern via Shadow-Nodes. +depends = default +optional_depends = areas, myschool, morelights_modern, morelights_vintage +author = Rage87 +version = 1005 diff --git a/nodes.lua b/nodes.lua new file mode 100644 index 0000000..c9e4018 --- /dev/null +++ b/nodes.lua @@ -0,0 +1,37 @@ +-- 1. LAMPEN-REGISTRIERUNG +function smart_light.register_lamp_control(node_name) + local def = minetest.registered_nodes[node_name] + if not def then return end + + local levels = { off = 0, low = 6, mid = 8, high = 12, max = 15 } + local shadows = {} + local base_name = node_name:gsub(":", "_") + + local function cleanup_after_dig(pos, oldnode, oldmetadata) + local area = oldmetadata.fields.sl_area + local chan = oldmetadata.fields.sl_chan + if area and chan then + smart_light.unregister_light(pos, area, chan) + end + end + + for suffix, light_val in pairs(levels) do + local shadow_name = ":smart_light:" .. base_name .. "_" .. suffix + local shadow_def = table.copy(def) + shadow_def.light_source = light_val + shadow_def.groups = table.copy(def.groups or {}) + shadow_def.groups.not_in_creative_inventory = 1 + shadow_def.drop = node_name + shadow_def.after_dig_node = cleanup_after_dig + minetest.register_node(shadow_name, shadow_def) + shadows[suffix] = "smart_light:" .. base_name .. "_" .. suffix + smart_light.shadow_to_original["smart_light:" .. base_name .. "_" .. suffix] = node_name + end + + minetest.override_item(node_name, { + after_dig_node = cleanup_after_dig + }) + + shadows["on"] = node_name + smart_light.original_to_shadows[node_name] = shadows +end diff --git a/overrides.lua b/overrides.lua new file mode 100644 index 0000000..cf87fff --- /dev/null +++ b/overrides.lua @@ -0,0 +1,23 @@ +-- Hier können beliebig viele Lampen registriert werden +minetest.register_on_mods_loaded(function() + smart_light.register_lamp_control("myschool:light") + smart_light.register_lamp_control("morelights_modern:walllamp") + smart_light.register_lamp_control("morelights_modern:post_d") + smart_light.register_lamp_control("morelights_modern:post_l") + smart_light.register_lamp_control("morelights_modern:barlight_c") + smart_light.register_lamp_control("morelights_modern:barlight_s") + smart_light.register_lamp_control("morelights_modern:ceilinglight") + smart_light.register_lamp_control("morelights_modern:canlight_d") + smart_light.register_lamp_control("morelights_modern:canlight_l") + smart_light.register_lamp_control("morelights_modern:tablelamp_d") + smart_light.register_lamp_control("morelights_modern:tablelamp_l") + smart_light.register_lamp_control("morelights_modern:pathlight_d") + smart_light.register_lamp_control("morelights_modern:pathlight_l") + smart_light.register_lamp_control("morelights_vintage:lantern_f") + smart_light.register_lamp_control("morelights_vintage:lantern_c") + smart_light.register_lamp_control("morelights_vintage:lantern_w") + smart_light.register_lamp_control("morelights_vintage:hangingbulb") + smart_light.register_lamp_control("morelights_vintage:chandelier") + + -- smart_light.register_lamp_control("andere_mod:lampe") +end) diff --git a/panel.lua b/panel.lua new file mode 100644 index 0000000..3539b33 --- /dev/null +++ b/panel.lua @@ -0,0 +1,78 @@ +-- 4. CONTROLLER (Das Panel) +minetest.register_node("smart_light:controller", { + description = "Smart Light Controller Panel", + tiles = { + "smart_light_panel_sides.png", "smart_light_panel_sides.png", + "smart_light_panel_sides.png", "smart_light_panel_sides.png", + "smart_light_panel_sides.png", "smart_light_panel_front_normal.png" + }, + drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir", + groups = {cracky = 2, oddly_breakable_by_hand = 1}, + node_box = { type = "fixed", fixed = {{-0.5, -0.5, 0.4, 0.5, 0.5, 0.5}} }, + on_rightclick = function(pos, node, clicker) + local meta = minetest.get_meta(pos) + local area = meta:get_string("area_id") + local name = clicker:get_player_name() + + if area == "" then + local fs = "size[5,3]field[0.8,1;4,1;area_id;Panel Area ID (z.B. Schule);]button_exit[1,2;3,1;set_area;Area festlegen]" + minetest.show_formspec(name, "smart_light:setup_" .. minetest.pos_to_string(pos), fs) + return + end + + local fs = "size[11,9]label[0.5,0.2;Zentrale: " .. area:upper() .. "]" .. + "label[6,0.2;Global:]" .. + "button[7,0;1.2,0.6;all_off;OFF]button[8.5,0;1.2,0.6;all_on;ON]" + + local y, x, count, channels = 1.2, 0.5, 0, {} + if smart_light.registry.areas[area] and smart_light.registry.areas[area].channels then + for c_id, _ in pairs(smart_light.registry.areas[area].channels) do table.insert(channels, c_id) end + table.sort(channels) + for _, c_id in ipairs(channels) do + -- Status AN/AUS statt Anzahl + local status = smart_light.get_status_text(area, c_id) + fs = fs .. "button["..x..","..y..";2.5,0.8;chan_"..c_id..";" .. c_id .. " ("..status..")]" + x, count = x + 2.6, count + 1 + if count % 4 == 0 then x, y = 0.5, y + 1 end + end + else + fs = fs .. "label[0.5,2;Keine Lichter für diese Area registriert.]" + end + minetest.show_formspec(name, "smart_light:main_" .. minetest.pos_to_string(pos), fs) + end, + + after_dig_node = function(pos, oldnode, oldmetadata) + local area = oldmetadata.fields.area_id + if area and area ~= "" and smart_light.registry.areas[area] then + if smart_light.registry.areas[area].channels then + for c_id, c_data in pairs(smart_light.registry.areas[area].channels) do + -- 1. Lampen zurücksetzen + local nodes = c_data.nodes or {} + for p_str, _ in pairs(nodes) do + local l_pos = minetest.string_to_pos(p_str) + local l_node = minetest.get_node(l_pos) + if l_node.name ~= "ignore" then + local original = smart_light.shadow_to_original[l_node.name] or l_node.name + minetest.swap_node(l_pos, {name = original, param2 = l_node.param2}) + local l_meta = minetest.get_meta(l_pos) + l_meta:set_string("sl_area", "") + l_meta:set_string("sl_chan", "") + end + end + -- 2. Schalter zurücksetzen + local switches = c_data.switches or {} + for s_str, _ in pairs(switches) do + local s_pos = minetest.string_to_pos(s_str) + minetest.swap_node(s_pos, {name = "smart_light:switch"}) + local s_meta = minetest.get_meta(s_pos) + s_meta:set_string("sl_area", "") + s_meta:set_string("sl_chan", "") + s_meta:set_string("infotext", "") + end + end + end + smart_light.registry.areas[area] = nil + smart_light.save() + end + end, +}) diff --git a/switch.lua b/switch.lua new file mode 100644 index 0000000..e3a79df --- /dev/null +++ b/switch.lua @@ -0,0 +1,70 @@ +local switch_box = { type = "fixed", fixed = { { -6/32, -6/32, 14/32, 6/32, 6/32, 16/32} } } + +minetest.register_node("smart_light:switch", { + description = "Smart Light Switch", + tiles = { + "smart_light_case.png", "smart_light_case.png", + "smart_light_case.png", "smart_light_case.png", + "smart_light_case.png", "smart_light_case.png^smart_light_button_off.png", + }, + drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir", + sunlight_propagates = true, groups = {cracky=2, crumbly=2}, + node_box = switch_box, + + on_punch = function(pos, node, puncher) + if not puncher:get_player_control().sneak then return end + + local meta = minetest.get_meta(pos) + local area, chan = meta:get_string("sl_area"), meta:get_string("sl_chan") + if area ~= "" and chan ~= "" and smart_light.registry.areas[area] and smart_light.registry.areas[area].channels[chan] then + local count = smart_light.get_count(area, chan) + local status = smart_light.get_status_text(area, chan) + local last_lvl = smart_light.registry.areas[area].channels[chan].last_level or "max" + + local subfs = "size[4,5.5]label[0.5,0.2;Channel: " .. chan .. "]" .. + "label[0.5,0.7;Anzahl Leuchten: " .. count .. "]" .. + "label[0.5,1.2;Status: " .. status .. "]" .. + "label[0.5,1.7;Dimmlevel: " .. last_lvl .. "]" .. + "button[0.5,2.5;1.5,0.8;sub_"..chan.."_on;An]" .. + "button[2.2,2.5;1.0,0.8;sub_"..chan.."_up;D+]" .. + "button[0.5,3.5;1.5,0.8;sub_"..chan.."_off;Aus]" .. + "button[2.2,3.5;1.0,0.8;sub_"..chan.."_down;D-]" .. + "button_exit[0.5,4.7;3,0.6;exit;Schließen]" + minetest.show_formspec(puncher:get_player_name(), "smart_light:sub_" .. minetest.pos_to_string(pos), subfs) + end + end, + + on_rightclick = function(pos, node, clicker) + local meta = minetest.get_meta(pos) + local area, chan = meta:get_string("sl_area"), meta:get_string("sl_chan") + if area ~= "" and chan ~= "" and smart_light.registry.areas[area] and smart_light.registry.areas[area].channels[chan] then + local status = smart_light.get_status_text(area, chan) + smart_light.switch_channel(area, chan, (status == "AUS") and "on" or "off") + end + end, + + after_dig_node = function(pos, oldnode, oldmetadata) + local area, chan = oldmetadata.fields.sl_area, oldmetadata.fields.sl_chan + if area and chan and smart_light.registry.areas[area] and smart_light.registry.areas[area].channels[chan] then + if smart_light.registry.areas[area].channels[chan].switches then + smart_light.registry.areas[area].channels[chan].switches[minetest.pos_to_string(pos)] = nil + smart_light.save() + end + end + end, +}) + +minetest.register_node("smart_light:switch_active", { + description = "Smart Light Switch", + tiles = { + "smart_light_case.png", "smart_light_case.png", + "smart_light_case.png", "smart_light_case.png", + "smart_light_case.png", "smart_light_case.png^smart_light_button_on.png", + }, + drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir", + sunlight_propagates = true, groups = {cracky=2, crumbly=2, not_in_creative_inventory=1}, + node_box = switch_box, drop = "smart_light:switch", + on_punch = minetest.registered_nodes["smart_light:switch"].on_punch, + on_rightclick = minetest.registered_nodes["smart_light:switch"].on_rightclick, + after_dig_node = minetest.registered_nodes["smart_light:switch"].after_dig_node, +}) diff --git a/textures/smart_light_button_off.png b/textures/smart_light_button_off.png new file mode 100644 index 0000000..dd0d6ba Binary files /dev/null and b/textures/smart_light_button_off.png differ diff --git a/textures/smart_light_button_on.png b/textures/smart_light_button_on.png new file mode 100644 index 0000000..f6d0233 Binary files /dev/null and b/textures/smart_light_button_on.png differ diff --git a/textures/smart_light_case.png b/textures/smart_light_case.png new file mode 100644 index 0000000..35c7125 Binary files /dev/null and b/textures/smart_light_case.png differ diff --git a/textures/smart_light_panel_front_normal.png b/textures/smart_light_panel_front_normal.png new file mode 100644 index 0000000..a6c244d Binary files /dev/null and b/textures/smart_light_panel_front_normal.png differ diff --git a/textures/smart_light_panel_led_alarm.png b/textures/smart_light_panel_led_alarm.png new file mode 100644 index 0000000..48a4233 Binary files /dev/null and b/textures/smart_light_panel_led_alarm.png differ diff --git a/textures/smart_light_panel_led_supervisory.png b/textures/smart_light_panel_led_supervisory.png new file mode 100644 index 0000000..285ebab Binary files /dev/null and b/textures/smart_light_panel_led_supervisory.png differ diff --git a/textures/smart_light_panel_led_trouble.png b/textures/smart_light_panel_led_trouble.png new file mode 100644 index 0000000..5196dde Binary files /dev/null and b/textures/smart_light_panel_led_trouble.png differ diff --git a/textures/smart_light_panel_sides.png b/textures/smart_light_panel_sides.png new file mode 100644 index 0000000..e9db926 Binary files /dev/null and b/textures/smart_light_panel_sides.png differ diff --git a/textures/smart_light_programmer.png b/textures/smart_light_programmer.png new file mode 100644 index 0000000..4006e05 Binary files /dev/null and b/textures/smart_light_programmer.png differ diff --git a/tools.lua b/tools.lua new file mode 100644 index 0000000..f7cbbf5 --- /dev/null +++ b/tools.lua @@ -0,0 +1,117 @@ +-- 3. PROGRAMMER +minetest.register_tool("smart_light:programmer", { + description = "Smart Light Programmer", + inventory_image = "smart_light_programmer.png", + + on_use = function(itemstack, user, pointed_thing) + if pointed_thing.type ~= "node" then return end + local pos = pointed_thing.under + local name = user:get_player_name() + local node = minetest.get_node(pos) + + local t_meta = itemstack:get_meta() + local area = t_meta:get_string("last_area") + local chan = t_meta:get_string("last_channel") + + if area == "" or chan == "" then + minetest.chat_send_player(name, "Programmer leer! Nutze Rechtsklick zum Einstellen.") + return + end + + local pos_str = minetest.pos_to_string(pos) + + -- LAMPE PASTEN + local original = smart_light.shadow_to_original[node.name] or node.name + if smart_light.original_to_shadows[original] then + smart_light.registry.areas[area].channels[chan] = smart_light.registry.areas[area].channels[chan] or { nodes = {}, last_level = "max" } + smart_light.registry.areas[area].channels[chan].nodes[pos_str] = true + smart_light.save() + local n_meta = minetest.get_meta(pos) + n_meta:set_string("sl_area", area) + n_meta:set_string("sl_chan", chan) + minetest.chat_send_player(name, "PASTE (Lampe): " .. area .. ":" .. chan) + return itemstack + end + + -- SCHALTER PASTEN + if node.name:sub(1, 18) == "smart_light:switch" then + if not smart_light.registry.areas[area] or not smart_light.registry.areas[area].channels[chan] then + minetest.chat_send_player(name, "FEHLER: Ziel-Kanal existiert nicht!") + return + end + smart_light.registry.areas[area].channels[chan].switches = smart_light.registry.areas[area].channels[chan].switches or {} + smart_light.registry.areas[area].channels[chan].switches[pos_str] = true + smart_light.save() + local n_meta = minetest.get_meta(pos) + n_meta:set_string("sl_area", area) + n_meta:set_string("sl_chan", chan) + n_meta:set_string("infotext", "Schalter: " .. area .. ":" .. chan) + smart_light.update_switch_visuals(area, chan, "on") + minetest.chat_send_player(name, "PASTE (Schalter): " .. area .. ":" .. chan) + return itemstack + end + end, + + on_place = function(itemstack, user, pointed_thing) + if pointed_thing.type ~= "node" then return end + local pos = pointed_thing.under + local name = user:get_player_name() + local node = minetest.get_node(pos) + + -- ADMIN PANEL + if node.name == "smart_light:controller" then + local area = minetest.get_meta(pos):get_string("area_id") + minetest.show_formspec(name, "smart_light:admin_" .. minetest.pos_to_string(pos), smart_light.get_admin_fs(area)) + return itemstack + end + + -- SCHALTER SETUP (Beide Dropdowns mit Platzhalter) + if node.name:sub(1, 18) == "smart_light:switch" then + local n_meta = minetest.get_meta(pos) + local curr_area = n_meta:get_string("sl_area") + + local areas_table = {"-- Bitte wählen --"} + for a_id, _ in pairs(smart_light.registry.areas) do table.insert(areas_table, a_id) end + + local area_idx = 1 + for i, v in ipairs(areas_table) do if v == curr_area then area_idx = i end end + + local channels_table = {"-- Bitte wählen --"} + if curr_area ~= "" and curr_area ~= "-- Bitte wählen --" and smart_light.registry.areas[curr_area] then + local tmp = {} + for c_id, _ in pairs(smart_light.registry.areas[curr_area].channels) do table.insert(tmp, c_id) end + table.sort(tmp) + for _, c in ipairs(tmp) do table.insert(channels_table, c) end + end + + local fs = "size[5,4.5]label[0.5,0.2;Schalter Programmierung]" .. + "dropdown[0.5,1.2;4,1;area_sel;" .. table.concat(areas_table, ",") .. ";" .. area_idx .. "]" .. + "label[0.5,2.2;Kanal auswählen:]" .. + "dropdown[0.5,2.7;4,1;chan_sel;" .. table.concat(channels_table, ",") .. ";1]" .. + "button[0.5,3.8;1.5,1;cancel;Abbruch]" .. + "button_exit[2.5,3.8;2,1;save_switch;Speichern]" + + minetest.show_formspec(name, "smart_light:prog_sw_" .. minetest.pos_to_string(pos), fs) + return itemstack + end + + -- LAMPEN SETUP + local original = smart_light.shadow_to_original[node.name] or node.name + if not smart_light.original_to_shadows[original] then return end + local n_meta = minetest.get_meta(pos) + local curr_area, curr_chan = n_meta:get_string("sl_area"), n_meta:get_string("sl_chan") + + local areas_table = {"-- Bitte wählen --"} + for a_id, _ in pairs(smart_light.registry.areas) do table.insert(areas_table, a_id) end + local area_idx = 1 + for i, v in ipairs(areas_table) do if v == curr_area then area_idx = i end end + + local fs = "size[5,4.5]label[0.5,0.2;Licht Programmierung]" .. + "dropdown[0.5,1.2;4,1;area_sel;" .. table.concat(areas_table, ",") .. ";" .. area_idx .. "]" .. + "field[0.8,2.5;4,1;chan_in;Channel ID;" .. curr_chan .. "]" .. + "button[0.5,3.5;1.5,1;cancel;Abbruch]" .. + "button_exit[2.5,3.5;2,1;save;Übernehmen]" + minetest.show_formspec(name, "smart_light:prog_" .. minetest.pos_to_string(pos), fs) + return itemstack + end, +})