201 lines
7.1 KiB
Lua
201 lines
7.1 KiB
Lua
-- 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)
|