923 lines
36 KiB
Lua
923 lines
36 KiB
Lua
local plyMeta = FindMetaTable("Player")
|
||
|
||
-----------------------------------------------------------
|
||
-- Job commands --
|
||
-----------------------------------------------------------
|
||
local function declareTeamCommands(CTeam)
|
||
local k = 0
|
||
for num, v in pairs(RPExtraTeams) do
|
||
if v.command == CTeam.command then
|
||
k = num
|
||
end
|
||
end
|
||
|
||
local chatcommandCondition = function(ply)
|
||
local plyTeam = ply:Team()
|
||
|
||
if plyTeam == k then return false end
|
||
if CTeam.admin == 1 and not ply:IsAdmin() or CTeam.admin == 2 and not ply:IsSuperAdmin() then return false end
|
||
if isnumber(CTeam.NeedToChangeFrom) and plyTeam ~= CTeam.NeedToChangeFrom then return false end
|
||
if istable(CTeam.NeedToChangeFrom) and not table.HasValue(CTeam.NeedToChangeFrom, plyTeam) then return false end
|
||
if CTeam.customCheck and CTeam.customCheck(ply) == false then return false end
|
||
if ply:isArrested() then return false end
|
||
local numPlayers = team.NumPlayers(k)
|
||
if CTeam.max ~= 0 and ((CTeam.max % 1 == 0 and numPlayers >= CTeam.max) or (CTeam.max % 1 ~= 0 and (numPlayers + 1) / player.GetCount() > CTeam.max)) then return false end
|
||
if ply.LastJob and 10 - (CurTime() - ply.LastJob) >= 0 then return false end
|
||
if ply.LastVoteCop and CurTime() - ply.LastVoteCop < 80 then return false end
|
||
|
||
return true
|
||
end
|
||
|
||
if CTeam.vote or CTeam.RequiresVote then
|
||
DarkRP.declareChatCommand{
|
||
command = "vote" .. CTeam.command,
|
||
description = "Vote to become " .. CTeam.name .. ".",
|
||
delay = 1.5,
|
||
condition =
|
||
function(ply)
|
||
if CTeam.RequiresVote and not CTeam.RequiresVote(ply, k) then return false end
|
||
if CTeam.canStartVote and not CTeam.canStartVote(ply) then return false end
|
||
|
||
return chatcommandCondition(ply)
|
||
end
|
||
}
|
||
|
||
DarkRP.declareChatCommand{
|
||
command = CTeam.command,
|
||
description = "Become " .. CTeam.name .. " and skip the vote.",
|
||
delay = 1.5,
|
||
condition =
|
||
function(ply)
|
||
local requiresVote = CTeam.RequiresVote and CTeam.RequiresVote(ply, k)
|
||
|
||
if requiresVote then return false end
|
||
if requiresVote ~= false and CTeam.admin == 0 and not ply:IsAdmin() or CTeam.admin == 1 and not ply:IsSuperAdmin() then return false end
|
||
if CTeam.canStartVote and not CTeam.canStartVote(ply) then return false end
|
||
|
||
return chatcommandCondition(ply)
|
||
end
|
||
}
|
||
else
|
||
DarkRP.declareChatCommand{
|
||
command = CTeam.command,
|
||
description = "Become " .. CTeam.name .. ".",
|
||
delay = 1.5,
|
||
condition = chatcommandCondition
|
||
}
|
||
end
|
||
end
|
||
|
||
local function addTeamCommands(CTeam, max)
|
||
if CLIENT then return end
|
||
|
||
local k = 0
|
||
for num, v in pairs(RPExtraTeams) do
|
||
if v.command == CTeam.command then
|
||
k = num
|
||
end
|
||
end
|
||
|
||
if CTeam.vote or CTeam.RequiresVote then
|
||
DarkRP.defineChatCommand("vote" .. CTeam.command, function(ply)
|
||
if CTeam.RequiresVote and not CTeam.RequiresVote(ply, k) then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("job_doesnt_require_vote_currently"))
|
||
|
||
return ""
|
||
end
|
||
|
||
if CTeam.canStartVote and not CTeam.canStartVote(ply) then
|
||
local reason = isfunction(CTeam.canStartVoteReason) and CTeam.canStartVoteReason(ply, CTeam) or CTeam.canStartVoteReason or ""
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("unable", "/vote" .. CTeam.command, reason))
|
||
|
||
return ""
|
||
end
|
||
|
||
if CTeam.admin == 1 and not ply:IsAdmin() then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_admin", "/" .. "vote" .. CTeam.command))
|
||
|
||
return ""
|
||
elseif CTeam.admin > 1 and not ply:IsSuperAdmin() then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_sadmin", "/" .. "vote" .. CTeam.command))
|
||
|
||
return ""
|
||
end
|
||
|
||
if isnumber(CTeam.NeedToChangeFrom) and ply:Team() ~= CTeam.NeedToChangeFrom then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_to_be_before", team.GetName(CTeam.NeedToChangeFrom), CTeam.name))
|
||
|
||
return ""
|
||
elseif istable(CTeam.NeedToChangeFrom) and not table.HasValue(CTeam.NeedToChangeFrom, ply:Team()) then
|
||
local teamnames = ""
|
||
|
||
for _, b in pairs(CTeam.NeedToChangeFrom) do
|
||
teamnames = teamnames .. " or " .. team.GetName(b)
|
||
end
|
||
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_to_be_before", string.sub(teamnames, 5), CTeam.name))
|
||
|
||
return ""
|
||
end
|
||
|
||
if CTeam.customCheck and not CTeam.customCheck(ply) then
|
||
local message = isfunction(CTeam.CustomCheckFailMsg) and CTeam.CustomCheckFailMsg(ply, CTeam) or CTeam.CustomCheckFailMsg or DarkRP.getPhrase("unable", team.GetName(t), "")
|
||
DarkRP.notify(ply, 1, 4, message)
|
||
|
||
return ""
|
||
end
|
||
|
||
local allowed, time = ply:changeAllowed(k)
|
||
if not allowed then
|
||
local notif = time and DarkRP.getPhrase("have_to_wait", math.ceil(time), "/job, " .. DarkRP.getPhrase("banned_or_demoted")) or DarkRP.getPhrase("unable", team.GetName(k), DarkRP.getPhrase("banned_or_demoted"))
|
||
DarkRP.notify(ply, 1, 4, notif)
|
||
|
||
return ""
|
||
end
|
||
|
||
if ply:Team() == k then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("unable", CTeam.command, ""))
|
||
|
||
return ""
|
||
end
|
||
|
||
local numPlayers = team.NumPlayers(k)
|
||
if max ~= 0 and ((max % 1 == 0 and numPlayers >= max) or (max % 1 ~= 0 and (numPlayers + 1) / player.GetCount() > max)) then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("team_limit_reached", CTeam.name))
|
||
|
||
return ""
|
||
end
|
||
|
||
if ply.LastJob and 10 - (CurTime() - ply.LastJob) >= 0 then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("have_to_wait", math.ceil(10 - (CurTime() - ply.LastJob)), GAMEMODE.Config.chatCommandPrefix .. CTeam.command))
|
||
|
||
return ""
|
||
end
|
||
|
||
ply.LastVoteCop = ply.LastVoteCop or -80
|
||
|
||
if CurTime() - ply.LastVoteCop < 80 then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("have_to_wait", math.ceil(80 - (CurTime() - ply:GetTable().LastVoteCop)), GAMEMODE.Config.chatCommandPrefix .. CTeam.command))
|
||
|
||
return ""
|
||
end
|
||
|
||
DarkRP.createVote(DarkRP.getPhrase("wants_to_be", ply:Nick(), CTeam.name), "job", ply, 20, function(vote, choice)
|
||
local target = vote.target
|
||
if not IsValid(target) then return end
|
||
|
||
if choice >= 0 then
|
||
target:changeTeam(k)
|
||
else
|
||
DarkRP.notifyAll(1, 4, DarkRP.getPhrase("has_not_been_made_team", target:Nick(), CTeam.name))
|
||
end
|
||
end, nil, nil, {
|
||
targetTeam = k
|
||
})
|
||
|
||
ply.LastVoteCop = CurTime()
|
||
|
||
return ""
|
||
end)
|
||
|
||
local function onJobCommand(ply, hasPriv)
|
||
if hasPriv then
|
||
ply:changeTeam(k)
|
||
return
|
||
end
|
||
|
||
local a = CTeam.admin
|
||
if a > 0 and not ply:IsAdmin()
|
||
or a > 1 and not ply:IsSuperAdmin()
|
||
then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_admin", CTeam.name))
|
||
return
|
||
end
|
||
|
||
if not CTeam.RequiresVote and
|
||
(a == 0 and not ply:IsAdmin()
|
||
or a == 1 and not ply:IsSuperAdmin()
|
||
or a == 2)
|
||
or CTeam.RequiresVote and CTeam.RequiresVote(ply, k)
|
||
then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_to_make_vote", CTeam.name))
|
||
return
|
||
end
|
||
|
||
ply:changeTeam(k)
|
||
end
|
||
DarkRP.defineChatCommand(CTeam.command, function(ply)
|
||
CAMI.PlayerHasAccess(ply, "DarkRP_GetJob_" .. CTeam.command, fp{onJobCommand, ply})
|
||
|
||
return ""
|
||
end)
|
||
else
|
||
DarkRP.defineChatCommand(CTeam.command, function(ply)
|
||
if CTeam.admin == 1 and not ply:IsAdmin() then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_admin", "/" .. CTeam.command))
|
||
|
||
return ""
|
||
end
|
||
|
||
if CTeam.admin > 1 and not ply:IsSuperAdmin() then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_sadmin", "/" .. CTeam.command))
|
||
|
||
return ""
|
||
end
|
||
|
||
ply:changeTeam(k)
|
||
|
||
return ""
|
||
end)
|
||
end
|
||
|
||
concommand.Add("rp_" .. CTeam.command, function(ply, cmd, args)
|
||
if ply:EntIndex() ~= 0 and not ply:IsAdmin() then
|
||
ply:PrintMessage(HUD_PRINTCONSOLE, DarkRP.getPhrase("need_admin", cmd))
|
||
return
|
||
end
|
||
|
||
if CTeam.admin > 1 and not ply:IsSuperAdmin() and ply:EntIndex() ~= 0 then
|
||
ply:PrintMessage(HUD_PRINTCONSOLE, DarkRP.getPhrase("need_sadmin", cmd))
|
||
return
|
||
end
|
||
|
||
if CTeam.vote then
|
||
if CTeam.admin >= 1 and ply:EntIndex() ~= 0 and not ply:IsSuperAdmin() then
|
||
ply:PrintMessage(HUD_PRINTCONSOLE, DarkRP.getPhrase("need_sadmin", cmd))
|
||
return
|
||
elseif CTeam.admin > 1 and ply:IsSuperAdmin() and ply:EntIndex() ~= 0 then
|
||
ply:PrintMessage(HUD_PRINTCONSOLE, DarkRP.getPhrase("need_to_make_vote", CTeam.name))
|
||
return
|
||
end
|
||
end
|
||
|
||
if not args or not args[1] then
|
||
DarkRP.printConsoleMessage(ply, DarkRP.getPhrase("invalid_x", DarkRP.getPhrase("arguments"), ""))
|
||
return
|
||
end
|
||
|
||
local target = DarkRP.findPlayer(args[1])
|
||
|
||
if not target then
|
||
DarkRP.printConsoleMessage(ply, DarkRP.getPhrase("could_not_find", tostring(args[1])))
|
||
return
|
||
end
|
||
|
||
target:changeTeam(k, true)
|
||
local nick
|
||
if (ply:EntIndex() ~= 0) then
|
||
nick = ply:Nick()
|
||
else
|
||
nick = "Console"
|
||
end
|
||
DarkRP.notify(target, 0, 4, DarkRP.getPhrase("x_made_you_a_y", nick, CTeam.name))
|
||
end)
|
||
end
|
||
|
||
local function addEntityCommands(tblEnt)
|
||
DarkRP.declareChatCommand{
|
||
command = tblEnt.cmd,
|
||
description = "Purchase a " .. tblEnt.name,
|
||
delay = tblEnt.delay or GAMEMODE.Config.EntitySpamTime,
|
||
condition =
|
||
function(ply)
|
||
if not tblEnt.allowPurchaseWhileDead and not ply:Alive() then return false end
|
||
if ply:isArrested() then return false end
|
||
if istable(tblEnt.allowed) and not table.HasValue(tblEnt.allowed, ply:Team()) then return false end
|
||
if not ply:canAfford(tblEnt.price) then return false end
|
||
if tblEnt.customCheck and tblEnt.customCheck(ply) == false then return false end
|
||
|
||
return true
|
||
end
|
||
}
|
||
|
||
if CLIENT then return end
|
||
|
||
-- Default spawning function of an entity
|
||
-- used if tblEnt.spawn is not defined
|
||
local function defaultSpawn(ply, tr, tblE)
|
||
local ent = ents.Create(tblE.ent)
|
||
|
||
if not ent:IsValid() then error("Entity '" .. tblE.ent .. "' does not exist or is not valid.") end
|
||
if ent.Setowning_ent then ent:Setowning_ent(ply) end
|
||
|
||
ent:SetPos(tr.HitPos)
|
||
-- These must be set before :Spawn()
|
||
ent.SID = ply.SID
|
||
ent.allowed = tblE.allowed
|
||
ent.DarkRPItem = tblE
|
||
ent:Spawn()
|
||
ent:Activate()
|
||
|
||
DarkRP.placeEntity(ent, tr, ply)
|
||
|
||
local phys = ent:GetPhysicsObject()
|
||
if phys:IsValid() then phys:Wake() end
|
||
|
||
return ent
|
||
end
|
||
|
||
local function buythis(ply, args)
|
||
if ply:isArrested() then return "" end
|
||
if not tblEnt.allowPurchaseWhileDead and not ply:Alive() then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("must_be_alive_to_do_x", DarkRP.getPhrase("buy_x", tblEnt.name)))
|
||
return ""
|
||
end
|
||
if istable(tblEnt.allowed) and not table.HasValue(tblEnt.allowed, ply:Team()) then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("incorrect_job", tblEnt.name))
|
||
return ""
|
||
end
|
||
|
||
if tblEnt.customCheck and not tblEnt.customCheck(ply) then
|
||
local message = isfunction(tblEnt.CustomCheckFailMsg) and tblEnt.CustomCheckFailMsg(ply, tblEnt) or
|
||
tblEnt.CustomCheckFailMsg or
|
||
DarkRP.getPhrase("not_allowed_to_purchase")
|
||
DarkRP.notify(ply, 1, 4, message)
|
||
return ""
|
||
end
|
||
|
||
if ply:customEntityLimitReached(tblEnt) then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("limit", tblEnt.name))
|
||
return ""
|
||
end
|
||
|
||
local canbuy, suppress, message, price = hook.Call("canBuyCustomEntity", nil, ply, tblEnt)
|
||
|
||
local cost = price or tblEnt.getPrice and tblEnt.getPrice(ply, tblEnt.price) or tblEnt.price
|
||
|
||
if not ply:canAfford(cost) then
|
||
DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("cant_afford", tblEnt.name))
|
||
return ""
|
||
end
|
||
|
||
if canbuy == false then
|
||
if not suppress and message then DarkRP.notify(ply, 1, 4, message) end
|
||
return ""
|
||
end
|
||
|
||
ply:addMoney(-cost)
|
||
|
||
local trace = {}
|
||
trace.start = ply:EyePos()
|
||
trace.endpos = trace.start + ply:GetAimVector() * 85
|
||
trace.filter = ply
|
||
|
||
local tr = util.TraceLine(trace)
|
||
|
||
local ent = (tblEnt.spawn or defaultSpawn)(ply, tr, tblEnt)
|
||
ent.onlyremover = not tblEnt.allowTools
|
||
-- Repeat these properties to alleviate work in tblEnt.spawn:
|
||
ent.SID = ply.SID
|
||
ent.allowed = tblEnt.allowed
|
||
ent.DarkRPItem = tblEnt
|
||
|
||
hook.Call("playerBoughtCustomEntity", nil, ply, tblEnt, ent, cost)
|
||
|
||
if cost == 0 then
|
||
DarkRP.notify(ply, 0, 4, DarkRP.getPhrase("you_got_yourself", tblEnt.name))
|
||
else
|
||
DarkRP.notify(ply, 0, 4, DarkRP.getPhrase("you_bought", tblEnt.name, DarkRP.formatMoney(cost), ""))
|
||
end
|
||
|
||
ply:addCustomEntity(tblEnt)
|
||
return ""
|
||
end
|
||
DarkRP.defineChatCommand(tblEnt.cmd, buythis)
|
||
end
|
||
|
||
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 = function(ply)
|
||
local tbl = RPExtraTeams[ply:Team()]
|
||
-- don't error when the player has not fully joined yet
|
||
if not tbl and (ply.DarkRPInitialised or ply.DarkRPDataRetrievalFailed) then
|
||
DarkRP.error(
|
||
string.format("There is a player with an invalid team!\n\nThe player's name is %s, their team number is \"%s\", which has the name \"%s\"",
|
||
ply:EntIndex() == 0 and "Console" or IsValid(ply) and ply:Nick() or "unknown",
|
||
ply:Team(),
|
||
team.GetName(ply:Team())),
|
||
1,
|
||
{
|
||
"It is the server owner's responsibility to figure out why that player has no valid team.",
|
||
"This error is very likely to be caused by an earlier error. If you don't see any errors in your own console, look at the server console."
|
||
}
|
||
)
|
||
end
|
||
return tbl
|
||
end
|
||
|
||
function DarkRP.createJob(Name, colorOrTable, model, Description, Weapons, command, maximum_amount_of_this_class, Salary, admin, Vote, Haslicense, NeedToChangeFrom, CustomCheck)
|
||
local tableSyntaxUsed = not IsColor(colorOrTable)
|
||
|
||
local CustomTeam = tableSyntaxUsed and colorOrTable or
|
||
{color = colorOrTable, model = model, description = Description, weapons = Weapons, command = command,
|
||
max = maximum_amount_of_this_class, salary = Salary, admin = admin or 0, vote = tobool(Vote), hasLicense = Haslicense,
|
||
NeedToChangeFrom = NeedToChangeFrom, customCheck = CustomCheck
|
||
}
|
||
CustomTeam.name = Name
|
||
CustomTeam.default = DarkRP.DARKRP_LOADING
|
||
|
||
-- Disabled job
|
||
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["jobs"][CustomTeam.command] then return end
|
||
|
||
local valid, err, hints = DarkRP.validateJob(CustomTeam)
|
||
if not valid then DarkRP.error(string.format("Corrupt team: %s!\n%s", CustomTeam.name or "", err), 2, hints) end
|
||
|
||
if not (GM or GAMEMODE):CustomObjFitsMap(CustomTeam) then return end
|
||
|
||
local jobCount = #RPExtraTeams + 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)
|
||
DarkRP.addToCategory(CustomTeam, "jobs", CustomTeam.category)
|
||
|
||
team.SetUp(jobCount, Name, CustomTeam.color)
|
||
|
||
timer.Simple(0, function()
|
||
declareTeamCommands(CustomTeam)
|
||
addTeamCommands(CustomTeam, CustomTeam.max)
|
||
end)
|
||
|
||
-- Precache model here. Not right before the job change is done
|
||
if istable(CustomTeam.model) then
|
||
for _, v in pairs(CustomTeam.model) do util.PrecacheModel(v) end
|
||
else
|
||
util.PrecacheModel(CustomTeam.model)
|
||
end
|
||
return jobCount
|
||
end
|
||
AddExtraTeam = DarkRP.createJob
|
||
|
||
local function removeCustomItem(tbl, category, hookName, reloadF4, i)
|
||
local item = tbl[i]
|
||
tbl[i] = nil
|
||
if category then DarkRP.removeFromCategory(item, category) end
|
||
if istable(item) and (item.command or item.cmd) then DarkRP.removeChatCommand(item.command or item.cmd) end
|
||
hook.Run(hookName, i, item)
|
||
if CLIENT and reloadF4 and IsValid(DarkRP.getF4MenuPanel()) then DarkRP.getF4MenuPanel():Remove() end -- Rebuild entire F4 menu frame
|
||
end
|
||
|
||
function DarkRP.removeJob(i)
|
||
local job = RPExtraTeams[i]
|
||
jobByCmd[job.command] = nil
|
||
|
||
DarkRP.removeChatCommand("vote" .. job.command)
|
||
removeCustomItem(RPExtraTeams, "jobs", "onJobRemoved", true, i)
|
||
end
|
||
|
||
RPExtraTeamDoors = {}
|
||
RPExtraTeamDoorIDs = {}
|
||
local maxTeamDoorID = 0
|
||
function DarkRP.createEntityGroup(name, ...)
|
||
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["doorgroups"][name] then return end
|
||
RPExtraTeamDoors[name] = {...}
|
||
RPExtraTeamDoors[name].name = name
|
||
|
||
maxTeamDoorID = maxTeamDoorID + 1
|
||
RPExtraTeamDoorIDs[name] = maxTeamDoorID
|
||
end
|
||
AddDoorGroup = DarkRP.createEntityGroup
|
||
|
||
DarkRP.removeEntityGroup = fp{removeCustomItem, RPExtraTeamDoors, nil, "onEntityGroupRemoved", false}
|
||
|
||
CustomVehicles = {}
|
||
CustomShipments = {}
|
||
local shipByName = {}
|
||
DarkRP.getShipmentByName = function(name)
|
||
name = string.lower(name or "")
|
||
|
||
if not shipByName[name] then return nil, nil end
|
||
return CustomShipments[shipByName[name]], shipByName[name]
|
||
end
|
||
|
||
function DarkRP.createShipment(name, model, entity, price, Amount_of_guns_in_one_shipment, Sold_separately, price_separately, noshipment, classes, shipmodel, CustomCheck)
|
||
local tableSyntaxUsed = istable(model)
|
||
|
||
price = tonumber(price)
|
||
local shipmentmodel = shipmodel or "models/Items/item_item_crate.mdl"
|
||
|
||
local customShipment = tableSyntaxUsed and model or
|
||
{model = model, entity = entity, price = price, amount = Amount_of_guns_in_one_shipment,
|
||
seperate = Sold_separately, pricesep = price_separately, noship = noshipment, allowed = classes,
|
||
shipmodel = shipmentmodel, customCheck = CustomCheck, weight = 5}
|
||
|
||
-- The pains of backwards compatibility when dealing with ancient spelling errors...
|
||
if customShipment.separate ~= nil then
|
||
customShipment.seperate = customShipment.separate
|
||
end
|
||
customShipment.separate = customShipment.seperate
|
||
|
||
if customShipment.allowed == nil then
|
||
customShipment.allowed = {}
|
||
for k in pairs(team.GetAllTeams()) do
|
||
table.insert(customShipment.allowed, k)
|
||
end
|
||
end
|
||
|
||
customShipment.name = name
|
||
customShipment.default = DarkRP.DARKRP_LOADING
|
||
customShipment.shipmodel = customShipment.shipmodel or shipmentmodel
|
||
|
||
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["shipments"][customShipment.name] then return end
|
||
|
||
local valid, err, hints = DarkRP.validateShipment(customShipment)
|
||
if not valid then DarkRP.error(string.format("Corrupt shipment: %s!\n%s", name or "", err), 2, hints) end
|
||
|
||
customShipment.spawn = customShipment.spawn and fp{DarkRP.simplerrRun, customShipment.spawn}
|
||
customShipment.allowed = isnumber(customShipment.allowed) and {customShipment.allowed} or customShipment.allowed
|
||
customShipment.customCheck = customShipment.customCheck and fp{DarkRP.simplerrRun, customShipment.customCheck}
|
||
customShipment.CustomCheckFailMsg = isfunction(customShipment.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, customShipment.CustomCheckFailMsg} or customShipment.CustomCheckFailMsg
|
||
|
||
if not customShipment.noship then DarkRP.addToCategory(customShipment, "shipments", customShipment.category) end
|
||
if customShipment.separate then DarkRP.addToCategory(customShipment, "weapons", customShipment.category) end
|
||
|
||
shipByName[string.lower(name or "")] = table.insert(CustomShipments, customShipment)
|
||
util.PrecacheModel(customShipment.model)
|
||
end
|
||
AddCustomShipment = DarkRP.createShipment
|
||
|
||
function DarkRP.removeShipment(i)
|
||
local ship = CustomShipments[i]
|
||
shipByName[ship.name] = nil
|
||
removeCustomItem(CustomShipments, "shipments", "onShipmentRemoved", true, i)
|
||
end
|
||
|
||
function DarkRP.createVehicle(Name_of_vehicle, model, price, Jobs_that_can_buy_it, customcheck)
|
||
local vehicle = istable(Name_of_vehicle) and Name_of_vehicle or
|
||
{name = Name_of_vehicle, model = model, price = price, allowed = Jobs_that_can_buy_it, customCheck = customcheck}
|
||
|
||
vehicle.default = DarkRP.DARKRP_LOADING
|
||
|
||
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["vehicles"][vehicle.name] then return end
|
||
|
||
local found = false
|
||
for k in pairs(DarkRP.getAvailableVehicles()) do
|
||
if string.lower(k) == string.lower(vehicle.name) then found = true break end
|
||
end
|
||
|
||
local valid, err, hints = DarkRP.validateVehicle(vehicle)
|
||
if not valid then DarkRP.error(string.format("Corrupt vehicle: %s!\n%s", vehicle.name or "", err), 2, hints) end
|
||
|
||
if not found then DarkRP.error("Vehicle invalid: " .. vehicle.name .. ". Unknown vehicle name.", 2) end
|
||
|
||
vehicle.customCheck = vehicle.customCheck and fp{DarkRP.simplerrRun, vehicle.customCheck}
|
||
vehicle.CustomCheckFailMsg = isfunction(vehicle.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, vehicle.CustomCheckFailMsg} or vehicle.CustomCheckFailMsg
|
||
|
||
table.insert(CustomVehicles, vehicle)
|
||
DarkRP.addToCategory(vehicle, "vehicles", vehicle.category)
|
||
end
|
||
AddCustomVehicle = DarkRP.createVehicle
|
||
|
||
DarkRP.removeVehicle = fp{removeCustomItem, CustomVehicles, "vehicles", "onVehicleRemoved", true}
|
||
|
||
--[[---------------------------------------------------------------------------
|
||
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 _, v in pairs(obj.maps) do
|
||
if string.lower(v) == map then return true end
|
||
end
|
||
return false
|
||
end
|
||
|
||
DarkRPEntities = {}
|
||
function DarkRP.createEntity(name, entity, model, price, max, command, classes, CustomCheck)
|
||
local tableSyntaxUsed = istable(entity)
|
||
|
||
local tblEnt = tableSyntaxUsed and entity or
|
||
{ent = entity, model = model, price = price, max = max,
|
||
cmd = command, allowed = classes, customCheck = CustomCheck}
|
||
tblEnt.name = name
|
||
tblEnt.default = DarkRP.DARKRP_LOADING
|
||
|
||
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["entities"][tblEnt.name] then return end
|
||
|
||
if isnumber(tblEnt.allowed) then
|
||
tblEnt.allowed = {tblEnt.allowed}
|
||
end
|
||
|
||
local valid, err, hints = DarkRP.validateEntity(tblEnt)
|
||
if not valid then DarkRP.error(string.format("Corrupt entity: %s!\n%s", name or "", err), 2, hints) end
|
||
|
||
tblEnt.customCheck = tblEnt.customCheck and fp{DarkRP.simplerrRun, tblEnt.customCheck}
|
||
tblEnt.CustomCheckFailMsg = isfunction(tblEnt.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, tblEnt.CustomCheckFailMsg} or tblEnt.CustomCheckFailMsg
|
||
tblEnt.getPrice = tblEnt.getPrice and fp{DarkRP.simplerrRun, tblEnt.getPrice}
|
||
tblEnt.getMax = tblEnt.getMax and fp{DarkRP.simplerrRun, tblEnt.getMax}
|
||
tblEnt.spawn = tblEnt.spawn and fp{DarkRP.simplerrRun, tblEnt.spawn}
|
||
|
||
-- if SERVER and FPP then
|
||
-- FPP.AddDefaultBlocked(blockTypes, tblEnt.ent)
|
||
-- end
|
||
|
||
table.insert(DarkRPEntities, tblEnt)
|
||
DarkRP.addToCategory(tblEnt, "entities", tblEnt.category)
|
||
timer.Simple(0, function() addEntityCommands(tblEnt) end)
|
||
end
|
||
AddEntity = DarkRP.createEntity
|
||
|
||
DarkRP.removeEntity = fp{removeCustomItem, DarkRPEntities, "entities", "onEntityRemoved", true}
|
||
|
||
-- 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 = DarkRP.validateAgenda(agenda)
|
||
if not valid then DarkRP.error(string.format("Corrupt agenda: %s!\n%s", agenda.Title or "", err), 2, hints) end
|
||
|
||
for _, v in pairs(agenda.Listeners) do
|
||
agendas[v] = agenda
|
||
end
|
||
|
||
for _, v in pairs(istable(agenda.Manager) and agenda.Manager or {agenda.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 DarkRPAgendas[k] = nil end
|
||
end
|
||
hook.Run("onAgendaRemoved", title, agenda)
|
||
end
|
||
|
||
GM.DarkRPGroupChats = {}
|
||
local groupChatNumber = 0
|
||
function DarkRP.createGroupChat(funcOrTeam, ...)
|
||
local gm = GM or GAMEMODE
|
||
gm.DarkRPGroupChats = gm.DarkRPGroupChats or {}
|
||
if DarkRP.DARKRP_LOADING then
|
||
groupChatNumber = groupChatNumber + 1
|
||
if DarkRP.disabledDefaults["groupchat"][groupChatNumber] then return end
|
||
end
|
||
-- People can enter either functions or a list of teams as parameter(s)
|
||
if isfunction(funcOrTeam) then
|
||
table.insert(gm.DarkRPGroupChats, fp{DarkRP.simplerrRun, funcOrTeam})
|
||
else
|
||
local teams = {funcOrTeam, ...}
|
||
table.insert(gm.DarkRPGroupChats, function(ply) return table.HasValue(teams, ply:Team()) end)
|
||
end
|
||
end
|
||
GM.AddGroupChat = function(_, ...) DarkRP.createGroupChat(...) end
|
||
|
||
DarkRP.removeGroupChat = fp{removeCustomItem, GM.DarkRPGroupChats, nil, "onGroupChatRemoved", false}
|
||
|
||
DarkRP.getGroupChats = fp{fn.Id, GM.DarkRPGroupChats}
|
||
|
||
GM.AmmoTypes = {}
|
||
|
||
function DarkRP.createAmmoType(ammoType, name, model, price, amountGiven, customCheck)
|
||
local gm = GM or GAMEMODE
|
||
gm.AmmoTypes = gm.AmmoTypes or {}
|
||
local ammo = istable(name) and name or {
|
||
name = name,
|
||
model = model,
|
||
price = price,
|
||
amountGiven = amountGiven,
|
||
customCheck = customCheck
|
||
}
|
||
ammo.ammoType = ammoType
|
||
ammo.default = DarkRP.DARKRP_LOADING
|
||
|
||
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["ammo"][ammo.name] then return end
|
||
|
||
ammo.customCheck = ammo.customCheck and fp{DarkRP.simplerrRun, ammo.customCheck}
|
||
ammo.CustomCheckFailMsg = isfunction(ammo.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, ammo.CustomCheckFailMsg} or ammo.CustomCheckFailMsg
|
||
ammo.id = table.insert(gm.AmmoTypes, ammo)
|
||
|
||
DarkRP.addToCategory(ammo, "ammo", ammo.category)
|
||
end
|
||
GM.AddAmmoType = function(_, ...) DarkRP.createAmmoType(...) end
|
||
|
||
DarkRP.removeAmmoType = fp{removeCustomItem, GM.AmmoTypes, "ammo", "onAmmoTypeRemoved", true}
|
||
|
||
local demoteGroups = {}
|
||
function DarkRP.createDemoteGroup(name, tbl)
|
||
if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["demotegroups"][name] then return end
|
||
if not tbl or not tbl[1] then error("No members in the demote group!") end
|
||
|
||
local set = demoteGroups[tbl[1]] or disjoint.MakeSet(tbl[1])
|
||
set.name = name
|
||
for i = 2, #tbl do
|
||
set = (demoteGroups[tbl[i]] or disjoint.MakeSet(tbl[i])) + set
|
||
set.name = name
|
||
end
|
||
|
||
for _, teamNr in ipairs(tbl) do
|
||
if demoteGroups[teamNr] then
|
||
-- Unify the sets if there was already one there
|
||
demoteGroups[teamNr] = demoteGroups[teamNr] + set
|
||
else
|
||
demoteGroups[teamNr] = set
|
||
end
|
||
end
|
||
end
|
||
|
||
function DarkRP.removeDemoteGroup(name)
|
||
local foundSet
|
||
for k, v in pairs(demoteGroups) do
|
||
local set = disjoint.FindSet(v)
|
||
if set.name == name then
|
||
foundSet = set
|
||
demoteGroups[k] = nil
|
||
end
|
||
end
|
||
hook.Run("onDemoteGroupRemoved", name, foundSet)
|
||
end
|
||
|
||
function DarkRP.getDemoteGroup(teamNr)
|
||
demoteGroups[teamNr] = demoteGroups[teamNr] or disjoint.MakeSet(teamNr)
|
||
return disjoint.FindSet(demoteGroups[teamNr])
|
||
end
|
||
|
||
DarkRP.getDemoteGroups = fp{fn.Id, demoteGroups}
|
||
|
||
local categories = {
|
||
jobs = {},
|
||
entities = {},
|
||
shipments = {},
|
||
weapons = {},
|
||
vehicles = {},
|
||
ammo = {},
|
||
}
|
||
local categoriesMerged = false -- whether categories and custom items are merged.
|
||
|
||
DarkRP.getCategories = fp{fn.Id, categories}
|
||
|
||
local categoryOrder = function(a, b)
|
||
local aso = a.sortOrder or 100
|
||
local bso = b.sortOrder or 100
|
||
return aso < bso or aso == bso and a.name < b.name
|
||
end
|
||
|
||
local function insertCategory(destination, tbl)
|
||
-- Override existing category of applicable
|
||
for k, cat in pairs(destination) do
|
||
if cat.name ~= tbl.name then continue end
|
||
|
||
destination[k] = tbl
|
||
tbl.members = cat.members
|
||
return
|
||
end
|
||
|
||
table.insert(destination, tbl)
|
||
local i = #destination
|
||
|
||
while i > 1 do
|
||
if categoryOrder(destination[i - 1], tbl) then break end
|
||
destination[i - 1], destination[i] = destination[i], destination[i - 1]
|
||
i = i - 1
|
||
end
|
||
end
|
||
|
||
function DarkRP.createCategory(tbl)
|
||
local valid, err, hints = DarkRP.validateCategory(tbl)
|
||
if not valid then DarkRP.error(string.format("Corrupt category: %s!\n%s", tbl.name or "", err), 2, hints) end
|
||
tbl.members = {}
|
||
|
||
local destination = categories[tbl.categorises]
|
||
insertCategory(destination, tbl)
|
||
|
||
-- Too many people made the mistake of not creating a category for weapons as well as shipments
|
||
-- when having shipments that can also be sold separately.
|
||
if tbl.categorises == "shipments" then
|
||
insertCategory(categories.weapons, table.Copy(tbl))
|
||
end
|
||
end
|
||
|
||
function DarkRP.addToCategory(item, kind, cat)
|
||
cat = cat or "Другое"
|
||
item.category = cat
|
||
|
||
-- The merge process will take care of the category:
|
||
if not categoriesMerged then return end
|
||
|
||
-- Post-merge: manual insertion into category
|
||
local cats = categories[kind]
|
||
for _, c in ipairs(cats) do
|
||
if c.name ~= cat then continue end
|
||
|
||
insertCategory(c.members, item)
|
||
return
|
||
end
|
||
|
||
DarkRP.errorNoHalt(string.format([[The category of "%s" ("%s") does not exist!]], item.name, cat), 2, {
|
||
"Make sure the category is created with DarkRP.createCategory.",
|
||
"The category name is case sensitive!",
|
||
"Categories must be created before DarkRP finished loading.",
|
||
})
|
||
end
|
||
|
||
function DarkRP.removeFromCategory(item, kind)
|
||
local cats = categories[kind]
|
||
if not cats then DarkRP.error(string.format("Invalid category kind '%s'.", kind), 2) end
|
||
local cat = item.category
|
||
if not cat then return end
|
||
for _, v in pairs(cats) do
|
||
if v.name ~= item.category then continue end
|
||
for k, mem in pairs(v.members) do
|
||
if mem ~= item then continue end
|
||
table.remove(v.members, k)
|
||
break
|
||
end
|
||
break
|
||
end
|
||
end
|
||
|
||
-- Assign custom stuff to their categories
|
||
local function mergeCategories(customs, catKind, path)
|
||
local cats = categories[catKind]
|
||
local catByName = {}
|
||
for _, v in pairs(cats) do catByName[v.name] = v end
|
||
for _, v in pairs(customs) do
|
||
-- Override default thing categories:
|
||
local catName = v.default and (GAMEMODE.Config.CategoryOverride[catKind] or {})[v.name] or v.category or "Другое"
|
||
local cat = catByName[catName]
|
||
if not cat then
|
||
DarkRP.errorNoHalt(string.format([[The category of "%s" ("%s") does not exist!]], v.name, catName), 3, {
|
||
"Make sure the category is created with DarkRP.createCategory.",
|
||
"The category name is case sensitive!",
|
||
"Categories must be created before DarkRP finished loading."
|
||
}, path, -1, path)
|
||
cat = catByName.Другое
|
||
end
|
||
|
||
cat.members = cat.members or {}
|
||
table.insert(cat.members, v)
|
||
end
|
||
|
||
-- Sort category members
|
||
for _, v in pairs(cats) do table.sort(v.members, categoryOrder) end
|
||
end
|
||
|
||
hook.Add("loadCustomDarkRPItems", "mergeCategories", function()
|
||
local shipments = fn.Filter(fc{fn.Not, fp{fn.GetValue, "noship"}}, CustomShipments)
|
||
local guns = fn.Filter(fp{fn.GetValue, "separate"}, CustomShipments)
|
||
|
||
mergeCategories(RPExtraTeams, "jobs", "your jobs")
|
||
mergeCategories(DarkRPEntities, "entities", "your custom entities")
|
||
mergeCategories(shipments, "shipments", "your custom shipments")
|
||
mergeCategories(guns, "weapons", "your custom weapons")
|
||
mergeCategories(CustomVehicles, "vehicles", "your custom vehicles")
|
||
mergeCategories(GAMEMODE.AmmoTypes, "ammo", "your custom ammo")
|
||
|
||
categoriesMerged = true
|
||
end)
|