582 lines
23 KiB
Lua
582 lines
23 KiB
Lua
-- Map Party GUI System for Persistent Map Mod
|
|
-- Provides a graphical interface for managing map parties
|
|
-- Includes proper permission controls for admins and party leaders
|
|
|
|
local S = minetest.get_translator(minetest.get_current_modname())
|
|
|
|
-- GUI state storage for each player
|
|
local gui_state = {}
|
|
|
|
-- Helper function to check if player is server admin
|
|
local function is_server_admin(player_name)
|
|
return minetest.check_player_privs(player_name, {server = true}) or
|
|
minetest.check_player_privs(player_name, {ban = true}) or
|
|
minetest.check_player_privs(player_name, {kick = true})
|
|
end
|
|
|
|
-- Helper function to get party data from map-party.lua
|
|
local function get_map_parties()
|
|
local storage = persistent_map.storage
|
|
if not storage then
|
|
return {}
|
|
end
|
|
|
|
local data = storage:get_string("map_parties")
|
|
if data ~= "" then
|
|
return minetest.deserialize(data) or {}
|
|
end
|
|
return {}
|
|
end
|
|
|
|
-- Helper function to get player's current party
|
|
local function get_player_party(player_name)
|
|
local parties = get_map_parties()
|
|
for party_name, party_data in pairs(parties) do
|
|
for _, member in ipairs(party_data.members) do
|
|
if member == player_name then
|
|
return party_name, party_data
|
|
end
|
|
end
|
|
end
|
|
return nil, nil
|
|
end
|
|
|
|
-- Helper function to check if player is party owner
|
|
local function is_party_owner(player_name, party_name)
|
|
local parties = get_map_parties()
|
|
local party = parties[party_name]
|
|
return party and party.owner == player_name
|
|
end
|
|
|
|
-- Helper function to save map parties
|
|
local function save_map_parties(parties)
|
|
local storage = persistent_map.storage
|
|
if storage then
|
|
storage:set_string("map_parties", minetest.serialize(parties))
|
|
end
|
|
end
|
|
|
|
-- Main party management GUI
|
|
function persistent_map.show_party_gui(player_name)
|
|
local player = minetest.get_player_by_name(player_name)
|
|
if not player then return end
|
|
|
|
local is_admin = is_server_admin(player_name)
|
|
local current_party_name, current_party_data = get_player_party(player_name)
|
|
local is_owner = current_party_name and is_party_owner(player_name, current_party_name)
|
|
local parties = get_map_parties()
|
|
|
|
-- Initialize GUI state if not exists
|
|
if not gui_state[player_name] then
|
|
gui_state[player_name] = {
|
|
view_mode = "main", -- main, create, manage, list
|
|
selected_party = nil,
|
|
scroll_pos = 0
|
|
}
|
|
end
|
|
|
|
local state = gui_state[player_name]
|
|
local formspec = {}
|
|
|
|
-- Base formspec setup
|
|
formspec[1] = "formspec_version[6]"
|
|
formspec[2] = "size[16,12]"
|
|
formspec[3] = "bgcolor[#00000080;true]"
|
|
|
|
local formspec_index = 4
|
|
|
|
if state.view_mode == "main" then
|
|
-- Main menu view
|
|
formspec[formspec_index] = "label[8,0.5;Map Party Management]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Current party status
|
|
if current_party_name then
|
|
formspec[formspec_index] = string.format("label[1,2;Current Party: %s]", current_party_name)
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = string.format("label[1,2.8;Members (%d): %s]",
|
|
#current_party_data.members, table.concat(current_party_data.members, ", "))
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = string.format("label[1,3.6;Owner: %s]", current_party_data.owner)
|
|
formspec_index = formspec_index + 1
|
|
|
|
if is_owner then
|
|
formspec[formspec_index] = "label[1,4.4;You are the party owner]"
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
else
|
|
formspec[formspec_index] = "label[1,2;You are not in any party]"
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Action buttons
|
|
local button_y = 6
|
|
|
|
-- Create party button (always available)
|
|
if not current_party_name then
|
|
formspec[formspec_index] = string.format("button[1,%f;4,1;create_party;Create New Party]", button_y)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Manage current party button (owner only)
|
|
if current_party_name and is_owner then
|
|
formspec[formspec_index] = string.format("button[6,%f;4,1;manage_party;Manage Party]", button_y)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Leave party button (if in a party)
|
|
if current_party_name then
|
|
formspec[formspec_index] = string.format("button[11,%f;4,1;leave_party;Leave Party]", button_y)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- List all parties button
|
|
formspec[formspec_index] = string.format("button[1,%f;4,1;list_parties;List All Parties]", button_y + 1.5)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Admin controls (admin only)
|
|
if is_admin then
|
|
formspec[formspec_index] = "label[1,9;Admin Controls:]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "button[1,9.8;4,1;admin_manage;Manage All Parties]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "button[6,9.8;4,1;admin_delete;Delete Any Party]"
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
elseif state.view_mode == "create" then
|
|
-- Create party view
|
|
formspec[formspec_index] = "label[8,0.5;Create New Party]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "label[1,2;Party Name:]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "field[1,2.8;8,1;party_name;;]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "label[1,4;Initial Members (optional, one per line):]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "textarea[1,4.8;8,4;initial_members;;]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "button[1,9.5;3,1;create_confirm;Create Party]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "button[5,9.5;3,1;back_main;Back]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
elseif state.view_mode == "manage" then
|
|
-- Manage party view
|
|
formspec[formspec_index] = string.format("label[8,0.5;Manage Party: %s]", current_party_name or "Unknown")
|
|
formspec_index = formspec_index + 1
|
|
|
|
if current_party_data then
|
|
-- Current members list
|
|
formspec[formspec_index] = "label[1,2;Current Members:]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
local member_list = {}
|
|
for i, member in ipairs(current_party_data.members) do
|
|
local status = ""
|
|
if member == current_party_data.owner then
|
|
status = " (Owner)"
|
|
end
|
|
if minetest.get_player_by_name(member) then
|
|
status = status .. " [Online]"
|
|
else
|
|
status = status .. " [Offline]"
|
|
end
|
|
table.insert(member_list, member .. status)
|
|
end
|
|
|
|
formspec[formspec_index] = string.format("textlist[1,2.8;7,4;member_list;%s;1;false]",
|
|
table.concat(member_list, ","))
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Add member section
|
|
formspec[formspec_index] = "label[10,2;Add Member:]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "field[10,2.8;5,1;add_member_name;;]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "button[10,3.8;3,1;add_member;Add Member]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Remove member section (only show if there are members to remove)
|
|
if #current_party_data.members > 1 then
|
|
formspec[formspec_index] = "label[10,5;Remove Selected Member:]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "button[10,5.8;3,1;remove_member;Remove Member]"
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Delete party button (owner only)
|
|
if is_owner then
|
|
formspec[formspec_index] = "button[10,7.5;3,1;delete_party;Delete Party]"
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
end
|
|
|
|
formspec[formspec_index] = "button[1,10.5;3,1;back_main;Back to Main]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
elseif state.view_mode == "list" then
|
|
-- List all parties view
|
|
formspec[formspec_index] = "label[8,0.5;All Map Parties]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
if next(parties) == nil then
|
|
formspec[formspec_index] = "label[1,3;No parties exist]"
|
|
formspec_index = formspec_index + 1
|
|
else
|
|
local party_list = {}
|
|
for party_name, party_data in pairs(parties) do
|
|
local online_count = 0
|
|
for _, member in ipairs(party_data.members) do
|
|
if minetest.get_player_by_name(member) then
|
|
online_count = online_count + 1
|
|
end
|
|
end
|
|
|
|
local party_info = string.format("%s | Owner: %s | Members: %d (%d online)",
|
|
party_name, party_data.owner, #party_data.members, online_count)
|
|
table.insert(party_list, party_info)
|
|
end
|
|
|
|
formspec[formspec_index] = string.format("textlist[1,2;13,7;party_list;%s;1;false]",
|
|
table.concat(party_list, ","))
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
formspec[formspec_index] = "button[1,10.5;3,1;back_main;Back to Main]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
elseif state.view_mode == "admin" then
|
|
-- Admin management view
|
|
formspec[formspec_index] = "label[8,0.5;Admin Party Management]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
if next(parties) == nil then
|
|
formspec[formspec_index] = "label[1,3;No parties exist]"
|
|
formspec_index = formspec_index + 1
|
|
else
|
|
local party_list = {}
|
|
for party_name, party_data in pairs(parties) do
|
|
local party_info = string.format("%s | Owner: %s | Members: %d | Created: %s",
|
|
party_name, party_data.owner, #party_data.members,
|
|
os.date("%Y-%m-%d", party_data.created or 0))
|
|
table.insert(party_list, party_info)
|
|
end
|
|
|
|
formspec[formspec_index] = string.format("textlist[1,2;13,6;admin_party_list;%s;1;false]",
|
|
table.concat(party_list, ","))
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "button[1,9;3,1;admin_delete_selected;Delete Selected]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = "button[5,9;3,1;admin_view_details;View Details]"
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
formspec[formspec_index] = "button[1,10.5;3,1;back_main;Back to Main]"
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Close button (always present)
|
|
formspec[formspec_index] = "button[13,10.5;2,1;close;Close]"
|
|
|
|
minetest.show_formspec(player_name, "persistent_map:party_gui", table.concat(formspec))
|
|
end
|
|
|
|
-- Handle formspec input
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname ~= "persistent_map:party_gui" then return end
|
|
|
|
local player_name = player:get_player_name()
|
|
local is_admin = is_server_admin(player_name)
|
|
local current_party_name, current_party_data = get_player_party(player_name)
|
|
local is_owner = current_party_name and is_party_owner(player_name, current_party_name)
|
|
|
|
if not gui_state[player_name] then
|
|
gui_state[player_name] = {view_mode = "main", selected_party = nil, scroll_pos = 0}
|
|
end
|
|
|
|
local state = gui_state[player_name]
|
|
|
|
-- Handle navigation
|
|
if fields.close or fields.quit then
|
|
gui_state[player_name] = nil
|
|
return
|
|
elseif fields.back_main then
|
|
state.view_mode = "main"
|
|
persistent_map.show_party_gui(player_name)
|
|
return
|
|
elseif fields.create_party then
|
|
if current_party_name then
|
|
minetest.chat_send_player(player_name, S("You are already in a party. Leave it first."))
|
|
return
|
|
end
|
|
state.view_mode = "create"
|
|
persistent_map.show_party_gui(player_name)
|
|
return
|
|
elseif fields.manage_party then
|
|
if not is_owner then
|
|
minetest.chat_send_player(player_name, S("Only party owners can manage parties."))
|
|
return
|
|
end
|
|
state.view_mode = "manage"
|
|
persistent_map.show_party_gui(player_name)
|
|
return
|
|
elseif fields.list_parties then
|
|
state.view_mode = "list"
|
|
persistent_map.show_party_gui(player_name)
|
|
return
|
|
elseif fields.admin_manage then
|
|
if not is_admin then
|
|
minetest.chat_send_player(player_name, S("Admin privileges required."))
|
|
return
|
|
end
|
|
state.view_mode = "admin"
|
|
persistent_map.show_party_gui(player_name)
|
|
return
|
|
end
|
|
|
|
-- Handle actions based on current view
|
|
if state.view_mode == "create" then
|
|
if fields.create_confirm then
|
|
local party_name = fields.party_name or ""
|
|
party_name = party_name:trim()
|
|
|
|
if party_name == "" then
|
|
minetest.chat_send_player(player_name, S("Party name cannot be empty."))
|
|
return
|
|
end
|
|
|
|
-- Check if party already exists
|
|
local parties = get_map_parties()
|
|
if parties[party_name] then
|
|
minetest.chat_send_player(player_name, S("Party '@1' already exists.", party_name))
|
|
return
|
|
end
|
|
|
|
-- Create the party using the chat command system
|
|
local initial_members = fields.initial_members or ""
|
|
local cmd_params = "create " .. party_name
|
|
|
|
if initial_members ~= "" then
|
|
local members = initial_members:split("\n")
|
|
for _, member in ipairs(members) do
|
|
member = member:trim()
|
|
if member ~= "" and member ~= player_name then
|
|
cmd_params = cmd_params .. " " .. member
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Execute the mapparty command
|
|
local success, message = minetest.registered_chatcommands["mapparty"].func(player_name, cmd_params)
|
|
minetest.chat_send_player(player_name, message)
|
|
|
|
if success then
|
|
state.view_mode = "main"
|
|
persistent_map.show_party_gui(player_name)
|
|
end
|
|
end
|
|
|
|
elseif state.view_mode == "manage" then
|
|
if fields.add_member then
|
|
local member_name = fields.add_member_name or ""
|
|
member_name = member_name:trim()
|
|
|
|
if member_name == "" then
|
|
minetest.chat_send_player(player_name, S("Member name cannot be empty."))
|
|
return
|
|
end
|
|
|
|
if not is_owner then
|
|
minetest.chat_send_player(player_name, S("Only party owners can add members."))
|
|
return
|
|
end
|
|
|
|
-- Use the mapparty command to add member
|
|
local success, message = minetest.registered_chatcommands["mapparty"].func(
|
|
player_name, "add " .. current_party_name .. " " .. member_name)
|
|
minetest.chat_send_player(player_name, message)
|
|
|
|
if success then
|
|
persistent_map.show_party_gui(player_name)
|
|
end
|
|
|
|
elseif fields.remove_member then
|
|
if not is_owner then
|
|
minetest.chat_send_player(player_name, S("Only party owners can remove members."))
|
|
return
|
|
end
|
|
|
|
local selected_idx = tonumber(fields.member_list) or 0
|
|
if selected_idx > 0 and current_party_data and selected_idx <= #current_party_data.members then
|
|
local member_to_remove = current_party_data.members[selected_idx]
|
|
|
|
if member_to_remove == player_name then
|
|
minetest.chat_send_player(player_name, S("Use 'Leave Party' to remove yourself."))
|
|
return
|
|
end
|
|
|
|
-- Use the mapparty command to remove member
|
|
local success, message = minetest.registered_chatcommands["mapparty"].func(
|
|
player_name, "remove " .. current_party_name .. " " .. member_to_remove)
|
|
minetest.chat_send_player(player_name, message)
|
|
|
|
if success then
|
|
persistent_map.show_party_gui(player_name)
|
|
end
|
|
else
|
|
minetest.chat_send_player(player_name, S("Please select a member to remove."))
|
|
end
|
|
|
|
elseif fields.delete_party then
|
|
if not is_owner then
|
|
minetest.chat_send_player(player_name, S("Only party owners can delete parties."))
|
|
return
|
|
end
|
|
|
|
-- Use the mapparty command to delete party
|
|
local success, message = minetest.registered_chatcommands["mapparty"].func(
|
|
player_name, "delete " .. current_party_name)
|
|
minetest.chat_send_player(player_name, message)
|
|
|
|
if success then
|
|
state.view_mode = "main"
|
|
persistent_map.show_party_gui(player_name)
|
|
end
|
|
end
|
|
|
|
elseif state.view_mode == "admin" then
|
|
if fields.admin_delete_selected then
|
|
if not is_admin then
|
|
minetest.chat_send_player(player_name, S("Admin privileges required."))
|
|
return
|
|
end
|
|
|
|
local selected_idx = tonumber(fields.admin_party_list) or 0
|
|
local parties = get_map_parties()
|
|
local party_names = {}
|
|
for party_name, _ in pairs(parties) do
|
|
table.insert(party_names, party_name)
|
|
end
|
|
table.sort(party_names)
|
|
|
|
if selected_idx > 0 and selected_idx <= #party_names then
|
|
local party_to_delete = party_names[selected_idx]
|
|
local party_data = parties[party_to_delete]
|
|
|
|
-- Notify all members
|
|
for _, member_name in ipairs(party_data.members) do
|
|
if minetest.get_player_by_name(member_name) then
|
|
minetest.chat_send_player(member_name,
|
|
S("Map party '@1' has been deleted by admin @2", party_to_delete, player_name))
|
|
end
|
|
end
|
|
|
|
-- Delete the party
|
|
parties[party_to_delete] = nil
|
|
save_map_parties(parties)
|
|
|
|
minetest.chat_send_player(player_name, S("Party '@1' deleted successfully.", party_to_delete))
|
|
persistent_map.show_party_gui(player_name)
|
|
else
|
|
minetest.chat_send_player(player_name, S("Please select a party to delete."))
|
|
end
|
|
|
|
elseif fields.admin_view_details then
|
|
local selected_idx = tonumber(fields.admin_party_list) or 0
|
|
local parties = get_map_parties()
|
|
local party_names = {}
|
|
for party_name, _ in pairs(parties) do
|
|
table.insert(party_names, party_name)
|
|
end
|
|
table.sort(party_names)
|
|
|
|
if selected_idx > 0 and selected_idx <= #party_names then
|
|
local party_name = party_names[selected_idx]
|
|
local success, message = minetest.registered_chatcommands["mapparty"].func(
|
|
player_name, "info " .. party_name)
|
|
minetest.chat_send_player(player_name, message)
|
|
else
|
|
minetest.chat_send_player(player_name, S("Please select a party to view details."))
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Handle main view actions
|
|
if state.view_mode == "main" then
|
|
if fields.leave_party then
|
|
if not current_party_name then
|
|
minetest.chat_send_player(player_name, S("You are not in any party."))
|
|
return
|
|
end
|
|
|
|
-- Use the mapparty command to leave party
|
|
local success, message = minetest.registered_chatcommands["mapparty"].func(player_name, "leave")
|
|
minetest.chat_send_player(player_name, message)
|
|
|
|
if success then
|
|
persistent_map.show_party_gui(player_name)
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Clean up GUI state when players leave
|
|
minetest.register_on_leaveplayer(function(player)
|
|
local player_name = player:get_player_name()
|
|
gui_state[player_name] = nil
|
|
end)
|
|
|
|
-- Add button to marker GUI to access party management
|
|
local original_show_marker_gui = persistent_map.show_marker_gui
|
|
if original_show_marker_gui then
|
|
function persistent_map.show_marker_gui(player_name)
|
|
-- Call original function first
|
|
original_show_marker_gui(player_name)
|
|
|
|
-- We could modify the marker GUI to include a party management button
|
|
-- but for now, we'll keep them separate
|
|
end
|
|
end
|
|
|
|
-- Chat command to open party GUI
|
|
minetest.register_chatcommand("partygui", {
|
|
description = S("Open the map party management GUI"),
|
|
func = function(name)
|
|
persistent_map.show_party_gui(name)
|
|
return true, S("Party management GUI opened")
|
|
end,
|
|
})
|
|
|
|
-- Add party management button to the main map GUI
|
|
local original_show_map = persistent_map.show_map
|
|
if original_show_map then
|
|
-- We'll hook into the formspec handler instead to add the button
|
|
local original_receive_fields = minetest.registered_on_player_receive_fields
|
|
|
|
-- Register additional handler for map formspec to add party button
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname == "persistent_map:map" and fields.party_gui then
|
|
local player_name = player:get_player_name()
|
|
persistent_map.show_party_gui(player_name)
|
|
return true
|
|
end
|
|
end)
|
|
end
|
|
|
|
minetest.log("action", "[persistent_map] Map party GUI system loaded successfully") |