dobrograd-13-06-2022/garrysmod/gamemodes/darkrp/gamemode/modules/base/sh_createitems.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

240 lines
12 KiB
Lua

local plyMeta = FindMetaTable("Player")
-- Assert function, asserts a property and returns the error if false.
-- Allows f to override err and hints by simply returning them
local ass = function(f, err, hints) return function(...)
local res = {f(...)}
table.insert(res, err)
table.insert(res, hints)
return unpack(res)
end end
-- Returns whether a value is nil
local isnil = fn.Curry(fn.Eq, 2)(nil)
-- Optional value, when filled in it must meet the conditions
local optional = function(...) return fn.FOr{isnil, ...} end
-- Check the correctness of a model
local checkModel = isstring
-- A table of which each element must meet condition f
local tableOf = function(f) return function(tbl)
if not istable(tbl) then return false end
for k,v in pairs(tbl) do if not f(v) then return false end end
return true
end end
-- A table that is nonempty, wrap around tableOf
local nonempty = function(f) return function(tbl) return istable(tbl) and #tbl > 0 and f(tbl) end end
local uniqueJob = function(v, tbl)
local job = DarkRP.getJobByCommand(v)
if job then return false, "This job does not have a unique command.", {"There must be some other job that has the same command.", "Fix this by changing the 'command' of your job to something else."} end
return true
end
-- Template for a correct job
local requiredTeamItems = {
color = ass(tableOf(isnumber), "The color must be a Color value.", {"Color values look like this: Color(r, g, b, a), where r, g, b and a are numbers between 0 and 255."}),
weapons = ass(optional(istable), "The weapons must be a valid table of strings.", {"Example: weapons = {\"med_kit\", \"weapon_bugbait\"},"}),
command = ass(fn.FAnd{isstring, uniqueJob}, "The command must be a string."),
max = ass(fn.FAnd{isnumber, fp{fn.Lte, 0}}, "The max must be a number greater than or equal to zero.", {"Zero means infinite.", "A decimal between 0 and 1 is seen as a percentage."}),
salary = ass(fn.FAnd{isnumber, fp{fn.Lte, 0}}, "The salary must be a number greater than zero."),
admin = ass(fn.FAnd{isnumber, fp{fn.Lte, 0}, fp{fn.Gte, 2}}, "The admin value must be a number greater than or equal to zero and smaller than three."),
-- Optional advanced stuff
category = ass(optional(isstring), "The category must be the name of an existing category!"),
sortOrder = ass(optional(isnumber), "The sortOrder must be a number."),
buttonColor = ass(optional(tableOf(isnumber)), "The buttonColor must be a Color value."),
label = ass(optional(isstring), "The label must be a valid string."),
ammo = ass(optional(tableOf(isnumber)), "The ammo must be a table containing numbers.", {"See example on http://wiki.darkrp.com/index.php/DarkRP:CustomJobFields"}),
hasLicense = ass(optional(isbool), "The hasLicense must be either true or false."),
NeedToChangeFrom = ass(optional(tableOf(isnumber), isnumber), "The NeedToChangeFrom must be either an existing team or a table of existing teams", {"Is there a job here that doesn't exist (anymore)?"}),
customCheck = ass(optional(isfunction), "The customCheck must be a function."),
CustomCheckFailMsg = ass(optional(isstring, isfunction), "The CustomCheckFailMsg must be either a string or a function."),
modelScale = ass(optional(isnumber), "The modelScale must be a number."),
maxpocket = ass(optional(isnumber), "The maxPocket must be a number."),
maps = ass(optional(tableOf(isstring)), "The maps value must be a table of valid map names."),
candemote = ass(optional(isbool), "The candemote value must be either true or false."),
mayor = ass(optional(isbool), "The mayor value must be either true or false."),
chief = ass(optional(isbool), "The chief value must be either true or false."),
medic = ass(optional(isbool), "The medic value must be either true or false."),
cook = ass(optional(isbool), "The cook value must be either true or false."),
hobo = ass(optional(isbool), "The hobo value must be either true or false."),
playerClass = ass(optional(isstring), "The playerClass must be a valid string."),
CanPlayerSuicide = ass(optional(isfunction), "The CanPlayerSuicide must be a function."),
PlayerCanPickupWeapon = ass(optional(isfunction), "The PlayerCanPickupWeapon must be a function."),
PlayerDeath = ass(optional(isfunction), "The PlayerDeath must be a function."),
PlayerLoadout = ass(optional(isfunction), "The PlayerLoadout must be a function."),
PlayerSelectSpawn = ass(optional(isfunction), "The PlayerSelectSpawn must be a function."),
PlayerSetModel = ass(optional(isfunction), "The PlayerSetModel must be a function."),
PlayerSpawn = ass(optional(isfunction), "The PlayerSpawn must be a function."),
PlayerSpawnProp = ass(optional(isfunction), "The PlayerSpawnProp must be a function."),
RequiresVote = ass(optional(isfunction), "The RequiresVote must be a function."),
ShowSpare1 = ass(optional(isfunction), "The ShowSpare1 must be a function."),
ShowSpare2 = ass(optional(isfunction), "The ShowSpare2 must be a function."),
canStartVote = ass(optional(isfunction), "The canStartVote must be a function."),
canStartVoteReason = ass(optional(isstring, isfunction), "The canStartVoteReason must be either a string or a function."),
}
local validAgenda = {
Title = ass(isstring, "The title must be a string."),
Manager = ass(fn.FOr{isnumber, nonempty(tableOf(isnumber))}, "The Manager must either be a single team or a non-empty table of existing teams.", {"Is there a job here that doesn't exist (anymore)?"}),
Listeners = ass(nonempty(tableOf(isnumber)), "The Listeners must be a non-empty table of existing teams.",
{
"Is there a job here that doesn't exist (anymore)?",
"Are you trying to have multiple manager jobs in this agenda? In that case you must put the list of manager jobs in curly braces.",
[[Like so: DarkRP.createAgenda("Some agenda", {TEAM_MANAGER1, TEAM_MANAGER2}, {TEAM_LISTENER1, TEAM_LISTENER2})]]
})
}
-- Check template against actual implementation
local env = {} -- environment used to be check propositions between multiple tables
local function checkValid(tbl, requiredItems, oEnv) -- Allow override environment
for k,v in pairs(requiredItems) do
local correct, err, hints = tbl[v] ~= nil
if isfunction(v) then correct, err, hints = v(tbl[k], tbl, oEnv or env) end
err = err or string.format("Element '%s' is corrupt!", k)
if not correct then return correct, err, hints end
end
return true
end
-----------------------------------------------------------
-- Job commands --
-----------------------------------------------------------
RPExtraTeams = {}
local jobByCmd = {}
DarkRP.getJobByCommand = function(cmd)
if not jobByCmd[cmd] then return nil, nil end
return RPExtraTeams[jobByCmd[cmd]], jobByCmd[cmd]
end
plyMeta.getJobTable = fn.FOr{fn.Compose{fn.Curry(fn.Flip(fn.GetValue), 2)(RPExtraTeams), plyMeta.Team}, fn.Curry(fn.Id, 2)({})}
local jobCount = 0
function DarkRP.createJob(Name, colorOrTable, Weapons, command, maximum_amount_of_this_class, Salary, admin, Haslicense, NeedToChangeFrom, CustomCheck)
local tableSyntaxUsed = not IsColor(colorOrTable)
local CustomTeam = tableSyntaxUsed and colorOrTable or
{color = colorOrTable, weapons = Weapons, command = command,
max = maximum_amount_of_this_class, salary = Salary, admin = admin or 0, hasLicense = Haslicense,
NeedToChangeFrom = NeedToChangeFrom, customCheck = CustomCheck
}
CustomTeam.name = Name
CustomTeam.default = DarkRP.DARKRP_LOADING
local valid, err, hints = checkValid(CustomTeam, requiredTeamItems)
if not valid then DarkRP.error(string.format("Corrupt team: %s!\n%s", CustomTeam.name or "", err), 3, hints) end
jobCount = jobCount + 1
CustomTeam.team = jobCount
CustomTeam.salary = math.floor(CustomTeam.salary)
CustomTeam.customCheck = CustomTeam.customCheck and fp{DarkRP.simplerrRun, CustomTeam.customCheck}
CustomTeam.CustomCheckFailMsg = isfunction(CustomTeam.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, CustomTeam.CustomCheckFailMsg} or CustomTeam.CustomCheckFailMsg
CustomTeam.CanPlayerSuicide = CustomTeam.CanPlayerSuicide and fp{DarkRP.simplerrRun, CustomTeam.CanPlayerSuicide}
CustomTeam.PlayerCanPickupWeapon = CustomTeam.PlayerCanPickupWeapon and fp{DarkRP.simplerrRun, CustomTeam.PlayerCanPickupWeapon}
CustomTeam.PlayerDeath = CustomTeam.PlayerDeath and fp{DarkRP.simplerrRun, CustomTeam.PlayerDeath}
CustomTeam.PlayerLoadout = CustomTeam.PlayerLoadout and fp{DarkRP.simplerrRun, CustomTeam.PlayerLoadout}
CustomTeam.PlayerSelectSpawn = CustomTeam.PlayerSelectSpawn and fp{DarkRP.simplerrRun, CustomTeam.PlayerSelectSpawn}
CustomTeam.PlayerSetModel = CustomTeam.PlayerSetModel and fp{DarkRP.simplerrRun, CustomTeam.PlayerSetModel}
CustomTeam.PlayerSpawn = CustomTeam.PlayerSpawn and fp{DarkRP.simplerrRun, CustomTeam.PlayerSpawn}
CustomTeam.PlayerSpawnProp = CustomTeam.PlayerSpawnProp and fp{DarkRP.simplerrRun, CustomTeam.PlayerSpawnProp}
CustomTeam.RequiresVote = CustomTeam.RequiresVote and fp{DarkRP.simplerrRun, CustomTeam.RequiresVote}
CustomTeam.ShowSpare1 = CustomTeam.ShowSpare1 and fp{DarkRP.simplerrRun, CustomTeam.ShowSpare1}
CustomTeam.ShowSpare2 = CustomTeam.ShowSpare2 and fp{DarkRP.simplerrRun, CustomTeam.ShowSpare2}
CustomTeam.canStartVote = CustomTeam.canStartVote and fp{DarkRP.simplerrRun, CustomTeam.canStartVote}
jobByCmd[CustomTeam.command] = table.insert(RPExtraTeams, CustomTeam)
team.SetUp(#RPExtraTeams, Name, CustomTeam.color)
local Team = #RPExtraTeams
return Team
end
AddExtraTeam = DarkRP.createJob
local function removeCustomItem(tbl, hookName, i)
local item = tbl[i]
tbl[i] = nil
hook.Run(hookName, i, item)
end
function DarkRP.removeJob(i)
local job = RPExtraTeams[i]
jobByCmd[job.command] = nil
jobCount = jobCount - 1
removeCustomItem(RPExtraTeams, "onJobRemoved", i)
end
/*---------------------------------------------------------------------------
Decides whether a custom job or shipmet or whatever can be used in a certain map
---------------------------------------------------------------------------*/
function GM:CustomObjFitsMap(obj)
if not obj or not obj.maps then return true end
local map = string.lower(game.GetMap())
for k,v in pairs(obj.maps) do
if string.lower(v) == map then return true end
end
return false
end
-- here for backwards compatibility
DarkRPAgendas = {}
local agendas = {}
-- Returns the agenda managed by the player
plyMeta.getAgenda = fn.Compose{fn.Curry(fn.Flip(fn.GetValue), 2)(DarkRPAgendas), plyMeta.Team}
-- Returns the agenda this player is member of
function plyMeta:getAgendaTable()
return agendas[self:Team()]
end
DarkRP.getAgendas = fp{fn.Id, agendas}
function DarkRP.createAgenda(Title, Manager, Listeners)
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["agendas"][Title] then return end
local agenda = {Manager = Manager, Title = Title, Listeners = Listeners, ManagersByKey = {}}
agenda.default = DarkRP.DARKRP_LOADING
local valid, err, hints = checkValid(agenda, validAgenda)
if not valid then DarkRP.error(string.format("Corrupt agenda: %s!\n%s", agenda.Title or "", err), 2, hints) end
for k,v in pairs(Listeners) do
agendas[v] = agenda
end
for k,v in pairs(istable(Manager) and Manager or {Manager}) do
agendas[v] = agenda
DarkRPAgendas[v] = agenda -- backwards compat
agenda.ManagersByKey[v] = true
end
if SERVER then
timer.Simple(0, function()
-- Run after scripts have loaded
agenda.text = hook.Run("agendaUpdated", nil, agenda, "")
end)
end
end
AddAgenda = DarkRP.createAgenda
function DarkRP.removeAgenda(title)
local agenda
for k,v in pairs(agendas) do
if v.Title == title then
agenda = v
agendas[k] = nil
end
end
for k,v in pairs(DarkRPAgendas) do
if v.Title == title then agendas[k] = nil end
end
hook.Run("onAgendaRemoved", title, agenda)
end