--[[ INITIALIZING: basics ]]-- -- global API table modpol = { } -- table for all active governance data modpol.orgs = { } -- record of governance interactions -- every state change should appear here modpol.ledger = { } -- update from mod_storage -- https://dev.minetest.net/StorageRef local mod_storage = minetest.get_mod_storage() -- load orgs local stored_orgs = minetest.deserialize(mod_storage:get_string("orgs")) if (stored_orgs ~= nil) then modpol.orgs = stored_orgs end -- load orgs local stored_ledger = minetest.deserialize(mod_storage:get_string("ledger")) if (stored_ledger ~= nil) then modpol.ledger = stored_ledger end --[[ FUNCTIONS:basics ]]-- -- record(message, org) -- writes all governance events to storage and ledger function modpol.record(message, org) -- record to ledger table.insert(modpol.ledger, message) -- record to org_ledger if (modpol.orgs[org] ~= nil) then local org_ledg = modpol.orgs[org]["ledger"] if (org_ledg == nil) then modpol.orgs[org]["ledger"] = {message} else modpol.orgs[org]["ledger"] = table.insert(org_ledg,message) end end -- record to storage mod_storage:set_string("orgs", minetest.serialize(modpol.orgs)) mod_storage:set_string("ledger", minetest.serialize(modpol.ledger)) end --[[ FUNCTIONS:orgs ]]-- -- new_org() -- create an org and add it to the list function modpol.new_org(orgName, orgMembers) if (orgName == "") then -- blank orgName input return "-!- Org needs a name" end if (modpol.orgs[orgName] == nil) then -- copy check modpol.orgs[orgName] = {members = orgMembers} else return "-!- Org already exists" end local message = "New org: " .. orgName .. " (" .. table.concat(orgMembers, ", ") .. ")" modpol.record(message, orgName) return message end -- /neworg [name] -- creates a new org with the current user as sole member minetest.register_chatcommand( "neworg", { privs = {}, func = function(user, param) local result = modpol.new_org(param,{user}) return true, result end, }) -- rename_org() function modpol.rename_org(oldName, newName) -- TKTK local message = "Org renamed: " .. oldName .. " > " .. newName modpol.record(message, newName) end -- /listorgs -- lists the orgs currently in the game minetest.register_chatcommand( "listorgs", { privs = {}, func = function(user, param) local orglist = "" for key, value in pairs(modpol.orgs) do -- first, set up member list local membs = modpol.orgs[key]["members"] if (membs == nil) then membs = "" else membs = " (" .. table.concat(membs, ", ") .. ")" end -- now, assemble the list if (orglist == "") -- first element only then orglist = key .. membs else orglist = orglist .. ", " .. key .. membs end end return true, "Orgs: " .. orglist end, }) -- rm_orgs() -- removes all orgs function modpol.rm_orgs() modpol.orgs["instance"] = {members = modpol.list_members()} local message = "Orgs purged" modpol.record(message, nil) return message end -- /rmorgs minetest.register_chatcommand( "rmorgs", { privs = {}, func = function(user, param) modpol.orgs = {} return true, modpol.rm_orgs() end, }) --[[ FUNCTIONS:users ]]-- -- list_members(domain) -- produces a table with names of players currently in the game -- if empty, lists all players; if an org name, lists its members function modpol.list_members(domain) local members = {} if (domain == nil) then -- no specified domain; all players for _,player in ipairs(minetest.get_connected_players()) do local name = player:get_player_name() table.insert(members,name) end else -- if an org is specified if (modpol.orgs[domain] ~= nil) then -- org exists members = modpol.orgs[domain]["members"] end end return members end -- /listplayers minetest.register_chatcommand( "listplayers", { privs = {}, func = function(user) local result = table.concat(modpol.list_members(),", ") return true, "All players: " .. result end, }) function modpol.add_member(org, member) if (modpol.orgs.org == nil) then return "-!- No such org" else table.insert(modpol.orgs.org["members"], member) local message = member .. " added to org " .. org modpol.record(message, org) return message end end -- /joinorg minetest.register_chatcommand( "joinorg", { privs = {}, func = function(user, param) local result = modpol.add_member(param, user) return true, result end, }) function modpol.remove_member(org, member) -- remove from all child orgs also local message = member .. " removed from org " .. org modpol.record(message, org) return message end -- /listmembers [org] -- lists the members of an org minetest.register_chatcommand( "listmembers", { privs = {}, func = function(user, param) local orglist = modpol.list_members(param) return true, param .. ": " .. table.concat(orglist,", ") end, }) -- PERMISSIONS FUNCTIONS -- PRIVILEGE FUNCTIONS -- Minetest-specific -- manages user privileges according to org membership function modpol.assign_privilege(org, privilege) -- add privilege to all members of an org end function modpol.remove_privilege(org, privilege) -- remove privilege from all members of an org, unless they have it from other orgs end --[[ USER INTERACTIONS ]]-- -- modpol.binary_poll_user(user, question) -- presents a yes/no/abstain poll to a user, returns answer function modpol.binary_poll_user(user, question) -- set up formspec local text = "Poll: " .. question local formspec = { "formspec_version[4]", "size[5,3]", "label[0.375,0.5;", minetest.formspec_escape(text), "]", "button[1,1.5;1,0.8;yes;Yes]", "button[2,1.5;1,0.8;no;No]", "button[3,1.5;1,0.8;abstain;Abstain]" --TKTK can we enable text wrapping? } local formspec_string = table.concat(formspec, "") -- present to player minetest.show_formspec(user, "modpol:binary_poll", formspec_string) end -- Receiving fields minetest.register_on_player_receive_fields(function (player, formname, fields) -- modpol:poll if formname == "modpol:binary_poll" then local pname = player:get_player_name() local vote = nil if fields.yes then vote = fields.yes elseif fields.no then vote = fields.no elseif fields.abstain then vote = fields.abstain end if vote then minetest.chat_send_all(pname .. " voted " .. vote) end minetest.close_formspec(pname, formname) return vote else -- if the form is not a recognized name return end end) -- /pollself [question] -- asks the user a question minetest.register_chatcommand( "pollself", { privs = {}, func = function(user, param) modpol.binary_poll_user(user, param) return true, result end, }) --[[ TKTK need to enable more complex ineractions - checkboxes, radio - write-in ]]-- -- MESSAGE FUNCTIONS function modpol.org_message(org, speaker, message) -- If org doesn't exit, broadcast to all -- If org doesn't exist, don't broadcast -- use: minetest.chat_send_player("player1", "This is a chat message for player1") end -- register at chat command for this -- Add HUD interface that shows status: orgs, privileges https://rubenwardy.com/minetest_modding_book/en/players/hud.html -- toggle it on and off --[[ INITIALIZING: post-functions ]]-- -- create instance if not present if (modpol.orgs["instance"] == nil) then modpol.new_org("instance", modpol.list_members()) end -- TKTK does this need to be on_joinplayer? still isn't adding the singleplayer