Files
modolith/mods/discovery_maps/map-party-gui.lua
T

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")