Dateien nach "/" hochladen
This commit is contained in:
200
mecha_controller.lua
Normal file
200
mecha_controller.lua
Normal 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)
|
||||
Reference in New Issue
Block a user