local mod_storage = minetest.get_mod_storage() local collective = {} -- ################### -- #### FUNCTIONS #### -- ################### function collective.disband(name) --[[ Disbands name's collective. Params: name[string]: current player's name ]]-- if not collective.in_collective(name) then minetest.chat_send_player(name, "You're not in a collective.") return end local player = minetest.get_player_by_name(name) local pmeta = player:get_meta() pmeta:set_string("collective", "") minetest.chat_send_player(name, "Disbanding collective.") local members = {} members = minetest.deserialize(mod_storage:get_string(name)) for i, p in pairs(members) do if name ~= p then local exists = minetest.get_player_by_name(p) if exists then local cmeta = p:get_meta() local membership = cmeta:get_string("collective") if membership == name then cmeta:set_string("collective", "") minetest.chat_send_player(p, name.."'s collective has been disbanded") end end end end mod_storage:set_string(name, "") end function collective.invite(name, param) --[[ Invite users to join name's collective. Params: name[string]: current player's name param[list]: list of player name strings ]]-- if not collective.in_collective(name) then minetest.chat_send_player(name, "You're not in a collective. Use /collective start to make one.") return end local players = {} if #param > 0 then players = param else minetest.chat_send_player(name, "Usage: /collective invite [player name]...") return end for i, p in pairs(players) do local exists = minetest.get_player_by_name(p) local membership = collective.in_collective(p) if exists then if membership then minetest.chat_send_player(name, "Player "..p.." already in a collective.") minetest.chat_send_player(p, "You've been invited to "..name.."'s collective, but you can only be in one collective at a time.") else table.append(mod_storage[name], p) minetest.chat_send_player(p, "You've been invited to "..name.."'s collective. Type /collective join "..name.." to join.") minetest.chat_send_player(name, "Player "..p.." invited to your collective.") end else minetest.chat_send_player(name, "Player "..p.." doesn't exist!") end end end function collective.join(name, param) --[[ Join a collective. Requires being invited by the collective owner Params: name[string]: current player's name param[list]: list of player name strings; expecting a single value ]]-- if collective.in_collective(name) then minetest.chat_send_player(name, "You're already in a collective!") return end if #param ~= 1 then minetest.chat_send_player(name, "Usage: /collective join ") return end local player = minetest.get_player_by_name(name) local pmeta = player:get_meta() local members = mod_storage:get_string(param) if members then if collective.membership(name, members) then pmeta:set_string("collective", param) table.append(mod_storage[name], p) minetest.chat_send_player(name, "You've joined "..name.."'s collective.") else minetest.chat_send_player(name, param.." has not established a collective.") end end function collective.kick(name, param) --[[ Kick a player from name's collective. Params: name[string]: current player's name param[list]: list of player name strings; expecting a single value ]]-- if not collective.in_collective(name) then minetest.chat_send_player(name, "You're not in a collective.") return end if #param ~= 1 then minetest.chat_send_player(name, "Usage: /collective kick ") return end if name == param[1] then minetest.chat_send_player(name, "Cannot kick self! Use /collective disband") return end local exists = minetest.get_player_by_name(param[1]) local member = collective.membership(name, param[1]) if exists then if member then minetest.chat_send_player(name, "Kicking "..param[1].." from your collective.") collective.reform(name, param) minetest.chat_send_player(param[1], "You have been kicked from "..name.."'s collective.") else minetest.chat_send_player(name, param[1].." is not a member of your collective.") end else minetest.chat_send_player(name, param[1].." is not an active player.") end end function collective.leave(name) --[[ Leave a collective, if currently in one. If name is the owner of the collective, also disband the collective. Params: name[string]: current player's name ]]-- if not collective.in_collective(name) then minetest.chat_send_player(name, "You're not in a collective.") return end local player = minetest.get_player_by_name(name) local pmeta = player:get_meta() local membership = pmeta:get_string("collective") if name == membership then collective.disband(name) else collective.reform(membership, name) pmeta:set_string("collective", "") minetest.chat_send_player(name, "You have left "..membership.."'s collective.") minetest.chat_send_player(membership, name.." has left your collective.") end end function collective.start(name, param) --[[ Start a collective, and invite players if provided. Params: name[string]: current player's name param[list]: list of player name strings ]]-- if collective.in_collective(name) then minetest.chat_send_player(name, "You're already in a collective!") return end local players = {} if #param > 0 then players = param end local player = minetest.get_player_by_name(name) local pmeta = player:get_meta() pmeta:set_string("collective", name) mod_storage:set_string(name, minetest.serialize({name})) minetest.chat_send_player(name, "Collective established!") collective.invite(name, players) end function collective.status(name) --[[ Shows current collective information Params: name[string]: current player's name ]]-- local player = minetest.get_player_by_name(name) local pmeta = player:get_meta() local player_collective = pmeta:get_string("collective") minetest.chat_send_player(name, "Current collective: "..player_collective) local members = mod_storage:get_string(name) minetest.chat_send_player(name, "Collective members: "..members) end -- ########################## -- #### HELPER FUNCTIONS #### -- ########################## function collective.in_collective(name) --[[ Check if a player is in any collectives Params: name[string]: player name Returns: boolean; false if the player's "collective" metadata is "" or nil true otherwise ]]-- local player = minetest.get_player_by_name(name) local pmeta = player:get_meta() local membership = pmeta:get_string("collective") if membership == "" or membership == nil then return false else return true end end function collective.membership(name, param) --[[ Check if current player is a member of a specific collective Params: name[string]: current player's name param[list]: list of player name strings; expecting a single value Returns: boolean; true if name is a member of param's collective false otherwise ]]-- local members = mod_storage:get_string(param) if string.match(cmeta, name) then return true else return false end end function collective.print_usage() --[[ Print the /collective usage message Returns: string; the usage message ]]-- return "Usage: /collective [join,leave,start,disband] [player {,player...}]" end function collective.reform(name, param) --[[ Reform name's collective without param Params: name[string]: player's name; used for collective param[list]: list of player name strings ]]-- local members = {} members = minetest.deserialize(mod_storage:get_string(name)) local new_members = {} -- For each member of the collective, and each player provided in param, if -- the member does not match the param, add the member to the new_members -- list. -- -- This is expensive. Is there a better way to handle this? for i,m in pairs(members) do for j,p in pairs(param) do if not m == p then table.append(new_members, m) end end end mod_storage:set_string(name, minetest.serialize(new_members)) end -- ####################### -- #### CHAT COMMANDS #### -- ####################### minetest.register_chatcommand("collective", { func = function(name, param) if #param <= 0 then return false, collective.print_usage() end local player = minetest.get_player_by_name(name) if not player then return false, "You must be online to interact with the collective." end local parsed = {} for w in string.gmatch(param, "%g+") do table.insert(parsed, w) end local command = table.remove(parsed, 1) if command == "start" then collective.start(name, parsed) return true elseif command == "invite" then collective.invite(name, parsed) return true elseif command == "join" then collective.join(name, parsed) return true elseif command == "leave" then collective.leave(name) return true elseif command == "kick" then collective.leave(name, parsed) return true elseif command == "disband" then collective.disband(name) return true elseif command == "status" then collective.status(name) return true else return false, collective.print_usage() end end, })