mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
492 lines
23 KiB
Lua
492 lines
23 KiB
Lua
--- A full ranking system for factorio.
|
|
-- @module ExpGamingCore.Ranking
|
|
-- @alias Ranking
|
|
-- @author Cooldude2606
|
|
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
|
|
|
|
local Game = require('FactorioStdLib.Game')
|
|
local Color = require('FactorioStdLib.Color')
|
|
|
|
local Ranking = {}
|
|
local module_verbose = false --true|false
|
|
|
|
--- Global Table
|
|
-- @table global
|
|
-- @field old contains the previous rank a use had before a rank change
|
|
-- @field preset contains the preset ranks that users will recive apon joining
|
|
-- @field last_change contains the name of the player who last had there rank chagned
|
|
local global = global{old={},preset={},last_change=nil}
|
|
|
|
--- Called when there is a rank change for a user
|
|
-- @event on_rank_change
|
|
-- @field name the rank id
|
|
-- @field tick the tick which the event was raised on
|
|
-- @field player_index the player whos rank was changed
|
|
-- @field by_player_index the player who changed the rank, 0 means server
|
|
-- @field new_rank the name of the rank that was given
|
|
-- @field old_rank the name of the rank the player had
|
|
script.generate_event_name('on_rank_change')
|
|
|
|
--- Outputs as a string all the ranks and the loaded order
|
|
-- @usage Ranking.output_ranks(player) -- prints to player
|
|
-- @tparam[opt=server] ?player_name|player_index|LuaPlayer player the player that the info will be printed to, nil will print to server
|
|
-- @todo show inheritance of ranks
|
|
function Ranking.output_ranks(player)
|
|
local player = Game.get_player(player) or game.player or nil
|
|
local function output(rank)
|
|
local admin = 'No'; if rank.is_root then admin = 'Root' elseif rank.is_admin then admin = 'Yes' end
|
|
local rtn = string.format('%s) %q %s > Admin: %s Group: %q AFK: %s Time: %s',
|
|
rank.power,rank.name,rank.tag,admin,rank.group,tostring(rank.base_afk_time),tostring(rank.time))
|
|
player_return(rtn,rank.colour,player)
|
|
end
|
|
local function recur(_rank)
|
|
for name,rank in pairs(_rank.children) do output(Ranking.ranks[rank]) end
|
|
for name,rank in pairs(_rank.children) do recur(Ranking.ranks[rank]) end
|
|
end
|
|
local root = Ranking.get_rank(Ranking.meta.root)
|
|
output(root)
|
|
recur(root)
|
|
end
|
|
|
|
--- Contains the location of all the ranks, readonly during runtime
|
|
-- @table Ranking.ranks
|
|
Ranking.ranks = setmetatable({},{
|
|
__metatable=false,
|
|
__index=table.autokey,
|
|
__newindex=function(tbl,key,value) if game then error('Can not create new ranks during runtime',2) else rawset(tbl,key,value) end end,
|
|
__len=function(tbl)
|
|
local rtn = 0
|
|
for name,rank in pairs(tbl) do
|
|
rtn=rtn+1
|
|
end
|
|
return rtn
|
|
end
|
|
})
|
|
|
|
--- Contains the location of all the rank groups, readonly during runtime
|
|
-- @table Ranking.ranks
|
|
Ranking.groups = setmetatable({},{
|
|
__metatable=false,
|
|
__index=table.autokey,
|
|
__newindex=function(tbl,key,value) if game then error('Can not create new rank groups during runtime',2) else rawset(tbl,key,value) end end,
|
|
__len=function(tbl)
|
|
local rtn = 0
|
|
for name,rank in pairs(tbl) do
|
|
rtn=rtn+1
|
|
end
|
|
return rtn
|
|
end
|
|
})
|
|
|
|
--- Contains some meta data about the ranks
|
|
-- @table Ranking.meta
|
|
-- @field default this is the name of the default rank
|
|
-- @field root this is the name of the root rank
|
|
-- @field time_ranks a list of all ranks which have a time requirement
|
|
-- @field time_highest the power of the highest rank that has a time requirement
|
|
-- @field time_lowest the lowest amount of time required for a time rank
|
|
Ranking.meta = setmetatable({},{
|
|
__metatable=false,
|
|
__call=function(tbl)
|
|
local count = 0
|
|
rawset(tbl,'time_ranks',{})
|
|
for name,rank in pairs(Ranking.ranks) do
|
|
count=count+1
|
|
if not rawget(tbl,'default') and rank.is_default then rawset(tbl,'default',rank.name) end
|
|
if not rawget(tbl,'root') and rank.is_root then rawset(tbl,'root',rank.name) end
|
|
if rank.time then
|
|
table.insert(tbl.time_ranks,rank.name)
|
|
if not rawget(tbl,'time_highest') or rank.power < tbl.time_highest then if rank.power then rawset(tbl,'time_highest',rank.power) end end
|
|
if not rawget(tbl,'time_lowest') or rank.time < tbl.time_lowest then rawset(tbl,'time_lowest',rank.time) end
|
|
end
|
|
end
|
|
rawset(tbl,'rank_count',count)
|
|
if not rawget(tbl,'default') then error('No default rank') end
|
|
if not rawget(tbl,'root') then error('No root rank') end
|
|
end,
|
|
__index=function(tbl,key)
|
|
tbl()
|
|
return rawget(tbl,key)
|
|
end,
|
|
__newindex=function() error('Ranking metadata is read only',2) end
|
|
})
|
|
|
|
--- Used to set the prset ranks that will be given to players
|
|
-- @usage Ranking._base_preset{name=rank_name,nameTwo=rank_name_two} -- sets player name to have rank rank_name on join
|
|
-- @tparam table ranks table of player names with the player name as the key and rank name as the value
|
|
function Ranking._base_preset(ranks)
|
|
if not is_type(ranks,'table') then error('Ranking._base_preset was not given a table',2) end
|
|
global.preset = ranks
|
|
end
|
|
|
|
--- Returns a rank object given a player or rank name
|
|
-- @usage Ranking.get_rank(game.player) -- returns player's rank
|
|
-- @usage Ranking.get_rank('admin') -- returns rank by the name of admin
|
|
-- @tparam ?player|player_index|player_name|rank_name|Ranking._rank|'server'|'root' mixed what rank to get
|
|
-- @treturn[1] table the rank that is linked to mixed
|
|
-- @treturn[2] nil there was no rank found
|
|
function Ranking.get_rank(mixed)
|
|
if not mixed then return error('Ranking.get_rank recived no paramerters') end
|
|
local ranks = Ranking.ranks
|
|
local _return = false
|
|
if is_type(mixed,'table') then
|
|
-- is it a player, then get player rank; if it is a rank then return the rank
|
|
if mixed.index then _return = game.players[mixed.index] and ranks[mixed.permission_group.name] or nil
|
|
else _return = mixed.group and mixed or nil end
|
|
else
|
|
-- if it is a player name/index, then get player rank; if it is a rank name, get that rank; if it is server or root; return root rank; else nil
|
|
_return = game and game.players[mixed] and ranks[game.players[mixed].permission_group.name]
|
|
or table.autokey(ranks,mixed) and table.autokey(ranks,mixed)
|
|
or string.find(mixed,'server') and Ranking.get_rank(Ranking.meta.root)
|
|
or string.find(mixed,'root') and Ranking.get_rank(Ranking.meta.root)
|
|
or nil
|
|
end
|
|
return _return
|
|
end
|
|
|
|
--- Returns the group object used to sort ranks given group name or rank
|
|
-- @usage Ranking.get_group(game.player) -- returns player's rank group
|
|
-- @usage Ranking.get_group('root') -- returns group by name of root
|
|
-- @tparam ?player|player_index|player_name|rank_name|rank|'server'|'root'|group_name|group mixed what group to get
|
|
-- @see Ranking.get_rank
|
|
-- @treturn[1] table the group that is linked to mixed
|
|
-- @treturn[2] nil there was no rank group found
|
|
function Ranking.get_group(mixed)
|
|
if not mixed then return error('Ranking.get_group recived no paramerters') end
|
|
local groups = Ranking.groups
|
|
local rank = Ranking.get_rank(mixed)
|
|
-- if it is a table see if it is a group, return the group; if it is a string, return group by that name; if there is a rank found, return the ranks group
|
|
return is_type(mixed,'table') and not mixed.__self and mixed.ranks and mixed
|
|
or is_type(mixed,'string') and table.autokey(groups,mixed)
|
|
or rank and rank.group
|
|
or nil
|
|
end
|
|
|
|
--- Prints to all rank of greater/lower power of the rank given
|
|
-- @usage Ranking.print('admin','We got a grifer')
|
|
-- @todo change to use parent and child ranks rather than power
|
|
-- @tparam ?Ranking._rank|pointerToRank rank_base the rank that acts as the cut off point (rank is always included)
|
|
-- @param rtn what do you want to return to the players
|
|
-- @tparam[opt=defines.color.white] defines.color colour the colour that will be used to print
|
|
-- @tparam[opt=false] boolean below if true print to children rather than parents
|
|
function Ranking.print(rank_base,rtn,colour,below)
|
|
local colour = colour or defines.color.white
|
|
local rank_base = Ranking.get_rank(rank_base)
|
|
local ranks = Ranking._ranks()
|
|
if below then
|
|
for power,rank in pairs(ranks) do
|
|
if rank_base.power <= power then rank:print(rtn,colour,true) end
|
|
end
|
|
else
|
|
for power,rank in pairs(ranks) do
|
|
if rank_base.power >= power then rank:print(rtn,colour) end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Gives a user a rank
|
|
-- @usage Ranking.give_rank(1,'admin')
|
|
-- @tparam ?LuaPlayer|pointerToPlayer player the player to give the rank to
|
|
-- @tparam[opt=default] ?Ranking._rank|pointerToRank rank the rank to give to the player
|
|
-- @tparam[opt='server'] ?LuaPlayer|pointerToPlayer by_player the player who is giving the rank
|
|
-- @tparam[opt=game.tick] number tick the tick that the rank is being given on, used as pass though
|
|
function Ranking.give_rank(player,rank,by_player,tick)
|
|
local print_colour = defines.textcolor.info
|
|
local tick = tick or game.tick
|
|
local by_player_name = Game.get_player(by_player) and Game.get_player(by_player).name or game.player and game.player.name or is_type(by_player,'string') and by_player or 'server'
|
|
local rank = Ranking.get_rank(rank) or Ranking.get_rank(Ranking.meta.default)
|
|
local player = Game.get_player(player) or error('No player given to Ranking.give_rank',2)
|
|
local old_rank = Ranking.get_rank(player) or Ranking.get_rank(Ranking.meta.default)
|
|
local message = 'ranking.rank-down'
|
|
-- messaging
|
|
if old_rank.name == rank.name then return end
|
|
if rank.power < old_rank.power then message = 'ranking.rank-up' player.play_sound{path='utility/achievement_unlocked'}
|
|
else player.play_sound{path='utility/game_lost'} end
|
|
if player.online_time > 60 or by_player_name ~= 'server' then game.print({message,player.name,rank.name,by_player_name},print_colour) end
|
|
if rank.group ~= 'User' then player_return({'ranking.rank-given',rank.name},print_colour,player) end
|
|
if player.tag ~= old_rank.tag then player_return({'ranking.tag-reset'},print_colour,player) end
|
|
-- rank change
|
|
player.permission_group = game.permissions.get_group(rank.name)
|
|
player.tag = rank.tag
|
|
if old_rank.group ~= 'Jail' then global.old[player.index] = old_rank.name end
|
|
player.admin = rank.is_admin or false
|
|
player.spectator = rank.is_spectator or false
|
|
local by_player_index = by_player_name == 'server' and 0 or Game.get_player(by_player_name).index
|
|
script.raise_event(defines.events.on_rank_change,{
|
|
name=defines.events.on_rank_change,
|
|
tick=tick,
|
|
player_index=player.index,
|
|
by_player_index=by_player_index,
|
|
new_rank=rank.name,
|
|
old_rank=old_rank.name
|
|
})
|
|
-- logs to file if rank is chagned after first join
|
|
if player.online_time > 60 then
|
|
game.write_file('ranking-change.json',
|
|
table.json({
|
|
tick=tick,
|
|
play_time=player.online_time,
|
|
player_name=player.name,
|
|
by_player_name=by_player_name,
|
|
new_rank=rank.name,
|
|
old_rank=old_rank.name
|
|
})..'\n'
|
|
, true, 0)
|
|
end
|
|
end
|
|
|
|
--- Revert the last change to a players rank
|
|
-- @usage Ranking.revert(1) -- reverts the rank of player with index 1
|
|
-- @tparam ?LuaPlayer|pointerToPlayer player the player to revert the rank of
|
|
-- @param[opt=nil] by_player the player who is doing the revert
|
|
function Ranking.revert(player,by_player)
|
|
local player = Game.get_player(player)
|
|
Ranking.give_rank(player,global.old[player.index],by_player)
|
|
end
|
|
|
|
--- Given that the player has a rank in the preset table it is given; also will attempt to promote players if a time requirement is met
|
|
-- @usage Ranking.find_preset(1) -- attemps to find the preset for player with index 1
|
|
-- @tparam ?LuaPlayer|pointerToPlayer player the player to test for an auto rank
|
|
-- @tparam[opt=nil] number tick the tick it happens on
|
|
function Ranking.find_preset(player,tick)
|
|
local presets = global.preset
|
|
local meta_data = Ranking.meta
|
|
local default = Ranking.get_rank(meta_data.default)
|
|
local player = Game.get_player(player)
|
|
local current_rank = Ranking.get_rank(player) or {power=-1,group='not jail'}
|
|
local ranks = {default}
|
|
-- users in rank group jail are ingroned
|
|
if current_rank.group == 'Jail' then return end
|
|
-- looks in preset table for player name
|
|
if presets[string.lower(player.name)] then
|
|
local rank = Ranking.get_rank(presets[string.lower(player.name)])
|
|
table.insert(ranks,rank)
|
|
end
|
|
-- if the player mets check requirements then play time is checked
|
|
if current_rank.power > meta_data.time_highest and tick_to_min(player.online_time) > meta_data.time_lowest then
|
|
for _,rank_name in pairs(meta_data.time_ranks) do
|
|
local rank = Ranking.get_rank(rank_name)
|
|
if tick_to_min(player.online_time) > rank.time then
|
|
table.insert(ranks,rank)
|
|
end
|
|
end
|
|
end
|
|
-- if the new rank is closer to root then it is the new rank
|
|
local _rank = current_rank
|
|
for _,rank in pairs(ranks) do
|
|
if rank.power < _rank.power or _rank.power == -1 then _rank = rank end
|
|
end
|
|
-- this new rank is given to the player
|
|
if _rank.name == current_rank.name then return end
|
|
if _rank.name == default.name then
|
|
player.tag = _rank.tag
|
|
player.permission_group = game.permissions.get_group(_rank.name)
|
|
else
|
|
Ranking.give_rank(player,_rank,nil,tick)
|
|
end
|
|
end
|
|
|
|
--- The class for the ranks
|
|
-- @type Rank
|
|
-- @alias Ranking._rank
|
|
-- @field name the name that is given to the rank, must be unique
|
|
-- @field short_hand the shorter way of displaying this rank, can be used by other modules
|
|
-- @field tag the tag that player in this rank will be given
|
|
-- @field colour the colour that modules should display this rank as in guis
|
|
-- @field parent the name of the rank that permissions are inherited from, allow comes from children, disallow given to children
|
|
-- @field base_afk_time a relative number that the rank should be given that other modules can use for relitive importance
|
|
-- @field time the time that is requied for this rank to be given, can be nil for manal only
|
|
-- @field allow a list of permissions that this rank is allowed
|
|
-- @field disallow a list of acctions that is blocked by the ingame permission system
|
|
-- @field is_default will be given to all players if no other rank is set for them
|
|
-- @field is_admin will promote player to ingame admin if flag set (will auto demote if not set)
|
|
-- @field is_spectator will auto set the spectator option for the player (will cleat option if not set)
|
|
-- @field is_root rank is always allowed all action, when present in root group will become the root child that all ranks are indexed from
|
|
Ranking._rank = {}
|
|
|
|
--- Is this rank allowed to open this gui or use this command etc.
|
|
-- @usage rank:allowed('interface') -- does the rank have permision for 'interface'
|
|
-- @tparam teh action to test for
|
|
-- @treturn boolean is it allowed
|
|
function Ranking._rank:allowed(action)
|
|
return self.allow[action] or self.is_root or false
|
|
end
|
|
|
|
--- Get all the players in this rank
|
|
-- @usage rank:get_players()
|
|
-- @tparam[opt=false] boolean online get only online players
|
|
-- @treturn table a table of all players in this rank
|
|
function Ranking._rank:get_players(online)
|
|
local players = game.permissions.get_group(self.name).players
|
|
local _return = {}
|
|
if online then
|
|
for _,player in pairs(players) do if player.connected then table.insert(_return,player) end end
|
|
else _return = players end
|
|
return _return
|
|
end
|
|
|
|
--- Print a message to all players of this rank
|
|
-- @usage rank:print('foo') -- prints to all members of this rank
|
|
-- @param rtn any value you want to return
|
|
-- @tparam[opt=defines.color.white] define.color colour the colour that will be used to print
|
|
-- @tparam[opt=false] boolean show_default weather to use the default rank name for the print, used as a pass though
|
|
function Ranking._rank:print(rtn,colour,show_default)
|
|
local colour = colour or defines.color.white
|
|
local default = Ranking.get_rank(Ranking.meta.default)
|
|
for _,player in pairs(self:get_players(true)) do
|
|
if self.name == default.name or show_default then player_return({'ranking.all-rank-print',rtn},colour,player)
|
|
else player_return({'ranking.rank-print',self.name,rtn},colour,player) end
|
|
end
|
|
end
|
|
|
|
--- Allows for a clean way to edit rank objects
|
|
-- @usage rank:edit('allow',{'interface'}) -- allows this rank to use 'interface'
|
|
-- @tparam string key the key to edit, often allow or disallow
|
|
-- @param value the new value to be set
|
|
function Ranking._rank:edit(key,value)
|
|
if game then return end
|
|
verbose('Edited Rank: '..self.group..'/'..self.name..'/'..key)
|
|
if key == 'disallow' then self.disallow = table.merge(self.disallow,value,true)
|
|
elseif key == 'allow' then self.allow = table.merge(self.allow,value)
|
|
else self[key] = value end
|
|
end
|
|
|
|
--- The class for the rank groups, the way to allow modules to idex a group that is always present, ranks will always look to there group as a parent
|
|
-- @type Group
|
|
-- @alias Ranking._group
|
|
-- @field name the name that is given to the rank group, must be unique
|
|
-- @field parent the name of the group that permissions are inherited from
|
|
-- @field allow a list of permissions that this rank is allowed
|
|
-- @field disallow a list of acctions that is blocked by the ingame permission system
|
|
Ranking._group = {}
|
|
|
|
--- Creates a new group
|
|
-- @usage Ranking._group:create{name='root'} -- returns group with name root
|
|
-- @tparam table obj the fields for this object
|
|
-- @treturn Ranking._group returns the object to allow chaining
|
|
function Ranking._group:create(obj)
|
|
if game then return end
|
|
if not is_type(obj.name,'string') then error('Group creationg is invalid',2) end
|
|
verbose('Created Group: '..obj.name)
|
|
setmetatable(obj,{__index=Ranking._group})
|
|
obj.ranks = {}
|
|
obj.allow = obj.allow or {}
|
|
obj.disallow = obj.disallow or {}
|
|
Ranking.groups[obj.name] = obj
|
|
return obj
|
|
end
|
|
|
|
--- Creats a new rank with this group as its group
|
|
-- @usage group:add_rank{name='root'} -- returns self
|
|
-- @tparam table obj the fields for this object
|
|
-- @treturn Ranking._group returns the object to allow chaining
|
|
function Ranking._group:add_rank(obj)
|
|
if game then return end
|
|
if not is_type(obj.name,'string') or
|
|
not is_type(obj.short_hand,'string') or
|
|
not is_type(obj.tag,'string') or
|
|
not is_type(obj.colour,'table') then error('Rank creation is invalid',2) end
|
|
verbose('Created Rank: '..obj.name)
|
|
setmetatable(obj,{__index=Ranking._rank})
|
|
obj.group = self.name
|
|
obj.children = {}
|
|
obj.allow = obj.allow or {}
|
|
obj.disallow = obj.disallow or {}
|
|
table.insert(self.ranks,obj.name)
|
|
Ranking.ranks[obj.name] = obj
|
|
return self
|
|
end
|
|
|
|
--- Allows for a clean way to edit rank group objects
|
|
-- @usage group:edit('allow',{'interface'}) -- allows this rank to use 'interface'
|
|
-- @tparam string key the key to edit, often allow or disallow
|
|
-- @param value the new value to be set
|
|
function Ranking._group:edit(key,value)
|
|
if game then return end
|
|
verbose('Edited Group: '..self.name..'/'..key)
|
|
if key == 'disallow' then self.disallow = table.merge(self.disallow,value,true)
|
|
elseif key == 'allow' then self.allow = table.merge(self.allow,value)
|
|
else self[key] = value end
|
|
end
|
|
|
|
script.on_event('on_player_joined_game',function(event)
|
|
Ranking.find_preset(event.player_index)
|
|
end)
|
|
|
|
script.on_event('on_init',function(event)
|
|
for name,rank in pairs(Ranking.ranks) do
|
|
local perm = game.permissions.create_group(name)
|
|
for _,toRemove in pairs(rank.disallow) do
|
|
perm.set_allows_action(defines.input_action[toRemove],false)
|
|
end
|
|
end
|
|
end)
|
|
|
|
script.on_event('on_tick',function(event)
|
|
if (((event.tick+10)/(3600*game.speed))+(15/2))% 15 == 0 then
|
|
-- this is the system to auto rank players
|
|
for _,player in pairs(game.connected_players) do
|
|
Ranking.find_preset(player,tick)
|
|
end
|
|
end
|
|
end)
|
|
|
|
verbose('Loading rank core...')
|
|
require(module_path..'/src/core',{Ranking=Ranking})
|
|
verbose('Loading rank configs...')
|
|
require(module_path..'/src/config',{Ranking=Ranking})
|
|
|
|
function Ranking:on_init()
|
|
if loaded_modules['ExpGamingCore.Server'] then verbose('ExpGamingCore.Server is installed; Loading server src') require(module_path..'/src/server',{Ranking=Ranking}) end
|
|
if loaded_modules['ExpGamingCore.Commands'] then verbose('ExpGamingCore.Server is installed; Loading commands src') require(module_path..'/src/commands',{Ranking=Ranking}) end
|
|
end
|
|
|
|
function Ranking:on_post()
|
|
-- other modules can creat ranks during init and this will then set up the meta data
|
|
-- sets up the power system, the lower the power the closer to root, root is 0
|
|
-- there must be a rank with is_root flag set and one rank with is_default flag set, if multiple found then first found is used
|
|
local root = Ranking.get_rank(Ranking.meta.root)
|
|
root:edit('power',0)
|
|
-- asigning of children
|
|
verbose('Creating Rank Tree')
|
|
for name,rank in pairs(Ranking.ranks) do
|
|
if rank ~= root then
|
|
if not rank.parent then error('Rank has no parent: "'..name..'"') end
|
|
if not Ranking.ranks[rank.parent] then error('Invalid parent rank: "'..rank.parent..'"') end
|
|
table.insert(Ranking.ranks[rank.parent].children,name)
|
|
Ranking.ranks[rank.parent]:edit('allow',rank.allow)
|
|
rank:edit('disallow',Ranking.ranks[rank.parent].disallow)
|
|
end
|
|
end
|
|
-- asigning of powers
|
|
-- @todo need a better system for non liner rank trees
|
|
verbose('Assigning Rank Powers')
|
|
local power = 1
|
|
local function set_powers(rank)
|
|
for _,name in pairs(rank.children) do
|
|
Ranking.ranks[name]:edit('power',power)
|
|
power=power+1
|
|
end
|
|
for _,name in pairs(rank.children) do set_powers(Ranking.ranks[name]) end
|
|
end
|
|
set_powers(root)
|
|
-- asigning group meta data
|
|
verbose('Creating Rank-Group Relationship')
|
|
for name,group in pairs(Ranking.groups) do
|
|
if name ~= 'Root' then
|
|
if not group.parent then error('Group has no parent: "'..name..'"') end
|
|
if not Ranking.groups[group.parent] then error('Invalid parent rank: "'..group.parent..'"') end
|
|
Ranking.groups[group.parent]:edit('allow',group.allow)
|
|
group:edit('disallow',Ranking.groups[group.parent].disallow)
|
|
end
|
|
for _,name in pairs(group.ranks) do
|
|
local rank = Ranking.ranks[name]
|
|
rank:edit('disallow',group.disallow)
|
|
rank:edit('allow',group.allow)
|
|
if not group.highest or Ranking.ranks[group.highest].power > rank.power then group.highest = rank.name end
|
|
if not group.lowest or Ranking.ranks[group.highest].power < rank.power then group.lowest = rank.name end
|
|
end
|
|
end
|
|
end
|
|
|
|
return Ranking |