Advertisement
Guest User

Untitled

a guest
Jul 2nd, 2015
267
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 46.52 KB | None | 0 0
  1. local plyMeta = FindMetaTable("Player")
  2. -- automatically block players from doing certain things with their DarkRP entities
  3. local blockTypes = {"Physgun1", "Spawning1", "Toolgun1"}
  4.  
  5. -- Assert function, asserts a property and returns the error if false.
  6. -- Allows f to override err and hints by simply returning them
  7. local ass = function(f, err, hints) return function(...)
  8. local res = {f(...)}
  9. table.insert(res, err)
  10. table.insert(res, hints)
  11.  
  12. return unpack(res)
  13. end end
  14.  
  15. -- Returns whether a value is nil
  16. local isnil = fn.Curry(fn.Eq, 2)(nil)
  17. -- Optional value, when filled in it must meet the conditions
  18. local optional = function(...) return fn.FOr{isnil, ...} end
  19. -- Check the correctness of a model
  20. local checkModel = isstring
  21.  
  22. -- A table of which each element must meet condition f
  23. local tableOf = function(f) return function(tbl)
  24. if not istable(tbl) then return false end
  25. for k,v in pairs(tbl) do if not f(v) then return false end end
  26. return true
  27. end end
  28.  
  29. -- Any of the given elements
  30. local oneOf = function(f) return fp{table.HasValue, f} end
  31.  
  32. -- A table that is nonempty, wrap around tableOf
  33. local nonempty = function(f) return function(tbl) return istable(tbl) and #tbl > 0 and f(tbl) end end
  34.  
  35. -- A value must be unique amongst all `kind`. Uses optional `hash` function to create custom hashes in the internal table
  36. local uniqueEntity = function(cmd, tbl)
  37. for k, v in pairs(DarkRPEntities) do
  38. if v.cmd ~= cmd then continue end
  39. return false, "This entity does not have a unique command.", {"There must be some other end that has the same thing for 'cmd'.", "Fix this by changing the 'cmd' field of your entity to something else."}
  40. end
  41. return true
  42. end
  43.  
  44. local uniqueJob = function(v, tbl)
  45. local job = DarkRP.getJobByCommand(v)
  46. 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
  47. return true
  48. end
  49.  
  50. -- Template for a correct job
  51. local requiredTeamItems = {
  52. 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."}),
  53. model = ass(fn.FOr{checkModel, nonempty(tableOf(checkModel))}, "The model must either be a table of correct model strings or a single correct model string.", {"This error could happens when the model does not exist on the server.", "Are you sure the model path is right?", "Is the model from an addon that is not properly installed?"}),
  54. description = ass(isstring, "The description must be a string."),
  55. weapons = ass(optional(tableOf(isstring)), "The weapons must be a valid table of strings.", {"Example: weapons = {\"med_kit\", \"weapon_bugbait\"},"}),
  56. command = ass(fn.FAnd{isstring, uniqueJob}, "The command must be a string."),
  57. 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."}),
  58. salary = ass(fn.FAnd{isnumber, fp{fn.Lte, 0}}, "The salary must be a number greater than zero."),
  59. 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."),
  60. vote = ass(optional(isbool), "The vote must be either true or false."),
  61.  
  62. -- Optional advanced stuff
  63. category = ass(optional(isstring), "The category must be the name of an existing category!"),
  64. sortOrder = ass(optional(isnumber), "The sortOrder must be a number."),
  65. buttonColor = ass(optional(tableOf(isnumber)), "The buttonColor must be a Color value."),
  66. label = ass(optional(isstring), "The label must be a valid string."),
  67. ammo = ass(optional(tableOf(isnumber)), "The ammo must be a table containing numbers.", {"See example on http://wiki.darkrp.com/index.php/DarkRP:CustomJobFields"}),
  68. hasLicense = ass(optional(isbool), "The hasLicense must be either true or false."),
  69. 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)?"}),
  70. customCheck = ass(optional(isfunction), "The customCheck must be a function."),
  71. CustomCheckFailMsg = ass(optional(isstring, isfunction), "The CustomCheckFailMsg must be either a string or a function."),
  72. modelScale = ass(optional(isnumber), "The modelScale must be a number."),
  73. maxpocket = ass(optional(isnumber), "The maxPocket must be a number."),
  74. maps = ass(optional(tableOf(isstring)), "The maps value must be a table of valid map names."),
  75. candemote = ass(optional(isbool), "The candemote value must be either true or false."),
  76. mayor = ass(optional(isbool), "The mayor value must be either true or false."),
  77. chief = ass(optional(isbool), "The chief value must be either true or false."),
  78. medic = ass(optional(isbool), "The medic value must be either true or false."),
  79. cook = ass(optional(isbool), "The cook value must be either true or false."),
  80. hobo = ass(optional(isbool), "The hobo value must be either true or false."),
  81. CanPlayerSuicide = ass(optional(isfunction), "The CanPlayerSuicide must be a function."),
  82. PlayerCanPickupWeapon = ass(optional(isfunction), "The PlayerCanPickupWeapon must be a function."),
  83. PlayerDeath = ass(optional(isfunction), "The PlayerDeath must be a function."),
  84. PlayerLoadout = ass(optional(isfunction), "The PlayerLoadout must be a function."),
  85. PlayerSelectSpawn = ass(optional(isfunction), "The PlayerSelectSpawn must be a function."),
  86. PlayerSetModel = ass(optional(isfunction), "The PlayerSetModel must be a function."),
  87. PlayerSpawn = ass(optional(isfunction), "The PlayerSpawn must be a function."),
  88. PlayerSpawnProp = ass(optional(isfunction), "The PlayerSpawnProp must be a function."),
  89. RequiresVote = ass(optional(isfunction), "The RequiresVote must be a function."),
  90. ShowSpare1 = ass(optional(isfunction), "The ShowSpare1 must be a function."),
  91. ShowSpare2 = ass(optional(isfunction), "The ShowSpare2 must be a function."),
  92. canStartVote = ass(optional(isfunction), "The canStartVote must be a function."),
  93. canStartVoteReason = ass(optional(isstring, isfunction), "The canStartVoteReason must be either a string or a function."),
  94. }
  95.  
  96. -- Template for correct shipment
  97. local validShipment = {
  98. model = ass(checkModel, "The model of the shipment must be a valid model.", {"This error could happens when the model does not exist on the server.", "Are you sure the model path is right?", "Is the model from an addon that is not properly installed?"}),
  99. entity = ass(isstring, "The entity of the shipment must be a string."),
  100. price = ass(function(v, tbl) return isnumber(v) or isfunction(tbl.getPrice) end, "The price must be an existing number or (for advanced users) the getPrice field must be a function."),
  101. amount = ass(fn.FAnd{isnumber, fp{fn.Lte, 0}}, "The amount must be a number greater than zero."),
  102. seperate = ass(optional(isbool), "the seperate field must be either true or false.", {"It's spelled as 'seperate' because of a really old mistake."}),
  103. pricesep = ass(function(v, tbl) return not tbl.seperate or isnumber(v) and v >= 0 end, "The pricesep must be a number greater than or equal to zero."),
  104. allowed = ass(optional(tableOf(isnumber), isnumber), "The allowed field must be either an existing team or a table of existing teams", {"Is there a job here that doesn't exist (anymore)?"}),
  105.  
  106. category = ass(optional(isstring), "The category must be the name of an existing category!"),
  107. sortOrder = ass(optional(isnumber), "The sortOrder must be a number."),
  108. buttonColor = ass(optional(tableOf(isnumber)), "The buttonColor must be a Color value."),
  109. label = ass(optional(isstring), "The label must be a valid string."),
  110. noship = ass(optional(isbool), "The noship must be either true or false."),
  111. shipmodel = ass(optional(checkModel), "The shipmodel must be a valid model.", {"This error could happens when the model does not exist on the server.", "Are you sure the model path is right?", "Is the model from an addon that is not properly installed?"}),
  112. customCheck = ass(optional(isfunction), "The customCheck must be a function."),
  113. CustomCheckFailMsg = ass(optional(isstring, isfunction), "The CustomCheckFailMsg must be either a string or a function."),
  114. weight = ass(optional(isnumber), "The weight must be a number."),
  115. spareammo = ass(optional(isnumber), "The spareammo must be a number."),
  116. clip1 = ass(optional(isnumber), "The clip1 must be a number."),
  117. clip2 = ass(optional(isnumber), "The clip2 must be a number."),
  118. shipmentClass = ass(optional(isstring), "The shipmentClass must be a string."),
  119. onBought = ass(optional(isfunction), "The onBought must be a function."),
  120. getPrice = ass(optional(isfunction), "The getPrice must be a function."),
  121. }
  122.  
  123. -- Template for correct vehicle
  124. local validVehicle = {
  125. name = ass(isstring, "The name of the vehicle must be a string."),
  126. model = ass(checkModel, "The model of the vehicle must be a valid model.", {"This error could happens when the model does not exist on the server.", "Are you sure the model path is right?", "Is the model from an addon that is not properly installed?"}),
  127. price = ass(function(v, tbl) return isnumber(v) or isfunction(tbl.getPrice) end, "The price must be an existing number or (for advanced users) the getPrice field must be a function."),
  128. allowed = ass(optional(tableOf(isnumber), isnumber), "The allowed field must be either an existing team or a table of existing teams", {"Is there a job here that doesn't exist (anymore)?"}),
  129.  
  130. category = ass(optional(isstring), "The category must be the name of an existing category!"),
  131. sortOrder = ass(optional(isnumber), "The sortOrder must be a number."),
  132. distance = ass(optional(isnumber), "The distance must be a number."),
  133. angle = ass(optional(isangle), "The distance must be a valid Angle."),
  134. buttonColor = ass(optional(tableOf(isnumber)), "The buttonColor must be a Color value."),
  135. label = ass(optional(isstring), "The label must be a valid string."),
  136. customCheck = ass(optional(isfunction), "The customCheck must be a function."),
  137. CustomCheckFailMsg = ass(optional(isstring, isfunction), "The CustomCheckFailMsg must be either a string or a function."),
  138. getPrice = ass(optional(isfunction), "The getPrice must be a function."),
  139. }
  140.  
  141. -- Template for correct entity
  142. local validEntity = {
  143. ent = ass(isstring, "The name of the entity must be a string."),
  144. model = ass(checkModel, "The model of the entity must be a valid model.", {"This error could happens when the model does not exist on the server.", "Are you sure the model path is right?", "Is the model from an addon that is not properly installed?"}),
  145. price = ass(function(v, tbl) return isnumber(v) or isfunction(tbl.getPrice) end, "The price must be an existing number or (for advanced users) the getPrice field must be a function."),
  146. max = ass(function(v, tbl) return isnumber(v) or isfunction(tbl.getMax) end, "The max must be an existing number or (for advanced users) the getMax field must be a function."),
  147. cmd = ass(fn.FAnd{isstring, uniqueEntity}, "The cmd must be a valid string."),
  148. name = ass(isstring, "The name must be a valid string."),
  149.  
  150. category = ass(optional(isstring), "The category must be the name of an existing category!"),
  151. sortOrder = ass(optional(isnumber), "The sortOrder must be a number."),
  152. buttonColor = ass(optional(tableOf(isnumber)), "The buttonColor must be a Color value."),
  153. label = ass(optional(isstring), "The label must be a valid string."),
  154. customCheck = ass(optional(isfunction), "The customCheck must be a function."),
  155. CustomCheckFailMsg = ass(optional(isstring, isfunction), "The CustomCheckFailMsg must be either a string or a function."),
  156. getPrice = ass(optional(isfunction), "The getPrice must be a function."),
  157. }
  158.  
  159. local validAgenda = {
  160. Title = ass(isstring, "The title must be a string."),
  161. 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)?"}),
  162. Listeners = ass(nonempty(tableOf(isnumber)), "The Listeners must be a non-empty table of existing teams.",
  163. {
  164. "Is there a job here that doesn't exist (anymore)?",
  165. "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.",
  166. [[Like so: DarkRP.createAgenda("Some agenda", {TEAM_MANAGER1, TEAM_MANAGER2}, {TEAM_LISTENER1, TEAM_LISTENER2})]]
  167. })
  168. }
  169.  
  170. local validCategory = {
  171. name = ass(isstring, "The name must be a string."),
  172. categorises = ass(oneOf{"jobs", "entities", "shipments", "weapons", "vehicles", "ammo"},
  173. [[The categorises must be one of "jobs", "entities", "shipments", "weapons", "vehicles", "ammo"]],
  174. {"Mind that this is case sensitive.", "Also mind the quotation marks."}),
  175. startExpanded = ass(isbool, "The startExpanded must be either true or false."),
  176. color = ass(tableOf(isnumber), "The color must be a Color value."),
  177. canSee = ass(optional(isfunction), "The canSee must be a function."),
  178. sortOrder = ass(optional(isnumber), "The sortOrder must be a number."),
  179. }
  180.  
  181. -- Check template against actual implementation
  182. local env = {} -- environment used to be check propositions between multiple tables
  183. local function checkValid(tbl, requiredItems, oEnv) -- Allow override environment
  184. for k,v in pairs(requiredItems) do
  185. local correct, err, hints = tbl[v] ~= nil
  186. if isfunction(v) then correct, err, hints = v(tbl[k], tbl, oEnv or env) end
  187. err = err or string.format("Element '%s' is corrupt!", k)
  188. if not correct then return correct, err, hints end
  189. end
  190.  
  191. return true
  192. end
  193.  
  194. -----------------------------------------------------------
  195. -- Job commands --
  196. -----------------------------------------------------------
  197. local function declareTeamCommands(CTeam)
  198. local k = 0
  199. for num,v in pairs(RPExtraTeams) do
  200. if v.command == CTeam.command then
  201. k = num
  202. end
  203. end
  204.  
  205. if CTeam.vote or CTeam.RequiresVote then
  206. DarkRP.declareChatCommand{
  207. command = "vote"..CTeam.command,
  208. description = "Vote to become " .. CTeam.name .. ".",
  209. delay = 1.5,
  210. condition = fn.FAnd
  211. {
  212. fn.If(
  213. fn.Curry(isfunction, 2)(CTeam.RequiresVote),
  214. fn.Curry(fn.Flip(fn.FOr{fn.Curry(fn.Const, 2)(CTeam.RequiresVote), fn.Curry(fn.Const, 2)(-1)}()), 2)(k),
  215. fn.Curry(fn.Const, 2)(true)
  216. )(),
  217. fn.If(
  218. fn.Curry(isnumber, 2)(CTeam.NeedToChangeFrom),
  219. fn.Compose{fn.Curry(fn.Eq, 2)(CTeam.NeedToChangeFrom), plyMeta.Team},
  220. fn.If(
  221. fn.Curry(istable, 2)(CTeam.NeedToChangeFrom),
  222. fn.Compose{fn.Curry(table.HasValue, 2)(CTeam.NeedToChangeFrom), plyMeta.Team},
  223. fn.Curry(fn.Const, 2)(true)
  224. )()
  225. )(),
  226. fn.If(
  227. fn.Curry(isfunction, 2)(CTeam.customCheck),
  228. CTeam.customCheck,
  229. fn.Curry(fn.Const, 2)(true)
  230. )(),
  231. fn.Compose{fn.Curry(fn.Neq, 2)(k), plyMeta.Team},
  232. fn.FOr {
  233. fn.Curry(fn.Lte, 3)(CTeam.admin)(0),
  234. fn.FAnd{fn.Curry(fn.Eq, 3)(CTeam.admin)(1), plyMeta.IsAdmin},
  235. fn.FAnd{fn.Curry(fn.Gte, 3)(CTeam.admin)(2), plyMeta.IsSuperAdmin}
  236. }
  237. }
  238. }
  239.  
  240. DarkRP.declareChatCommand{
  241. command = CTeam.command,
  242. description = "Become " .. CTeam.name .. " and skip the vote.",
  243. delay = 1.5,
  244. condition = fn.FAnd {
  245. fn.FOr {
  246. fn.Curry(fn.Flip(plyMeta.hasDarkRPPrivilege), 2)("rp_"..CTeam.command),
  247. fn.FAnd {
  248. fn.FOr {
  249. fn.Curry(fn.Lte, 3)(CTeam.admin)(0),
  250. fn.FAnd{fn.Curry(fn.Eq, 3)(CTeam.admin)(1), plyMeta.IsAdmin},
  251. fn.FAnd{fn.Curry(fn.Gte, 3)(CTeam.admin)(2), plyMeta.IsSuperAdmin}
  252. },
  253. fn.If(
  254. fn.Curry(isfunction, 2)(CTeam.RequiresVote),
  255. fn.Curry(fn.Flip(fn.FOr{fn.Curry(fn.Const, 2)(CTeam.RequiresVote), fn.Curry(fn.Const, 2)(-1)}()), 2)(k),
  256. fn.FOr {
  257. fn.FAnd{fn.Curry(fn.Eq, 3)(CTeam.admin)(0), plyMeta.IsAdmin},
  258. fn.FAnd{fn.Curry(fn.Eq, 3)(CTeam.admin)(1), plyMeta.IsSuperAdmin}
  259. }
  260. )()
  261. }
  262. },
  263. fn.Compose{fn.Not, plyMeta.isArrested},
  264. fn.If(
  265. fn.Curry(isnumber, 2)(CTeam.NeedToChangeFrom),
  266. fn.Compose{fn.Curry(fn.Eq, 2)(CTeam.NeedToChangeFrom), plyMeta.Team},
  267. fn.If(
  268. fn.Curry(istable, 2)(CTeam.NeedToChangeFrom),
  269. fn.Compose{fn.Curry(table.HasValue, 2)(CTeam.NeedToChangeFrom), plyMeta.Team},
  270. fn.Curry(fn.Const, 2)(true)
  271. )()
  272. )(),
  273. fn.If(
  274. fn.Curry(isfunction, 2)(CTeam.customCheck),
  275. CTeam.customCheck,
  276. fn.Curry(fn.Const, 2)(true)
  277. )(),
  278. fn.Compose{fn.Curry(fn.Neq, 2)(k), plyMeta.Team}
  279. }
  280. }
  281. else
  282. DarkRP.declareChatCommand{
  283. command = CTeam.command,
  284. description = "Become " .. CTeam.name .. ".",
  285. delay = 1.5,
  286. condition = fn.FAnd
  287. {
  288. fn.Compose{fn.Not, plyMeta.isArrested},
  289. fn.If(
  290. fn.Curry(isnumber, 2)(CTeam.NeedToChangeFrom),
  291. fn.Compose{fn.Curry(fn.Eq, 2)(CTeam.NeedToChangeFrom), plyMeta.Team},
  292. fn.If(
  293. fn.Curry(istable, 2)(CTeam.NeedToChangeFrom),
  294. fn.Compose{fn.Curry(table.HasValue, 2)(CTeam.NeedToChangeFrom), plyMeta.Team},
  295. fn.Curry(fn.Const, 2)(true)
  296. )()
  297. )(),
  298. fn.If(
  299. fn.Curry(isfunction, 2)(CTeam.customCheck),
  300. CTeam.customCheck,
  301. fn.Curry(fn.Const, 2)(true)
  302. )(),
  303. fn.Compose{fn.Curry(fn.Neq, 2)(k), plyMeta.Team},
  304. fn.FOr {
  305. fn.Curry(fn.Lte, 3)(CTeam.admin)(0),
  306. fn.FAnd{fn.Curry(fn.Eq, 3)(CTeam.admin)(1), plyMeta.IsAdmin},
  307. fn.FAnd{fn.Curry(fn.Gte, 3)(CTeam.admin)(2), plyMeta.IsSuperAdmin}
  308. }
  309. }
  310. }
  311. end
  312. end
  313.  
  314. local function addTeamCommands(CTeam, max)
  315. if CLIENT then return end
  316.  
  317. if not GAMEMODE:CustomObjFitsMap(CTeam) then return end
  318. local k = 0
  319. for num,v in pairs(RPExtraTeams) do
  320. if v.command == CTeam.command then
  321. k = num
  322. end
  323. end
  324.  
  325. if CTeam.vote or CTeam.RequiresVote then
  326. DarkRP.defineChatCommand("vote"..CTeam.command, function(ply)
  327. if CTeam.RequiresVote and not CTeam.RequiresVote(ply, k) then
  328. DarkRP.notify(ply, 1,4, DarkRP.getPhrase("job_doesnt_require_vote_currently"))
  329. return ""
  330. end
  331.  
  332. if CTeam.canStartVote and not CTeam.canStartVote(ply) then
  333. local reason = isfunction(CTeam.canStartVoteReason) and CTeam.canStartVoteReason(ply, CTeam) or CTeam.canStartVoteReason or ""
  334. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("unable", "/vote"..CTeam.command, reason))
  335. return ""
  336. end
  337.  
  338. if CTeam.admin == 1 and not ply:IsAdmin() then
  339. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_admin", "/".."vote"..CTeam.command))
  340. return ""
  341. elseif CTeam.admin > 1 and not ply:IsSuperAdmin() then
  342. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_sadmin", "/".."vote"..CTeam.command))
  343. return ""
  344. end
  345.  
  346. if type(CTeam.NeedToChangeFrom) == "number" and ply:Team() ~= CTeam.NeedToChangeFrom then
  347. DarkRP.notify(ply, 1,4, DarkRP.getPhrase("need_to_be_before", team.GetName(CTeam.NeedToChangeFrom), CTeam.name))
  348. return ""
  349. elseif type(CTeam.NeedToChangeFrom) == "table" and not table.HasValue(CTeam.NeedToChangeFrom, ply:Team()) then
  350. local teamnames = ""
  351. for a,b in pairs(CTeam.NeedToChangeFrom) do teamnames = teamnames.." or "..team.GetName(b) end
  352. DarkRP.notify(ply, 1,4, DarkRP.getPhrase("need_to_be_before", string.sub(teamnames, 5), CTeam.name))
  353. return ""
  354. end
  355.  
  356. if CTeam.customCheck and not CTeam.customCheck(ply) then
  357. local message = isfunction(CTeam.CustomCheckFailMsg) and CTeam.CustomCheckFailMsg(ply, CTeam) or
  358. CTeam.CustomCheckFailMsg or
  359. DarkRP.getPhrase("unable", team.GetName(t), "")
  360. DarkRP.notify(ply, 1, 4, message)
  361. return ""
  362. end
  363. if not ply:changeAllowed(k) then
  364. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("unable", "/vote"..CTeam.command, DarkRP.getPhrase("banned_or_demoted")))
  365. return ""
  366. end
  367. if ply:Team() == k then
  368. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("unable", CTeam.command, ""))
  369. return ""
  370. end
  371. local max = CTeam.max
  372. if max ~= 0 and ((max % 1 == 0 and team.NumPlayers(k) >= max) or (max % 1 ~= 0 and (team.NumPlayers(k) + 1) / #player.GetAll() > max)) then
  373. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("team_limit_reached", CTeam.name))
  374. return ""
  375. end
  376. if ply.LastJob and 10 - (CurTime() - ply.LastJob) >= 0 then
  377. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("have_to_wait", math.ceil(10 - (CurTime() - ply.LastJob)), GAMEMODE.Config.chatCommandPrefix..CTeam.command))
  378. return ""
  379. end
  380. if #player.GetAll() == 1 then
  381. DarkRP.notify(ply, 0, 4, DarkRP.getPhrase("vote_alone"))
  382. ply:changeTeam(k)
  383. return ""
  384. end
  385. if CurTime() - ply:GetTable().LastVoteCop < 80 then
  386. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("have_to_wait", math.ceil(80 - (CurTime() - ply:GetTable().LastVoteCop)), GAMEMODE.Config.chatCommandPrefix..CTeam.command))
  387. return ""
  388. end
  389. DarkRP.createVote(DarkRP.getPhrase("wants_to_be", ply:Nick(), CTeam.name), "job", ply, 20, function(vote, choice)
  390. local ply = vote.target
  391.  
  392. if not IsValid(ply) then return end
  393. if choice >= 0 then
  394. ply:changeTeam(k)
  395. else
  396. DarkRP.notifyAll(1, 4, DarkRP.getPhrase("has_not_been_made_team", ply:Nick(), CTeam.name))
  397. end
  398. end, nil, nil, {targetTeam = k})
  399. ply:GetTable().LastVoteCop = CurTime()
  400. return ""
  401. end)
  402.  
  403. DarkRP.defineChatCommand(CTeam.command, function(ply)
  404. if ply:hasDarkRPPrivilege("rp_"..CTeam.command) then
  405. ply:changeTeam(k)
  406. return ""
  407. end
  408.  
  409. local a = CTeam.admin
  410. if a > 0 and not ply:IsAdmin()
  411. or a > 1 and not ply:IsSuperAdmin()
  412. then
  413. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_admin", CTeam.name))
  414. return ""
  415. end
  416.  
  417. if not CTeam.RequiresVote and
  418. (a == 0 and not ply:IsAdmin()
  419. or a == 1 and not ply:IsSuperAdmin()
  420. or a == 2)
  421. or CTeam.RequiresVote and CTeam.RequiresVote(ply, k)
  422. then
  423. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_to_make_vote", CTeam.name))
  424. return ""
  425. end
  426.  
  427. ply:changeTeam(k)
  428. return ""
  429. end)
  430. else
  431. DarkRP.defineChatCommand(CTeam.command, function(ply)
  432. if CTeam.admin == 1 and not ply:IsAdmin() then
  433. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_admin", "/"..CTeam.command))
  434. return ""
  435. end
  436. if CTeam.admin > 1 and not ply:IsSuperAdmin() then
  437. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("need_sadmin", "/"..CTeam.command))
  438. return ""
  439. end
  440. ply:changeTeam(k)
  441. return ""
  442. end)
  443. end
  444.  
  445. concommand.Add("rp_"..CTeam.command, function(ply, cmd, args)
  446. if ply:EntIndex() ~= 0 and not ply:IsAdmin() then
  447. ply:PrintMessage(HUD_PRINTCONSOLE, DarkRP.getPhrase("need_admin", cmd))
  448. return
  449. end
  450.  
  451. if CTeam.admin > 1 and not ply:IsSuperAdmin() and ply:EntIndex() ~= 0 then
  452. ply:PrintMessage(HUD_PRINTCONSOLE, DarkRP.getPhrase("need_sadmin", cmd))
  453. return
  454. end
  455.  
  456. if CTeam.vote then
  457. if CTeam.admin >= 1 and ply:EntIndex() ~= 0 and not ply:IsSuperAdmin() then
  458. ply:PrintMessage(HUD_PRINTCONSOLE, DarkRP.getPhrase("need_sadmin", cmd))
  459. return
  460. elseif CTeam.admin > 1 and ply:IsSuperAdmin() and ply:EntIndex() ~= 0 then
  461. ply:PrintMessage(HUD_PRINTCONSOLE, DarkRP.getPhrase("need_to_make_vote", CTeam.name))
  462. return
  463. end
  464. end
  465.  
  466. if not args or not args[1] then
  467. DarkRP.printConsoleMessage(ply, DarkRP.getPhrase("invalid_x", DarkRP.getPhrase("arguments"), ""))
  468. return
  469. end
  470.  
  471. local target = DarkRP.findPlayer(args[1])
  472.  
  473. if (target) then
  474. target:changeTeam(k, true)
  475. local nick
  476. if (ply:EntIndex() ~= 0) then
  477. nick = ply:Nick()
  478. else
  479. nick = "Console"
  480. end
  481. DarkRP.notify(target, 0, 4, DarkRP.getPhrase("x_made_you_a_y", nick, CTeam.name))
  482. else
  483. DarkRP.printConsoleMessage(ply, DarkRP.getPhrase("could_not_find", tostring(args[1])))
  484. end
  485. end)
  486. end
  487.  
  488. local function addEntityCommands(tblEnt)
  489. DarkRP.declareChatCommand{
  490. command = tblEnt.cmd,
  491. description = "Purchase a " .. tblEnt.name,
  492. delay = 2,
  493. condition = fn.FAnd
  494. {
  495. fn.Compose{fn.Not, plyMeta.isArrested},
  496. fn.If(
  497. fn.Curry(istable, 2)(tblEnt.allowed),
  498. fn.Compose{fn.Curry(table.HasValue, 2)(tblEnt.allowed), plyMeta.Team},
  499. fn.Curry(fn.Const, 2)(true)
  500. )(),
  501. fn.If(
  502. fn.Curry(isfunction, 2)(tblEnt.customCheck),
  503. tblEnt.customCheck,
  504. fn.Curry(fn.Const, 2)(true)
  505. )(),
  506. fn.Curry(fn.Flip(plyMeta.canAfford), 2)(tblEnt.price)
  507. }
  508. }
  509. if CLIENT then return end
  510.  
  511. -- Default spawning function of an entity
  512. -- used if tblEnt.spawn is not defined
  513. local function defaultSpawn(ply, tr, tblEnt)
  514. local ent = ents.Create(tblEnt.ent)
  515. if not ent:IsValid() then error("Entity '"..tblEnt.ent.."' does not exist or is not valid.") end
  516. ent.dt = ent.dt or {}
  517. ent.dt.owning_ent = ply
  518. if ent.Setowning_ent then ent:Setowning_ent(ply) end
  519. ent:SetPos(tr.HitPos)
  520. -- These must be set before :Spawn()
  521. ent.SID = ply.SID
  522. ent.allowed = tblEnt.allowed
  523. ent.DarkRPItem = tblEnt
  524. ent:Spawn()
  525.  
  526. local phys = ent:GetPhysicsObject()
  527. if phys:IsValid() then phys:Wake() end
  528.  
  529. return ent
  530. end
  531.  
  532. local function buythis(ply, args)
  533. if ply:isArrested() then return "" end
  534. if type(tblEnt.allowed) == "table" and not table.HasValue(tblEnt.allowed, ply:Team()) then
  535. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("incorrect_job", tblEnt.cmd))
  536. return ""
  537. end
  538.  
  539. if tblEnt.customCheck and not tblEnt.customCheck(ply) then
  540. local message = isfunction(tblEnt.CustomCheckFailMsg) and tblEnt.CustomCheckFailMsg(ply, tblEnt) or
  541. tblEnt.CustomCheckFailMsg or
  542. DarkRP.getPhrase("not_allowed_to_purchase")
  543. DarkRP.notify(ply, 1, 4, message)
  544. return ""
  545. end
  546.  
  547. if ply:customEntityLimitReached(tblEnt) then
  548. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("limit", tblEnt.cmd))
  549. return ""
  550. end
  551.  
  552. local canbuy, suppress, message, price = hook.Call("canBuyCustomEntity", nil, ply, tblEnt)
  553.  
  554. local cost = price or tblEnt.getPrice and tblEnt.getPrice(ply, tblEnt.price) or tblEnt.price
  555.  
  556. if not ply:canAfford(cost) then
  557. DarkRP.notify(ply, 1, 4, DarkRP.getPhrase("cant_afford", tblEnt.cmd))
  558. return ""
  559. end
  560.  
  561. if canbuy == false then
  562. if not suppress and message then DarkRP.notify(ply, 1, 4, message) end
  563. return ""
  564. end
  565.  
  566. ply:addMoney(-cost)
  567.  
  568. local trace = {}
  569. trace.start = ply:EyePos()
  570. trace.endpos = trace.start + ply:GetAimVector() * 85
  571. trace.filter = ply
  572.  
  573. local tr = util.TraceLine(trace)
  574.  
  575. local ent = (tblEnt.spawn or defaultSpawn)(ply, tr, tblEnt)
  576. ent.onlyremover = true
  577. -- Repeat these properties to alleviate work in tblEnt.spawn:
  578. ent.SID = ply.SID
  579. ent.allowed = tblEnt.allowed
  580. ent.DarkRPItem = tblEnt
  581.  
  582. hook.Call("playerBoughtCustomEntity", nil, ply, tblEnt, ent, cost)
  583.  
  584. DarkRP.notify(ply, 0, 4, DarkRP.getPhrase("you_bought", tblEnt.name, DarkRP.formatMoney(cost), ""))
  585.  
  586. ply:addCustomEntity(tblEnt)
  587. return ""
  588. end
  589. DarkRP.defineChatCommand(tblEnt.cmd, buythis)
  590. end
  591.  
  592. RPExtraTeams = {}
  593. local jobByCmd = {}
  594. DarkRP.getJobByCommand = function(cmd)
  595. if not jobByCmd[cmd] then return nil, nil end
  596. return RPExtraTeams[jobByCmd[cmd]], jobByCmd[cmd]
  597. end
  598. plyMeta.getJobTable = fn.FOr{fn.Compose{fn.Curry(fn.Flip(fn.GetValue), 2)(RPExtraTeams), plyMeta.Team}, fn.Curry(fn.Id, 2)({})}
  599. local jobCount = 0
  600. function DarkRP.createJob(Name, colorOrTable, model, Description, Weapons, command, maximum_amount_of_this_class, Salary, admin, Vote, Haslicense, NeedToChangeFrom, CustomCheck)
  601. local tableSyntaxUsed = not IsColor(colorOrTable)
  602.  
  603. local CustomTeam = tableSyntaxUsed and colorOrTable or
  604. {color = colorOrTable, model = model, description = Description, weapons = Weapons, command = command,
  605. max = maximum_amount_of_this_class, salary = Salary, admin = admin or 0, vote = tobool(Vote), hasLicense = Haslicense,
  606. NeedToChangeFrom = NeedToChangeFrom, customCheck = CustomCheck
  607. }
  608. CustomTeam.name = Name
  609. CustomTeam.default = DarkRP.DARKRP_LOADING
  610.  
  611. -- Disabled job
  612. if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["jobs"][CustomTeam.command] then return end
  613.  
  614. local valid, err, hints = checkValid(CustomTeam, requiredTeamItems)
  615. if not valid then DarkRP.error(string.format("Corrupt team: %s!\n%s", CustomTeam.name or "", err), 3, hints) end
  616.  
  617. jobCount = jobCount + 1
  618. CustomTeam.team = jobCount
  619.  
  620. CustomTeam.salary = math.floor(CustomTeam.salary)
  621.  
  622. CustomTeam.customCheck = CustomTeam.customCheck and fp{DarkRP.simplerrRun, CustomTeam.customCheck}
  623. CustomTeam.CustomCheckFailMsg = isfunction(CustomTeam.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, CustomTeam.CustomCheckFailMsg} or CustomTeam.CustomCheckFailMsg
  624. CustomTeam.CanPlayerSuicide = CustomTeam.CanPlayerSuicide and fp{DarkRP.simplerrRun, CustomTeam.CanPlayerSuicide}
  625. CustomTeam.PlayerCanPickupWeapon = CustomTeam.PlayerCanPickupWeapon and fp{DarkRP.simplerrRun, CustomTeam.PlayerCanPickupWeapon}
  626. CustomTeam.PlayerDeath = CustomTeam.PlayerDeath and fp{DarkRP.simplerrRun, CustomTeam.PlayerDeath}
  627. CustomTeam.PlayerLoadout = CustomTeam.PlayerLoadout and fp{DarkRP.simplerrRun, CustomTeam.PlayerLoadout}
  628. CustomTeam.PlayerSelectSpawn = CustomTeam.PlayerSelectSpawn and fp{DarkRP.simplerrRun, CustomTeam.PlayerSelectSpawn}
  629. CustomTeam.PlayerSetModel = CustomTeam.PlayerSetModel and fp{DarkRP.simplerrRun, CustomTeam.PlayerSetModel}
  630. CustomTeam.PlayerSpawn = CustomTeam.PlayerSpawn and fp{DarkRP.simplerrRun, CustomTeam.PlayerSpawn}
  631. CustomTeam.PlayerSpawnProp = CustomTeam.PlayerSpawnProp and fp{DarkRP.simplerrRun, CustomTeam.PlayerSpawnProp}
  632. CustomTeam.RequiresVote = CustomTeam.RequiresVote and fp{DarkRP.simplerrRun, CustomTeam.RequiresVote}
  633. CustomTeam.ShowSpare1 = CustomTeam.ShowSpare1 and fp{DarkRP.simplerrRun, CustomTeam.ShowSpare1}
  634. CustomTeam.ShowSpare2 = CustomTeam.ShowSpare2 and fp{DarkRP.simplerrRun, CustomTeam.ShowSpare2}
  635. CustomTeam.canStartVote = CustomTeam.canStartVote and fp{DarkRP.simplerrRun, CustomTeam.canStartVote}
  636.  
  637. jobByCmd[CustomTeam.command] = table.insert(RPExtraTeams, CustomTeam)
  638. DarkRP.addToCategory(CustomTeam, "jobs", CustomTeam.category)
  639. team.SetUp(#RPExtraTeams, Name, CustomTeam.color)
  640. local Team = #RPExtraTeams
  641.  
  642. timer.Simple(0, function()
  643. declareTeamCommands(CustomTeam)
  644. addTeamCommands(CustomTeam, CustomTeam.max)
  645. end)
  646.  
  647. // Precache model here. Not right before the job change is done
  648. if type(CustomTeam.model) == "table" then
  649. for k,v in pairs(CustomTeam.model) do util.PrecacheModel(v) end
  650. else
  651. util.PrecacheModel(CustomTeam.model)
  652. end
  653. return Team
  654. end
  655. AddExtraTeam = DarkRP.createJob
  656.  
  657. local function removeCustomItem(tbl, category, hookName, reloadF4, i)
  658. local item = tbl[i]
  659. tbl[i] = nil
  660. if category then DarkRP.removeFromCategory(item, category) end
  661. if istable(item) and (item.command or item.cmd) then DarkRP.removeChatCommand(item.command or item.cmd) end
  662. hook.Run(hookName, i, item)
  663. if CLIENT and reloadF4 and ValidPanel(DarkRP.getF4MenuPanel()) then DarkRP.getF4MenuPanel():Remove() end -- Rebuild entire F4 menu frame
  664. end
  665.  
  666. function DarkRP.removeJob(i)
  667. local job = RPExtraTeams[i]
  668. jobByCmd[job.command] = nil
  669. jobCount = jobCount - 1
  670.  
  671. DarkRP.removeChatCommand("vote" .. job.command)
  672. removeCustomItem(RPExtraTeams, "jobs", "onJobRemoved", true, i)
  673. end
  674.  
  675. RPExtraTeamDoors = {}
  676. function DarkRP.createEntityGroup(name, ...)
  677. if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["doorgroups"][name] then return end
  678. RPExtraTeamDoors[name] = {...}
  679. RPExtraTeamDoors[name].name = name
  680. end
  681. AddDoorGroup = DarkRP.createEntityGroup
  682.  
  683. DarkRP.removeEntityGroup = fp{removeCustomItem, RPExtraTeamDoors, nil, "onEntityGroupRemoved", false}
  684.  
  685. CustomVehicles = {}
  686. CustomShipments = {}
  687. local shipByName = {}
  688. DarkRP.getShipmentByName = function(name)
  689. name = string.lower(name or "")
  690.  
  691. if not shipByName[name] then return nil, nil end
  692. return CustomShipments[shipByName[name]], shipByName[name]
  693. end
  694.  
  695. function DarkRP.createShipment(name, model, entity, price, Amount_of_guns_in_one_shipment, Sold_seperately, price_seperately, noshipment, classes, shipmodel, CustomCheck)
  696. local tableSyntaxUsed = type(model) == "table"
  697.  
  698. local price = tonumber(price)
  699. local shipmentmodel = shipmodel or "models/Items/item_item_crate.mdl"
  700.  
  701. local customShipment = tableSyntaxUsed and model or
  702. {model = model, entity = entity, price = price, amount = Amount_of_guns_in_one_shipment,
  703. seperate = Sold_seperately, pricesep = price_seperately, noship = noshipment, allowed = classes,
  704. shipmodel = shipmentmodel, customCheck = CustomCheck, weight = 5}
  705.  
  706. if customShipment.separate ~= nil then
  707. customShipment.seperate = customShipment.separate
  708. end
  709.  
  710. if customShipment.allowed == nil then
  711. customShipment.allowed = {}
  712. for k,v in pairs(team.GetAllTeams()) do
  713. table.insert(customShipment.allowed, k)
  714. end
  715. end
  716.  
  717. customShipment.name = name
  718. customShipment.default = DarkRP.DARKRP_LOADING
  719.  
  720. if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["shipments"][customShipment.name] then return end
  721.  
  722. local valid, err, hints = checkValid(customShipment, validShipment)
  723. if not valid then DarkRP.error(string.format("Corrupt shipment: %s!\n%s", name or "", err), 3, hints) end
  724.  
  725. customShipment.allowed = isnumber(customShipment.allowed) and {customShipment.allowed} or customShipment.allowed
  726. customShipment.customCheck = customShipment.customCheck and fp{DarkRP.simplerrRun, customShipment.customCheck}
  727. CustomVehicles.CustomCheckFailMsg = isfunction(CustomVehicles.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, CustomVehicles.CustomCheckFailMsg} or CustomVehicles.CustomCheckFailMsg
  728.  
  729. if not customShipment.noship then DarkRP.addToCategory(customShipment, "shipments", customShipment.category) end
  730. if customShipment.seperate then DarkRP.addToCategory(customShipment, "weapons", customShipment.category) end
  731.  
  732. shipByName[string.lower(name or "")] = table.insert(CustomShipments, customShipment)
  733. util.PrecacheModel(customShipment.model)
  734. end
  735. AddCustomShipment = DarkRP.createShipment
  736.  
  737. function DarkRP.removeShipment(i)
  738. local ship = CustomShipments[i]
  739. shipByName[ship.name] = nil
  740. removeCustomItem(CustomShipments, "shipments", "onShipmentRemoved", true, i)
  741. end
  742.  
  743. function DarkRP.createVehicle(Name_of_vehicle, model, price, Jobs_that_can_buy_it, customcheck)
  744. local vehicle = istable(Name_of_vehicle) and Name_of_vehicle or
  745. {name = Name_of_vehicle, model = model, price = price, allowed = Jobs_that_can_buy_it, customCheck = customcheck}
  746.  
  747. vehicle.default = DarkRP.DARKRP_LOADING
  748.  
  749. if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["vehicles"][vehicle.name] then return end
  750.  
  751. local found = false
  752. for k,v in pairs(DarkRP.getAvailableVehicles()) do
  753. if string.lower(k) == string.lower(vehicle.name) then found = true break end
  754. end
  755.  
  756. local valid, err, hints = checkValid(vehicle, validVehicle)
  757. if not valid then DarkRP.error(string.format("Corrupt vehicle: %s!\n%s", vehicle.name or "", err), 3, hints) end
  758.  
  759. if not found then DarkRP.error("Vehicle invalid: " .. vehicle.name .. ". Unknown vehicle name.", 3) end
  760.  
  761. CustomVehicles.customCheck = CustomVehicles.customCheck and fp{DarkRP.simplerrRun, CustomVehicles.customCheck}
  762. CustomVehicles.CustomCheckFailMsg = isfunction(CustomVehicles.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, CustomVehicles.CustomCheckFailMsg} or CustomVehicles.CustomCheckFailMsg
  763.  
  764. table.insert(CustomVehicles, vehicle)
  765. DarkRP.addToCategory(vehicle, "vehicles", vehicle.category)
  766. end
  767. AddCustomVehicle = DarkRP.createVehicle
  768.  
  769. DarkRP.removeVehicle = fp{removeCustomItem, CustomVehicles, "vehicles", "onVehicleRemoved", true}
  770.  
  771. /*---------------------------------------------------------------------------
  772. Decides whether a custom job or shipmet or whatever can be used in a certain map
  773. ---------------------------------------------------------------------------*/
  774. function GM:CustomObjFitsMap(obj)
  775. if not obj or not obj.maps then return true end
  776.  
  777. local map = string.lower(game.GetMap())
  778. for k,v in pairs(obj.maps) do
  779. if string.lower(v) == map then return true end
  780. end
  781. return false
  782. end
  783.  
  784. DarkRPEntities = {}
  785. function DarkRP.createEntity(name, entity, model, price, max, command, classes, CustomCheck)
  786. local tableSyntaxUsed = type(entity) == "table"
  787.  
  788. local tblEnt = tableSyntaxUsed and entity or
  789. {ent = entity, model = model, price = price, max = max,
  790. cmd = command, allowed = classes, customCheck = CustomCheck}
  791. tblEnt.name = name
  792. tblEnt.default = DarkRP.DARKRP_LOADING
  793.  
  794. if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["entities"][tblEnt.name] then return end
  795.  
  796. if type(tblEnt.allowed) == "number" then
  797. tblEnt.allowed = {tblEnt.allowed}
  798. end
  799.  
  800. local valid, err, hints = checkValid(tblEnt, validEntity)
  801. if not valid then DarkRP.error(string.format("Corrupt entity: %s!\n%s", name or "", err), 3, hints) end
  802.  
  803. tblEnt.customCheck = tblEnt.customCheck and fp{DarkRP.simplerrRun, tblEnt.customCheck}
  804. tblEnt.CustomCheckFailMsg = isfunction(tblEnt.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, tblEnt.CustomCheckFailMsg} or tblEnt.CustomCheckFailMsg
  805. tblEnt.getPrice = tblEnt.getPrice and fp{DarkRP.simplerrRun, tblEnt.getPrice}
  806. tblEnt.getMax = tblEnt.getMax and fp{DarkRP.simplerrRun, tblEnt.getMax}
  807. tblEnt.spawn = tblEnt.spawn and fp{DarkRP.simplerrRun, tblEnt.spawn}
  808.  
  809. -- if SERVER and FPP then
  810. -- FPP.AddDefaultBlocked(blockTypes, tblEnt.ent)
  811. -- end
  812.  
  813. table.insert(DarkRPEntities, tblEnt)
  814. DarkRP.addToCategory(tblEnt, "entities", tblEnt.category)
  815. timer.Simple(0, function() addEntityCommands(tblEnt) end)
  816. end
  817. AddEntity = DarkRP.createEntity
  818.  
  819. DarkRP.removeEntity = fp{removeCustomItem, DarkRPEntities, "entities", "onEntityRemoved", true}
  820.  
  821. -- here for backwards compatibility
  822. DarkRPAgendas = {}
  823.  
  824. local agendas = {}
  825. -- Returns the agenda managed by the player
  826. plyMeta.getAgenda = fn.Compose{fn.Curry(fn.Flip(fn.GetValue), 2)(DarkRPAgendas), plyMeta.Team}
  827.  
  828. -- Returns the agenda this player is member of
  829. function plyMeta:getAgendaTable()
  830. return agendas[self:Team()]
  831. end
  832.  
  833. DarkRP.getAgendas = fp{fn.Id, agendas}
  834.  
  835. function DarkRP.createAgenda(Title, Manager, Listeners)
  836. if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["agendas"][Title] then return end
  837.  
  838. local agenda = {Manager = Manager, Title = Title, Listeners = Listeners, ManagersByKey = {}}
  839. agenda.default = DarkRP.DARKRP_LOADING
  840.  
  841. local valid, err, hints = checkValid(agenda, validAgenda)
  842. if not valid then DarkRP.error(string.format("Corrupt agenda: %s!\n%s", agenda.Title or "", err), 2, hints) end
  843.  
  844. for k,v in pairs(Listeners) do
  845. agendas[v] = agenda
  846. end
  847.  
  848. for k,v in pairs(istable(Manager) and Manager or {Manager}) do
  849. agendas[v] = agenda
  850. DarkRPAgendas[v] = agenda -- backwards compat
  851. agenda.ManagersByKey[v] = true
  852. end
  853.  
  854. if SERVER then
  855. timer.Simple(0, function()
  856. -- Run after scripts have loaded
  857. agenda.text = hook.Run("agendaUpdated", nil, agenda, "")
  858. end)
  859. end
  860. end
  861. AddAgenda = DarkRP.createAgenda
  862.  
  863. function DarkRP.removeAgenda(title)
  864. local agenda
  865. for k,v in pairs(agendas) do
  866. if v.Title == title then
  867. agenda = v
  868. agendas[k] = nil
  869. end
  870. end
  871.  
  872. for k,v in pairs(DarkRPAgendas) do
  873. if v.Title == title then agendas[k] = nil end
  874. end
  875. hook.Run("onAgendaRemoved", title, agenda)
  876. end
  877.  
  878. GM.DarkRPGroupChats = {}
  879. local groupChatNumber = 0
  880. function DarkRP.createGroupChat(funcOrTeam, ...)
  881. local gm = GM or GAMEMODE
  882. gm.DarkRPGroupChats = gm.DarkRPGroupChats or {}
  883. if DarkRP.DARKRP_LOADING then
  884. groupChatNumber = groupChatNumber + 1
  885. if DarkRP.disabledDefaults["groupchat"][groupChatNumber] then return end
  886. end
  887. -- People can enter either functions or a list of teams as parameter(s)
  888. if type(funcOrTeam) == "function" then
  889. table.insert(gm.DarkRPGroupChats, fp{DarkRP.simplerrRun, funcOrTeam})
  890. else
  891. local teams = {funcOrTeam, ...}
  892. table.insert(gm.DarkRPGroupChats, function(ply) return table.HasValue(teams, ply:Team()) end)
  893. end
  894. end
  895. GM.AddGroupChat = function(GM, ...) DarkRP.createGroupChat(...) end
  896.  
  897. DarkRP.removeGroupChat = fp{removeCustomItem, GM.DarkRPGroupChats, nil, "onGroupChatRemoved", false}
  898.  
  899. DarkRP.getGroupChats = fp{fn.Id, GM.DarkRPGroupChats}
  900.  
  901. GM.AmmoTypes = {}
  902.  
  903. function DarkRP.createAmmoType(ammoType, name, model, price, amountGiven, customCheck)
  904. local gm = GM or GAMEMODE
  905. gm.AmmoTypes = gm.AmmoTypes or {}
  906. local ammo = istable(name) and name or {
  907. name = name,
  908. model = model,
  909. price = price,
  910. amountGiven = amountGiven,
  911. customCheck = customCheck
  912. }
  913. ammo.ammoType = ammoType
  914. ammo.default = DarkRP.DARKRP_LOADING
  915.  
  916. if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["ammo"][ammo.name] then return end
  917.  
  918. ammo.customCheck = ammo.customCheck and fp{DarkRP.simplerrRun, ammo.customCheck}
  919. ammo.CustomCheckFailMsg = isfunction(ammo.CustomCheckFailMsg) and fp{DarkRP.simplerrRun, ammo.CustomCheckFailMsg} or ammo.CustomCheckFailMsg
  920. ammo.id = table.insert(gm.AmmoTypes, ammo)
  921.  
  922. DarkRP.addToCategory(ammo, "ammo", ammo.category)
  923. end
  924. GM.AddAmmoType = function(GM, ...) DarkRP.createAmmoType(...) end
  925.  
  926. DarkRP.removeAmmoType = fp{removeCustomItem, GM.AmmoTypes, "ammo", "onAmmoTypeRemoved", true}
  927.  
  928. local demoteGroups = {}
  929. function DarkRP.createDemoteGroup(name, tbl)
  930. if DarkRP.DARKRP_LOADING and DarkRP.disabledDefaults["demotegroups"][name] then return end
  931. if not tbl or not tbl[1] then error("No members in the demote group!") end
  932.  
  933. local set = demoteGroups[tbl[1]] or disjoint.MakeSet(tbl[1])
  934. set.name = name
  935. for i = 2, #tbl do
  936. set = (demoteGroups[tbl[i]] or disjoint.MakeSet(tbl[i])) + set
  937. set.name = name
  938. end
  939.  
  940. for _, teamNr in pairs(tbl) do
  941. if demoteGroups[teamNr] then
  942. -- Unify the sets if there was already one there
  943. demoteGroups[teamNr] = demoteGroups[teamNr] + set
  944. else
  945. demoteGroups[teamNr] = set
  946. end
  947. end
  948. end
  949.  
  950. function DarkRP.removeDemoteGroup(name)
  951. local foundSet
  952. for k,v in pairs(demoteGroups) do
  953. local set = disjoint.FindSet(v)
  954. if set.name == name then
  955. foundSet = set
  956. demoteGroups[k] = nil
  957. end
  958. end
  959. hook.Run("onDemoteGroupRemoved", name, foundSet)
  960. end
  961.  
  962. function DarkRP.getDemoteGroup(teamNr)
  963. demoteGroups[teamNr] = demoteGroups[teamNr] or disjoint.MakeSet(teamNr)
  964. return disjoint.FindSet(demoteGroups[teamNr])
  965. end
  966.  
  967. DarkRP.getDemoteGroups = fp{fn.Id, demoteGroups}
  968.  
  969. local categories = {
  970. jobs = {},
  971. entities = {},
  972. shipments = {},
  973. weapons = {},
  974. vehicles = {},
  975. ammo = {},
  976. }
  977. local categoriesMerged = false -- whether categories and custom items are merged.
  978.  
  979. DarkRP.getCategories = fp{fn.Id, categories}
  980.  
  981. local categoryOrder = function(a, b)
  982. local aso = a.sortOrder or 100
  983. local bso = b.sortOrder or 100
  984. return aso < bso or aso == bso and a.name < b.name
  985. end
  986.  
  987. local function insertCategory(destination, tbl)
  988. table.insert(destination, tbl)
  989. local i = #destination
  990.  
  991. while i > 1 do
  992. if categoryOrder(destination[i - 1], tbl) then break end
  993. destination[i - 1], destination[i] = destination[i], destination[i - 1]
  994. i = i - 1
  995. end
  996. end
  997.  
  998. function DarkRP.createCategory(tbl)
  999. local valid, err, hints = checkValid(tbl, validCategory)
  1000. if not valid then DarkRP.error(string.format("Corrupt category: %s!\n%s", tbl.name or "", err), 2, hints) end
  1001. tbl.members = {}
  1002.  
  1003. local destination = categories[tbl.categorises]
  1004. insertCategory(destination, tbl)
  1005.  
  1006. -- Too many people made the mistake of not creating a category for weapons as well as shipments
  1007. -- when having shipments that can also be sold separately.
  1008. if tbl.categorises == "shipments" then
  1009. insertCategory(categories.weapons, table.Copy(tbl))
  1010. end
  1011. end
  1012.  
  1013. function DarkRP.addToCategory(item, kind, cat)
  1014. cat = cat or "Other"
  1015. item.category = cat
  1016.  
  1017. -- The merge process will take care of the category:
  1018. if not categoriesMerged then return end
  1019.  
  1020. -- Post-merge: manual insertion into category
  1021. local cats = categories[kind]
  1022. for _, c in ipairs(cats) do
  1023. if c.name ~= cat then continue end
  1024.  
  1025. insertCategory(c.members, item)
  1026. return
  1027. end
  1028.  
  1029. DarkRP.error(string.format([[The category of "%s" ("%s") does not exist!]], item.name, cat), 2, {
  1030. "Make sure the category is created with DarkRP.createCategory.",
  1031. "The category name is case sensitive!",
  1032. "Categories must be created before DarkRP finished loading.",
  1033. })
  1034. end
  1035.  
  1036. function DarkRP.removeFromCategory(item, kind)
  1037. local cats = categories[kind]
  1038. if not cats then DarkRP.error(string.format("Invalid category kind '%s'.", kind), 2) end
  1039. local cat = item.category
  1040. if not cat then return end
  1041. for _, v in pairs(cats) do
  1042. if v.name ~= item.category then continue end
  1043. for k, mem in pairs(v.members) do
  1044. if mem ~= item then continue end
  1045. table.remove(v.members, k)
  1046. break
  1047. end
  1048. break
  1049. end
  1050. end
  1051.  
  1052. -- Assign custom stuff to their categories
  1053. local function mergeCategories(customs, catKind, path)
  1054. local categories = categories[catKind]
  1055. local catByName = {}
  1056. for k,v in pairs(categories) do catByName[v.name] = v end
  1057. for k,v in pairs(customs) do
  1058. -- Override default thing categories:
  1059. local catName = v.default and GAMEMODE.Config.CategoryOverride[catKind][v.name] or v.category or "Other"
  1060. local cat = catByName[catName]
  1061. if not cat then
  1062. DarkRP.error(string.format([[The category of "%s" ("%s") does not exist!]], v.name, catName), 1, {
  1063. "Make sure the category is created with DarkRP.createCategory.",
  1064. "The category name is case sensitive!",
  1065. "Categories must be created before DarkRP finished loading."
  1066. }, path, -1, path)
  1067. end
  1068.  
  1069. cat.members = cat.members or {}
  1070. table.insert(cat.members, v)
  1071. end
  1072.  
  1073. -- Sort category members
  1074. for k,v in pairs(categories) do table.sort(v.members, categoryOrder) end
  1075. end
  1076.  
  1077. hook.Add("loadCustomDarkRPItems", "mergeCategories", function()
  1078. local shipments = fn.Filter(fc{fn.Not, fp{fn.GetValue, "noship"}}, CustomShipments)
  1079. local guns = fn.Filter(fp{fn.GetValue, "seperate"}, CustomShipments)
  1080.  
  1081. mergeCategories(RPExtraTeams, "jobs", "your jobs")
  1082. mergeCategories(DarkRPEntities, "entities", "your custom entities")
  1083. mergeCategories(shipments, "shipments", "your custom shipments")
  1084. mergeCategories(guns, "weapons", "your custom weapons")
  1085. mergeCategories(CustomVehicles, "vehicles", "your custom vehicles")
  1086. mergeCategories(GAMEMODE.AmmoTypes, "ammo", "your custom ammo")
  1087.  
  1088. categoriesMerged = true
  1089. end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement