Correction: files added
This commit is contained in:
		
							
								
								
									
										16
									
								
								GOVERNANCE.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								GOVERNANCE.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | One administrator, @ntnsndr, holds ultimate decision-making power over the project. This is a temporary arrangement while we build trust as a community and adopt a more inclusive structure. | ||||||
|  |  | ||||||
|  | * **Autocracy** The administrator holds ultimate decision-making power in the community. | ||||||
|  |     * **Executive** The administrator is responsible for implementing—or delegating implementation of—policies and other decisions. | ||||||
|  |     * **Lobbying** If participants are not happy with the administrator's leadership, they may voice their concerns or leave the community. | ||||||
|  | * **Do-ocracy** Those who step forward to do a given task can decide how it should be done, in ongoing consultation with each other and the administrator. | ||||||
|  |     * **Membership** Participation is open to anyone who wants to contribute. The administrator can remove misbehaving participants at will for the sake of the common good. | ||||||
|  | * **Code of Conduct** Participants are expected to abide by the Contributor Covenant (contributor-covenant.org). | ||||||
|  | * **Ownership** This is a project of the Media Enterprise Design Lab at the University of Colorado Boulder and is owned by the university. | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | Created by [Nathan Schneider](https://gitlab.com/medlabboulder/modpol) | ||||||
|  |  | ||||||
|  | [](https://communityrule.info)    | ||||||
|  | [Creative Commons BY-SA](https://creativecommons.org/licenses/by-sa/4.0/) | ||||||
							
								
								
									
										108
									
								
								modpol_minetest/chatcommands.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								modpol_minetest/chatcommands.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | |||||||
|  | -- =================================================================== | ||||||
|  | -- Minetest commands | ||||||
|  | -- =================================================================== | ||||||
|  |  | ||||||
|  | command_list = {}               -- user-facing table of commands | ||||||
|  |  | ||||||
|  | local chat_table                -- MT chat command definitions table | ||||||
|  | local regchat                   -- Chat-command registration function | ||||||
|  |  | ||||||
|  | regchat = minetest.register_chatcommand | ||||||
|  |  | ||||||
|  | regchat = function(name, command_table) | ||||||
|  |    minetest.register_chatcommand(name, command_table) | ||||||
|  |    table.insert(command_list, name) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- =================================================================== | ||||||
|  | -- /modpol | ||||||
|  | -- Presents a menu of options to users | ||||||
|  | regchat( | ||||||
|  |    "modpol", { | ||||||
|  |       privs = {}, | ||||||
|  |       func = function(user) | ||||||
|  |          modpol.interactions.dashboard(user) | ||||||
|  |       end, | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | -- =================================================================== | ||||||
|  | -- /reset | ||||||
|  | -- For testing only | ||||||
|  | -- Clears the system and recreates instance with all players | ||||||
|  | regchat( | ||||||
|  |    "reset", { | ||||||
|  |       privs = {}, | ||||||
|  |       func = function(user) | ||||||
|  |          modpol.orgs.reset(); | ||||||
|  |          return true, "Reset orgs" | ||||||
|  |       end, | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- =================================================================== | ||||||
|  | -- /addorg | ||||||
|  | -- This code defines a chat command which creates a new | ||||||
|  | -- "org". Presently, the command makes the user the sole member of the | ||||||
|  | -- "org". | ||||||
|  |  | ||||||
|  | regchat( | ||||||
|  |    "addorg", { | ||||||
|  |       privs        = {} , | ||||||
|  |       func         = function (user, param) | ||||||
|  |          local success, message = modpol.instance:add_org (param) | ||||||
|  |          return true, message | ||||||
|  |       end         | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | -- =================================================================== | ||||||
|  | -- /listorgs | ||||||
|  | -- In Minetest mode, this code defines a chat command which lists | ||||||
|  | -- existing "orgs". | ||||||
|  | -- The list shows one "org" per line in the following format: | ||||||
|  | -- org_name (member, member, ...) | ||||||
|  |  | ||||||
|  | regchat( | ||||||
|  |    "listorgs", { | ||||||
|  |       privs = {} , | ||||||
|  |       func  = function (user, param) | ||||||
|  |          return true, "Orgs: " .. | ||||||
|  |             table.concat(modpol.orgs.list_all(), ", ") | ||||||
|  |       end | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | -- =================================================================== | ||||||
|  | -- /listplayers | ||||||
|  | regchat( | ||||||
|  |    "listplayers", { | ||||||
|  |       privs = {}, | ||||||
|  |       func = function(user) | ||||||
|  |          local result = table.concat(modpol.list_users(),", ") | ||||||
|  |          return true, "All players: " .. result | ||||||
|  |       end, | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | -- =================================================================== | ||||||
|  | -- /joinorg | ||||||
|  | regchat( | ||||||
|  |    "joinorg", { | ||||||
|  |       privs = {}, | ||||||
|  |       func = function(user, param) | ||||||
|  |          local org = modpol.orgs.get_org(param) | ||||||
|  |          local success, result = org:add_member(user) | ||||||
|  |          return true, result | ||||||
|  |       end, | ||||||
|  | }) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- =================================================================== | ||||||
|  | -- /pollself [question] | ||||||
|  | -- asks the user a question specified in param | ||||||
|  | regchat( | ||||||
|  |    "pollself", { | ||||||
|  |       privs = {}, | ||||||
|  |       func = function(user, param) | ||||||
|  |          modpol.interactions.binary_poll_user(user, param) | ||||||
|  |          return true, result | ||||||
|  |       end, | ||||||
|  | }) | ||||||
							
								
								
									
										479
									
								
								modpol_minetest/overrides/interactions.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										479
									
								
								modpol_minetest/overrides/interactions.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,479 @@ | |||||||
|  | -- INTERACTIONS.LUA (for Minetest) | ||||||
|  |  | ||||||
|  | -- CONTEXTUAL STUFF | ||||||
|  | -- ================ | ||||||
|  |  | ||||||
|  | -- _contexts to enable passing across formspecs | ||||||
|  | -- https://rubenwardy.com/minetest_modding_book/en/players/formspecs.html#contexts | ||||||
|  |  | ||||||
|  | local _contexts = {} | ||||||
|  | local function get_context(name) | ||||||
|  |     local context = _contexts[name] or {} | ||||||
|  |     _contexts[name] = context | ||||||
|  |     return context | ||||||
|  | end | ||||||
|  | minetest.register_on_leaveplayer(function(player) | ||||||
|  |     _contexts[player:get_player_name()] = nil | ||||||
|  | end) | ||||||
|  |  | ||||||
|  | -- UTILITIES | ||||||
|  | -- ========= | ||||||
|  |  | ||||||
|  | -- Function: formspec_list | ||||||
|  | -- for use generating option lists in formspecs from tables | ||||||
|  | -- input: table of strings | ||||||
|  | -- output: a formspec-ready list of the strings | ||||||
|  | local function formspec_list(array) | ||||||
|  |    local escaped = {} | ||||||
|  |    if not array then | ||||||
|  |       return "" | ||||||
|  |    end | ||||||
|  |    for i = 1, #array do | ||||||
|  |       escaped[i] = minetest.formspec_escape(array[i]) | ||||||
|  |    end | ||||||
|  |    return table.concat(escaped,",") | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- DASHBOARDS | ||||||
|  | -- ========== | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.dashboard(user) | ||||||
|  | -- Params: user (string) | ||||||
|  | -- Q: Should this return a menu of commands relevant to the specific user? | ||||||
|  | -- Output: Displays a menu of commands to the user | ||||||
|  | -- TODO currently a manually curated list---needs major improvement | ||||||
|  | function modpol.interactions.dashboard(user) | ||||||
|  |    -- prepare data | ||||||
|  |    -- to add: nested orgs map | ||||||
|  |    local all_orgs = modpol.orgs.list_all() | ||||||
|  |    local user_orgs = modpol.orgs.user_orgs(user) | ||||||
|  |    local all_users = modpol.list_users() | ||||||
|  |    -- set up formspec | ||||||
|  |     local formspec = { | ||||||
|  |        "formspec_version[4]", | ||||||
|  |        "size[10,8]", | ||||||
|  |        "label[0.5,0.5;MODPOL DASHBOARD]", | ||||||
|  |        "label[0.5,2;All orgs:]", | ||||||
|  |        "dropdown[2,1.5;5,0.8;all_orgs;"..formspec_list(all_orgs)..";;]", | ||||||
|  |        "label[0.5,3;Your orgs:]", | ||||||
|  |        "dropdown[2,2.5;5,0.8;user_orgs;"..formspec_list(user_orgs)..";;]", | ||||||
|  |        "label[0.5,4;All users:]", | ||||||
|  |        "dropdown[2,3.5;5,0.8;all_users;"..formspec_list(all_users)..";;]", | ||||||
|  |        "button[0.5,7;1,0.8;test_poll;Test poll]", | ||||||
|  |        "button[2,7;1,0.8;add_org;Add org]", | ||||||
|  |        "button[3.5,7;1.5,0.8;remove_org;Remove org]", | ||||||
|  |        "button[5.5,7;1.5,0.8;reset_orgs;Reset orgs]", | ||||||
|  |        "button_exit[8.5,7;1,0.8;close;Close]", | ||||||
|  |     } | ||||||
|  |     local formspec_string = table.concat(formspec, "") | ||||||
|  |     -- present to player | ||||||
|  |     minetest.show_formspec(user, "modpol:dashboard", formspec_string) | ||||||
|  | end | ||||||
|  | -- receive input | ||||||
|  | minetest.register_on_player_receive_fields(function (player, formname, fields) | ||||||
|  |       if formname == "modpol:dashboard" then | ||||||
|  |          local pname = player:get_player_name() | ||||||
|  |          if nil then | ||||||
|  |             -- buttons first | ||||||
|  |          elseif fields.test_poll then | ||||||
|  |             -- FOR TESTING PURPOSES ONLY | ||||||
|  |             modpol.interactions.text_query( | ||||||
|  |                pname,"Poll question:", | ||||||
|  |                function(input) | ||||||
|  |                   modpol.interactions.binary_poll_user( | ||||||
|  |                      pname, input, | ||||||
|  |                      function(vote) | ||||||
|  |                         modpol.interactions.message( | ||||||
|  |                            pname, pname .. " voted " .. vote) | ||||||
|  |                   end) | ||||||
|  |             end) | ||||||
|  |          elseif fields.add_org then | ||||||
|  |             modpol.interactions.add_org(pname, 1) | ||||||
|  |          elseif fields.remove_org then | ||||||
|  |             modpol.interactions.remove_org(pname) | ||||||
|  |          elseif fields.reset_orgs then | ||||||
|  |             modpol.orgs.reset() | ||||||
|  |             modpol.instance:add_member(pname) | ||||||
|  |             modpol.interactions.dashboard(pname) | ||||||
|  |              | ||||||
|  |          -- Put all dropdowns at the end | ||||||
|  |          elseif fields.close then | ||||||
|  |             minetest.close_formspec(pname, formname) | ||||||
|  |          elseif fields.all_orgs or fields.user_orgs then | ||||||
|  |             local org_name = fields.all_orgs or fields.user_orgs | ||||||
|  |             modpol.interactions.org_dashboard(pname, org_name) | ||||||
|  |          end | ||||||
|  |       end | ||||||
|  | end) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.org_dashboard | ||||||
|  | -- Params: user (string), org_name (string) | ||||||
|  | -- Output: Displays a menu of org-specific commands to the user | ||||||
|  | function modpol.interactions.org_dashboard(user, org_name) | ||||||
|  |    -- prepare data | ||||||
|  |    local org = modpol.orgs.get_org(org_name) | ||||||
|  |    if not org then return nil end | ||||||
|  |    local is_member = org:has_member(user) | ||||||
|  |    local membership_toggle = function() | ||||||
|  |       local toggle_code = "" | ||||||
|  |       if is_member then | ||||||
|  |          toggle_code = toggle_code | ||||||
|  |             ..minetest.formspec_escape("leave")..";" | ||||||
|  |             ..minetest.formspec_escape("Leave").."]" | ||||||
|  |       else | ||||||
|  |          toggle_code = toggle_code | ||||||
|  |             ..minetest.formspec_escape("join")..";" | ||||||
|  |             ..minetest.formspec_escape("Join").."]" | ||||||
|  |       end | ||||||
|  |       return toggle_code | ||||||
|  |    end | ||||||
|  |  | ||||||
|  |    -- identify parent | ||||||
|  |    local parent = modpol.orgs.get_org(org.parent) | ||||||
|  |    if parent then parent = parent.name | ||||||
|  |    else parent = "none" end | ||||||
|  |  | ||||||
|  |    -- prepare children menu | ||||||
|  |    local children = {"View..."} | ||||||
|  |    for k,v in ipairs(org.children) do | ||||||
|  |       local this_child = modpol.orgs.get_org(v) | ||||||
|  |       table.insert(children, this_child.name) | ||||||
|  |    end | ||||||
|  |  | ||||||
|  |    -- prepare modules menu | ||||||
|  |    local modules = {"View..."} | ||||||
|  |    if org.modules then | ||||||
|  |       for k,v in ipairs(org.modules) do | ||||||
|  |          table.insert(modules, org.modules[k].slug) | ||||||
|  |       end | ||||||
|  |    end | ||||||
|  |  | ||||||
|  |    -- prepare actions menu | ||||||
|  |    local actions = {"View..."} | ||||||
|  |    if org.pending[user] then | ||||||
|  |       for k,v in pairs(org.pending[user]) do | ||||||
|  |          local action_string = "[" .. k .. "] " .. | ||||||
|  |             org.processes[k].name             | ||||||
|  |          table.insert(actions, action_string) | ||||||
|  |       end | ||||||
|  |    end | ||||||
|  |  | ||||||
|  |    -- set player context | ||||||
|  |    local user_context = {} | ||||||
|  |    user_context["current_org"] = org_name | ||||||
|  |    _contexts[user] = user_context | ||||||
|  |    -- set up formspec | ||||||
|  |     local formspec = { | ||||||
|  |        "formspec_version[4]", | ||||||
|  |        "size[10,8]", | ||||||
|  |        "label[0.5,0.5;Org: ".. | ||||||
|  |           minetest.formspec_escape(org_name).."]", | ||||||
|  |        "label[0.5,1;Parent: "..parent.."]", | ||||||
|  |        "button[8.5,0.5;1,0.8;"..membership_toggle(), | ||||||
|  |        "label[0.5,2;Members:]", | ||||||
|  |        "dropdown[2,1.5;5,0.8;user_orgs;"..formspec_list(org.members)..";;]", | ||||||
|  |        "label[0.5,3;Children:]", | ||||||
|  |        "dropdown[2,2.5;5,0.8;children;"..formspec_list(children)..";;]", | ||||||
|  |        "label[0.5,4;Modules:]", | ||||||
|  |        "dropdown[2,3.5;5,0.8;modules;"..formspec_list(modules)..";;]", | ||||||
|  |        "label[0.5,5;Actions:]", | ||||||
|  |        "dropdown[2,4.5;5,0.8;actions;"..formspec_list(actions)..";;]", | ||||||
|  |        "button[0.5,7;1,0.8;test_poll;Test poll]", | ||||||
|  |        "button[2,7;1,0.8;add_child;Add child]", | ||||||
|  |        "button[3.5,7;1.5,0.8;remove_org;Remove org]", | ||||||
|  |        "button[8.5,7;1,0.8;back;Back]", | ||||||
|  |     } | ||||||
|  |     local formspec_string = table.concat(formspec, "") | ||||||
|  |     -- present to player | ||||||
|  |     minetest.show_formspec(user, "modpol:org_dashboard", formspec_string) | ||||||
|  | end | ||||||
|  | -- receive input | ||||||
|  | minetest.register_on_player_receive_fields(function (player, formname, fields) | ||||||
|  |       if formname == "modpol:org_dashboard" then | ||||||
|  |          local pname = player:get_player_name() | ||||||
|  |          local org = modpol.orgs.get_org(_contexts[pname].current_org) | ||||||
|  |          if nil then | ||||||
|  |          elseif fields.join then | ||||||
|  |             local new_request = { | ||||||
|  |                user = pname, | ||||||
|  |                type = "add_member", | ||||||
|  |                params = {pname} | ||||||
|  |             } | ||||||
|  |             org:make_request(new_request) | ||||||
|  |             modpol.interactions.org_dashboard(pname,org.name) | ||||||
|  |          elseif fields.leave then | ||||||
|  |             org:remove_member(pname) | ||||||
|  |             modpol.interactions.dashboard(pname) | ||||||
|  |          elseif fields.test_poll then | ||||||
|  |             modpol.interactions.binary_poll_org( | ||||||
|  |                pname, org.id, | ||||||
|  |                function(input) | ||||||
|  |                   modpol.interactions.message_org( | ||||||
|  |                      pname, | ||||||
|  |                      org.id, | ||||||
|  |                      "New response: " .. input) | ||||||
|  |             end) | ||||||
|  |          elseif fields.add_child then | ||||||
|  |             modpol.interactions.text_query( | ||||||
|  |                pname, "Child org name:", | ||||||
|  |                function(input)    | ||||||
|  |                   local new_request = { | ||||||
|  |                      user = pname, | ||||||
|  |                      type = "add_org", | ||||||
|  |                      params = {input} | ||||||
|  |                   } | ||||||
|  |                   org:make_request(new_request) | ||||||
|  |                   modpol.interactions.message(pname,"requested") | ||||||
|  |                   modpol.interactions.org_dashboard( | ||||||
|  |                      pname,org.name) | ||||||
|  |             end) | ||||||
|  |          elseif fields.remove_org then | ||||||
|  |             local new_request = { | ||||||
|  |                user = pname, | ||||||
|  |                type = "delete", | ||||||
|  |                params = {} | ||||||
|  |             } | ||||||
|  |             org:make_request(new_request) | ||||||
|  |             modpol.interactions.org_dashboard(pname,org.name) | ||||||
|  |          elseif fields.back then | ||||||
|  |             modpol.interactions.dashboard(pname) | ||||||
|  |              | ||||||
|  |          -- Put all dropdowns at the end | ||||||
|  |          -- Receiving modules | ||||||
|  |          elseif fields.modules | ||||||
|  |             and fields.modules ~= "View..." then | ||||||
|  |             local module = fields.modules | ||||||
|  |             org:call_module(module, user) | ||||||
|  |  | ||||||
|  |          -- Receiving actions | ||||||
|  |          elseif fields.actions | ||||||
|  |             and fields.actions ~= "View..." then | ||||||
|  |             local action = string.match( | ||||||
|  |                fields.actions,"%[(%d)%]") | ||||||
|  |             local process = org.processes[tonumber(action)] | ||||||
|  |             if process then | ||||||
|  |                org:interact(process, user) | ||||||
|  |             end | ||||||
|  |  | ||||||
|  |          -- Children | ||||||
|  |          elseif fields.children | ||||||
|  |                and fields.children ~= "View..." then | ||||||
|  |             local org_name = fields.children | ||||||
|  |             modpol.interactions.org_dashboard(pname, org_name) | ||||||
|  |          end | ||||||
|  |       end | ||||||
|  | end) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.policy_dashboard | ||||||
|  | -- input: user (string), org_id (int), policy (string) | ||||||
|  | -- output: opens a dashboard for viewing/editing policy details | ||||||
|  | -- TODO | ||||||
|  | function modpol.interactions.policy_dashboard( | ||||||
|  |       user, org_id, policy) | ||||||
|  |    modpol.interactions.message( | ||||||
|  |       user, | ||||||
|  |       "Not yet implemented: " .. policy) | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- BASIC INTERACTION FUNCTIONS | ||||||
|  | -- =========================== | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.message | ||||||
|  | -- input: message (string) | ||||||
|  | -- output | ||||||
|  | function modpol.interactions.message(user, message) | ||||||
|  |    minetest.chat_send_player(user, message) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.text_query | ||||||
|  | -- Overrides function at modpol/interactions.lua | ||||||
|  | -- input: user (string), query (string), func (function) | ||||||
|  | --   func input: user input (string) | ||||||
|  | -- output: Applies "func" to user input | ||||||
|  | function modpol.interactions.text_query(user, query, func) | ||||||
|  |    -- set up formspec | ||||||
|  |     local formspec = { | ||||||
|  |        "formspec_version[4]", | ||||||
|  |        "size[10,4]", | ||||||
|  |        "label[0.5,1;", minetest.formspec_escape(query), "]", | ||||||
|  |        "field[0.5,1.25;9,0.8;input;;]",        | ||||||
|  |        "button[0.5,2.5;1,0.8;yes;OK]", | ||||||
|  |     } | ||||||
|  |     local formspec_string = table.concat(formspec, "") | ||||||
|  |     -- present to players | ||||||
|  |     minetest.show_formspec(user, "modpol:text_query", formspec_string) | ||||||
|  |     -- put func in _contexts | ||||||
|  |     if _contexts[user] == nil then _contexts[user] = {} end | ||||||
|  |     _contexts[user]["text_query_func"] = func | ||||||
|  | end | ||||||
|  | -- receive fields | ||||||
|  | minetest.register_on_player_receive_fields(function (player, formname, fields) | ||||||
|  |       if formname == "modpol:text_query" then | ||||||
|  |          local pname = player:get_player_name() | ||||||
|  |          local input = fields.input | ||||||
|  |          if not input then | ||||||
|  |             -- no input, do nothing | ||||||
|  |          else | ||||||
|  |             local func = _contexts[pname]["text_query_func"] | ||||||
|  |             if func then | ||||||
|  |                func(input) | ||||||
|  |             else | ||||||
|  |                modpol.interactions.message(pname, "text_query: " .. input) | ||||||
|  |             end | ||||||
|  |          end | ||||||
|  |          minetest.close_formspec(pname, formname) | ||||||
|  |       end | ||||||
|  | end) | ||||||
|  |  | ||||||
|  | -- Function: dropdown_query | ||||||
|  | -- input: user (string), label (string), options (table of strings), func (function) | ||||||
|  | --    func input: choice (string) | ||||||
|  | -- output: calls func on user choice | ||||||
|  | function modpol.interactions.dropdown_query(user, label, options, func) | ||||||
|  |    -- set up formspec | ||||||
|  |    local formspec = { | ||||||
|  |       "formspec_version[4]", | ||||||
|  |       "size[10,4]", | ||||||
|  |       "label[0.5,1;"..minetest.formspec_escape(label).."]", | ||||||
|  |       "dropdown[0.5,1.25;9,0.8;input;"..formspec_list(options)..";;]", | ||||||
|  |       "button[0.5,2.5;1,0.8;cancel;Cancel]", | ||||||
|  |    } | ||||||
|  |    local formspec_string = table.concat(formspec, "") | ||||||
|  |    -- present to players | ||||||
|  |    minetest.show_formspec(user, "modpol:dropdown_query", formspec_string) | ||||||
|  |    -- put func in _contexts | ||||||
|  |    if _contexts[user] == nil then _contexts[user] = {} end | ||||||
|  |    _contexts[user]["dropdown_query_func"] = func | ||||||
|  | end | ||||||
|  | -- receive fields | ||||||
|  | minetest.register_on_player_receive_fields(function (player, formname, fields) | ||||||
|  |       if formname == "modpol:dropdown_query" then | ||||||
|  |          local pname = player:get_player_name()             | ||||||
|  |          if fields.cancel ~= "cancel" then | ||||||
|  |             local choice = fields.input | ||||||
|  |             local func = _contexts[pname]["dropdown_query_func"] | ||||||
|  |             if not choice then | ||||||
|  |                -- no choice, do nothing | ||||||
|  |             elseif func then | ||||||
|  |                func(choice) | ||||||
|  |             else | ||||||
|  |                modpol.interactions.message(pname, "dropdown_query: " .. choice) | ||||||
|  |             end | ||||||
|  |          end | ||||||
|  |          minetest.close_formspec(pname, formname) | ||||||
|  |       end | ||||||
|  | end) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- SECONDARY INTERACTIONS | ||||||
|  | -- ====================== | ||||||
|  |  | ||||||
|  | -- Function: modpol.binary_poll_user(user, question, function) | ||||||
|  | -- Overrides function at modpol/interactions.lua | ||||||
|  | -- Params: user (string), question (string), func (function) | ||||||
|  | --   func input: user input (string: y/n) | ||||||
|  | -- Output: Applies "func" to user input | ||||||
|  | function modpol.interactions.binary_poll_user(user, question, func) | ||||||
|  |    -- set up formspec | ||||||
|  |    local formspec = { | ||||||
|  |       "formspec_version[4]", | ||||||
|  |       "size[5,3]", | ||||||
|  |       "label[0.375,0.5;",minetest.formspec_escape(question), "]", | ||||||
|  |       "button[1,1.5;1,0.8;yes;Yes]", | ||||||
|  |       "button[2,1.5;1,0.8;no;No]", | ||||||
|  |       --TKTK can we enable text wrapping? | ||||||
|  |       --TKTK we could use scroll boxes to contain the text | ||||||
|  |    } | ||||||
|  |    local formspec_string = table.concat(formspec, "") | ||||||
|  |    if _contexts[user] == nil then _contexts[user] = {} end | ||||||
|  |    _contexts[user]["binary_poll_func"] = func | ||||||
|  |    -- present to player | ||||||
|  |    minetest.show_formspec(user, "modpol:binary_poll_user", formspec_string) | ||||||
|  | end | ||||||
|  | minetest.register_on_player_receive_fields(function (player, formname, fields) | ||||||
|  |       local pname = player:get_player_name() | ||||||
|  |       -- modpol:binary_poll | ||||||
|  |       if formname == "modpol:binary_poll_user" then | ||||||
|  |          local vote = nil | ||||||
|  |          if fields.yes then vote = fields.yes | ||||||
|  |          elseif fields.no then vote = fields.no | ||||||
|  |          end | ||||||
|  |          if vote then | ||||||
|  |             modpol.interactions.message(pname, "Responded " .. vote) | ||||||
|  |             local func = _contexts[pname]["binary_poll_func"] | ||||||
|  |             if func then func(vote) end | ||||||
|  |          end | ||||||
|  |          minetest.close_formspec(pname, formname) | ||||||
|  |       end | ||||||
|  | end) | ||||||
|  |  | ||||||
|  | -- COMPLEX INTERACTIONS | ||||||
|  | -- ==================== | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.message_org | ||||||
|  | -- input: initiator (string), org_id (number), message (string) | ||||||
|  | -- output: broadcasts message to all org members | ||||||
|  | function modpol.interactions.message_org(initiator, org_id, message) | ||||||
|  |    local org = modpol.orgs.get_org(org_id) | ||||||
|  |    local users = org:list_members() | ||||||
|  |    for k,v in ipairs(users) do | ||||||
|  |       modpol.interactions.message(v, message) | ||||||
|  |    end | ||||||
|  | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.binary_poll_org | ||||||
|  | -- input: initator (user string), org_id (number) | ||||||
|  | -- output: gets question from initiator, asks all org members, broadcasts answers | ||||||
|  | -- TODO for testing. This should be implemented as a request. | ||||||
|  | function modpol.interactions.binary_poll_org(initiator, org_id, func) | ||||||
|  |    local org = modpol.orgs.get_org(org_id) | ||||||
|  |    local users = org:list_members() | ||||||
|  |    modpol.interactions.text_query( | ||||||
|  |       initiator, "Yes/no poll question:", | ||||||
|  |       function(input) | ||||||
|  |          for k,v in ipairs(users) do | ||||||
|  |             modpol.interactions.binary_poll_user(v, input, func) | ||||||
|  |          end | ||||||
|  |    end) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.add_org | ||||||
|  | -- input: initator (user string), base_org_id (ID) | ||||||
|  | -- output: interaction begins | ||||||
|  | -- GODMODE | ||||||
|  | function modpol.interactions.add_org(user, base_org_id) | ||||||
|  |    modpol.interactions.text_query( | ||||||
|  |       user,"Org name:", | ||||||
|  |       function(input) | ||||||
|  |          local base_org = modpol.orgs.get_org(1) | ||||||
|  |          local result = base_org:add_org(input, user) | ||||||
|  |          local message = input .. " created" | ||||||
|  |          modpol.interactions.message(user, message) | ||||||
|  |          modpol.interactions.dashboard(user) | ||||||
|  |    end) | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- Function: modpol.interactions.remove_org | ||||||
|  | -- input: initator (user string) | ||||||
|  | -- output: interaction begins | ||||||
|  | -- GODMODE | ||||||
|  | function modpol.interactions.remove_org(user) | ||||||
|  |    -- start formspec | ||||||
|  |    local orgs_list = modpol.orgs.list_all() | ||||||
|  |    local label = "Choose an org to remove:" | ||||||
|  |    modpol.interactions.dropdown_query( | ||||||
|  |       user, label, orgs_list, | ||||||
|  |       function(input) | ||||||
|  |          if input then | ||||||
|  |             local target_org = modpol.orgs.get_org(input) | ||||||
|  |             local result = target_org:delete() | ||||||
|  |             local message = input .. " deleted" | ||||||
|  |             modpol.interactions.message(user, message) | ||||||
|  |          end | ||||||
|  |          modpol.interactions.dashboard(user) | ||||||
|  |    end) | ||||||
|  | end | ||||||
							
								
								
									
										21
									
								
								modpol_minetest/overrides/users.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								modpol_minetest/overrides/users.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  |  | ||||||
|  | -- =================================================================== | ||||||
|  | -- Function: modpol.list_users(org) | ||||||
|  | -- Overwrites function at /users.lua | ||||||
|  | -- Params: | ||||||
|  | -- if nil, lists instance members; if an org name, lists its members | ||||||
|  | -- Output: a table with names of players currently in the game | ||||||
|  | modpol.list_users = function(org) | ||||||
|  |     local users = {} | ||||||
|  |     if (org == nil) then -- no specified org; all players | ||||||
|  |        for _,player in ipairs(minetest.get_connected_players()) do | ||||||
|  |           local name = player:get_player_name() | ||||||
|  |           table.insert(users,name) | ||||||
|  |        end | ||||||
|  |     else -- if an org is specified | ||||||
|  |        if (modpol.orgs[org] ~= nil) then -- org exists | ||||||
|  |           users = modpol.orgs[org]["members"] | ||||||
|  |        end | ||||||
|  |     end | ||||||
|  |     return users | ||||||
|  |  end | ||||||
		Reference in New Issue
	
	Block a user