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

200
mecha_controller.lua Normal file
View File

@@ -0,0 +1,200 @@
-- assorted_mecha/mecha_controller.lua
-- Remote control item for managing all nearby mechs
local FORMNAME = "assorted_mecha:controller"
if not assorted_mecha_controller_refs then
assorted_mecha_controller_refs = {}
end
-- Find all main mech entities within radius (no owner filter)
local function find_mechs_nearby(player, radius)
local pos = player:get_pos()
local mechs = {}
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, radius or 512)) do
if not obj:is_player() then
local ent = obj:get_luaentity()
if ent and ent.name and string.match(ent.name, "^assorted_mecha:mech%d+$") then
table.insert(mechs, {ent = ent, pos = obj:get_pos()})
end
end
end
return mechs
end
local function build_overview(pname, mechs, selected_idx)
local fs = "formspec_version[4]"
.. "size[10,9.5]"
.. "bgcolor[#1a1a2e;true]"
.. "box[0,0;10,0.8;#0f3460]"
.. "label[0.3,0.5;MECHA REMOTE | " .. pname .. "]"
if #mechs == 0 then
fs = fs
.. "box[0.5,1.5;9,1.2;#16213e]"
.. "label[0.8,2.0;No mechs found within 512 nodes.]"
.. "label[0.8,2.55;Move closer to your mech and reopen.]"
else
local rows = "Type,AI,Owner,Position"
for _, entry in ipairs(mechs) do
local ent = entry.ent
local p = entry.pos
local typ = string.gsub(ent.name, "assorted_mecha:", "")
local ai = ent._ai_enabled and "ON" or "off"
local own = (ent._ai_owner and ent._ai_owner ~= "") and ent._ai_owner or "-"
local pstr = string.format("%d/%d/%d", math.floor(p.x), math.floor(p.y), math.floor(p.z))
rows = rows .. "," .. typ .. "," .. ai .. "," .. own .. "," .. pstr
end
-- selected_idx is 1-based index into mechs table (nil = none)
local table_selected = selected_idx and (selected_idx + 1) or 1
fs = fs
.. "tablecolumns[text,align=left,width=4;text,align=center,width=2;text,align=center,width=3;text,align=left,width=4]"
.. "table[0.3,0.9;9.4,6.8;mech_table;" .. rows .. ";" .. table_selected .. "]"
.. "box[0,7.8;10,0.05;#16213e]"
.. "button[0.3,7.9;2.9,0.75;open_panel;Configure]"
.. "button[3.3,7.9;2.9,0.75;toggle_ai;Toggle AI]"
.. "button[6.3,7.9;3.4,0.75;claim_selected;Claim]"
.. "box[0,8.75;10,0.05;#16213e]"
.. "button[0.3,8.85;4.0,0.55;claim_all;Claim all nearby]"
end
fs = fs .. "button_exit[7.5,8.85;2.2,0.55;close;Close]"
return fs
end
local function open_overview(player, selected_idx)
local pname = player:get_player_name()
local ref = assorted_mecha_controller_refs[pname] or {}
local mechs = find_mechs_nearby(player)
-- preserve selection across refreshes
ref.mechs = mechs
ref.selected = selected_idx or ref.selected
assorted_mecha_controller_refs[pname] = ref
minetest.show_formspec(pname, FORMNAME, build_overview(pname, mechs, ref.selected))
end
-- Register the remote control item
minetest.register_craftitem("assorted_mecha:mecha_controller", {
description = "Mecha Remote Control\nLeft-click: open mech manager\nRight-click on mech: configure directly",
inventory_image = "mecha_controller.png",
stack_max = 1,
on_use = function(itemstack, user, pointed_thing)
if user and user:is_player() then
open_overview(user)
end
return itemstack
end,
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "object" then
local obj = pointed_thing.ref
if obj and not obj:is_player() then
local ent = obj:get_luaentity()
if ent and ent.name and string.match(ent.name, "^assorted_mecha:mech%d+$") then
assorted_mecha_open_panel(ent, placer)
return itemstack
end
end
end
return itemstack
end,
})
-- Formspec receive
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= FORMNAME then return false end
local pname = player:get_player_name()
local ref = assorted_mecha_controller_refs[pname]
if not ref then return true end
local mechs = ref.mechs or {}
if fields.quit or fields.close then
assorted_mecha_controller_refs[pname] = nil
return true
end
-- Update selected index whenever table is interacted with
-- Luanti table field format on click: "CHG:N" where N is row (1=header, 2=first data row)
if fields.mech_table then
local row = tonumber(string.match(fields.mech_table, "%a+:(%d+)"))
if row then
local idx = row - 1 -- subtract header row
if idx >= 1 and idx <= #mechs then
ref.selected = idx
end
end
end
local function get_selected_ent()
local idx = ref.selected
if idx and mechs[idx] and mechs[idx].ent then
-- verify entity still alive
if mechs[idx].ent.object and mechs[idx].ent.object:get_pos() then
return mechs[idx].ent
end
end
return nil
end
if fields.open_panel then
local ent = get_selected_ent()
if ent then
assorted_mecha_controller_refs[pname] = nil
assorted_mecha_open_panel(ent, player)
else
minetest.chat_send_player(pname, "[Remote] Select a mech first.")
open_overview(player, ref.selected)
end
return true
end
if fields.toggle_ai then
local ent = get_selected_ent()
if ent then
ent._ai_enabled = not ent._ai_enabled
if ent._ai_enabled then
assorted_mecha_ai_start(ent)
minetest.chat_send_player(pname, "[Remote] AI enabled.")
else
ent._ai_running = false
minetest.chat_send_player(pname, "[Remote] AI disabled.")
end
else
minetest.chat_send_player(pname, "[Remote] Select a mech first.")
end
open_overview(player, ref.selected)
return true
end
if fields.claim_selected then
local ent = get_selected_ent()
if ent then
ent._ai_owner = pname
minetest.chat_send_player(pname, "[Remote] Mech claimed.")
else
minetest.chat_send_player(pname, "[Remote] Select a mech first.")
end
open_overview(player, ref.selected)
return true
end
if fields.claim_all then
local count = 0
for _, entry in ipairs(mechs) do
if entry.ent and entry.ent.object and entry.ent.object:get_pos() then
entry.ent._ai_owner = pname
count = count + 1
end
end
minetest.chat_send_player(pname, "[Remote] Claimed " .. count .. " mech(s).")
open_overview(player, ref.selected)
return true
end
-- Re-render on any table click to keep selection visible
open_overview(player, ref.selected)
return true
end)