Dateien nach "/" hochladen

This commit is contained in:
2026-03-06 10:50:54 +00:00
commit 1862429c38
5 changed files with 2171 additions and 0 deletions

193
mecha_control_panel.lua Normal file
View File

@@ -0,0 +1,193 @@
-- assorted_mecha/mecha_control_panel.lua
-- Per-mech configuration UI, opened via the remote control item
-- State is stored directly in self_ent._ai_* fields (no persistent meta on entities)
local FORMNAME = "assorted_mecha:control_panel"
if not assorted_mecha_panel_refs then
assorted_mecha_panel_refs = {}
end
local function build_formspec(ent, clicker_name)
local ai_on = ent._ai_enabled == true
local atk_mob = ent._ai_attack_mobs ~= false
local atk_ply = ent._ai_attack_players == true
local prot = ent._ai_protect_owner ~= false
local radius = tonumber(ent._ai_scan_radius) or 20
local owner = ent._ai_owner or ""
local mode = ent._ai_mode or "guard"
local enemies = ent._ai_enemy_players or {}
local enemy_set = {}
for _, n in ipairs(enemies) do enemy_set[n] = true end
local player_list = {}
for _, p in ipairs(minetest.get_connected_players()) do
local pn = p:get_player_name()
if pn ~= clicker_name then table.insert(player_list, pn) end
end
local fs = "formspec_version[4]"
.. "size[9,10.5]"
.. "bgcolor[#1a1a2e;true]"
.. "box[0,0;9,0.8;#0f3460]"
.. "label[0.3,0.5;MECHA CONTROL PANEL]"
-- AI on/off status
fs = fs .. "box[0.2,1.0;8.6,1.3;#16213e]"
if ai_on then
fs = fs
.. "box[3.4,1.05;5.2,1.2;#0d4f1a]"
.. "label[3.7,1.7;ACTIVE - boarding disabled]"
.. "button[0.5,1.1;2.7,0.9;toggle_ai;Deactivate]"
else
fs = fs
.. "box[3.4,1.05;5.2,1.2;#4f1a0d]"
.. "label[3.7,1.7;MANUAL - mech is boardable]"
.. "button[0.5,1.1;2.7,0.9;toggle_ai;Activate AI]"
end
-- Owner
fs = fs
.. "box[0.2,2.45;8.6,0.7;#16213e]"
.. "label[0.5,2.85;Owner: " .. (owner ~= "" and owner or "(none)") .. "]"
.. "button[6.5,2.5;2.1,0.55;claim_owner;Claim]"
-- Owner protection
fs = fs
.. "box[0.2,3.3;8.6,0.7;#16213e]"
.. "checkbox[0.5,3.7;cb_protect;Protect owner (no friendly fire);"
.. (prot and "true" or "false") .. "]"
-- AI mode
fs = fs
.. "box[0.2,4.1;8.6,0.75;#16213e]"
.. "label[0.5,4.4;AI Mode:]"
.. "button[2.5,4.15;2.9,0.55;mode_guard;" .. (mode == "guard" and "[GUARD]" or "Guard") .. "]"
.. "button[5.5,4.15;2.9,0.55;mode_freerun;" .. (mode == "freerun" and "[FREERUN]" or "Freerun") .. "]"
-- Attack targets
fs = fs
.. "box[0.2,5.0;8.6,1.65;#16213e]"
.. "label[0.5,5.35;Attack targets:]"
.. "checkbox[0.5,5.75;cb_mobs;Hostile mobs and entities;"
.. (atk_mob and "true" or "false") .. "]"
.. "checkbox[0.5,6.25;cb_players;Other players (PvP);"
.. (atk_ply and "true" or "false") .. "]"
-- Scan radius
local bar_val = math.floor((radius / 50) * 1000)
fs = fs
.. "box[0.2,6.85;8.6,1.05;#16213e]"
.. "label[0.5,7.2;Scan radius: " .. radius .. " nodes]"
.. "scrollbar[0.5,7.4;8.0,0.45;horizontal;radius_bar;" .. bar_val .. "]"
-- Enemy player list (only shown when PvP is enabled)
if atk_ply then
fs = fs .. "box[0.2,8.05;8.6,1.6;#16213e]"
.. "label[0.5,8.4;Mark as enemy:]"
if #player_list > 0 then
local col, row = 0, 0
for _, pname in ipairs(player_list) do
local x = 0.5 + col * 4.3
local y = 8.75 + row * 0.55
fs = fs .. "checkbox[" .. x .. "," .. y .. ";enemy_" .. pname
.. ";" .. pname .. ";" .. (enemy_set[pname] and "true" or "false") .. "]"
col = col + 1
if col >= 2 then col = 0; row = row + 1 end
end
else
fs = fs .. "label[0.5,8.8;(No other players online)]"
end
end
-- Save / Cancel
fs = fs
.. "box[0,9.9;9,0.6;#0f3460]"
.. "button_exit[0.5,9.95;3.5,0.85;save;Save]"
.. "button_exit[5.0,9.95;3.5,0.85;cancel;Cancel]"
return fs
end
function assorted_mecha_open_panel(ent, clicker)
if not ent or not clicker then return end
local cname = clicker:get_player_name()
assorted_mecha_panel_refs[cname] = ent
minetest.show_formspec(cname, FORMNAME, build_formspec(ent, cname))
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= FORMNAME then return false end
local pname = player:get_player_name()
local ent = assorted_mecha_panel_refs[pname]
if not ent or not ent.object or not ent.object:get_pos() then
assorted_mecha_panel_refs[pname] = nil
return true
end
if fields.toggle_ai then
ent._ai_enabled = not ent._ai_enabled
if ent._ai_enabled then
assorted_mecha_ai_start(ent)
else
ent._ai_running = false
end
minetest.show_formspec(pname, FORMNAME, build_formspec(ent, pname))
return true
end
if fields.claim_owner then
ent._ai_owner = pname
minetest.show_formspec(pname, FORMNAME, build_formspec(ent, pname))
return true
end
if fields.cancel then
assorted_mecha_panel_refs[pname] = nil
return true
end
if fields.mode_guard then
ent._ai_mode = "guard"
ent._ai_waypoint = nil
minetest.show_formspec(pname, FORMNAME, build_formspec(ent, pname))
return true
end
if fields.mode_freerun then
ent._ai_mode = "freerun"
minetest.show_formspec(pname, FORMNAME, build_formspec(ent, pname))
return true
end
if fields.save then
if fields.cb_mobs ~= nil then ent._ai_attack_mobs = fields.cb_mobs == "true" end
if fields.cb_players ~= nil then ent._ai_attack_players = fields.cb_players == "true" end
if fields.cb_protect ~= nil then ent._ai_protect_owner = fields.cb_protect == "true" end
if fields.radius_bar then
local bar_val = tonumber(string.match(fields.radius_bar, "CHG:(%d+)") or
string.match(fields.radius_bar, "(%d+)") or "400")
local r = math.max(5, math.min(50, math.floor((bar_val / 1000) * 50)))
ent._ai_scan_radius = r
end
local enemies = {}
for k, v in pairs(fields) do
if string.sub(k, 1, 6) == "enemy_" and v == "true" then
table.insert(enemies, string.sub(k, 7))
end
end
ent._ai_enemy_players = enemies
if ent._ai_enabled and not ent._ai_running then
assorted_mecha_ai_start(ent)
end
assorted_mecha_panel_refs[pname] = nil
minetest.chat_send_player(pname, "[Mecha] Settings saved.")
return true
end
return true
end)