general overhaul for 5.0.0 (#11)

* general overhaul for 5.0.0

- overhauled English language
- overhauled French language
- adds Spanish locale
- adds German locale
- adds mtt integration testing
- adds github workflow for mtt
- refactores handle_command
- standardizes usage of table.getn() (nothing crucial in this mod)
- standardizes variables to have same format and same name for same
purpouse
- DB-fix also adds missing owners to members
- fixes some situations where admins couldn't do things
- fixes display of dynamic admin priv and registration
- alows uppercase for subcommands
- adds valid_password() for cleaner checks
- ensures that existing factions don't get overwritten

* provide alternative to table.pack()

* add disband hooks support

* remove local f == factions
This commit is contained in:
Luke aka SwissalpS 2024-10-14 04:24:58 +02:00 committed by GitHub
parent 72f52af392
commit c629b298f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 1236 additions and 498 deletions

15
.github/workflows/test.yml vendored Normal file

@ -0,0 +1,15 @@
name: test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: buckaroobanzay/mtt@main
with:
modname: playerfactions
git_dependencies: |
https://github.com/OgelGames/fakelib.git

@ -4,5 +4,7 @@ globals = {
read_globals = { read_globals = {
"minetest", "minetest",
"table" "dump", "dump2",
"table",
"mtt",
} }

714
init.lua

@ -1,36 +1,48 @@
-- Translation support -- Translation support
local S = minetest.get_translator("playerfactions") local S = minetest.get_translator("playerfactions")
-- Data -- Global factions table
factions = {} factions = {}
-- This variable "version" can be used by other mods to check the compatibility of this mod -- This variable "version" can be used by other mods to check
-- the compatibility of this mod
factions.version = 2 factions.version = 2
-- Settings
factions.mode_unique_faction = minetest.settings:get_bool(
"player_factions.mode_unique_faction", true)
factions.max_members_list = tonumber(minetest.settings:get(
"player_factions.max_members_list")) or 50
factions.priv = minetest.settings:get(
"player_factions.priv_admin") or "playerfactions_admin"
-- Privilege registration (if needed)
minetest.register_on_mods_loaded(function() minetest.register_on_mods_loaded(function()
if not minetest.registered_privileges[factions.priv] then if not minetest.registered_privileges[factions.priv] then
minetest.register_privilege("playerfactions_admin", { minetest.register_privilege(factions.priv, {
description = S("Allow the use of all playerfactions commands"), description = S("Allow the use of all playerfactions commands"),
give_to_singleplayer = false give_to_singleplayer = false
}) })
end end
end) end)
-- Hooks
local disband_hooks = {}
-- When a faction is disbanded, these callbacks are called
-- hook(faction_name)
function factions.register_disband_hook(hook)
if 'function' ~= hook then
return false
end
table.insert(disband_hooks, hook)
return true
end
-- Data
local facts = {} local facts = {}
local storage = minetest.get_mod_storage() local storage = minetest.get_mod_storage()
if storage:get_string("facts") ~= "" then if storage:get_string("facts") ~= "" then
facts = minetest.deserialize(storage:get_string("facts")) facts = minetest.deserialize(storage:get_string("facts"))
end end
-- Fix factions
for _, fact in pairs(facts) do
if fact.members == nil then
fact.members = {}
end
end
factions.mode_unique_faction = minetest.settings:get_bool("player_factions.mode_unique_faction", true)
factions.max_members_list = tonumber(minetest.settings:get("player_factions.max_members_list")) or 50
factions.priv = minetest.settings:get("player_factions.priv_admin") or "playerfactions_admin"
local function save_factions() local function save_factions()
storage:set_string("facts", minetest.serialize(facts)) storage:set_string("facts", minetest.serialize(facts))
@ -48,402 +60,401 @@ local function table_copy(data)
end end
end end
-- Data manipulation (API)
-- Data manipulation
function factions.get_facts() function factions.get_facts()
return table_copy(facts) return table_copy(facts)
end end
function factions.player_is_in_faction(fname, player_name) function factions.player_is_in_faction(faction_name, player_name)
if not minetest.player_exists(player_name) or facts[fname] == nil then if not (facts[faction_name] and minetest.player_exists(player_name)) then
return false return false
end end
return facts[fname].members[player_name] return facts[faction_name].members[player_name]
end end
function factions.get_player_faction(name) function factions.get_player_faction(player_name)
if not minetest.player_exists(name) then minetest.log("warning", "Function factions.get_player_faction() "
.. "is deprecated in favor of factions.get_player_factions(). "
.. "Please check updates of mods depending on playerfactions.")
if not minetest.player_exists(player_name) then
return false return false
end end
minetest.log("warning", "Function factions.get_player_faction() is deprecated in favor of " .. for faction_name, fact in pairs(facts) do
"factions.get_player_factions(). Please check updates of mods depending on playerfactions.") if fact.members[player_name] then
for fname, fact in pairs(facts) do return faction_name
if fact.members[name] then
return fname
end end
end end
return nil return nil
end end
function factions.get_player_factions(name) function factions.get_player_factions(player_name)
if not minetest.player_exists(name) then if not minetest.player_exists(player_name) then
return false return false
end end
local player_factions = nil local player_factions = {}
for fname, fact in pairs(facts) do for faction_name, fact in pairs(facts) do
if fact.members[name] then if fact.members[player_name] then
if not player_factions then table.insert(player_factions, faction_name)
player_factions = {}
end
table.insert(player_factions, fname)
end end
end end
return player_factions return 0 < table.getn(player_factions) and player_factions or false
end end
function factions.get_owned_factions(name) function factions.get_owned_factions(player_name)
local own_factions = nil local owned_factions = {}
for fname, fact in pairs(facts) do for faction_name, fact in pairs(facts) do
if fact.owner == name then if fact.owner == player_name then
if not own_factions then table.insert(owned_factions, faction_name)
own_factions = {}
end
table.insert(own_factions, fname)
end end
end end
return own_factions return 0 < table.getn(owned_factions) and owned_factions or false
end end
function factions.get_administered_factions(name) function factions.get_administered_factions(player_name)
local adm_factions = nil local is_admin = minetest.get_player_privs(player_name)[factions.priv]
for fname, fact in pairs(facts) do local adm_factions = {}
if minetest.get_player_privs(name)[factions.priv] or fact.owner == name then for faction_name, fact in pairs(facts) do
if not adm_factions then if is_admin or fact.owner == player_name then
adm_factions = {} table.insert(adm_factions, faction_name)
end
table.insert(adm_factions, fname)
end end
end end
return adm_factions return 0 < table.getn(adm_factions) and adm_factions or false
end end
function factions.get_owner(fname) function factions.get_members(faction_name)
if facts[fname] == nil then if not facts[faction_name] then
return false return false
end end
return facts[fname].owner local faction_members = {}
for player_name in pairs(facts[faction_name].members) do
table.insert(faction_members, player_name)
end
return 0 < table.getn(faction_members) and faction_members or false
end end
function factions.chown(fname, owner) function factions.get_owner(faction_name)
if facts[fname] == nil then if not facts[faction_name] then
return false return false
end end
facts[fname].owner = owner return facts[faction_name].owner
end
function factions.chown(faction_name, player_name)
if not facts[faction_name] then
return false
end
facts[faction_name].owner = player_name
save_factions() save_factions()
return true return true
end end
function factions.register_faction(fname, founder, pw) function factions.register_faction(faction_name, player_name, password)
if facts[fname] ~= nil then if not ('string' == type(faction_name) and 'string' == type(player_name)
and 'string' == type(password)) then
return false return false
end end
facts[fname] = { if facts[faction_name] then
name = fname, return false
owner = founder, end
password = pw, facts[faction_name] = {
members = {[founder] = true} name = faction_name,
owner = player_name,
password = password,
members = { [player_name] = true }
} }
save_factions() save_factions()
return true return true
end end
function factions.disband_faction(fname) function factions.disband_faction(faction_name)
if facts[fname] == nil then if not facts[faction_name] then
return false return false
end end
facts[fname] = nil facts[faction_name] = nil
save_factions()
for _, hook in ipairs(disband_hooks) do
hook(faction_name)
end
return true
end
function factions.valid_password(faction_name, password)
if not facts[faction_name] or not password then
return false
end
return password == facts[faction_name].password
end
function factions.get_password(faction_name)
if not facts[faction_name] then
return false
end
return facts[faction_name].password
end
function factions.set_password(faction_name, password)
if not (facts[faction_name] and 'string' == type(password)) then
return false
end
facts[faction_name].password = password
save_factions() save_factions()
return true return true
end end
function factions.get_password(fname) function factions.join_faction(faction_name, player_name)
if facts[fname] == nil then if not (facts[faction_name] and 'string' == type(player_name)
and minetest.player_exists(player_name)) then
return false return false
end end
return facts[fname].password facts[faction_name].members[player_name] = true
end
function factions.set_password(fname, password)
if facts[fname] == nil then
return false
end
facts[fname].password = password
save_factions() save_factions()
return true return true
end end
function factions.join_faction(fname, player) function factions.leave_faction(faction_name, player_name)
if facts[fname] == nil or not minetest.player_exists(player) then if not (facts[faction_name] and 'string' == type(player_name)
and minetest.player_exists(player_name)) then
return false return false
end end
facts[fname].members[player] = true facts[faction_name].members[player_name] = nil
save_factions()
return true
end
function factions.leave_faction(fname, player_name)
if facts[fname] == nil or not minetest.player_exists(player_name) then
return false
end
facts[fname].members[player_name] = nil
save_factions() save_factions()
return true return true
end end
-- Chat commands -- Chat commands
local function handle_command(name, param) local cc = {}
local params = {}
for p in string.gmatch(param, "[^%s]+") do function cc.create(player_name, params)
table.insert(params, p)
end
if params == nil then
return false, S("Unknown subcommand. Run '/help factions' for help.")
end
local action = params[1]
if action == "create" then
local faction_name = params[2] local faction_name = params[2]
local password = params[3] local password = params[3]
if factions.mode_unique_faction and factions.get_player_faction(name) ~= nil then if not faction_name then
return false, S("You are already in a faction.")
elseif faction_name == nil then
return false, S("Missing faction name.") return false, S("Missing faction name.")
elseif password == nil then elseif not password then
return false, S("Missing password.") return false, S("Missing password.")
elseif facts[faction_name] ~= nil then elseif factions.mode_unique_faction and factions.get_player_factions(player_name) then
return false, S("That faction already exists.") return false, S("You are already in a faction.")
elseif facts[faction_name] then
return false, S("Faction @1 already exists.", faction_name)
else else
factions.register_faction(faction_name, name, password) factions.register_faction(faction_name, player_name, password)
return true, S("Registered @1.", faction_name) return true, S("Registered @1.", faction_name)
end end
elseif action == "disband" then
local password = nil
local faction_name = nil
local own_factions = factions.get_administered_factions(name)
local number_factions = own_factions and #own_factions or 0
if number_factions == 0 then
return false, S("You are the owner of no faction.")
elseif #params == 1 then
return false, S("Missing password.")
elseif #params == 2 and number_factions == 1 then
password = params[2]
faction_name = own_factions[1]
elseif #params >= 3 then
faction_name = params[3]
password = params[2]
end end
if password == nil then
function cc.disband(player_name, params, not_admin)
local password = params[2]
if not password then
return false, S("Missing password.") return false, S("Missing password.")
elseif faction_name == nil then end
local faction_name = params[3]
local owned_factions = factions.get_administered_factions(player_name)
local number_factions = owned_factions and table.getn(owned_factions) or 0
if not_admin and number_factions == 0 then
return false, S("You don't own any factions.")
elseif not faction_name and number_factions == 1 then
faction_name = owned_factions[1]
elseif not faction_name then
return false, S( return false, S(
"You are the owner of many factions, you have to choose one of them: @1.", "You are the owner of multiple factions, you have to choose one of them: @1.",
table.concat(own_factions, ", ") table.concat(owned_factions, ", "))
) end
elseif not facts[faction_name] then if not facts[faction_name] then
return false, S("This faction doesn't exists.") return false, S("Faction @1 doesn't exist.", faction_name)
elseif name ~= factions.get_owner(faction_name) and not minetest.get_player_privs(name)[factions.priv] then elseif not_admin and player_name ~= factions.get_owner(faction_name) then
return false, S("Permission denied: You are not the owner of this faction, " .. return false, S("Permission denied: You are not the owner of that faction,"
"and don't have the playerfactions_admin privilege.") .. " and don't have the @1 privilege.", factions.priv)
elseif password ~= factions.get_password(faction_name) then elseif not_admin and not factions.valid_password(faction_name, password) then
return false, S("Permission denied: Wrong password.") return false, S("Permission denied: Wrong password.")
else else
factions.disband_faction(faction_name) factions.disband_faction(faction_name)
return true, S("Disbanded @1.", faction_name) return true, S("Disbanded @1.", faction_name)
end end
elseif action == "list" then end
function cc.list()
local faction_list = {} local faction_list = {}
for k in pairs(facts) do for k in pairs(facts) do
table.insert(faction_list, k) table.insert(faction_list, k)
end end
if #faction_list ~= 0 then if table.getn(faction_list) == 0 then
return true, S("Factions (@1): @2.", #faction_list, table.concat(faction_list, ", "))
else
return true, S("There are no factions yet.") return true, S("There are no factions yet.")
else
return true, S("Factions (@1): @2.",
table.getn(faction_list), table.concat(faction_list, ", "))
end end
elseif action == "info" then end
function cc.info(player_name, params, not_admin)
local faction_name = params[2] local faction_name = params[2]
if faction_name == nil then if not faction_name then
local player_factions = factions.get_player_factions(name) local player_factions = factions.get_player_factions(player_name)
if not player_factions then if not player_factions then
return true, S("no faction found") return true, S("No factions found.")
elseif #player_factions == 1 then elseif table.getn(player_factions) == 1 then
faction_name = player_factions[1] faction_name = player_factions[1]
else else
return false, S( return false, S(
"You are in many factions, you have to choose one of them: @1.", "You are in multiple factions, you have to choose one of them: @1.",
table.concat(player_factions, ", ") table.concat(player_factions, ", "))
)
end end
end end
if facts[faction_name] == nil then if not facts[faction_name] then
return false, S("This faction doesn't exists.") return false, S("Faction @1 doesn't exist.", faction_name)
else else
local fmembers = "" local faction_members = factions.get_members(faction_name)
if table.getn(facts[faction_name].members) > factions.max_members_list then if table.getn(faction_members) > factions.max_members_list then
fmembers = S("The faction has more than @1 members, the members list can't be shown.", factions.max_members_list) faction_members = { S("The faction has more than @1 members,"
else .. " the members list can't be shown.", factions.max_members_list) }
for play,_ in pairs(facts[faction_name].members) do
if fmembers == "" then
fmembers = play
else
fmembers = fmembers..", "..play
end end
end local summary = S("Name: @1\nOwner: @2\nMembers: @3",
end faction_name, factions.get_owner(faction_name),
local summary = S("Name: @1\nOwner: @2\nMembers: @3", faction_name, factions.get_owner(faction_name), fmembers) table.concat(faction_members, ", "))
if factions.get_owner(faction_name) == name or minetest.get_player_privs(name)[factions.priv] then if not not_admin or factions.get_owner(faction_name) == player_name then
summary = summary .. "\n" .. S("Password: @1", factions.get_password(faction_name)) summary = summary .. "\n"
.. S("Password: @1", factions.get_password(faction_name))
end end
return true, summary return true, summary
end end
elseif action == "player_info" then end
local player_name = params[2]
if not player_name then function cc.player_info(player_name, params)
return false, S("The player name is nil or empty.") player_name = params[2] or player_name
if not player_name or "" == player_name then
return false, S("Missing player name.")
end end
local player_factions = factions.get_player_factions(player_name) local player_factions = factions.get_player_factions(player_name)
if not player_factions then if not player_factions then
return false, S("This player doesn't exists or is in no faction") return false, S(
"Player @1 doesn't exist or isn't in any faction.", player_name)
else else
local str_owner = "" local summary = S("@1 is in the following factions: @2.",
local str_member = "" player_name, table.concat(player_factions, ", "))
for _,v in ipairs(player_factions) do
if str_member == "" then
str_member = str_member..v
else
str_member = str_member..", "..v
end
end
local summary = S("@1 is in the following factions: @2.", player_name, str_member)
local owned_factions = factions.get_owned_factions(player_name) local owned_factions = factions.get_owned_factions(player_name)
if not owned_factions then if owned_factions then
summary = summary.. "\n" .. S("This player is the owner of no faction.") summary = summary .. "\n" .. S(
"@1 is the owner of the following factions: @2.",
player_name, table.concat(owned_factions, ", "))
else else
for _,v in ipairs(owned_factions) do summary = summary .. "\n" .. S(
if str_owner == "" then "@1 doesn't own any factions.", player_name)
str_owner = str_owner..v
else
str_owner = str_owner..", "..v
end
end
summary = summary .. "\n" .. S("This player is the owner of the following factions: @1.", str_owner)
end end
if minetest.get_player_privs(player_name)[factions.priv] then if minetest.get_player_privs(player_name)[factions.priv] then
summary = summary .. "\n" .. S( summary = summary .. "\n" .. S(
"@1 has the playerfactions_admin privilege so they can admin every faction.", "@1 has the @2 privilege so they can admin every faction.",
player_name player_name, factions.priv)
)
end end
return true, summary return true, summary
end end
elseif action == "join" then end
function cc.join(player_name, params)
local faction_name = params[2] local faction_name = params[2]
local password = params[3] local password = params[3]
if factions.get_player_faction(name) ~= nil and factions.mode_unique_faction then if factions.mode_unique_faction and factions.get_player_factions(player_name) then
return false, S("You are already in a faction.") return false, S("You are already in a faction.")
elseif not faction_name then elseif not faction_name then
return false, S("Missing faction name.") return false, S("Missing faction name.")
elseif facts[faction_name] == nil then elseif not facts[faction_name] then
return false, S("The faction @1 doesn't exist.", faction_name) return false, S("Faction @1 doesn't exist.", faction_name)
elseif factions.get_password(faction_name) ~= password then elseif facts[faction_name].members[player_name] then
return false, S("You are already in faction @1.", faction_name)
elseif not factions.valid_password(faction_name, password) then
return false, S("Permission denied: Wrong password.") return false, S("Permission denied: Wrong password.")
else else
if factions.join_faction(faction_name, name) then if factions.join_faction(faction_name, player_name) then
return true, S("Joined @1.", faction_name) return true, S("Joined @1.", faction_name)
else else
return false, S("Error on joining.") return false, S("Error joining faction.")
end end
end end
elseif action == "leave" then end
local player_factions = factions.get_player_factions(name)
function cc.leave(player_name, params)
local player_factions = factions.get_player_factions(player_name)
local number_factions = player_factions and table.getn(player_factions) or 0 local number_factions = player_factions and table.getn(player_factions) or 0
local faction_name = nil local faction_name = params[2]
if number_factions == 0 then if number_factions == 0 then
return false, S("You are not in a faction.") return false, S("You are not in a faction.")
elseif #params == 1 then elseif not faction_name then
if number_factions == 1 then if number_factions == 1 then
faction_name = player_factions[1] faction_name = player_factions[1]
else else
return false, S( return false, S(
"You are in many factions, you have to choose one of them: @1.", "You are in multiple factions, you have to choose one of them: @1.",
table.concat(player_factions, ", ") table.concat(player_factions, ", "))
)
end end
elseif #params >= 1 and facts[params[2]] ~= nil then
faction_name = params[2]
end end
if faction_name == nil then if not facts[faction_name] then
return false, S("The given faction doesn't exists.") return false, S("Faction @1 doesn't exist.", faction_name)
elseif factions.get_owner(faction_name) == name then elseif factions.get_owner(faction_name) == player_name then
return false, S("You cannot leave your own faction, change owner or disband it.") return false, S("You cannot leave your own faction, change owner or disband it.")
elseif not facts[faction_name].members[player_name] then
return false, S("You aren't part of faction @1.", faction_name)
else else
if factions.leave_faction(faction_name, name) then if factions.leave_faction(faction_name, player_name) then
return true, S("Left @1.", faction_name) return true, S("Left @1.", faction_name)
else else
return false, S("Error on leaving faction.") return false, S("Error leaving faction.")
end end
end end
elseif action == "kick" then
local target = nil
local faction_name = nil
local own_factions = factions.get_administered_factions(name)
local number_factions = own_factions and table.getn(own_factions) or 0
if number_factions == 0 then
return false, S("You are the owner of no faction, you can't use this command.")
elseif #params == 2 and number_factions == 1 then
target = params[2]
faction_name = own_factions[1]
elseif #params >= 3 then
faction_name = params[3]
target = params[2]
end end
if faction_name == nil then
return false, S( function cc.kick(player_name, params, not_admin)
"You are the owner of many factions, you have to choose one of them: @1.", local target_name = params[2]
table.concat(own_factions, ", ") if not target_name then
)
elseif target == nil then
return false, S("Missing player name.") return false, S("Missing player name.")
elseif factions.get_owner(faction_name) ~= name and not minetest.get_player_privs(name)[factions.priv] then
return false, S("Permission denied: You are not the owner of this faction, " ..
"and don't have the playerfactions_admin privilege.")
elseif not facts[faction_name].members[target] then
return false, S("This player is not in the specified faction.")
elseif target == factions.get_owner(faction_name) then
return false, S("You cannot kick the owner of a faction, " ..
"use '/factions chown <player> [faction]' to change the ownership.")
else
if factions.leave_faction(faction_name, target) then
return true, S("Kicked @1 from faction.", target)
else
return false, S("Error kicking @1 from faction.", target)
end end
end local faction_name = params[3]
elseif action == "passwd" then local owned_factions = factions.get_administered_factions(player_name)
local password = nil local number_factions = owned_factions and table.getn(owned_factions) or 0
local faction_name = nil if number_factions == 0 then
local own_factions = factions.get_administered_factions(name) return false, S("You don't own any factions, you can't use this command.")
local number_factions = own_factions and table.getn(own_factions) or 0 elseif not faction_name and number_factions == 1 then
if #params == 1 then faction_name = owned_factions[1]
return false, S("Missing password.") elseif not faction_name then
elseif number_factions == 0 then
return false, S("You are the owner of no faction, you can't use this command.")
elseif #params == 2 and number_factions == 1 then
password = params[2]
faction_name = own_factions[1]
elseif #params >= 3 then
faction_name = params[3]
password = params[2]
end
if faction_name == nil then
return false, S( return false, S(
"You are the owner of many factions, you have to choose one of them: @1.", "You are the owner of multiple factions, you have to choose one of them: @1.",
table.concat(own_factions, ", ") table.concat(owned_factions, ", "))
) end
elseif password == nil then if not_admin and factions.get_owner(faction_name) ~= player_name then
return false, S("Permission denied: You are not the owner of that faction, "
.. "and don't have the @1 privilege.", factions.priv)
elseif not facts[faction_name].members[target_name] then
return false, S("@1 is not in the specified faction.", target_name)
elseif target_name == factions.get_owner(faction_name) then
return false, S("You cannot kick the owner of a faction, "
.. "use '/factions chown <player> <password> [<faction>]' "
.. "to change the ownership.")
else
if factions.leave_faction(faction_name, target_name) then
return true, S("Kicked @1 from faction.", target_name)
else
-- SwissalpS is quite positive that this portion is unreachable
return false, S("Error kicking @1 from faction.", target_name)
end
end
end
function cc.passwd(player_name, params, not_admin)
local password = params[2]
if not password then
return false, S("Missing password.") return false, S("Missing password.")
elseif factions.get_owner(faction_name) ~= name and not minetest.get_player_privs(name)[factions.priv] then end
return false, S("Permission denied: You are not the owner of this faction, " .. local faction_name = params[3]
"and don't have the playerfactions_admin privilege.") local owned_factions = factions.get_administered_factions(player_name)
local number_factions = owned_factions and table.getn(owned_factions) or 0
if number_factions == 0 then
return false, S("You don't own any factions, you can't use this command.")
elseif not faction_name and number_factions == 1 then
faction_name = owned_factions[1]
elseif not faction_name then
return false, S(
"You are the owner of multiple factions, you have to choose one of them: @1.",
table.concat(owned_factions, ", "))
end
if not_admin and factions.get_owner(faction_name) ~= player_name then
return false, S("Permission denied: You are not the owner of that faction, "
.. "and don't have the @1 privilege.", factions.priv)
else else
if factions.set_password(faction_name, password) then if factions.set_password(faction_name, password) then
return true, S("Password has been updated.") return true, S("Password has been updated.")
@ -451,95 +462,136 @@ local function handle_command(name, param)
return false, S("Failed to change password.") return false, S("Failed to change password.")
end end
end end
elseif action == "chown" then end
local own_factions = factions.get_administered_factions(name)
local number_factions = own_factions and table.getn(own_factions) or 0 function cc.chown(player_name, params, not_admin)
local faction_name = nil local target_name = params[2]
local target = nil local password = params[3]
local password = nil local faction_name = params[4]
if #params < 3 then if not target_name then
if params[2] ~= nil and minetest.player_exists(params[2]) then
return false, S("Missing password.")
else
return false, S("Missing player name.") return false, S("Missing player name.")
elseif not password then
return false, S("Missing password.")
end end
elseif number_factions == 0 then local owned_factions = factions.get_administered_factions(player_name)
return false, S("You are the owner of no faction, you can't use this command.") local number_factions = owned_factions and table.getn(owned_factions) or 0
elseif number_factions == 1 and #params == 3 then if number_factions == 0 then
faction_name = own_factions[1] return false, S("You don't own any factions, you can't use this command.")
target = params[2] elseif not faction_name and number_factions == 1 then
password = params[3] faction_name = owned_factions[1]
elseif #params >= 4 then elseif not faction_name then
faction_name = params[4]
target = params[2]
password = params[3]
end
if faction_name == nil then
return false, S( return false, S(
"You are the owner of many factions, you have to choose one of them: @1.", "You are the owner of multiple factions, you have to choose one of them: @1.",
table.concat(own_factions, ", ") table.concat(owned_factions, ", "))
) end
elseif target == nil then if not_admin and player_name ~= factions.get_owner(faction_name) then
return false, S("Missing player name.") return false, S("Permission denied: You are not the owner of that faction, "
elseif password == nil then .. "and don't have the @1 privilege.", factions.priv)
return false, S("Missing password.") elseif not facts[faction_name].members[target_name] then
elseif name ~= factions.get_owner(faction_name) and not minetest.get_player_privs(name)[factions.priv] then return false, S("@1 isn't in faction @2.", target_name, faction_name)
return false, S("Permission denied: You are not the owner of this faction, " .. elseif not_admin and not factions.valid_password(faction_name, password) then
"and don't have the playerfactions_admin privilege.")
elseif not facts[faction_name].members[target] then
return false, S("@1 isn't in your faction.", target)
elseif password ~= factions.get_password(faction_name) then
return false, S("Permission denied: Wrong password.") return false, S("Permission denied: Wrong password.")
else else
if factions.chown(faction_name, target) then if factions.chown(faction_name, target_name) then
return true, S("Ownership has been transferred to @1.", target) return true, S("Ownership has been transferred to @1.", target_name)
else else
return false, S("Failed to transfer ownership.") return false, S("Failed to transfer ownership.")
end end
end end
elseif action == "invite" then end
if not minetest.get_player_privs(name)[factions.priv] then
return false, S("Permission denied: You can't use this command, playerfactions_admin priv is needed.") function cc.invite(_, params, not_admin)
else if not_admin then
local target = params[2] return false, S(
"Permission denied: You can't use this command, @1 priv is needed.",
factions.priv)
end
local target_name = params[2]
local faction_name = params[3] local faction_name = params[3]
if not target then if not target_name then
return false, S("Missing target.") return false, S("Missing player name.")
elseif not faction_name then elseif not faction_name then
return false, S("Missing faction name.") return false, S("Missing faction name.")
elseif facts[faction_name] == nil then elseif not facts[faction_name] then
return false, S("The faction @1 doesn't exist.", faction_name) return false, S("Faction @1 doesn't exist.", faction_name)
elseif not minetest.player_exists(target) then elseif not minetest.player_exists(target_name) then
return false, S("The player doesn't exist.") return false, S("Player @1 doesn't exist.", target_name)
elseif factions.mode_unique_faction and factions.get_player_faction(target) ~= nil then end
return false, S("The player is already in the faction \"@1\".",factions.get_player_faction(target)) local player_factions = factions.get_player_factions(target_name)
if facts[faction_name].members[target_name] then
return false, S("Player @1 is already in faction @2.",
target_name, faction_name)
elseif player_factions and factions.mode_unique_faction then
return false, S("Player @1 is already in faction @2.",
target_name, player_factions[1])
else else
if factions.join_faction(faction_name, target) then if factions.join_faction(faction_name, target_name) then
return true, S("@1 is now a member of the faction @2.", target, faction_name) return true, S("@1 is now a member of faction @2.", target_name, faction_name)
else else
return false, S("Error on adding @1 into @2.", target, faction_name) -- is this portion ever reachable at all?
return false, S("Error adding @1 to @2.", target_name, faction_name)
end end
end end
end end
else
local function handle_command(player_name, param)
local params = {}
for p in string.gmatch(param, "[^%s]+") do
table.insert(params, p)
end
local action = params[1]
if not action or not cc[action:lower()] then
return false, S("Unknown subcommand. Run '/help factions' for help.") return false, S("Unknown subcommand. Run '/help factions' for help.")
end end
local not_admin = not minetest.get_player_privs(player_name)[factions.priv]
return cc[action:lower()](player_name, params, not_admin)
end end
minetest.register_chatcommand("factions", { minetest.register_chatcommand("factions", {
params = "create <faction> <password>: " .. S("Create a new faction") .. "\n" params = "create <faction> <password>: " .. S("Create a new faction") .. "\n"
.. "list: " .. S("List available factions") .. "\n" .. "list: " .. S("List available factions") .. "\n"
.."info <faction>: "..S("See information on a faction").."\n" .. "info [<faction>]: " .. S("See information about a faction") .. "\n"
.."player_info <player>: "..S("See information on a player").."\n" .. "player_info [<player>]: " .. S("See information about a player") .. "\n"
.. "join <faction> <password>: " .. S("Join an existing faction") .. "\n" .. "join <faction> <password>: " .. S("Join an existing faction") .. "\n"
.."leave [faction]: "..S("Leave your faction").."\n" .. "leave [<faction>]: " .. S("Leave your faction") .. "\n"
.."kick <player> [faction]: "..S("Kick someone from your faction or from the given faction").."\n" .. "kick <player> [<faction>]: "
.."disband <password> [faction]: "..S("Disband your faction or the given faction").."\n" .. S("Kick someone from your faction or from the given faction") .. "\n"
.."passwd <password> [faction]: "..S("Change your faction's password or the password of the given faction").."\n" .. "disband <password> [<faction>]: "
.."chown <player> [faction]: "..S("Transfer ownership of your faction").."\n" .. S("Disband your faction or the given faction") .. "\n"
.."invite <player> <faction>: "..S("Add player to a faction, you need playerfactions_admin privs").."\n", .. "passwd <password> [<faction>]: "
.. S("Change your faction's password or the password of the given faction") .." \n"
.. "chown <player> <password> [<faction>]: "
.. S("Transfer ownership of your faction") .. "\n"
.. "invite <player> <faction>: "
.. S("Add player to a faction, you need @1 priv", factions.priv) .. "\n",
description = "", description = "",
privs = {}, privs = {},
func = handle_command func = handle_command
}) })
-- Fix factions
do
local save_needed = false
for _, fact in pairs(facts) do
if not fact.members then
fact.members = {
[fact.owner] = true
}
save_needed = true
end
end
if save_needed then
save_factions()
end
end
-- Integration testing
if minetest.get_modpath("mtt") and mtt.enabled then
factions.S = S
factions.handle_command = handle_command
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/mtt.lua")
end
print("[playerfactions] loaded")

@ -0,0 +1,79 @@
# textdomain: playerfactions
### init.lua ###
@1 has the @2 privilege so they can admin every faction.=@1 hat das @2-Privileg, sodass er jede Fraktion verwalten kann.
@1 is in the following factions: @2.=@1 ist in den folgenden Fraktionen: @2.
@1 is now a member of faction @2.=@1 ist jetzt Mitglied der Fraktion @2.
@1 isn't in faction @2.=@1 ist nicht in der Fraktion @2.
Add player to a faction, you need @1 privs=Füge einen Spieler zu einer Fraktion hinzu, du benötigst @1-Privilegien
Allow the use of all playerfactions commands=Erlaubt die Verwendung aller Fraktionsbefehle
Change your faction's password or the password of the given faction=Ändere das Passwort deiner Fraktion oder das Passwort der angegebenen Fraktion
Create a new faction=Erstelle eine neue Fraktion
Disband your faction or the given faction=Löse deine Fraktion oder die angegebene Fraktion auf
Disbanded @1.=@1 aufgelöst.
Error kicking @1 from faction.=Fehler beim Rauswerfen von @1 aus der Fraktion.
Error adding @1 to @2.=Fehler beim Hinzufügen von @1 zu @2
Error joining faction.=Fehler beim Beitritt zur Fraktion.
Error leaving faction.=Fehler beim Verlassen der Fraktion.
Factions (@1): @2.=Fraktionen (@1): @2.
Failed to change password.=Passwort konnte nicht geändert werden.
Failed to transfer ownership.=Eigentum konnte nicht übertragen werden.
Join an existing faction=Trete einer bestehenden Fraktion bei
Joined @1.=Bist @1 beigetreten.
Kick someone from your faction or from the given faction=Jemanden aus deiner Fraktion oder der angegebenen Fraktion werfen
Kicked @1 from faction.=@1 aus Fraktion geworfen.
Leave your faction=Deine Fraktion verlassen
Left @1.=Hast @1 verlassen.
List available factions=Verfügbare Fraktionen auflisten
Missing faction name.=Fraktionsname fehlt.
Missing password.=Passwort fehlt.
Missing player name.=Spielername fehlt.
Name: @1@nOwner: @2@nMembers: @3=Name: @1@nBesitzer: @2@nMitglieder: @3
Ownership has been transferred to @1.=Eigentum wurde auf @1 übertragen.
Password has been updated.=Passwort wurde aktualisiert.
Password: @1=Passwort: @1
Permission denied: Wrong password.=Berechtigung verweigert: Falsches Passwort.
Permission denied: You are not the owner of that faction, and don't have the @1 privilege.=Berechtigung verweigert: Du bist nicht der Besitzer dieser Fraktion und hast nicht das @1-Privileg.
Permission denied: You can't use this command, @1 priv is needed.=Berechtigung verweigert: Du kannst diesen Befehl nicht verwenden, @1-Privileg ist erforderlich.
Registered @1.=@1 Registriert.
See information about a faction=Informationen zu einer Fraktion anzeigen
See information about a player=Informationen zu einem Spieler anzeigen
Faction @1 already exists.=Fraktion @1 existiert bereits.
Faction @1 doesn't exist.=Fraktion @1 existiert nicht.
The faction has more than @1 members, the members list can't be shown.=Die Fraktion hat mehr als @1 Mitglieder, die Mitgliederliste kann nicht angezeigt werden.
Player @1 doesn't exist.=Spieler @1 existiert nicht.
Player @1 is already in the faction @2.=Spieler @1 ist bereits in der Fraktion @2.
There are no factions yet.=Es gibt noch keine Fraktionen.
Player @1 doesn't exist or isn't in any faction.=Spieler @1 existiert nicht oder ist in keiner Fraktion.
@1 is not in the specified faction.=@1 ist nicht in der angegebenen Fraktion.
@1 doesn't own any factions.=@1 besitzt keine Fraktionen.
@1 is the owner of the following factions: @2.=@1 ist der Besitzer der folgenden Fraktionen: @2.
Transfer ownership of your faction=Eigentum deiner Fraktion übertragen
Unknown subcommand. Run '/help factions' for help.=Unbekannter Unterbefehl. Führe „/help factions“ aus, um Hilfe zu erhalten.
You are already in a faction.=Du bist bereits in einer Fraktion.
You are in multiple factions, you have to choose one of them: @1.=Du bist in mehreren Fraktionen, du musst eine davon auswählen: @1.
You are not in a faction.=Du bist in keiner Fraktion.
You are the owner of multiple factions, you have to choose one of them: @1.=Du bist der Besitzer mehrerer Fraktionen, du musst eine davon auswählen: @1.
You don't own any factions, you can't use this command.=Du besitzst keine Fraktionen, du kannst diesen Befehl nicht verwenden.
You don't own any factions.=Du besitzst keine Fraktionen.
You cannot kick the owner of a faction, use '/factions chown <player> <password> [<faction>]' to change the ownership.=Du kannst den Besitzer einer Fraktion nicht rauswerfen, verwende „/factions chown <Spieler> <Passwort> [<Fraktion>]“, um den Besitzer zu ändern.
You cannot leave your own faction, change owner or disband it.=Du kannst deine eigene Fraktion nicht verlassen, wechsle den Besitzer oder löse die Fraktion auf.
No factions found.=Keine Fraktionen gefunden.
You aren't part of faction @1.=Du bist nicht Teil der Fraktion @1.
You are already in faction @1.=Du bist bereits in der Fraktion @1.

@ -0,0 +1,79 @@
# textdomain: playerfactions
### init.lua ###
@1 has the @2 privilege so they can admin every faction.=@1 tiene el privilegio @2, por lo que puede administrar todas las facciones.
@1 is in the following factions: @2.=@1 está en las siguientes facciones: @2.
@1 is now a member of faction @2.=@1 ahora es miembro de la facción @2.
@1 isn't in faction @2.=@1 no está en la facción @2.
Add player to a faction, you need @1 privs=Agrega un jugador a una facción, necesitas los privilegios @1
Allow the use of all playerfactions commands=Permite el uso de todos los comandos de facciones
Change your faction's password or the password of the given faction=Cambiar la contraseña de tu facción o la contraseña de la facción indicada
Create a new faction=Crear una nueva facción
Disband your faction or the given faction=Disolver tu facción o la facción indicada
Disbanded @1.=Disuelto @1.
Error kicking @1 from faction.=Error al expulsar a @1 de la facción.
Error adding @1 to @2.=Error al agregar @1 a @2.
Error joining faction.=Error al unirse a la facción.
Error leaving faction.=Error al salir de la facción.
Factions (@1): @2.=Facciones (@1): @2.
Failed to change password.=Error al cambiar la contraseña.
Failed to transfer ownership.=Error al transferir la propiedad.
Join an existing faction=Unirse a una facción existente
Joined @1.=Te uniste @1.
Kick someone from your faction or from the given faction=Expulsar a alguien de tu facción o de la facción indicada
Kicked @1 from faction.=Expulsaste a @1 de la facción.
Leave your faction=Abandonar tu facción
Left @1.=Abandonaste @1.
List available factions=Lista de facciones disponibles
Missing faction name.=Falta el nombre de la facción.
Missing password.=Falta la contraseña.
Missing player name.=Falta el nombre del jugador.
Name: @1@nOwner: @2@nMembers: @3=Nombre: @1@nPropietario: @2@nMiembros: @3
Ownership has been transferred to @1.=La propiedad ha sido transferida a @1.
Password has been updated.=La contraseña ha sido actualizada.
Password: @1=Contraseña: @1
Permission denied: Wrong password.=Permiso denegado: Contraseña incorrecta.
Permission denied: You are not the owner of that faction, and don't have the @1 privilege.=Permiso denegado: No eres el propietario de esa facción y no tienes el privilegio @1.
Permission denied: You can't use this command, @1 priv is needed.=Permiso denegado: No puedes usar este comando, necesitas el privilegio @1.
Registered @1.=@1 registrado.
See information about a faction=Ver información sobre una facción
See information about a player=Ver información sobre un jugador
Faction @1 already exists.=La facción @1 ya existe.
Faction @1 doesn't exist.=La facción @1 no existe.
The faction has more than @1 members, the members list can't be shown.=La facción tiene más de @1 miembros, la lista de miembros no se puede mostrar.
Player @1 doesn't exist.=El jugador @1 no existe.
Player @1 is already in the faction @2.=El jugador @1 ya está en la facción @2.
There are no factions yet.=Todavía no hay facciones.
Player @1 doesn't exist or isn't in any faction.=El jugador @1 no existe o no está en ninguna facción.
@1 is not in the specified faction.=@1 no está en la facción especificada.
@1 doesn't own any factions.=@1 no posee ninguna facción.
@1 is the owner of the following factions: @2.=@1 es el propietario de las siguientes facciones: @2.
Transfer ownership of your faction=Transferir la propiedad de tu facción
Unknown subcommand. Run '/help factions' for help.=Subcomando desconocido. Ejecuta '/help factions' para obtener ayuda.
You are already in a faction.=Ya estás en una facción.
You are in multiple factions, you have to choose one of them: @1.=Estás en varias facciones, debes elegir una de ellas: @1.
You are not in a faction.=No estás en una facción.
You are the owner of multiple factions, you have to choose one of them: @1.=Eres el propietario de varias facciones, debes elegir una de ellas: @1.
You don't own any factions, you can't use this command.=No posees ninguna facción, no puedes usar este comando.
You don't own any factions.=No posees ninguna facción.
You cannot kick the owner of a faction, use '/factions chown <player> <password> [<faction>]' to change the ownership.=No puedes expulsar al propietario de una facción, usa '/factions chown <jugador> <contraseña> [<facción>]' para cambiar la propiedad.
You cannot leave your own faction, change owner or disband it.=No puedes abandonar tu propia facción, cambiar de propietario o disolverla.
No factions found.=Ninguna facción encontrado.
You aren't part of faction @1.=No eres parte de la facción @1.
You are already in faction @1.=Ya estás en la facción @1.

@ -3,79 +3,78 @@
### init.lua ### ### init.lua ###
@1 has the playerfactions_admin privilege so they can admin every faction.=@1 a le privilège playerfactions_admin et peut donc administrer toutes les factions. @1 has the @2 privilege so they can admin every faction.=@1 a le privilège @2 et peut donc administrer toutes les factions.
@1 is in the following factions: @2.=@1 est dans les factions suivantes : @2. @1 is in the following factions: @2.=@1 est dans les factions suivantes : @2.
@1 is now a member of the faction @2.=@1 est maintenant membre de la faction @2. @1 is now a member of faction @2.=@1 est maintenant membre de la faction @2.
@1 isn't in your faction.=@1 nest pas dans votre faction. @1 isn't in faction @2.=@1 nest pas dans la faction @2.
Add player to a faction, you need playerfactions_admin privs=Ajoute un joueur à une faction, nécessite le privilège playerfactions_admin Add player to a faction, you need @1 privs=Ajoute un joueur à une faction, nécessite le privilège @1
Allow the use of all playerfactions commands=Autorise lutilisation de toutes les commandes de playerfactions Allow the use of all playerfactions commands=Autorise lutilisation de toutes les commandes de playerfactions
Change your faction's password or the password of the given faction=Change le mot de passe de votre faction ou la faction donnée Change your faction's password or the password of the given faction=Change le mot de passe de ta faction ou la faction donnée
Create a new faction=Crée une nouvelle faction Create a new faction=Crée une nouvelle faction
Disband your faction or the given faction=Dissoudre votre faction ou la faction donnée Disband your faction or the given faction=Dissoudre ta faction ou la faction donnée
Disbanded @1.=@1 est dissoute. Disbanded @1.=@1 est dissoute.
Error kicking @1 from faction.=Erreur lors de la tentative de virer @1 de la faction. Error kicking @1 from faction.=Erreur lors de la tentative de virer @1 de la faction.
Error on adding @1 into @2.=Erreur lors de lajout de @1 dans @2. Error adding @1 to @2.=Erreur lors de lajout de @1 dans @2.
Error on joining.=Erreur lors de la tentative de rejoindre la faction. Error joining faction.=Erreur lors de la tentative de rejoindre la faction.
Error on leaving faction.=Erreur lors de la tentative de quitter la faction. Error leaving faction.=Erreur lors de la tentative de quitter la faction.
Factions (@1): @2.=Factions (@1) : @2. Factions (@1): @2.=Factions (@1) : @2.
Failed to change password.=Echec du changement de mot de passe. Failed to change password.=Echec du changement de mot de passe.
Failed to transfer ownership.=Echec du transfert de propriété. Failed to transfer ownership.=Echec du transfert de propriété.
Join an existing faction=Rejoindre une faction existante. Join an existing faction=Rejoindre une faction existante.
Joined @1.=Vous avez rejoint @1. Joined @1.=Tu as rejoint @1.
Kick someone from your faction or from the given faction=Virer quelquun de votre faction ou de la faction donnée. Kick someone from your faction or from the given faction=Virer quelquun de ta faction ou de la faction donnée.
Kicked @1 from faction.=@1 a été viré de la faction. Kicked @1 from faction.=@1 a été viré de la faction.
Leave your faction=Quitter votre faction Leave your faction=Quitter ta faction
Left @1.=Vous avez quitté @1. Left @1.=Tu as quitté @1.
List available factions=Liste les factions disponibles List available factions=Liste les factions disponibles
Missing faction name.=Nom de faction manquant. Missing faction name.=Nom de faction manquant.
Missing password.=Mot de passe manquant. Missing password.=Mot de passe manquant.
Missing player name.=Nom de joueur manquant. Missing player name.=Nom de joueur manquant.
Missing target.=Nom du joueur cible manquant.
Name: @1@nOwner: @2@nMembers: @3=Nom : @1@nPropriétaire : @2@nMembres : @3 Name: @1@nOwner: @2@nMembers: @3=Nom : @1@nPropriétaire : @2@nMembres : @3
Ownership has been transferred to @1.=La propriété a été transférée à @1. Ownership has been transferred to @1.=La propriété a été transférée à @1.
Password has been updated.=Le mot de passe a été mis à jour. Password has been updated.=Le mot de passe a été mis à jour.
Password: @1=Mot de passe : @1 Password: @1=Mot de passe : @1
Permission denied: Wrong password.=Permission refusée : mauvais mot de passe. Permission denied: Wrong password.=Permission refusée : mauvais mot de passe.
Permission denied: You are not the owner of this faction, and don't have the playerfactions_admin privilege.=Permission refusée : vous nêtes pas le propriétaire de cette faction, et navez pas le privilège playerfactions_admin. Permission denied: You are not the owner of that faction, and don't have the @1 privilege.=Permission refusée : tu n'es pas le propriétaire de cette faction, et tu n'as pas le privilège @1.
Permission denied: You can't use this command, playerfactions_admin priv is needed.=Permission refusée : vous ne pouvez pas utiliser cette commande, le privilège playerfactions_admin est nécessaire. Permission denied: You can't use this command, @1 priv is needed.=Permission refusée : tu ne peux pas utiliser cette commande, le privilège @1 est nécessaire.
Registered @1.=@1 enregistrée. Registered @1.=@1 enregistrée.
See information on a faction=Voir les informations dune faction See information about a faction=Voir les informations dune faction
See information on a player=Voir les informations dun joueur See information about a player=Voir les informations dun joueur
That faction already exists.=Cette faction existe déjà. Faction @1 already exists.=La faction @1 existe déjà.
The faction @1 doesn't exist.=La faction @1 nexiste pas. Faction @1 doesn't exist.=La faction @1 nexiste pas.
The faction has more than @1 members, the members list can't be shown.=Cette faction a plus que @1 membres, la liste des membres ne peut pas être affichée. The faction has more than @1 members, the members list can't be shown.=Cette faction a plus que @1 membres, la liste des membres ne peut pas être affichée.
The given faction doesn't exists.=La faction en question nexiste pas. Player @1 doesn't exist.=Le joueur @1 nexiste pas.
The player doesn't exist.=Le joueur nexiste pas. Player @1 is already in the faction @2.=Le joueur @1 est déjà dans la faction @2.
The player is already in the faction "@1".=Le joueur est déjà dans la faction "@1".
There are no factions yet.=Il ny a pas encore de factions. There are no factions yet.=Il ny a pas encore de factions.
This faction doesn't exists.=Cette faction nexiste pas. Player @1 doesn't exist or isn't in any faction.=Le joueur @1 nexiste pas ou nest dans aucune faction.
The player name is nil or empty.=Le nom du joueur est nul ou vide. @1 is not in the specified faction.=@1 nest pas dans la faction spécifiée.
This player doesn't exists or is in no faction=Ce joueur nexiste pas ou nest dans aucune faction. @1 doesn't own any factions.=@1 nest propriétaire daucune faction.
This player is not in the specified faction.=Le joueur nest pas dans la faction spécifiée. @1 is the owner of the following factions: @2.=@1 est le propriétaire des factions suivantes : @2.
This player is the owner of no faction.=Ce joueur nest propriétaire daucune faction. Transfer ownership of your faction=Transfert la propriété de ta faction
This player is the owner of the following factions: @1.=Ce joueur nest le propriétaire daucune des factions suivantes : @1. Unknown subcommand. Run '/help factions' for help.=Sous-commande inconnue. Fais '/help factions' pour laide.
Transfer ownership of your faction=Transfert la propriété de votre faction You are already in a faction.=Tu es déjà dans une faction.
Unknown subcommand. Run '/help factions' for help.=Sous-commande inconnue. Faites '/help factions' pour laide.
You are already in a faction.=Vous êtes déjà dans une faction.
You are in many factions, you have to choose one of them: @1.=Vous êtes dans plusieurs factions, vous devez choisir lune dentre elles : @1. You are in multiple factions, you have to choose one of them: @1.=Tu es dans plusieurs factions, tu dois choisir lune dentre elles : @1.
You are not in a faction.=Vous nêtes dans aucune faction. You are not in a faction.=Tu n'es dans aucune faction.
You are the owner of many factions, you have to choose one of them: @1.=Vous êtes propriétaire de plusieurs factions, vous devez choisir lune dentre elles : @1. You are the owner of multiple factions, you have to choose one of them: @1.=Tu es propriétaire de plusieurs factions, tu dois choisir lune dentre elles : @1.
You are the owner of no faction, you can't use this command.=Vous nêtes propriétaire daucune faction, vous ne pouvez pas utiliser cette commande. You don't own any factions, you can't use this command.=Tu n'es propriétaire daucune faction, tu ne peux pas utiliser cette commande.
You are the owner of no faction.=Vous nêtes propriétaire daucune faction. You don't own any factions.=Tu n'es propriétaire daucune faction.
You cannot kick the owner of a faction, use '/factions chown <player> [faction]' to change the ownership.=Vous ne pouvez pas virer le propriétaire de sa faction, utilisez '/factions chown <player> [faction]' pour changer le propriétaire. You cannot kick the owner of a faction, use '/factions chown <player> <password> [<faction>]' to change the ownership.=Tu ne peux pas virer le propriétaire de sa faction, utilise '/factions chown <joueur> <mot de passe> [<faction>]' pour changer le propriétaire.
You cannot leave your own faction, change owner or disband it.=Vous ne pouvez pas quitter votre propre faction, changez le propriétaire ou dissolvez la. You cannot leave your own faction, change owner or disband it.=Tu ne peux pas quitter ta propre faction, change le propriétaire ou dissout la.
No factions found.=Aucune faction trouvée.
You aren't part of faction @1.=Tu ne fais pas partie de la faction @1.
You are already in faction @1.=Tu es déjà dans la faction @1.

@ -3,12 +3,12 @@
### init.lua ### ### init.lua ###
@1 has the playerfactions_admin privilege so they can admin every faction.= @1 has the @2 privilege so they can admin every faction.=
@1 is in the following factions: @2.= @1 is in the following factions: @2.=
@1 is now a member of the faction @2.= @1 is now a member of faction @2.=
@1 isn't in your faction.= @1 isn't in faction @2.=
Add player to a faction, you need playerfactions_admin privs= Add player to a faction, you need @1 privs=
Allow the use of all playerfactions commands= Allow the use of all playerfactions commands=
Change your faction's password or the password of the given faction= Change your faction's password or the password of the given faction=
@ -17,9 +17,9 @@ Create a new faction=
Disband your faction or the given faction= Disband your faction or the given faction=
Disbanded @1.= Disbanded @1.=
Error kicking @1 from faction.= Error kicking @1 from faction.=
Error on adding @1 into @2.= Error adding @1 to @2.=
Error on joining.= Error joining faction.=
Error on leaving faction.= Error leaving faction.=
Factions (@1): @2.= Factions (@1): @2.=
Failed to change password.= Failed to change password.=
Failed to transfer ownership.= Failed to transfer ownership.=
@ -33,49 +33,48 @@ List available factions=
Missing faction name.= Missing faction name.=
Missing password.= Missing password.=
Missing player name.= Missing player name.=
Missing target.=
Name: @1@nOwner: @2@nMembers: @3= Name: @1@nOwner: @2@nMembers: @3=
Ownership has been transferred to @1.= Ownership has been transferred to @1.=
Password has been updated.= Password has been updated.=
Password: @1= Password: @1=
Permission denied: Wrong password.= Permission denied: Wrong password.=
Permission denied: You are not the owner of this faction, and don't have the playerfactions_admin privilege.= Permission denied: You are not the owner of that faction, and don't have the @1 privilege.=
Permission denied: You can't use this command, playerfactions_admin priv is needed.= Permission denied: You can't use this command, @1 priv is needed.=
Registered @1.= Registered @1.=
See information on a faction= See information about a faction=
See information on a player= See information about a player=
That faction already exists.= Faction @1 already exists.=
The faction @1 doesn't exist.= Faction @1 doesn't exist.=
The faction has more than @1 members, the members list can't be shown.= The faction has more than @1 members, the members list can't be shown.=
The given faction doesn't exists.= Player @1 doesn't exist.=
The player doesn't exist.= Player @1 is already in the faction @2.=
The player is already in the faction "@1".=
There are no factions yet.= There are no factions yet.=
This faction doesn't exists.= Player @1 doesn't exist or isn't in any faction.=
The player name is nil or empty.= @1 is not in the specified faction.=
This player doesn't exists or is in no faction= @1 doesn't own any factions.=
This player is not in the specified faction.= @1 is the owner of the following factions: @2.=
This player is the owner of no faction.=
This player is the owner of the following factions: @1.=
Transfer ownership of your faction= Transfer ownership of your faction=
Unknown subcommand. Run '/help factions' for help.= Unknown subcommand. Run '/help factions' for help.=
You are already in a faction.= You are already in a faction.=
You are in many factions, you have to choose one of them: @1.= You are in multiple factions, you have to choose one of them: @1.=
You are not in a faction.= You are not in a faction.=
You are the owner of many factions, you have to choose one of them: @1.= You are the owner of multiple factions, you have to choose one of them: @1.=
You are the owner of no faction, you can't use this command.= You don't own any factions, you can't use this command.=
You are the owner of no faction.= You don't own any factions.=
You cannot kick the owner of a faction, use '/factions chown <player> [faction]' to change the ownership.= You cannot kick the owner of a faction, use '/factions chown <player> <password> [<faction>]' to change the ownership.=
You cannot leave your own faction, change owner or disband it.= You cannot leave your own faction, change owner or disband it.=
No factions found.=
You aren't part of faction @1.=
You are already in faction @1.=

@ -1,2 +1,3 @@
name = playerfactions name = playerfactions
min_minetest_version = 5.0.0 min_minetest_version = 5.0.0
optional_depends = mtt

512
mtt.lua Normal file

@ -0,0 +1,512 @@
-- requires [fakelib] to work properly
-- https://github.com/OgelGames/fakelib.git
local pd
if table.pack then
pd = function(...) print(dump(table.pack(...))) end
else
pd = function(...) for _, v in ipairs({ ... }) do print(dump(v)) end end
end
local fcc, S = factions.handle_command, factions.S
factions.mode_unique_faction = false
factions.max_members_list = 11
-- factions chat command checker
-- b1: expected return bool
-- s1: expected return string
-- n: name of command executor
-- c: string of command parameters (the "/factions " part cut off)
local function fccc(b1, s1, n, c)
local b2, s2 = fcc(n, c)
return b1 == b2 and s1 == s2
end
local function resetDB()
for k in pairs(factions.get_facts()) do
factions.disband_faction(k)
end
end
local function makeFactions()
return factions.register_faction('Endorian', 'Endor', 'eEe')
and factions.register_faction('Alberian', 'Albert', 'a')
and factions.register_faction('Gandalfian', 'Gandalf', 'GgG♥💩☺')
end
local function dbChecks(callback)
-- basic db integrity tests
local facts = factions.get_facts()
assert('table' == type(facts))
assert('table' == type(facts.Alberian))
assert('Albert' == facts.Alberian.owner)
assert('Alberian' == facts.Alberian.name)
assert('table' == type(facts.Alberian.members))
-- make sure owners have been added as memebers
assert(true == facts.Alberian.members.Albert)
-- should never fail
assert('eEe' == facts.Endorian.password)
assert('a' == facts.Alberian.password)
assert('GgG♥💩☺' == facts.Gandalfian.password)
callback()
end
mtt.register('reset db', function(callback) resetDB() callback() end)
mtt.register('join & setup players', function(callback)
-- some player
assert('table' == type(mtt.join_player('Endor')))
-- faction admin
assert('table' == type(mtt.join_player('Albert')))
-- some other player
assert('table' == type(mtt.join_player('Gandalf')))
-- player without privs or factions
assert('table' == type(mtt.join_player('HanSolo')))
-- make Albert a faction-admin
local player_privs = minetest.get_player_privs('Albert')
player_privs[factions.priv] = true
minetest.set_player_privs('Albert', player_privs)
-- make sure the others aren't
for _, name in ipairs({ 'Endor', 'Gandalf', 'HanSolo' }) do
player_privs = minetest.get_player_privs(name)
player_privs[factions.priv] = nil
minetest.set_player_privs(name, player_privs)
end
callback()
end)
mtt.register('some players leave', function(callback)
-- let's test without the admin online
assert(true == mtt.leave_player('Albert'))
assert(true == mtt.leave_player('Gandalf'))
callback()
end)
mtt.register('make factions with backend', function(callback)
assert(makeFactions())
callback()
end)
mtt.register('basic db checks', dbChecks)
mtt.register('backend functions: player_is_in_faction', function(callback)
assert(false == factions.player_is_in_faction(
'notExistingFaction', 'notExistingPlayer'))
assert(false == factions.player_is_in_faction(
'notExistingFaction', 'Gandalf'))
assert(false == factions.player_is_in_faction(
'Gandalfian', 'notExistingPlayer'))
assert(nil == factions.player_is_in_faction(
'Gandalfian', 'Albert'))
assert(true == factions.player_is_in_faction(
'Gandalfian', 'Gandalf'))
callback()
end)
mtt.register('backend functions: get_player_faction', function(callback)
-- (depricated) --> check log output for messages
assert(false == factions.get_player_faction('notExistingPlayer'))
assert(nil == factions.get_player_faction('HanSolo'))
assert('Alberian' == factions.get_player_faction('Albert'))
callback()
end)
mtt.register('backend functions: get_player_factions', function(callback)
if pcall(factions.get_player_factions, nil) then
callback('did not fail with nil as player argument -> bad')
end
if pcall(factions.get_player_factions, 42) then
callback('did not fail with number as player argument -> bad')
end
assert(false == factions.get_player_factions('notExistingPlayer'))
assert(false == factions.get_player_factions('HanSolo'))
assert('Alberian' == factions.get_player_factions('Albert')[1])
callback()
end)
mtt.register('backend functions: get_owned_factions', function(callback)
assert(false == factions.get_owned_factions(nil))
assert(false == factions.get_owned_factions(42))
assert(false == factions.get_owned_factions('notExistingPlayer'))
assert(false == factions.get_owned_factions('HanSolo'))
local t = factions.get_owned_factions('Albert')
assert(1 == #t and 'Alberian' == t[1])
callback()
end)
mtt.register('backend functions: get_administered_factions', function(callback)
if pcall(factions.get_administered_factions) then
callback('calling get_administered_factions with nil did not raise error')
end
-- a bit strange that number as player name 'works'
assert(false == factions.get_administered_factions(42))
assert(false == factions.get_administered_factions('notExistingPlayer'))
assert(false == factions.get_administered_factions('HanSolo'))
local t = factions.get_administered_factions('Gandalf')
assert(1 == #t and 'Gandalfian' == t[1])
assert(3 == #factions.get_administered_factions('Albert'))
callback()
end)
mtt.register('backend functions: get_owner', function(callback)
assert(false == factions.get_owner('notExistingFaction'))
assert('Gandalf' == factions.get_owner('Gandalfian'))
callback()
end)
mtt.register('backend functions: chown', function(callback)
assert(false == factions.chown('notExistingFaction', 'Gandalf'))
assert(true == factions.chown('Endorian', 'Gandalf'))
-- revert the 'illegal' use
factions.chown('Endorian', 'Endor')
callback()
end)
mtt.register('backend functions: register_faction', function(callback)
-- (partly tested in setup)
assert(false == factions.register_faction('Endorian', 'Endor', 'rodnE'))
assert(false == factions.register_faction())
-- empty password
assert(factions.register_faction('foo', 'bar', ''))
callback()
end)
mtt.register('backend functions: disband_faction', function(callback)
-- (partly tested in setup)
assert(factions.disband_faction('foo'))
assert(false == factions.disband_faction())
assert(false == factions.disband_faction('notExistingFaction'))
callback()
end)
mtt.register('backend functions: valid_password', function(callback)
assert(false == factions.valid_password())
assert(false == factions.valid_password('Endorian'))
assert(false == factions.valid_password('Endorian', 'foobar'))
assert(true == factions.valid_password('Endorian', 'eEe'))
callback()
end)
mtt.register('backend functions: get_password', function(callback)
assert(false == factions.get_password())
assert('eEe' == factions.get_password('Endorian'))
callback()
end)
mtt.register('backend functions: set_password', function(callback)
assert(false == factions.set_password('notExistingFaction', 'foobar'))
assert(false == factions.set_password('Endorian'))
assert(true == factions.set_password('Endorian', 'EeE'))
assert(factions.valid_password('Endorian', 'EeE'))
-- revert that again
factions.set_password('Endorian', 'eEe')
callback()
end)
mtt.register('backend functions: join_faction', function(callback)
assert(false == factions.join_faction())
assert(false == factions.join_faction('Endorian'))
assert(false == factions.join_faction('Endorian', 'notExistingPlayer'))
assert(true == factions.join_faction('Endorian', 'Gandalf'))
callback()
end)
mtt.register('backend functions: leave_faction', function(callback)
assert(false == factions.leave_faction())
assert(false == factions.leave_faction('Endorian'))
assert(false == factions.leave_faction('Endorian', 'notExistingPlayer'))
assert(true == factions.leave_faction('Endorian', 'Gandalf'))
callback()
end)
mtt.register('intermediate db checks', dbChecks)
mtt.register('frontend functions: no arguments', function(callback)
assert(fccc(false, S("Unknown subcommand. Run '/help factions' for help."),
'', ''))
callback()
end)
mtt.register('frontend functions: create', function(callback)
assert(fccc(false, S("Missing faction name."), 'Gandalf', 'create'))
assert(fccc(false, S("Missing password."), 'Gandalf', 'create foobar'))
assert(fccc(false, S("Faction @1 already exists.", 'Gandalfian'),
'Gandalf', 'create Gandalfian foobar'))
factions.mode_unique_faction = true
assert(fccc(false, S("You are already in a faction."),
'Gandalf', 'create Gandalfian2 foobar'))
factions.mode_unique_faction = false
-- correct creation (also with capitals in sub-command)
assert(fccc(true, S("Registered @1.", 'Gandalfian2'),
'Gandalf', 'cREate Gandalfian2 foobar'))
callback()
end)
mtt.register('frontend functions: disband', function(callback)
assert(fccc(false, S("Missing password."), 'Gandalf', 'disband'))
-- list order is not predictable, so we try both orders
assert(fccc(false, S(
"You are the owner of multiple factions, you have to choose one of them: @1.",
'Gandalfian, Gandalfian2'), 'Gandalf', 'disband foobar')
or fccc(false, S(
"You are the owner of multiple factions, you have to choose one of them: @1.",
'Gandalfian2, Gandalfian'), 'Gandalf', 'disband foobar'))
assert(fccc(false, S("You don't own any factions."), 'HanSolo',
'disband foobar'))
assert(fccc(false, S("Permission denied: You are not the owner of that faction,"
.. " and don't have the @1 privilege.", factions.priv),
'Endor', 'disband foobar Gandalfian2'))
assert(fccc(false, S("Permission denied: Wrong password."),
'Endor', 'disband foobar'))
assert(fccc(true, S("Disbanded @1.", 'Endorian'),
'Endor', 'disband eEe'))
-- admin disbands other player's faction w/o knowing password
assert(fccc(true, S("Disbanded @1.", 'Gandalfian2'),
'Albert', 'disband foobar Gandalfian2'))
assert(fccc(false, S("Faction @1 doesn't exist.", 'Gandalfian2'),
'Gandalf', 'disband eEe Gandalfian2'))
callback()
end)
mtt.register('frontend functions: list', function(callback)
assert(fccc(true, S("Factions (@1): @2.", 2, 'Gandalfian, Alberian'),
'', 'list')
or fccc(true, S("Factions (@1): @2.", 2, 'Alberian, Gandalfian'),
'', 'list'))
resetDB()
assert(fccc(true, S("There are no factions yet."), '', 'list'))
callback()
end)
mtt.register('frontend functions: info', function(callback)
assert(fccc(true, S("No factions found."), 'HanSolo', 'info'))
makeFactions()
assert(fccc(false, S("Faction @1 doesn't exist.", 'foobar'),
'Endor', 'info foobar'))
factions.join_faction('Endorian', 'Gandalf')
assert(fccc(false, S("You are in multiple factions, you have to choose one of them: @1.",
'Endorian, Gandalfian'), 'Gandalf', 'info')
or fccc(false, S("You are in multiple factions, you have to choose one of them: @1.",
'Gandalfian, Endorian'), 'Gandalf', 'info'))
-- SwissalpS can't be bothered to check some of these results in depth,
-- so just dumping result for optical check.
-- owner sees password
pd('Endor executes: /factions info', fcc('Endor', 'info'))
assert(fcc('Endor', 'info'))
factions.max_members_list = 1
pd('max_members_list == 1 and Endor executes: /factions info',
fcc('Endor', 'info'))
assert(fcc('Endor', 'info'))
factions.max_members_list = 11
pd('Endor executes: /factions info Gandalfian', fcc('Endor', 'info Gandalfian'))
assert(fcc('Endor', 'info Gandalfian'))
-- admin sees password
pd('Albert executes: /factions info Gandalfian', fcc('Albert', 'info Gandalfian'))
assert(fcc('Albert', 'info Gandalfian'))
callback()
end)
mtt.register('frontend functions: player_info', function(callback)
-- should never happen
assert(fccc(false, S("Missing player name."), '', 'player_info'))
assert(fccc(false, S("Player @1 doesn't exist or isn't in any faction.",
'HanSolo'), 'HanSolo', 'player_info'))
assert(fccc(false, S("Player @1 doesn't exist or isn't in any faction.",
'notExistingPlayer'), 'Endor', 'player_info notExistingPlayer'))
assert(fccc(true, S("@1 is in the following factions: @2.",
'Endor', 'Endorian') .. "\n"
.. S("@1 is the owner of the following factions: @2.",
'Endor', 'Endorian'), 'Endor', 'player_info'))
assert(fccc(true, S("@1 is in the following factions: @2.",
'Albert', 'Alberian') .. "\n"
.. S("@1 is the owner of the following factions: @2.",
'Albert', 'Alberian') .. "\n"
.. S("@1 has the @2 privilege so they can admin every faction.",
'Albert', factions.priv), 'Endor', 'player_info Albert'))
callback()
end)
mtt.register('frontend functions: join', function(callback)
factions.mode_unique_faction = true
assert(fccc(false, S("You are already in a faction."),
'Endor', 'join'))
factions.mode_unique_faction = false
assert(fccc(false, S("Missing faction name."),
'Endor', 'join'))
assert(fccc(false, S("Faction @1 doesn't exist.", 'notExistingFaction'),
'Endor', 'join notExistingFaction'))
assert(fccc(false, S("You are already in faction @1.", 'Endorian'),
'Endor', 'join Endorian'))
assert(fccc(false, S("Permission denied: Wrong password."),
'Endor', 'join Gandalfian'))
assert(fccc(false, S("Permission denied: Wrong password."),
'Endor', 'join Gandalfian abc'))
assert(fccc(true, S("Joined @1.", 'Gandalfian'),
'Endor', 'join Gandalfian GgG♥💩☺'))
callback()
end)
mtt.register('frontend functions: leave', function(callback)
assert(fccc(false, S("You are not in a faction."),
'HanSolo', 'leave'))
assert(fccc(false, S("You are in multiple factions, you have to choose one of them: @1.",
'Gandalfian, Endorian'),
'Endor', 'leave')
or fccc(false, S("You are in multiple factions, you have to choose one of them: @1.",
'Endorian, Gandalfian'),
'Endor', 'leave'))
assert(fccc(false, S("Faction @1 doesn't exist.", 'notExistingFaction'),
'Endor', 'leave notExistingFaction'))
assert(fccc(false, S("You cannot leave your own faction, change owner or disband it."),
'Albert', 'leave'))
assert(fccc(false, S("You aren't part of faction @1.", 'Gandalfian'),
'Albert', 'leave Gandalfian'))
assert(fccc(true, S("Left @1.", 'Endorian'),
'Gandalf', 'leave Endorian'))
callback()
end)
mtt.register('frontend functions: kick', function(callback)
assert(fccc(false, S("Missing player name."),
'Gandalf', 'kick'))
assert(fccc(false, S("You don't own any factions, you can't use this command."),
'HanSolo', 'kick Endor'))
local b, s = fcc('Albert', 'kick Endor')
-- only works if run on English server
assert(false == b and nil ~= s:find('multiple factions,'))
assert(fccc(false, S("Permission denied: You are not the owner of that faction, "
.. "and don't have the @1 privilege.", factions.priv),
'Endor', 'kick Gandalf Gandalfian'))
assert(fccc(false, S("@1 is not in the specified faction.", 'Gandalf'),
'Endor', 'kick Gandalf Endorian'))
assert(fccc(false, S("You cannot kick the owner of a faction, "
.. "use '/factions chown <player> <password> [<faction>]' "
.. "to change the ownership."),
'Albert', 'kick Gandalf Gandalfian'))
assert(fccc(true, S("Kicked @1 from faction.", 'Endor'),
'Gandalf', 'kick Endor Gandalfian'))
callback()
end)
mtt.register('frontend functions: passwd', function(callback)
assert(fccc(false, S("Missing password."),
'HanSolo', 'passwd'))
assert(fccc(false, S("You don't own any factions, you can't use this command."),
'HanSolo', 'passwd foobar'))
local b, s = fcc('Albert', 'passwd foobar')
-- only works on English locale
assert(false == b and nil ~= s:find('multiple factions'))
assert(fccc(false, S("Permission denied: You are not the owner of that faction, "
.. "and don't have the @1 privilege.", factions.priv),
'Endor', 'passwd foobar Gandalfian'))
assert(fccc(true, S("Password has been updated."),
'Endor', 'passwd foobar'))
assert(factions.get_facts().Endorian.password == 'foobar')
assert(fccc(true, S("Password has been updated."),
'Gandalf', 'passwd foobar Gandalfian'))
assert(factions.get_facts().Gandalfian.password == 'foobar')
assert(fccc(true, S("Password has been updated."),
'Albert', 'passwd barf Gandalfian'))
assert(factions.get_facts().Gandalfian.password == 'barf')
callback()
end)
mtt.register('frontend functions: chown', function(callback)
assert(fccc(false, S("Missing player name."),
'Gandalf', 'chown'))
assert(fccc(false, S("Missing password."),
'Gandalf', 'chown notExistingPlayer'))
assert(fccc(false, S("You don't own any factions, you can't use this command."),
'HanSolo', 'chown notExistingPlayer foobar'))
local b, s = fcc('Albert', 'chown notExistingPlayer foobar')
assert(false == b and nil ~= s:find('multiple factions'))
assert(fccc(false, S("Permission denied: You are not the owner of that faction, "
.. "and don't have the @1 privilege.", factions.priv),
'Gandalf', 'chown Endor foobar Endorian'))
assert(fccc(false, S("@1 isn't in faction @2.", 'notExistingPlayer', 'Gandalfian'),
'Gandalf', 'chown notExistingPlayer foobar'))
assert(fccc(false, S("@1 isn't in faction @2.", 'Endor', 'Gandalfian'),
'Gandalf', 'chown Endor foobar'))
factions.join_faction('Gandalfian', 'Endor')
assert(fccc(false, S("Permission denied: Wrong password."),
'Gandalf', 'chown Endor foobar'))
assert(fccc(true, S("Ownership has been transferred to @1.", 'Endor'),
'Gandalf', 'chown Endor barf'))
assert('Endor' == factions.get_owner('Gandalfian'))
assert(fccc(true, S("Ownership has been transferred to @1.", 'Gandalf'),
'Albert', 'chown Gandalf foobar Gandalfian'))
assert('Gandalf' == factions.get_owner('Gandalfian'))
callback()
end)
mtt.register('frontend functions: invite', function(callback)
assert(fccc(false, S("Permission denied: You can't use this command, @1 priv is needed.",
factions.priv), 'notExistingPlayer', 'invite'))
assert(fccc(false, S("Permission denied: You can't use this command, @1 priv is needed.",
factions.priv), 'Endor', 'invite'))
assert(fccc(false, S("Missing player name."), 'Albert', 'invite'))
assert(fccc(false, S("Missing faction name."), 'Albert', 'invite Endor'))
assert(fccc(false, S("Faction @1 doesn't exist.", 'notExistingFaction'),
'Albert', 'invite Endor notExistingFaction'))
assert(fccc(false, S("Player @1 doesn't exist.", 'notExistingPlayer'),
'Albert', 'invite notExistingPlayer Gandalfian'))
assert(fccc(false, S("Player @1 is already in faction @2.", 'Endor', 'Gandalfian'),
'Albert', 'invite Endor Gandalfian'))
factions.mode_unique_faction = true
assert(fccc(false, S("Player @1 is already in faction @2.", 'Gandalf', 'Gandalfian'),
'Albert', 'invite Gandalf Endorian'))
factions.mode_unique_faction = false
assert(fccc(true, S("@1 is now a member of faction @2.", 'Gandalf', 'Endorian'),
'Albert', 'invite Gandalf Endorian'))
callback()
end)
mtt.register('final db checks', function(callback)
pd(factions.get_facts())
callback()
end)
mtt.register('remaining players leave', function(callback)
assert(true == mtt.leave_player('Endor'))
assert(true == mtt.leave_player('HanSolo'))
callback()
end)
mtt.register('final', function(callback)
print('total success')
callback()
end)