Files
factorio-scenario-ExpCluster/ExpCore/ranking.lua
2017-12-24 21:46:04 +00:00

315 lines
12 KiB
Lua

--[[
Explosive Gaming
This file can be used with permission but this and the credit below must remain in the file.
Contact a member of management on our discord to seek permission to use our code.
Any changes that you may make to the code are yours but that does not make the script yours.
Discord: https://discord.gg/r6dC2uK
]]
--Please Only Edit Below This Line-----------------------------------------------------------
local Ranking = {}
defines.events.rank_change = script.generate_event_name()
Ranking._rank = {}
Ranking._group = {}
-- this function is to avoid errors - see /ranks.lua
function Ranking._ranks(names)
return {}
end
-- this function is to avoid errors - see /ranks.lua
function Ranking._groups(names)
return {}
end
-- this function is to avoid errors - see /ranks.lua
function Ranking._meta()
return {}
end
-- this function is to avoid errors - see addons/playerRanks.lua
function Ranking._base_preset(table)
Ranking._presets().current = table
end
-- this returns a global list
function Ranking._presets()
if not global.exp_core then global.exp_core = {} end
if not global.exp_core.ranking then global.exp_core.ranking = {meta=Ranking._meta(),old={},current={}} end
return global.exp_core.ranking
end
--- Returns a rank object given a player or rank name
-- @usage Ranking.get_rank(game.player)
-- Ranking.get_rank('admin')
-- @param mixed player|player index|player name|rank name|rank|'server'|'root' what rank to get
-- @treturn table the rank that is linked to mixed
function Ranking.get_rank(mixed)
if not mixed then return false end
local ranks = Ranking._ranks(true)
local _return = false
if is_type(mixed,'table') then
if mixed.index then
_return = game.players[mixed.index] and ranks[mixed.permission_group.name] or false
else
_return = mixed.group and mixed or false
end
else
_return = game.players[mixed] and ranks[game.players[mixed].permission_group.name]
or table.autokey(ranks,mixed) and table.autokey(ranks,mixed)
or string.contains(mixed,'server') and Ranking.get_rank(Ranking._presets().meta.root)
or string.contains(mixed,'root') and Ranking.get_rank(Ranking._presets().meta.root)
or false
end
return _return
end
--- Returns the group object used to sort ranks given group name or see Ranking.get_rank
-- @usage Ranking.get_group(game.player)
-- Ranking.get_group('root')
-- @param mixed player|player index|player name|rank name|rank|'server'|'root'|group name|group what group to get
-- @treturn table the group that is linked to mixed
function Ranking.get_group(mixed)
if not mixed then return false end
local groups = Ranking._groups(true)
local rank = Ranking.get_rank(mixed)
return rank and rank.group
or is_type(mixed,'table') and mixed.ranks and mixed
or is_type(mixed,'string') and table.autokey(groups,mixed) and table.autokey(groups,mixed)
or false
end
--- Prints to all rank of greater/lower power of the rank given
-- @usage Ranking.print('admin','We got a grifer')
-- @param 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 bolean below if true rank below base are printed to
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) 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')
-- @param player the player to give the rank to
-- @param rank the rank to give to the player
-- @param[opt='server'] by_player the player who is giving the rank
-- @param[opt=game.tick] tick the tick that the rank is being given on
function Ranking.give_rank(player,rank,by_player,tick)
local print_colour = defines.text_color.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 'server'
local rank = Ranking.get_rank(rank) or Ranking.get_rank(Ranking._presets().meta.default)
local player = Game.get_player(player) or error('No Player To Give Rank')
local old_rank = Ranking.get_rank(player) or Ranking.get_rank(Ranking._presets().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
game.print({message,player.name,rank.name,by_player_name},print_colour)
if rank.group.name ~= '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 not old_rank.group.name == 'Jail' then Ranking._presets().old[player.index] = rank.name end
player.admin = rank.is_admin or false
if defines.events.rank_change then
script.raise_event(defines.events.rank_change,{
name=defines.events.rank_change,
tick=tick,
player_index=player.index,
by_player_name=by_player_name,
new_rank=rank,
old_rank=old_rank
})
end
end
--- Revert the last change to a players rank
-- @usage Ranking.revert(1)
-- @param 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,Ranking._presets().old[player.index],by_player)
end
--- Given the player has a rank in the preset table it is given
-- @usage Ranking.find_preset(1)
-- @param player the player to test for an auto rank
-- @tparam[opt=nil] tick the tick it happens on
function Ranking.find_preset(player,tick)
local presets = Ranking._presets().current
local meta_data = Ranking._presets().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={name='not jail'}}
local ranks = {default}
if current_rank.group.name == 'Jail' then return end
if presets[string.lower(player.name)] then
local rank = Ranking.get_rank(presets[string.lower(player.name)])
if current_rank.power >= rank.power then return end
table.insert(ranks,rank)
end
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
local _rank = nil
for _,rank in pairs(ranks) do
if rank.power < current_rank.power then _rank = rank end
end
if _rank then
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
end
-- this is the base rank object, do not store in global
--- Is this rank allowed to open this gui or use this command etc.
-- @usage rank:allowed('server-interface')
-- @tparam teh action to test for
-- @treturn bolean 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 bolean 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(rank.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')
-- @param rtn any value you want to return
function Ranking._rank:print(rtn,colour)
local colour = colour or defines.color.white
if not Server or not Server._thread then
for _,player in pairs(self:get_players()) do
player_return(rtn,colour,player)
end
else
-- using threads to make less lag
Server.new_thread{
data={rank=self,rtn=rtn}
}:on_event('resolve',function(thread)
return thread.data.rank:get_players(true)
end):on_event('success',function(thread,players)
for _,player in pairs(players) do
player_return(thread.data.rtn,colour,player)
end
end):queue()
end
end
-- this is used to edit a group once made key is what is being edited and set_value makes it over ride the current value
-- see Addons/playerRanks for examples
function Ranking._rank:edit(key,set_value,value)
if game then return end
if set_value then self[key] = value return end
if key == 'disallow' then
self.disallow = table.merge(self.disallow,value,true)
elseif key == 'allow' then
self.allow = table.merge(self.allow,value)
end
Ranking._update_rank(self)
end
-- this is the base group object, do not store in global, these cant be used in game
-- this makes a new group
-- {name='root',allow={},disallow={}}
function Ranking._group:create(obj)
if game then return end
if not is_type(obj.name,'string') then return end
setmetatable(obj,{__index=Ranking._group})
self.index = #Ranking._groups(names)+1
obj.ranks = {}
obj.allow = obj.allow or {}
obj.disallow = obj.disallow or {}
Ranking._add_group(obj)
return obj
end
-- this makes a new rank in side this group
-- {name='Root',short_hand='Root',tag='[Root]',time=nil,colour=defines.colors.white,allow={},disallow={}}
-- if the rank is given power then it is given that place realative to the highest rank in that group,if no power then it is added to the end
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 return end
setmetatable(obj,{__index=Ranking._rank})
obj.group = self
obj.allow = obj.allow or {}
obj.disallow = obj.disallow or {}
obj.power = obj.power and self.highest and self.highest.power+obj.power or obj.power or self.lowest and self.lowest.power+1 or nil
setmetatable(obj.allow,{__index=self.allow})
setmetatable(obj.disallow,{__index=self.disallow})
Ranking._add_rank(obj,obj.power)
Ranking._set_rank_power()
table.insert(self.ranks,obj)
if not self.highest or obj.power < self.highest.power then self.highest = obj end
if not self.lowest or obj.power > self.lowest.power then self.lowest = obj end
end
-- this is used to edit a group once made key is what is being edited and set_value makes it over ride the current value
-- see Addons/playerRanks for examples
function Ranking._group:edit(key,set_value,value)
if game then return end
if set_value then self[key] = value return end
if key == 'disallow' then
self.disallow = table.merge(self.disallow,value,true)
elseif key == 'allow' then
self.allow = table.merge(self.allow,value)
end
Ranking._update_group(self)
end
Event.register(defines.events.on_player_joined_game,function(event)
Ranking.find_preset(event.player_index)
end)
Event.register(-1,function(event)
for power,rank in pairs(Ranking._ranks()) do
local perm = game.permissions.create_group(rank.name)
for _,toRemove in pairs(rank.disallow) do
perm.set_allows_action(defines.input_action[toRemove],false)
end
end
end)
return Ranking