· 6 years ago · Mar 09, 2019, 02:42 PM
1--[[
2 © 2013 CloudSixteen.com do not share, re-distribute or modify
3 without permission of its author (kurozael@gmail.com).
4--]]
5
6local Clockwork = Clockwork;
7local Json = Json;
8local tostring = tostring;
9local tonumber = tonumber;
10local IsValid = IsValid;
11local CurTime = CurTime;
12local Vector = Vector;
13local Angle = Angle;
14local Color = Color;
15local pairs = pairs;
16local type = type;
17local player = player;
18local string = string;
19local table = table;
20local ents = ents;
21local math = math;
22local util = util;
23
24Clockwork.player = Clockwork.kernel:NewLibrary("Player");
25Clockwork.player.property = Clockwork.player.property or {};
26Clockwork.player.stored = Clockwork.player.stored or {};
27
28-- A function to run an inventory action for a player.
29function Clockwork.player:InventoryAction(player, itemTable, action)
30 return self:RunClockworkCommand(player, "InvAction", action, itemTable("uniqueID"), tostring(itemTable("itemID")));
31end;
32
33-- A function to get a player's gear.
34function Clockwork.player:GetGear(player, gearClass)
35 if (player.cwGearTab and IsValid(player.cwGearTab[gearClass])) then
36 return player.cwGearTab[gearClass];
37 end;
38end;
39
40-- A function to create a character from data.
41function Clockwork.player:CreateCharacterFromData(player, data)
42 if (player.cwIsCreatingChar) then
43 return;
44 end;
45
46 local minimumPhysDesc = Clockwork.config:Get("minimum_physdesc"):Get();
47 local attributesTable = Clockwork.attribute:GetAll();
48 local factionTable = Clockwork.faction:FindByID(data.faction);
49 local attributes = nil;
50 local info = {};
51
52 if (table.Count(attributesTable) > 0) then
53 for k, v in pairs(attributesTable) do
54 if (v.isOnCharScreen) then
55 attributes = true;
56 break;
57 end;
58 end;
59 end;
60
61 if (!factionTable) then
62 return Clockwork.player:SetCreateFault(
63 player, "You did not choose a faction, or the faction that you chose is not valid!"
64 );
65 end;
66
67 info.attributes = {};
68 info.faction = factionTable.name;
69 info.gender = data.gender;
70 info.model = data.model;
71 info.data = {};
72
73 local classes = false;
74
75 for k, v in pairs(Clockwork.class:GetAll()) do
76 if (v.isOnCharScreen and (v.factions
77 and table.HasValue(v.factions, factionTable.name))) then
78 classes = true;
79 end;
80 end;
81
82 if (classes) then
83 local classTable = Clockwork.class:FindByID(data.class);
84
85 if (!classTable) then
86 return Clockwork.player:SetCreateFault(
87 player, "You did not choose a class, or the class that you chose is not valid!"
88 );
89 else
90 info.data["class"] = classTable.name;
91 end;
92 end;
93
94 if (attributes and type(data.attributes) == "table") then
95 local maximumPoints = Clockwork.config:Get("default_attribute_points"):Get();
96 local pointsSpent = 0;
97
98 if (factionTable.attributePointsScale) then
99 maximumPoints = math.Round(maximumPoints * factionTable.attributePointsScale);
100 end;
101
102 if (factionTable.maximumAttributePoints) then
103 maximumPoints = factionTable.maximumAttributePoints;
104 end;
105
106 for k, v in pairs(data.attributes) do
107 local attributeTable = Clockwork.attribute:FindByID(k);
108
109 if (attributeTable and attributeTable.isOnCharScreen) then
110 local uniqueID = attributeTable.uniqueID;
111 local amount = math.Clamp(v, 0, attributeTable.maximum);
112
113 info.attributes[uniqueID] = {
114 amount = amount,
115 progress = 0
116 };
117
118 pointsSpent = pointsSpent + amount;
119 end;
120 end;
121
122 if (pointsSpent > maximumPoints) then
123 return Clockwork.player:SetCreateFault(
124 player, "You have chosen more "..Clockwork.option:GetKey("name_attribute", true).." points than you can afford to spend!"
125 );
126 end;
127 elseif (attributes) then
128 return Clockwork.player:SetCreateFault(
129 player, "You did not choose any "..Clockwork.option:GetKey("name_attributes", true).." or the ones that you did are not valid!"
130 );
131 end;
132
133 if (!factionTable.GetName) then
134 if (!factionTable.useFullName) then
135 if (data.forename and data.surname) then
136 data.forename = string.gsub(data.forename, "^.", string.upper);
137 data.surname = string.gsub(data.surname, "^.", string.upper);
138
139 if (string.find(data.forename, "[%p%s%d]") or string.find(data.surname, "[%p%s%d]")) then
140 return Clockwork.player:SetCreateFault(
141 player, "Your forename and surname must not contain punctuation, spaces or digits!"
142 );
143 end;
144
145 if (!string.find(data.forename, "[aeiou]") or !string.find(data.surname, "[aeiou]")) then
146 return Clockwork.player:SetCreateFault(
147 player, "Your forename and surname must both contain at least one vowel!"
148 );
149 end;
150
151 if (string.len(data.forename) < 2 or string.len(data.surname) < 2) then
152 return Clockwork.player:SetCreateFault(
153 player, "Your forename and surname must both be at least 2 characters long!"
154 );
155 end;
156
157 if (string.len(data.forename) > 16 or string.len(data.surname) > 16) then
158 return Clockwork.player:SetCreateFault(
159 player, "Your forename and surname must not be greater than 16 characters long!"
160 );
161 end;
162
163 if (string.match(data.forename, "([#~%%]+)") or string.match(data.surname, "([#~%%]+)")) then
164 return Clockwork.player:SetCreateFault(
165 player, "Your forename and surname must not contain special characters!"
166 );
167 end;
168 else
169 return Clockwork.player:SetCreateFault(
170 player, "You did not choose a name, or the name that you chose is not valid!"
171 );
172 end;
173 else
174 if (data.fullName) then
175 if (string.match(data.fullName, "([#~%%]+)")) then
176 return Clockwork.player:SetCreateFault(
177 player, "Your name must not contain special characters!"
178 );
179 end;
180 else
181 return Clockwork.player:SetCreateFault(
182 player, "You did not choose a name, or the name that you chose is not valid!"
183 );
184 end;
185 end;
186 end;
187
188 if (Clockwork.command:FindByID("CharPhysDesc") != nil) then
189 if (type(data.physDesc) != "string") then
190 return Clockwork.player:SetCreateFault(
191 player, "You did not enter a physical description!"
192 );
193 elseif (string.len(data.physDesc) < minimumPhysDesc) then
194 return Clockwork.player:SetCreateFault(
195 player, "The physical description must be at least "..minimumPhysDesc.." characters long!"
196 );
197 elseif (string.match(data.physDesc, "([#~%%]+)")) then
198 return Clockwork.player:SetCreateFault(
199 player, "The physical description must not contain special characters!"
200 );
201 end;
202
203 info.data["PhysDesc"] = Clockwork.kernel:ModifyPhysDesc(data.physDesc);
204 end;
205
206 if (!factionTable.GetModel and !info.model) then
207 return Clockwork.player:SetCreateFault(
208 player, "You did not choose a model, or the model that you chose is not valid!"
209 );
210 end;
211
212 if (!Clockwork.faction:IsGenderValid(info.faction, info.gender)) then
213 return Clockwork.player:SetCreateFault(
214 player, "You did not choose a gender, or the gender that you chose is not valid!"
215 );
216 end;
217
218 if (factionTable.whitelist and !Clockwork.player:IsWhitelisted(player, info.faction)) then
219 return Clockwork.player:SetCreateFault(
220 player, "You are not on the "..info.faction.." whitelist!"
221 );
222 elseif (Clockwork.faction:IsModelValid(factionTable.name, info.gender, info.model)
223 or (factionTable.GetModel and !info.model)) then
224 local charactersTable = Clockwork.config:Get("mysql_characters_table"):Get();
225 local schemaFolder = Clockwork.kernel:GetSchemaFolder();
226 local characterID = nil;
227 local characters = player:GetCharacters();
228
229 if (Clockwork.faction:HasReachedMaximum(player, factionTable.name)) then
230 return Clockwork.player:SetCreateFault(
231 player, "You cannot create any more characters in this faction."
232 );
233 end;
234
235 for i = 1, Clockwork.player:GetMaximumCharacters(player) do
236 print(Clockwork.player:GetMaximumCharacters(player))
237 if (!characters[i]) then
238 characterID = i;
239 break;
240 end;
241 end;
242
243 if (characterID) then
244 if (factionTable.GetName) then
245 info.name = factionTable:GetName(player, info, data);
246 elseif (!factionTable.useFullName) then
247 info.name = data.forename.." "..data.surname;
248 else
249 info.name = data.fullName;
250 end;
251
252 if (factionTable.GetModel) then
253 info.model = factionTable:GetModel(player, info, data);
254 else
255 info.model = data.model;
256 end;
257
258 if (factionTable.OnCreation) then
259 local fault = factionTable:OnCreation(player, info);
260
261 if (fault == false or type(fault) == "string") then
262 return Clockwork.player:SetCreateFault(
263 player, fault or "There was an error creating this character!"
264 );
265 end;
266 end;
267
268 for k, v in pairs(characters) do
269 if (v.name == info.name) then
270 return Clockwork.player:SetCreateFault(
271 player, "You already have a character with the name '"..info.name.."'!"
272 );
273 end;
274 end;
275
276 local fault = Clockwork.plugin:Call("PlayerAdjustCharacterCreationInfo", player, info, data);
277
278 if (fault == false or type(fault) == "string") then
279 return Clockwork.player:SetCreateFault(
280 player, fault or "There was an error creating this character!"
281 );
282 end;
283
284 local queryObj = Clockwork.database:Select(charactersTable);
285 queryObj:AddWhere("_Schema = ?", schemaFolder);
286 queryObj:AddWhere("_Name = ?", info.name);
287 queryObj:SetCallback(function(result)
288 if (!IsValid(player)) then return; end;
289
290 if (Clockwork.database:IsResult(result)) then
291 Clockwork.player:SetCreateFault(
292 player, "A character with the name '"..info.name.."' already exists!"
293 );
294 player.cwIsCreatingChar = nil;
295 else
296 Clockwork.player:LoadCharacter(player, characterID,
297 {
298 attributes = info.attributes,
299 faction = info.faction,
300 gender = info.gender,
301 model = info.model,
302 name = info.name,
303 data = info.data
304 },
305 function()
306 Clockwork.kernel:PrintLog(LOGTYPE_MINOR,
307 player:SteamName().." has created a "..info.faction.." character called '"..info.name.."'."
308 );
309
310 Clockwork.datastream:Start(player, "CharacterFinish", {bSuccess = true});
311
312 player.cwIsCreatingChar = nil;
313 end
314 );
315 end;
316 end);
317 queryObj:Pull();
318
319 player.cwIsCreatingChar = true;
320 else
321 return Clockwork.player:SetCreateFault(player, "You cannot create any more characters!");
322 end;
323 else
324 return Clockwork.player:SetCreateFault(
325 player, "You did not choose a model, or the model that you chose is not valid!"
326 );
327 end;
328end;
329
330-- A function to open the character menu.
331function Clockwork.player:SetCharacterMenuOpen(player, bReset)
332 if (player:HasInitialized()) then
333 Clockwork.datastream:Start(player, "CharacterOpen", (bReset == true));
334
335 if (bReset) then
336 player.cwCharMenuReset = true;
337 player:KillSilent();
338 end;
339 end;
340end;
341
342-- A function to start a sound for a player.
343function Clockwork.player:StartSound(player, uniqueID, sound, fVolume)
344 if (!player.cwSoundsPlaying) then
345 player.cwSoundsPlaying = {};
346 end;
347
348 if (!player.cwSoundsPlaying[uniqueID]
349 or player.cwSoundsPlaying[uniqueID] != sound) then
350 player.cwSoundsPlaying[uniqueID] = sound;
351
352 Clockwork.datastream:Start(player, "StartSound", {
353 uniqueID = uniqueID, sound = sound, volume = (fVolume or 0.75)
354 });
355 end;
356end;
357
358-- A function to stop a sound for a player.
359function Clockwork.player:StopSound(player, uniqueID, iFadeOut)
360 if (!player.cwSoundsPlaying) then
361 player.cwSoundsPlaying = {};
362 end;
363
364 if (player.cwSoundsPlaying[uniqueID]) then
365 player.cwSoundsPlaying[uniqueID] = nil;
366
367 Clockwork.datastream:Start(player, "StopSound", {
368 uniqueID = uniqueID, fadeOut = (iFadeOut or 0)
369 });
370 end;
371end;
372
373-- A function to remove a player's gear.
374function Clockwork.player:RemoveGear(player, gearClass)
375 if (player.cwGearTab and IsValid(player.cwGearTab[gearClass])) then
376 player.cwGearTab[gearClass]:Remove();
377 player.cwGearTab[gearClass] = nil;
378 end;
379end;
380
381-- A function to strip all of a player's gear.
382function Clockwork.player:StripGear(player)
383 if (!player.cwGearTab) then return; end;
384
385 for k, v in pairs(player.cwGearTab) do
386 if (IsValid(v)) then v:Remove(); end;
387 end;
388
389 player.cwGearTab = {};
390end;
391
392-- A function to create a player's gear.
393function Clockwork.player:CreateGear(player, gearClass, itemTable, bMustHave)
394 if (!player.cwGearTab) then
395 player.cwGearTab = {};
396 end;
397
398 if (IsValid(player.cwGearTab[gearClass])) then
399 player.cwGearTab[gearClass]:Remove();
400 end;
401
402 if (itemTable("isAttachment")) then
403 local position = player:GetPos();
404 local angles = player:GetAngles();
405 local model = itemTable("attachmentModel", itemTable("model"));
406
407 player.cwGearTab[gearClass] = ents.Create("cw_gear");
408 player.cwGearTab[gearClass]:SetParent(player);
409 player.cwGearTab[gearClass]:SetAngles(angles);
410 player.cwGearTab[gearClass]:SetModel(model);
411 player.cwGearTab[gearClass]:SetPos(position);
412 player.cwGearTab[gearClass]:Spawn();
413
414 if (itemTable("attachmentMaterial")) then
415 player.cwGearTab[gearClass]:SetMaterial(itemTable("attachmentMaterial"));
416 end;
417
418 if (itemTable("attachmentColor")) then
419 player.cwGearTab[gearClass]:SetColor(
420 Clockwork.kernel:UnpackColor(itemTable("attachmentColor"))
421 );
422 else
423 player.cwGearTab[gearClass]:SetColor(Color(255, 255, 255, 255));
424 end;
425
426 if (IsValid(player.cwGearTab[gearClass])) then
427 player.cwGearTab[gearClass]:SetOwner(player);
428 player.cwGearTab[gearClass]:SetMustHave(bMustHave);
429 player.cwGearTab[gearClass]:SetItemTable(gearClass, itemTable);
430 end;
431 end;
432end;
433
434-- A function to get whether a player is noclipping.
435function Clockwork.player:IsNoClipping(player)
436 if (player:GetMoveType() == MOVETYPE_NOCLIP
437 and !player:InVehicle()) then
438 return true;
439 end;
440end;
441
442-- A function to get whether a player is an admin.
443function Clockwork.player:IsAdmin(player)
444 if (self:HasFlags(player, "o")) then
445 return true;
446 end;
447end;
448
449-- A function to get whether a player can hear another player.
450function Clockwork.player:CanHearPlayer(player, target, iAllowance)
451 if (Clockwork.config:Get("messages_must_see_player"):Get()) then
452 return self:CanSeePlayer(player, target, (iAllowance or 0.5), true);
453 else
454 return true;
455 end;
456end;
457
458-- A functon to get all property.
459function Clockwork.player:GetAllProperty()
460 for k, v in pairs(self.property) do
461 if (!IsValid(v)) then
462 self.property[k] = nil;
463 end;
464 end;
465
466 return self.property;
467end;
468
469-- A function to set a player's action.
470function Clockwork.player:SetAction(player, action, duration, priority, Callback)
471 local currentAction = self:GetAction(player);
472
473 if (type(action) != "string" or action == "") then
474 Clockwork.kernel:DestroyTimer("Action"..player:UniqueID());
475
476 player:SetDTFloat(0, 0);
477 player:SetDTInt(3, 0);
478 player:SetDTString(3, "");
479
480 return;
481 elseif (duration == false or duration == 0) then
482 if (currentAction == action) then
483 return self:SetAction(player, false);
484 else
485 return false;
486 end;
487 end;
488
489 if (player.cwAction) then
490 if ((priority and priority > player.cwAction[2])
491 or currentAction == "" or action == player.cwAction[1]) then
492 player.cwAction = nil;
493 end;
494 end;
495
496 if (!player.cwAction) then
497 local curTime = CurTime();
498
499 player:SetDTFloat(0, curTime);
500 player:SetDTInt(3, duration);
501 player:SetDTString(3, action);
502
503 if (priority) then
504 player.cwAction = {action, priority};
505 else
506 player.cwAction = nil;
507 end;
508
509 Clockwork.kernel:CreateTimer("Action"..player:UniqueID(), duration, 1, function()
510 if (Callback) then
511 Callback();
512 end;
513 end);
514 end;
515end;
516
517-- A function to set the player's character menu state.
518function Clockwork.player:SetCharacterMenuState(player, state)
519 Clockwork.datastream:Start(player, "CharacterMenu", state);
520end;
521
522-- A function to get a player's action.
523function Clockwork.player:GetAction(player, percentage)
524 local startActionTime = player:GetDTFloat(0);
525 local actionDuration = player:GetDTInt(3);
526 local curTime = CurTime();
527 local action = player:GetDTString(3);
528
529 if (startActionTime and CurTime() < startActionTime + actionDuration) then
530 if (percentage) then
531 return action, (100 / actionDuration) * (actionDuration - ((startActionTime + actionDuration) - curTime));
532 else
533 return action, actionDuration, startActionTime;
534 end;
535 else
536 return "", 0, 0;
537 end;
538end;
539
540-- A function to run a Clockwork command on a player.
541function Clockwork.player:RunClockworkCommand(player, command, ...)
542 return Clockwork.command:ConsoleCommand(player, "cwCmd", {command, ...});
543end;
544
545-- A function to get a player's wages name.
546function Clockwork.player:GetWagesName(player)
547 return Clockwork.class:Query(player:Team(), "wagesName", Clockwork.config:Get("wages_name"):Get());
548end;
549
550-- A function to get whether a player can see an NPC.
551function Clockwork.player:CanSeeNPC(player, target, iAllowance, tIgnoreEnts)
552 if (!player:GetEyeTraceNoCursor().Entity == target) then
553 local trace = {};
554
555 trace.mask = CONTENTS_SOLID + CONTENTS_MOVEABLE + CONTENTS_OPAQUE + CONTENTS_DEBRIS + CONTENTS_HITBOX + CONTENTS_MONSTER;
556 trace.start = player:GetShootPos();
557 trace.endpos = target:GetShootPos();
558 trace.filter = {player, target};
559
560 if (tIgnoreEnts) then
561 if (type(tIgnoreEnts) == "table") then
562 table.Add(trace.filter, tIgnoreEnts);
563 else
564 table.Add(trace.filter, ents.GetAll());
565 end;
566 end;
567
568 trace = util.TraceLine(trace);
569
570 if (trace.Fraction >= (iAllowance or 0.75)) then
571 return true;
572 end;
573 else
574 return true;
575 end;
576end;
577
578-- A function to get whether a player can see a player.
579function Clockwork.player:CanSeePlayer(player, target, iAllowance, tIgnoreEnts)
580 if (!player:GetEyeTraceNoCursor().Entity == target
581 and !target:GetEyeTraceNoCursor().Entity == player) then
582 local trace = {};
583
584 trace.mask = CONTENTS_SOLID + CONTENTS_MOVEABLE + CONTENTS_OPAQUE + CONTENTS_DEBRIS + CONTENTS_HITBOX + CONTENTS_MONSTER;
585 trace.start = player:GetShootPos();
586 trace.endpos = target:GetShootPos();
587 trace.filter = {player, target};
588
589 if (tIgnoreEnts) then
590 if (type(tIgnoreEnts) == "table") then
591 table.Add(trace.filter, tIgnoreEnts);
592 else
593 table.Add(trace.filter, ents.GetAll());
594 end;
595 end;
596
597 trace = util.TraceLine(trace);
598
599 if (trace.Fraction >= (iAllowance or 0.75)) then
600 return true;
601 end;
602 else
603 return true;
604 end;
605end;
606
607-- A function to get whether a player can see an entity.
608function Clockwork.player:CanSeeEntity(player, target, iAllowance, tIgnoreEnts)
609 if (!player:GetEyeTraceNoCursor().Entity == target) then
610 local trace = {};
611
612 trace.mask = CONTENTS_SOLID + CONTENTS_MOVEABLE + CONTENTS_OPAQUE + CONTENTS_DEBRIS + CONTENTS_HITBOX + CONTENTS_MONSTER;
613 trace.start = player:GetShootPos();
614 trace.endpos = target:LocalToWorld(target:OBBCenter());
615 trace.filter = {player, target};
616
617 if (tIgnoreEnts) then
618 if (type(tIgnoreEnts) == "table") then
619 table.Add(trace.filter, tIgnoreEnts);
620 else
621 table.Add(trace.filter, ents.GetAll());
622 end;
623 end;
624
625 trace = util.TraceLine(trace);
626
627 if (trace.Fraction >= (iAllowance or 0.75)) then
628 return true;
629 end;
630 else
631 return true;
632 end;
633end;
634
635-- A function to get whether a player can see a position.
636function Clockwork.player:CanSeePosition(player, position, iAllowance, tIgnoreEnts)
637 local trace = {};
638
639 trace.mask = CONTENTS_SOLID + CONTENTS_MOVEABLE + CONTENTS_OPAQUE + CONTENTS_DEBRIS + CONTENTS_HITBOX + CONTENTS_MONSTER;
640 trace.start = player:GetShootPos();
641 trace.endpos = position;
642 trace.filter = {player};
643
644 if (tIgnoreEnts) then
645 if (type(tIgnoreEnts) == "table") then
646 table.Add(trace.filter, tIgnoreEnts);
647 else
648 table.Add(trace.filter, ents.GetAll());
649 end;
650 end;
651
652 trace = util.TraceLine(trace);
653
654 if (trace.Fraction >= (iAllowance or 0.75)) then
655 return true;
656 end;
657end;
658
659-- A function to update whether a player's weapon is raised.
660function Clockwork.player:UpdateWeaponRaised(player)
661 local bIsRaised = self:GetWeaponRaised(player);
662 local weapon = player:GetActiveWeapon();
663
664 player:SetDTBool(1, bIsRaised);
665
666 if (IsValid(weapon)) then
667 Clockwork.kernel:HandleWeaponFireDelay(player, bIsRaised, weapon, CurTime());
668 end;
669end;
670
671-- A function to get whether a player's weapon is raised.
672function Clockwork.player:GetWeaponRaised(player, bIsCached)
673 if (bIsCached) then
674 return player:GetDTBool(1);
675 end;
676
677 local weapon = player:GetActiveWeapon();
678
679 if (IsValid(weapon) and !weapon.NeverRaised) then
680 if (weapon.GetRaised) then
681 local bIsRaised = weapon:GetRaised();
682
683 if (bIsRaised != nil) then
684 return bIsRaised;
685 end;
686 end;
687
688 return Clockwork.plugin:Call("GetPlayerWeaponRaised", player, weapon:GetClass(), weapon);
689 end;
690
691 return false;
692end;
693
694-- A function to toggle whether a player's weapon is raised.
695function Clockwork.player:ToggleWeaponRaised(player)
696 self:SetWeaponRaised(player, !player.cwWeaponRaiseClass);
697end;
698
699-- A function to set whether a player's weapon is raised.
700function Clockwork.player:SetWeaponRaised(player, bIsRaised)
701 local weapon = player:GetActiveWeapon();
702
703 if (IsValid(weapon)) then
704 if (type(bIsRaised) == "number") then
705 player.cwAutoWepRaised = weapon:GetClass();
706 player:UpdateWeaponRaised();
707
708 Clockwork.kernel:CreateTimer("WeaponRaised"..player:UniqueID(), bIsRaised, 1, function()
709 if (IsValid(player)) then
710 player.cwAutoWepRaised = nil;
711 player:UpdateWeaponRaised();
712 end;
713 end);
714 elseif (bIsRaised) then
715 if (!player.cwWeaponRaiseClass) then
716 if (weapon.OnRaised) then
717 weapon:OnRaised();
718 end;
719 end;
720
721 player.cwWeaponRaiseClass = weapon:GetClass();
722 player.cwAutoWepRaised = nil;
723 player:UpdateWeaponRaised();
724 else
725 if (player.cwWeaponRaiseClass) then
726 if (weapon.OnLowered) then
727 weapon:OnLowered();
728 end;
729 end;
730
731 player.cwWeaponRaiseClass = nil;
732 player.cwAutoWepRaised = nil;
733 player:UpdateWeaponRaised();
734 end;
735 end;
736end;
737
738-- A function to setup a player's remove property delays.
739function Clockwork.player:SetupRemovePropertyDelays(player, bAllCharacters)
740 local uniqueID = player:UniqueID();
741 local key = player:GetCharacterKey();
742
743 for k, v in pairs(self:GetAllProperty()) do
744 local removeDelay = Clockwork.entity:QueryProperty(v, "removeDelay");
745
746 if (IsValid(v) and removeDelay) then
747 if (uniqueID == Clockwork.entity:QueryProperty(v, "uniqueID")
748 and (bAllCharacters or key == Clockwork.entity:QueryProperty(v, "key"))) then
749 Clockwork.kernel:CreateTimer("RemoveDelay"..v:EntIndex(), removeDelay, 1, function(entity)
750 if (IsValid(entity)) then
751 entity:Remove();
752 end;
753 end, v);
754 end;
755 end;
756 end;
757end;
758
759-- A function to disable a player's property.
760function Clockwork.player:DisableProperty(player, bCharacterOnly)
761 local uniqueID = player:UniqueID();
762 local key = player:GetCharacterKey();
763
764 for k, v in pairs(self:GetAllProperty()) do
765 if (IsValid(v) and uniqueID == Clockwork.entity:QueryProperty(v, "uniqueID")
766 and (!bCharacterOnly or key == Clockwork.entity:QueryProperty(v, "key"))) then
767 Clockwork.entity:SetPropertyVar(v, "owner", NULL);
768
769 if (Clockwork.entity:QueryProperty(v, "networked")) then
770 v:SetNetworkedEntity("Owner", NULL);
771 end;
772
773 v:SetOwnerKey(nil);
774 v:SetNetworkedBool("Owned", false);
775 v:SetNetworkedInt("Key", 0);
776
777 if (v.SetPlayer) then
778 v:SetVar("Founder", NULL);
779 v:SetVar("FounderIndex", 0);
780 v:SetNetworkedString("FounderName", "");
781 end;
782 end;
783 end;
784end;
785
786-- A function to give property to a player.
787function Clockwork.player:GiveProperty(player, entity, networked, removeDelay)
788 Clockwork.kernel:DestroyTimer("RemoveDelay"..entity:EntIndex());
789 Clockwork.entity:ClearProperty(entity);
790
791 entity.cwPropertyTab = {
792 key = player:GetCharacterKey(),
793 owner = player,
794 owned = true,
795 uniqueID = player:UniqueID(),
796 networked = networked,
797 removeDelay = removeDelay
798 };
799
800 if (entity.SetPlayer) then
801 entity:SetPlayer(player);
802 end;
803
804 if (networked) then
805 entity:SetNetworkedEntity("Owner", player);
806 end;
807
808 entity:SetOwnerKey(player:GetCharacterKey());
809 entity:SetNetworkedBool("Owned", true);
810 entity:SetNetworkedInt("Key", entity.cwPropertyTab.key);
811
812 self.property[entity:EntIndex()] = entity;
813 Clockwork.plugin:Call("PlayerPropertyGiven", player, entity, networked, removeDelay);
814end;
815
816-- A function to give property to an offline player.
817function Clockwork.player:GivePropertyOffline(key, uniqueID, entity, networked, removeDelay)
818 Clockwork.entity:ClearProperty(entity);
819
820 if (key and uniqueID) then
821 local propertyUniqueID = Clockwork.entity:QueryProperty(entity, "uniqueID");
822 local owner = player.GetByUniqueID(uniqueID);
823
824 if (IsValid(owner) and owner:GetCharacterKey() == key) then
825 self:GiveProperty(owner, entity, networked, removeDelay);
826 return;
827 else
828 owner = nil;
829 end;
830
831 if (propertyUniqueID) then
832 Clockwork.kernel:DestroyTimer("RemoveDelay"..entity:EntIndex().." "..cwPropertyTabUniqueID);
833 end;
834
835 entity.cwPropertyTab = {
836 key = key,
837 owner = owner,
838 owned = true,
839 uniqueID = uniqueID,
840 networked = networked,
841 removeDelay = removeDelay
842 };
843
844 if (IsValid(entity.cwPropertyTab.owner)) then
845 if (entity.SetPlayer) then
846 entity:SetPlayer(entity.cwPropertyTab.owner);
847 end;
848
849 if (networked) then
850 entity:SetNetworkedEntity("Owner", entity.cwPropertyTab.owner);
851 end;
852 end;
853
854 entity:SetNetworkedBool("Owned", true);
855 entity:SetNetworkedInt("Key", key);
856 entity:SetOwnerKey(key);
857
858 self.property[entity:EntIndex()] = entity;
859 Clockwork.plugin:Call("PlayerPropertyGivenOffline", key, uniqueID, entity, networked, removeDelay);
860 end;
861end;
862
863-- A function to take property from an offline player.
864function Clockwork.player:TakePropertyOffline(key, uniqueID, entity, bAnyCharacter)
865 if (key and uniqueID) then
866 local owner = player.GetByUniqueID(uniqueID);
867
868 if (IsValid(owner) and owner:GetCharacterKey() == key) then
869 self:TakeProperty(owner, entity);
870 return;
871 end;
872
873 if (Clockwork.entity:QueryProperty(entity, "uniqueID") == uniqueID
874 and Clockwork.entity:QueryProperty(entity, "key") == key) then
875 entity.cwPropertyTab = nil;
876 entity:SetNetworkedEntity("Owner", NULL);
877 entity:SetNetworkedBool("Owned", false);
878 entity:SetNetworkedInt("Key", 0);
879 entity:SetOwnerKey(nil);
880
881 if (entity.SetPlayer) then
882 entity:SetVar("Founder", nil);
883 entity:SetVar("FounderIndex", nil);
884 entity:SetNetworkedString("FounderName", "");
885 end;
886
887 self.property[entity:EntIndex()] = nil;
888 Clockwork.plugin:Call("PlayerPropertyTakenOffline", key, uniqueID, entity);
889 end;
890 end;
891end;
892
893-- A function to take property from a player.
894function Clockwork.player:TakeProperty(player, entity)
895 if (Clockwork.entity:GetOwner(entity) == player) then
896 entity.cwPropertyTab = nil;
897
898 entity:SetNetworkedEntity("Owner", NULL);
899 entity:SetNetworkedBool("Owned", false);
900 entity:SetNetworkedInt("Key", 0);
901 entity:SetOwnerKey(nil);
902
903 if (entity.SetPlayer) then
904 entity:SetVar("Founder", nil);
905 entity:SetVar("FounderIndex", nil);
906 entity:SetNetworkedString("FounderName", "");
907 end;
908
909 self.property[entity:EntIndex()] = nil;
910 Clockwork.plugin:Call("PlayerPropertyTaken", player, entity);
911 end;
912end;
913
914-- A function to set a player to their default skin.
915function Clockwork.player:SetDefaultSkin(player)
916 player:SetSkin(self:GetDefaultSkin(player));
917end;
918
919-- A function to get a player's default skin.
920function Clockwork.player:GetDefaultSkin(player)
921 return Clockwork.plugin:Call("GetPlayerDefaultSkin", player);
922end;
923
924-- A function to set a player to their default model.
925function Clockwork.player:SetDefaultModel(player)
926 player:SetModel(self:GetDefaultModel(player));
927end;
928
929-- A function to get a player's default model.
930function Clockwork.player:GetDefaultModel(player)
931 return Clockwork.plugin:Call("GetPlayerDefaultModel", player);
932end;
933
934-- A function to get whether a player is drunk.
935function Clockwork.player:GetDrunk(player)
936 if (player.cwDrunkTab) then return #player.cwDrunkTab; end;
937end;
938
939-- A function to set whether a player is drunk.
940function Clockwork.player:SetDrunk(player, expire)
941 local curTime = CurTime();
942
943 if (expire == false) then
944 player.cwDrunkTab = nil;
945 elseif (!player.cwDrunkTab) then
946 player.cwDrunkTab = {curTime + expire};
947 else
948 player.cwDrunkTab[#player.cwDrunkTab + 1] = curTime + expire;
949 end;
950
951 player:SetSharedVar("IsDrunk", self:GetDrunk(player) or 0);
952end;
953
954-- A function to strip a player's default ammo.
955function Clockwork.player:StripDefaultAmmo(player, weapon, itemTable)
956 if (!itemTable) then
957 itemTable = Clockwork.item:GetByWeapon(weapon);
958 end;
959
960 if (itemTable) then
961 local secondaryDefaultAmmo = itemTable("secondaryDefaultAmmo");
962 local primaryDefaultAmmo = itemTable("primaryDefaultAmmo");
963
964 if (primaryDefaultAmmo) then
965 local ammoClass = weapon:GetPrimaryAmmoType();
966
967 if (weapon:Clip1() != -1) then
968 weapon:SetClip1(0);
969 end;
970
971 if (type(primaryDefaultAmmo) == "number") then
972 player:SetAmmo(
973 math.max(player:GetAmmoCount(ammoClass) - primaryDefaultAmmo, 0), ammoClass
974 );
975 end;
976 end;
977
978 if (secondaryDefaultAmmo) then
979 local ammoClass = weapon:GetSecondaryAmmoType();
980
981 if (weapon:Clip2() != -1) then
982 weapon:SetClip2(0);
983 end;
984
985 if (type(secondaryDefaultAmmo) == "number") then
986 player:SetAmmo(
987 math.max(player:GetAmmoCount(ammoClass) - secondaryDefaultAmmo, 0), ammoClass
988 );
989 end;
990 end;
991 end;
992end;
993
994-- A function to check if a player is whitelisted for a faction.
995function Clockwork.player:IsWhitelisted(player, faction)
996 for k, v in pairs(player:GetData("Whitelisted")) do
997 if (v == faction) then
998 return true;
999 end;
1000 end;
1001end;
1002
1003-- A function to set whether a player is whitelisted for a faction.
1004function Clockwork.player:SetWhitelisted(player, faction, isWhitelisted)
1005 local whitelisted = player:GetData("Whitelisted");
1006
1007 if (isWhitelisted) then
1008 if (!self:IsWhitelisted(player, faction)) then
1009 whitelisted[table.Count(whitelisted) + 1] = faction;
1010 end;
1011 else
1012 for k, v in pairs(whitelisted) do
1013 if (v == faction) then
1014 whitelisted[k] = nil;
1015 end;
1016 end;
1017 end;
1018
1019 Clockwork.datastream:Start(
1020 player, "SetWhitelisted", {faction, isWhitelisted}
1021 );
1022end;
1023
1024-- A function to create a Condition timer.
1025function Clockwork.player:ConditionTimer(player, delay, Condition, Callback)
1026 local realDelay = CurTime() + delay;
1027 local uniqueID = player:UniqueID();
1028
1029 if (player.cwConditionTimer) then
1030 player.cwConditionTimer.Callback(false);
1031 player.cwConditionTimer = nil;
1032 end;
1033
1034 player.cwConditionTimer = {
1035 delay = realDelay,
1036 Callback = Callback,
1037 Condition = Condition
1038 };
1039
1040 Clockwork.kernel:CreateTimer("CondTimer"..uniqueID, 0, 0, function()
1041 if (!IsValid(player)) then
1042 Clockwork.kernel:DestroyTimer("CondTimer"..uniqueID);
1043 Callback(false);
1044 return;
1045 end;
1046
1047 if (Condition()) then
1048 if (CurTime() >= realDelay) then
1049 Callback(true); player.cwConditionTimer = nil;
1050 Clockwork.kernel:DestroyTimer("CondTimer"..uniqueID);
1051 end;
1052 else
1053 Callback(false); player.cwConditionTimer = nil;
1054 Clockwork.kernel:DestroyTimer("CondTimer"..uniqueID);
1055 end;
1056 end);
1057end;
1058
1059-- A function to create an entity Condition timer.
1060function Clockwork.player:EntityConditionTimer(player, target, entity, delay, distance, Condition, Callback)
1061 local realEntity = entity or target;
1062 local realDelay = CurTime() + delay;
1063 local uniqueID = player:UniqueID();
1064
1065 if (player.cwConditionEntTimer) then
1066 player.cwConditionEntTimer.Callback(false);
1067 player.cwConditionEntTimer = nil;
1068 end;
1069
1070 player.cwConditionEntTimer = {
1071 delay = realDelay, target = target,
1072 entity = realEntity, distance = distance,
1073 Callback = Callback, Condition = Condition
1074 };
1075
1076 Clockwork.kernel:CreateTimer("EntityCondTimer"..uniqueID, 0, 0, function()
1077 if (!IsValid(player)) then
1078 Clockwork.kernel:DestroyTimer("EntityCondTimer"..uniqueID);
1079 Callback(false);
1080 return;
1081 end;
1082
1083 local traceLine = player:GetEyeTraceNoCursor();
1084
1085 if (IsValid(target) and IsValid(realEntity) and traceLine.Entity == realEntity
1086 and traceLine.Entity:GetPos():Distance(player:GetShootPos()) <= distance
1087 and Condition()) then
1088 if (CurTime() >= realDelay) then
1089 Callback(true); player.cwConditionEntTimer = nil;
1090 Clockwork.kernel:DestroyTimer("EntityCondTimer"..uniqueID);
1091 end;
1092 else
1093 Callback(false); player.cwConditionEntTimer = nil;
1094 Clockwork.kernel:DestroyTimer("EntityCondTimer"..uniqueID);
1095 end;
1096 end);
1097end;
1098
1099-- A function to get a player's spawn ammo.
1100function Clockwork.player:GetSpawnAmmo(player, ammo)
1101 if (ammo) then
1102 return player.cwSpawnAmmo[ammo];
1103 else
1104 return player.cwSpawnAmmo;
1105 end;
1106end;
1107
1108-- A function to get a player's spawn weapon.
1109function Clockwork.player:GetSpawnWeapon(player, weapon)
1110 if (weapon) then
1111 return player.cwSpawnWeps[weapon];
1112 else
1113 return player.cwSpawnWeps;
1114 end;
1115end;
1116
1117-- A function to take spawn ammo from a player.
1118function Clockwork.player:TakeSpawnAmmo(player, ammo, amount)
1119 if (player.cwSpawnAmmo[ammo]) then
1120 if (player.cwSpawnAmmo[ammo] < amount) then
1121 amount = player.cwSpawnAmmo[ammo];
1122
1123 player.cwSpawnAmmo[ammo] = nil;
1124 else
1125 player.cwSpawnAmmo[ammo] = player.cwSpawnAmmo[ammo] - amount;
1126 end;
1127
1128 player:RemoveAmmo(amount, ammo);
1129 end;
1130end;
1131
1132-- A function to give the player spawn ammo.
1133function Clockwork.player:GiveSpawnAmmo(player, ammo, amount)
1134 if (player.cwSpawnAmmo[ammo]) then
1135 player.cwSpawnAmmo[ammo] = player.cwSpawnAmmo[ammo] + amount;
1136 else
1137 player.cwSpawnAmmo[ammo] = amount;
1138 end;
1139
1140 player:GiveAmmo(amount, ammo);
1141end;
1142
1143-- A function to take a player's spawn weapon.
1144function Clockwork.player:TakeSpawnWeapon(player, class)
1145 player.cwSpawnWeps[class] = nil;
1146 player:StripWeapon(class);
1147end;
1148
1149-- A function to give a player a spawn weapon.
1150function Clockwork.player:GiveSpawnWeapon(player, class)
1151 player.cwSpawnWeps[class] = true;
1152 player:Give(class);
1153end;
1154
1155-- A function to give a player an item weapon.
1156function Clockwork.player:GiveItemWeapon(player, itemTable)
1157 if (Clockwork.item:IsWeapon(itemTable)) then
1158 player:Give(itemTable("weaponClass"), itemTable);
1159 return true;
1160 end;
1161end;
1162
1163-- A function to give a player a spawn item weapon.
1164function Clockwork.player:GiveSpawnItemWeapon(player, itemTable)
1165 if (Clockwork.item:IsWeapon(itemTable)) then
1166 player.cwSpawnWeps[itemTable("weaponClass")] = true;
1167 player:Give(itemTable("weaponClass"), itemTable);
1168
1169 return true;
1170 end;
1171end;
1172
1173-- A function to give flags to a player.
1174function Clockwork.player:GiveFlags(player, flags)
1175 for i = 1, #flags do
1176 local flag = string.sub(flags, i, i);
1177
1178 if (!string.find(player:GetFlags(), flag)) then
1179 player:SetCharacterData("Flags", player:GetFlags()..flag, true);
1180
1181 Clockwork.plugin:Call("PlayerFlagsGiven", player, flag);
1182 end;
1183 end;
1184end;
1185
1186-- A function to play a sound to a player.
1187function Clockwork.player:PlaySound(player, sound)
1188 Clockwork.datastream:Start(player, "PlaySound",sound);
1189end;
1190
1191-- A function to get a player's maximum characters.
1192function Clockwork.player:GetMaximumCharacters(player)
1193 local maximum = Clockwork.config:Get("additional_characters"):Get();
1194
1195 for k, v in pairs(Clockwork.faction.stored) do
1196 if (!v.whitelist or self:IsWhitelisted(player, v.name)) then
1197 maximum = maximum + 1;
1198 end;
1199 end;
1200
1201 return maximum;
1202end;
1203
1204-- A function to query a player's character.
1205function Clockwork.player:Query(player, key, default)
1206 local character = player:GetCharacter();
1207
1208 if (character) then
1209 key = Clockwork.kernel:SetCamelCase(key, true);
1210
1211 if (character[key] != nil) then
1212 return character[key];
1213 end;
1214 end;
1215
1216 return default;
1217end;
1218
1219-- A function to set a player to a safe position.
1220function Clockwork.player:SetSafePosition(player, position, filter)
1221 position = self:GetSafePosition(player, position, filter);
1222
1223 if (position) then
1224 player:SetMoveType(MOVETYPE_NOCLIP);
1225 player:SetPos(position);
1226
1227 if (player:IsInWorld()) then
1228 player:SetMoveType(MOVETYPE_WALK);
1229 else
1230 player:Spawn();
1231 end;
1232 end;
1233end;
1234
1235-- A function to get the safest position near a position.
1236function Clockwork.player:GetSafePosition(player, position, filter)
1237 local closestPosition = nil;
1238 local distanceAmount = 8;
1239 local directions = {};
1240 local yawForward = player:EyeAngles().yaw;
1241 local angles = {
1242 math.NormalizeAngle(yawForward - 180),
1243 math.NormalizeAngle(yawForward - 135),
1244 math.NormalizeAngle(yawForward + 135),
1245 math.NormalizeAngle(yawForward + 45),
1246 math.NormalizeAngle(yawForward + 90),
1247 math.NormalizeAngle(yawForward - 45),
1248 math.NormalizeAngle(yawForward - 90),
1249 math.NormalizeAngle(yawForward)
1250 };
1251
1252 position = position + Vector(0, 0, 32);
1253
1254 if (!filter) then
1255 filter = {player};
1256 elseif (type(filter) != "table") then
1257 filter = {filter};
1258 end;
1259
1260 if (!table.HasValue(filter, player)) then
1261 filter[#filter + 1] = player;
1262 end;
1263
1264 for i = 1, 8 do
1265 for k, v in pairs(angles) do
1266 directions[#directions + 1] = {v, distanceAmount};
1267 end;
1268
1269 distanceAmount = distanceAmount * 2;
1270 end;
1271
1272 -- A function to get a lower position.
1273 local function GetLowerPosition(testPosition, ignoreHeight)
1274 local trace = {
1275 filter = filter,
1276 endpos = testPosition - Vector(0, 0, 256),
1277 start = testPosition
1278 };
1279
1280 return util.TraceLine(trace).HitPos + Vector(0, 0, 32);
1281 end;
1282
1283 local trace = {
1284 filter = filter,
1285 endpos = position + Vector(0, 0, 256),
1286 start = position
1287 };
1288
1289 local safePosition = GetLowerPosition(util.TraceLine(trace).HitPos);
1290
1291 if (safePosition) then
1292 position = safePosition;
1293 end;
1294
1295 for k, v in pairs(directions) do
1296 local angleVector = Angle(0, v[1], 0):Forward();
1297 local testPosition = position + (angleVector * v[2]);
1298
1299 local trace = {
1300 filter = filter,
1301 endpos = testPosition,
1302 start = position
1303 };
1304
1305 local traceLine = util.TraceEntity(trace, player);
1306
1307 if (traceLine.Hit) then
1308 trace = {
1309 filter = filter,
1310 endpos = traceLine.HitPos - (angleVector * v[2]),
1311 start = traceLine.HitPos
1312 };
1313
1314 traceLine = util.TraceEntity(trace, player);
1315
1316 if (!traceLine.Hit) then
1317 position = traceLine.HitPos;
1318 end;
1319 end;
1320
1321 if (!traceLine.Hit) then
1322 break;
1323 end;
1324 end;
1325
1326 for k, v in pairs(directions) do
1327 local angleVector = Angle(0, v[1], 0):Forward();
1328 local testPosition = position + (angleVector * v[2]);
1329
1330 local trace = {
1331 filter = filter,
1332 endpos = testPosition,
1333 start = position
1334 };
1335
1336 local traceLine = util.TraceEntity(trace, player);
1337
1338 if (!traceLine.Hit) then
1339 return traceLine.HitPos;
1340 end;
1341 end;
1342
1343 return position;
1344end;
1345
1346-- Called to convert a player's data to a string.
1347function Clockwork.player:ConvertDataString(player, data)
1348 local bSuccess, value = pcall(Clockwork.json.Decode, Clockwork.json, data);
1349
1350 if (bSuccess and value != nil) then
1351 return value;
1352 else
1353 return {};
1354 end;
1355end;
1356
1357-- A function to return a player's property.
1358function Clockwork.player:ReturnProperty(player)
1359 local uniqueID = player:UniqueID();
1360 local key = player:GetCharacterKey();
1361
1362 for k, v in pairs(self:GetAllProperty()) do
1363 if (IsValid(v)) then
1364 if (uniqueID == Clockwork.entity:QueryProperty(v, "uniqueID")) then
1365 if (key == Clockwork.entity:QueryProperty(v, "key")) then
1366 self:GiveProperty(player, v, Clockwork.entity:QueryProperty(v, "networked"));
1367 end;
1368 end;
1369 end;
1370 end;
1371
1372 Clockwork.plugin:Call("PlayerReturnProperty", player);
1373end;
1374
1375-- A function to take flags from a player.
1376function Clockwork.player:TakeFlags(player, flags)
1377 for i = 1, #flags do
1378 local flag = string.sub(flags, i, i);
1379
1380 if (string.find(player:GetFlags(), flag)) then
1381 player:SetCharacterData("Flags", string.gsub(player:GetFlags(), flag, ""), true);
1382
1383 Clockwork.plugin:Call("PlayerFlagsTaken", player, flag);
1384 end;
1385 end;
1386end;
1387
1388-- A function to set whether a player's menu is open.
1389function Clockwork.player:SetMenuOpen(player, isOpen)
1390 Clockwork.datastream:Start(player, "MenuOpen", isOpen);
1391end;
1392
1393-- A function to set whether a player has intialized.
1394function Clockwork.player:SetInitialized(player, bInitialized)
1395 player:SetDTBool(0, bInitialized);
1396end;
1397
1398-- A function to check if a player has any flags.
1399function Clockwork.player:HasAnyFlags(player, flags, bByDefault)
1400 if (player:GetCharacter()) then
1401 local playerFlags = player:GetFlags();
1402
1403 if (Clockwork.class:HasAnyFlags(player:Team(), flags) and !bByDefault) then
1404 return true;
1405 end;
1406
1407 for i = 1, #flags do
1408 local flag = string.sub(flags, i, i);
1409 local bSuccess = true;
1410
1411 if (!bByDefault) then
1412 local hasFlag = Clockwork.plugin:Call("PlayerDoesHaveFlag", player, flag);
1413
1414 if (hasFlag != false) then
1415 if (hasFlag) then
1416 return true;
1417 end;
1418 else
1419 bSuccess = nil;
1420 end;
1421 end;
1422
1423 if (bSuccess) then
1424 if (flag == "s") then
1425 if (player:IsSuperAdmin()) then
1426 return true;
1427 end;
1428 elseif (flag == "a") then
1429 if (player:IsAdmin()) then
1430 return true;
1431 end;
1432 elseif (flag == "o") then
1433 if (player:IsSuperAdmin() or player:IsAdmin()) then
1434 return true;
1435 elseif (player:IsUserGroup("operator")) then
1436 return true;
1437 end;
1438 elseif (string.find(playerFlags, flag)) then
1439 return true;
1440 end;
1441 end;
1442 end;
1443 end;
1444end;
1445
1446-- A function to check if a player has flags.
1447function Clockwork.player:HasFlags(player, flags, bByDefault)
1448 if (player:GetCharacter()) then
1449 local playerFlags = player:GetFlags();
1450
1451 if (Clockwork.class:HasFlags(player:Team(), flags) and !bByDefault) then
1452 return true;
1453 end;
1454
1455 for i = 1, #flags do
1456 local flag = string.sub(flags, i, i);
1457 local bSuccess;
1458
1459 if (!bByDefault) then
1460 local hasFlag = Clockwork.plugin:Call("PlayerDoesHaveFlag", player, flag);
1461
1462 if (hasFlag != false) then
1463 if (hasFlag) then
1464 bSuccess = true;
1465 end;
1466 else
1467 return;
1468 end;
1469 end;
1470
1471 if (!bSuccess) then
1472 if (flag == "s") then
1473 if (!player:IsSuperAdmin()) then
1474 return;
1475 end;
1476 elseif (flag == "a") then
1477 if (!player:IsAdmin()) then
1478 return;
1479 end;
1480 elseif (flag == "o") then
1481 if (!player:IsSuperAdmin() and !player:IsAdmin()) then
1482 if (!player:IsUserGroup("operator")) then
1483 return;
1484 end;
1485 end;
1486 elseif (!string.find(playerFlags, flag)) then
1487 return;
1488 end;
1489 end;
1490 end;
1491
1492 return true;
1493 end;
1494end;
1495
1496-- A function to use a player's death code.
1497function Clockwork.player:UseDeathCode(player, commandTable, arguments)
1498 Clockwork.plugin:Call("PlayerDeathCodeUsed", player, commandTable, arguments);
1499
1500 self:TakeDeathCode(player);
1501end;
1502
1503-- A function to get whether a player has a death code.
1504function Clockwork.player:GetDeathCode(player, authenticated)
1505 if (player.cwDeathCodeIdx and (!authenticated or player.cwDeathCodeAuth)) then
1506 return player.cwDeathCodeIdx;
1507 end;
1508end;
1509
1510-- A function to take a player's death code.
1511function Clockwork.player:TakeDeathCode(player)
1512 player.cwDeathCodeAuth = nil;
1513 player.cwDeathCodeIdx = nil;
1514end;
1515
1516-- A function to give a player their death code.
1517function Clockwork.player:GiveDeathCode(player)
1518 player.cwDeathCodeIdx = math.random(0, 99999);
1519 player.cwDeathCodeAuth = nil;
1520
1521 Clockwork.datastream:Start(player, "ChatBoxDeathCode", player.cwDeathCodeIdx);
1522end;
1523
1524-- A function to take a door from a player.
1525function Clockwork.player:TakeDoor(player, door, bForce, bThisDoorOnly, bChildrenOnly)
1526 local doorCost = Clockwork.config:Get("door_cost"):Get();
1527
1528 if (!bThisDoorOnly) then
1529 local doorParent = Clockwork.entity:GetDoorParent(door);
1530
1531 if (!doorParent or bChildrenOnly) then
1532 for k, v in pairs(Clockwork.entity:GetDoorChildren(door)) do
1533 if (IsValid(v)) then
1534 self:TakeDoor(player, v, true, true);
1535 end;
1536 end;
1537 else
1538 return self:TakeDoor(player, doorParent, bForce);
1539 end;
1540 end;
1541
1542 if (Clockwork.plugin:Call("PlayerCanUnlockEntity", player, door)) then
1543 door:Fire("Unlock", "", 0);
1544 door:EmitSound("doors/door_latch3.wav");
1545 end;
1546
1547 Clockwork.entity:SetDoorText(door, false);
1548 self:TakeProperty(player, door);
1549
1550 Clockwork.plugin:Call("PlayerDoorTaken", player, door)
1551
1552 if (door:GetClass() == "prop_dynamic") then
1553 if (!door:IsMapEntity()) then
1554 door:Remove();
1555 end;
1556 end;
1557
1558 if (!force and doorCost > 0) then
1559 self:GiveCash(player, doorCost / 2, "selling a door");
1560 end;
1561end;
1562
1563-- A function to make a player say text as a radio broadcast.
1564function Clockwork.player:SayRadio(player, text, check, noEavesdrop)
1565 local eavesdroppers = {};
1566 local listeners = {};
1567 local canRadio = true;
1568 local info = {listeners = {}, noEavesdrop = noEavesdrop, text = text};
1569
1570 Clockwork.plugin:Call("PlayerAdjustRadioInfo", player, info);
1571
1572 for k, v in pairs(info.listeners) do
1573 if (type(k) == "Player") then
1574 listeners[k] = k;
1575 elseif (type(v) == "Player") then
1576 listeners[v] = v;
1577 end;
1578 end;
1579
1580 if (!info.noEavesdrop) then
1581 local playerList = _player.GetAll();
1582
1583 for k, v in pairs(playerList) do
1584 if (v:HasInitialized() and !listeners[v]) then
1585 if (v:GetShootPos():Distance(player:GetShootPos()) <= Clockwork.config:Get("talk_radius"):Get()) then
1586 eavesdroppers[v] = v;
1587 end;
1588 end;
1589 end;
1590 end;
1591
1592 if (check) then
1593 canRadio = Clockwork.plugin:Call("PlayerCanRadio", player, info.text, listeners, eavesdroppers);
1594 end;
1595
1596 if (canRadio) then
1597 info = Clockwork.chatBox:Add(listeners, player, "radio", info.text);
1598
1599 if (info and IsValid(info.speaker)) then
1600 Clockwork.chatBox:Add(eavesdroppers, info.speaker, "radio_eavesdrop", info.text);
1601
1602 Clockwork.plugin:Call("PlayerRadioUsed", player, info.text, listeners, eavesdroppers);
1603 end;
1604 end;
1605end;
1606
1607-- A function to get a player's faction table.
1608function Clockwork.player:GetFactionTable(player)
1609 return Clockwork.faction.stored[player:GetFaction()];
1610end;
1611
1612-- A function to give a door to a player.
1613function Clockwork.player:GiveDoor(player, door, name, unsellable, override)
1614 if (Clockwork.entity:IsDoor(door)) then
1615 local doorParent = Clockwork.entity:GetDoorParent(door);
1616
1617 if (doorParent and !override) then
1618 self:GiveDoor(player, doorParent, name, unsellable);
1619 else
1620 for k, v in pairs(Clockwork.entity:GetDoorChildren(door)) do
1621 if (IsValid(v)) then
1622 self:GiveDoor(player, v, name, unsellable, true);
1623 end;
1624 end;
1625
1626 door.unsellable = unsellable;
1627 door.accessList = {};
1628
1629 Clockwork.entity:SetDoorText(door, name or "A purchased door.");
1630 self:GiveProperty(player, door, true);
1631
1632 Clockwork.plugin:Call("PlayerDoorGiven", player, door)
1633
1634 if (Clockwork.plugin:Call("PlayerCanUnlockEntity", player, door)) then
1635 door:EmitSound("doors/door_latch3.wav");
1636 door:Fire("Unlock", "", 0);
1637 end;
1638 end;
1639 end;
1640end;
1641
1642-- A function to get a player's real trace.
1643function Clockwork.player:GetRealTrace(player, useFilterTrace)
1644 local eyePos = player:EyePos();
1645 local trace = player:GetEyeTraceNoCursor();
1646
1647 local newTrace = util.TraceLine({
1648 endpos = eyePos + (player:GetAimVector() * 4096),
1649 filter = player,
1650 start = eyePos,
1651 mask = CONTENTS_SOLID + CONTENTS_MOVEABLE + CONTENTS_OPAQUE + CONTENTS_DEBRIS + CONTENTS_HITBOX + CONTENTS_MONSTER
1652 });
1653
1654 if ((IsValid(newTrace.Entity) and (!IsValid(trace.Entity)
1655 or trace.Entity:IsVehicle()) and !newTrace.HitWorld) or useFilterTrace) then
1656 trace = newTrace;
1657 end;
1658
1659 return trace;
1660end;
1661
1662-- A function to check if a player recognises another player.
1663function Clockwork.player:DoesRecognise(player, target, status, isAccurate)
1664 if (!status) then
1665 return self:DoesRecognise(player, target, RECOGNISE_PARTIAL);
1666 elseif (Clockwork.config:Get("recognise_system"):Get()) then
1667 local recognisedNames = player:GetRecognisedNames();
1668 local realValue = false;
1669 local key = target:GetCharacterKey();
1670
1671 if (recognisedNames and recognisedNames[key]) then
1672 if (isAccurate) then
1673 realValue = (recognisedNames[key] == status);
1674 else
1675 realValue = (recognisedNames[key] >= status);
1676 end;
1677 end;
1678
1679 return Clockwork.plugin:Call("PlayerDoesRecognisePlayer", player, target, status, isAccurate, realValue);
1680 else
1681 return true;
1682 end;
1683end;
1684
1685-- A function to send a player a creation fault.
1686function Clockwork.player:SetCreateFault(player, fault)
1687 if (!fault) then
1688 fault = "There has been an unknown error, please contact the administrator!";
1689 end;
1690
1691 Clockwork.datastream:Start(player, "CharacterFinish", {bSuccess = false, fault = fault});
1692end;
1693
1694-- A function to force a player to delete a character.
1695function Clockwork.player:ForceDeleteCharacter(player, characterID)
1696 local charactersTable = Clockwork.config:Get("mysql_characters_table"):Get();
1697 local schemaFolder = Clockwork.kernel:GetSchemaFolder();
1698 local character = player.cwCharacterList[characterID];
1699
1700 if (character) then
1701 local queryObj = Clockwork.database:Delete(charactersTable);
1702 queryObj:AddWhere("_Schema = ?", schemaFolder);
1703 queryObj:AddWhere("_SteamID = ?", player:SteamID());
1704 queryObj:AddWhere("_CharacterID = ?", characterID);
1705 queryObj:Push();
1706
1707 if (!Clockwork.plugin:Call("PlayerDeleteCharacter", player, character)) then
1708 Clockwork.kernel:PrintLog(LOGTYPE_GENERIC, player:SteamName().." has deleted the character '"..character.name.."'.");
1709 end;
1710
1711 player.cwCharacterList[characterID] = nil;
1712
1713 Clockwork.datastream:Start(player, "CharacterRemove", characterID);
1714 end;
1715end;
1716
1717-- A function to delete a player's character.
1718function Clockwork.player:DeleteCharacter(player, characterID)
1719 local character = player.cwCharacterList[characterID];
1720
1721 if (character) then
1722 if (player:GetCharacter() != character) then
1723 local fault = Clockwork.plugin:Call("PlayerCanDeleteCharacter", player, character);
1724
1725 if (fault == nil or fault == true) then
1726 self:ForceDeleteCharacter(player, characterID);
1727
1728 return true;
1729 elseif (type(fault) != "string") then
1730 return false, "You cannot delete this character!";
1731 else
1732 return false, fault;
1733 end;
1734 else
1735 return false, "You cannot delete the character you are using!";
1736 end;
1737 else
1738 return false, "This character does not exist!";
1739 end;
1740end;
1741
1742-- A function to use a player's character.
1743function Clockwork.player:UseCharacter(player, characterID)
1744 local isCharacterMenuReset = player:IsCharacterMenuReset();
1745 local currentCharacter = player:GetCharacter();
1746 local character = player.cwCharacterList[characterID];
1747
1748 if (!character) then
1749 return false, "This character does not exist!";
1750 end;
1751
1752 if (currentCharacter != character or isCharacterMenuReset) then
1753 local factionTable = Clockwork.faction:FindByID(character.faction);
1754 local fault = Clockwork.plugin:Call("PlayerCanUseCharacter", player, character);
1755
1756 if (fault == nil or fault == true) then
1757 local players = #Clockwork.faction:GetPlayers(character.faction);
1758 local limit = Clockwork.faction:GetLimit(factionTable.name);
1759
1760 if (isCharacterMenuReset and character.faction == currentCharacter.faction) then
1761 players = players - 1;
1762 end;
1763
1764 if (Clockwork.plugin:Call("PlayerCanBypassFactionLimit", player, character)) then
1765 limit = nil;
1766 end;
1767
1768 if (limit and players == limit) then
1769 return false, "The "..character.faction.." faction is full ("..limit.."/"..limit..")!";
1770 else
1771 if (currentCharacter) then
1772 local fault = Clockwork.plugin:Call("PlayerCanSwitchCharacter", player, character);
1773
1774 if (fault != nil and fault != true) then
1775 return false, fault or "You cannot switch to this character!";
1776 end;
1777 end;
1778
1779 Clockwork.kernel:PrintLog(LOGTYPE_GENERIC, player:SteamName().." has loaded the character '"..character.name.."'.");
1780
1781 if (isCharacterMenuReset) then
1782 player.cwCharMenuReset = false;
1783 player:Spawn();
1784 else
1785 self:LoadCharacter(player, characterID);
1786 end;
1787
1788 return true;
1789 end;
1790 else
1791 return false, fault or "You cannot use this character!";
1792 end;
1793 else
1794 return false, "You are already using this character!";
1795 end;
1796end;
1797
1798-- A function to get a player's character.
1799function Clockwork.player:GetCharacter(player)
1800 return player.cwCharacter;
1801end;
1802
1803-- A function to get a player's unrecognised name.
1804function Clockwork.player:GetUnrecognisedName(player, bFormatted)
1805 local unrecognisedPhysDesc = self:GetPhysDesc(player);
1806 local unrecognisedName = Clockwork.config:Get("unrecognised_name"):Get();
1807 local usedPhysDesc = false;
1808
1809 if (unrecognisedPhysDesc != "") then
1810 unrecognisedName = unrecognisedPhysDesc;
1811 usedPhysDesc = true;
1812 end;
1813
1814 if (bFormatted) then
1815 if (string.len(unrecognisedName) > 24) then
1816 unrecognisedName = string.sub(unrecognisedName, 1, 21).."...";
1817 end;
1818
1819 unrecognisedName = "["..unrecognisedName.."]";
1820 end;
1821
1822 return unrecognisedName, usedPhysDesc;
1823end;
1824
1825-- A function to format text based on a relationship.
1826function Clockwork.player:FormatRecognisedText(player, text, ...)
1827 local arguments = {...};
1828
1829 for i = 1, #arguments do
1830 if (string.find(text, "%%s") and IsValid(arguments[i])) then
1831 local unrecognisedName = "["..self:GetUnrecognisedName(arguments[i]).."]";
1832
1833 if (self:DoesRecognise(player, arguments[i])) then
1834 unrecognisedName = arguments[i]:Name();
1835 end;
1836
1837 text = string.gsub(text, "%%s", unrecognisedName, 1);
1838 end;
1839 end;
1840
1841 return text;
1842end;
1843
1844-- A function to restore a recognised name.
1845function Clockwork.player:RestoreRecognisedName(player, target)
1846 local recognisedNames = player:GetRecognisedNames();
1847 local key = target:GetCharacterKey();
1848
1849 if (recognisedNames[key]) then
1850 if (Clockwork.plugin:Call("PlayerCanRestoreRecognisedName", player, target)) then
1851 self:SetRecognises(player, target, recognisedNames[key], true);
1852 else
1853 recognisedNames[key] = nil;
1854 end;
1855 end;
1856end;
1857
1858-- A function to restore a player's recognised names.
1859function Clockwork.player:RestoreRecognisedNames(player)
1860 Clockwork.datastream:Start(player, "ClearRecognisedNames", true);
1861
1862 if (Clockwork.config:Get("save_recognised_names"):Get()) then
1863 local playerList = _player.GetAll();
1864
1865 for k, v in pairs(playerList) do
1866 if (v:HasInitialized()) then
1867 self:RestoreRecognisedName(player, v);
1868 self:RestoreRecognisedName(v, player);
1869 end;
1870 end;
1871 end;
1872end;
1873
1874-- A function to set whether a player recognises a player.
1875function Clockwork.player:SetRecognises(player, target, status, bForce)
1876 local recognisedNames = player:GetRecognisedNames();
1877 local name = target:Name();
1878 local key = target:GetCharacterKey();
1879
1880 --[[ I have no idea why this would happen. --]]
1881 if (key == nil) then return end;
1882
1883 if (status == RECOGNISE_SAVE) then
1884 if (Clockwork.config:Get("save_recognised_names"):Get()) then
1885 if (!Clockwork.plugin:Call("PlayerCanSaveRecognisedName", player, target)) then
1886 status = RECOGNISE_TOTAL;
1887 end;
1888 else
1889 status = RECOGNISE_TOTAL;
1890 end;
1891 end;
1892
1893 if (!status or bForce or !self:DoesRecognise(player, target, status)) then
1894 recognisedNames[key] = status or nil;
1895
1896 Clockwork.datastream:Start(player, "RecognisedName", {
1897 key = key, status = (status or 0)
1898 });
1899 end;
1900end;
1901
1902-- A function to get a player's physical description.
1903function Clockwork.player:GetPhysDesc(player)
1904 local physDesc = player:GetDTString(1);
1905 local team = player:Team();
1906
1907 if (physDesc == "") then
1908 physDesc = Clockwork.class:Query(team, "defaultPhysDesc", "");
1909 end;
1910
1911 if (physDesc == "") then
1912 physDesc = Clockwork.config:Get("default_physdesc"):Get();
1913 end;
1914
1915 if (!physDesc or physDesc == "") then
1916 physDesc = "This character has no physical description set.";
1917 else
1918 physDesc = Clockwork.kernel:ModifyPhysDesc(physDesc);
1919 end;
1920
1921 local override = Clockwork.plugin:Call("GetPlayerPhysDescOverride", player, physDesc);
1922
1923 if (override) then
1924 physDesc = override;
1925 end;
1926
1927 return physDesc;
1928end;
1929
1930-- A function to clear a player's recognised names list.
1931function Clockwork.player:ClearRecognisedNames(player, status, isAccurate)
1932 if (!status) then
1933 local character = player:GetCharacter();
1934
1935 if (character) then
1936 character.recognisedNames = {};
1937
1938 Clockwork.datastream:Start(player, "ClearRecognisedNames", true);
1939 end;
1940 else
1941 local playerList = _player.GetAll();
1942
1943 for k, v in pairs(playerList) do
1944 if (v:HasInitialized()) then
1945 if (self:DoesRecognise(player, v, status, isAccurate)) then
1946 self:SetRecognises(player, v, false);
1947 end;
1948 end;
1949 end;
1950 end;
1951
1952 Clockwork.plugin:Call("PlayerRecognisedNamesCleared", player, status, isAccurate);
1953end;
1954
1955-- A function to clear a player's name from being recognised.
1956function Clockwork.player:ClearName(player, status, isAccurate)
1957 local playerList = _player.GetAll();
1958
1959 for k, v in pairs(playerList) do
1960 if (v:HasInitialized()) then
1961 if (!status or self:DoesRecognise(v, player, status, isAccurate)) then
1962 self:SetRecognises(v, player, false);
1963 end;
1964 end;
1965 end;
1966
1967 Clockwork.plugin:Call("PlayerNameCleared", player, status, isAccurate);
1968end;
1969
1970-- A function to holsters all of a player's weapons.
1971function Clockwork.player:HolsterAll(player)
1972 for k, v in pairs(player:GetWeapons()) do
1973 local class = v:GetClass();
1974 local itemTable = Clockwork.item:GetByWeapon(v);
1975
1976 if (itemTable and Clockwork.plugin:Call("PlayerCanHolsterWeapon", player, itemTable, v, true, true)) then
1977 Clockwork.plugin:Call("PlayerHolsterWeapon", player, itemTable, v, true);
1978 player:StripWeapon(class);
1979 player:GiveItem(itemTable, true);
1980 end;
1981 end;
1982
1983 player:SelectWeapon("cw_hands");
1984end;
1985
1986-- A function to set a shared variable for a player.
1987function Clockwork.player:SetSharedVar(player, key, value)
1988 if (IsValid(player)) then
1989 local sharedVars = Clockwork.kernel:GetSharedVars():Player();
1990
1991 if (!sharedVars or !sharedVars[key]) then
1992 player:SetNetworkedVar(key, value);
1993 return;
1994 end;
1995
1996 local sharedVarData = sharedVars[key];
1997
1998 if (sharedVarData.bPlayerOnly) then
1999 local realValue = value;
2000
2001 if (value == nil) then
2002 realValue = Clockwork.kernel:GetDefaultNetworkedValue(sharedVarData.class);
2003 end;
2004
2005 if (player.cwSharedVars[key] != realValue) then
2006 player.cwSharedVars[key] = realValue;
2007
2008 Clockwork.datastream:Start(player, "SharedVar", {key = key, value = realValue});
2009 end;
2010 else
2011 local class = Clockwork.kernel:ConvertNetworkedClass(sharedVarData.class);
2012
2013 player.cwNetworkedVars = player.cwNetworkedVars or {};
2014
2015 if (class) then
2016 if (value == nil) then
2017 value = Clockwork.kernel:GetDefaultClassValue(class);
2018 end;
2019
2020 if (player.cwNetworkedVars[key] != value) then
2021 player.cwNetworkedVars[key] = value;
2022
2023 if (player["SetNW"..class.."2"]) then
2024 player["SetNW"..class.."2"](player, key, value);
2025 else
2026 player["SetNW"..class](player, key, value);
2027 end;
2028 end;
2029 else
2030 player:SetNetworkedVar(key, value);
2031 end;
2032 end;
2033 end;
2034end;
2035
2036-- A function to get a player's shared variable.
2037function Clockwork.player:GetSharedVar(player, key)
2038 if (IsValid(player)) then
2039 local sharedVars = Clockwork.kernel:GetSharedVars():Player();
2040
2041 if (!sharedVars or !sharedVars[key]) then
2042 return player:GetNetworkedVar(key);
2043 end;
2044
2045 local sharedVarData = sharedVars[key];
2046
2047 if (sharedVarData.bPlayerOnly) then
2048 if (!player.cwSharedVars[key]) then
2049 return Clockwork.kernel:GetDefaultNetworkedValue(sharedVarData.class);
2050 else
2051 return player.cwSharedVars[key];
2052 end;
2053 else
2054 local class = Clockwork.kernel:ConvertNetworkedClass(sharedVarData.class);
2055
2056 player.cwNetworkedVars = player.cwNetworkedVars or {};
2057
2058 if (class) then
2059 if (player.cwNetworkedVars[key] == nil) then
2060 return Clockwork.kernel:GetDefaultNetworkedValue(sharedVarData.class);
2061 end;
2062 end;
2063
2064 return player.cwNetworkedVars[key];
2065 end;
2066 end;
2067end;
2068
2069-- A function to set whether a player's character is banned.
2070function Clockwork.player:SetBanned(player, banned)
2071 player:SetCharacterData("CharBanned", banned);
2072 player:SaveCharacter();
2073 player:SetSharedVar("CharBanned", banned);
2074end;
2075
2076-- A function to set a player's name.
2077function Clockwork.player:SetName(player, name, saveless)
2078 local previousName = player:Name();
2079 local newName = name;
2080
2081 player:SetCharacterData("Name", newName, true);
2082 player:SetDTString(0, newName);
2083
2084 if (!player.cwFirstSpawn) then
2085 Clockwork.plugin:Call("PlayerNameChanged", player, previousName, newName);
2086 end;
2087
2088 if (!saveless) then
2089 player:SaveCharacter();
2090 end;
2091end;
2092
2093-- A function to get a player's generator count.
2094function Clockwork.player:GetGeneratorCount(player)
2095 local generators = Clockwork.generator:GetAll();
2096 local count = 0;
2097
2098 for k, v in pairs(generators) do
2099 count = count + self:GetPropertyCount(player, k);
2100 end;
2101
2102 return count;
2103end;
2104
2105-- A function to get a player's property entities.
2106function Clockwork.player:GetPropertyEntities(player, class)
2107 local uniqueID = player:UniqueID();
2108 local entities = {};
2109 local key = player:GetCharacterKey();
2110
2111 for k, v in pairs(self:GetAllProperty()) do
2112 if (uniqueID == Clockwork.entity:QueryProperty(v, "uniqueID")) then
2113 if (key == Clockwork.entity:QueryProperty(v, "key")) then
2114 if (!class or v:GetClass() == class) then
2115 entities[#entities + 1] = v;
2116 end;
2117 end;
2118 end;
2119 end;
2120
2121 return entities;
2122end;
2123
2124-- A function to get a player's property count.
2125function Clockwork.player:GetPropertyCount(player, class)
2126 local uniqueID = player:UniqueID();
2127 local count = 0;
2128 local key = player:GetCharacterKey();
2129
2130 for k, v in pairs(self:GetAllProperty()) do
2131 if (uniqueID == Clockwork.entity:QueryProperty(v, "uniqueID")) then
2132 if (key == Clockwork.entity:QueryProperty(v, "key")) then
2133 if (!class or v:GetClass() == class) then
2134 count = count + 1;
2135 end;
2136 end;
2137 end;
2138 end;
2139
2140 return count;
2141end;
2142
2143-- A function to get a player's door count.
2144function Clockwork.player:GetDoorCount(player)
2145 local uniqueID = player:UniqueID();
2146 local count = 0;
2147 local key = player:GetCharacterKey();
2148
2149 for k, v in pairs(self:GetAllProperty()) do
2150 if (Clockwork.entity:IsDoor(v) and !Clockwork.entity:GetDoorParent(v)) then
2151 if (uniqueID == Clockwork.entity:QueryProperty(v, "uniqueID")) then
2152 if (player:GetCharacterKey() == Clockwork.entity:QueryProperty(v, "key")) then
2153 count = count + 1;
2154 end;
2155 end;
2156 end;
2157 end;
2158
2159 return count;
2160end;
2161
2162-- A function to take a player's door access.
2163function Clockwork.player:TakeDoorAccess(player, door)
2164 if (door.accessList) then
2165 door.accessList[player:GetCharacterKey()] = false;
2166 end;
2167end;
2168
2169-- A function to give a player door access.
2170function Clockwork.player:GiveDoorAccess(player, door, access)
2171 local key = player:GetCharacterKey();
2172
2173 if (!door.accessList) then
2174 door.accessList = {
2175 [key] = access
2176 };
2177 else
2178 door.accessList[key] = access;
2179 end;
2180end;
2181
2182-- A function to check if a player has door access.
2183function Clockwork.player:HasDoorAccess(player, door, access, isAccurate)
2184 if (!access) then
2185 return self:HasDoorAccess(player, door, DOOR_ACCESS_BASIC, isAccurate);
2186 else
2187 local doorParent = Clockwork.entity:GetDoorParent(door);
2188 local key = player:GetCharacterKey();
2189
2190 if (doorParent and Clockwork.entity:DoorHasSharedAccess(doorParent)
2191 and (!door.accessList or door.accessList[key] == nil)) then
2192 return Clockwork.plugin:Call("PlayerDoesHaveDoorAccess", player, doorParent, access, isAccurate);
2193 else
2194 return Clockwork.plugin:Call("PlayerDoesHaveDoorAccess", player, door, access, isAccurate);
2195 end;
2196 end;
2197end;
2198
2199-- A function to check if a player can afford an amount.
2200function Clockwork.player:CanAfford(player, amount)
2201 if (Clockwork.config:Get("cash_enabled"):Get()) then
2202 return (player:GetCash() >= amount);
2203 else
2204 return true;
2205 end;
2206end;
2207
2208-- A function to give a player an amount of cash.
2209function Clockwork.player:GiveCash(player, amount, reason, bNoMsg)
2210 if (Clockwork.config:Get("cash_enabled"):Get()) then
2211 local positiveHintColor = "positive_hint";
2212 local negativeHintColor = "negative_hint";
2213 local roundedAmount = math.Round(amount);
2214 local cash = math.Round(math.max(player:GetCash() + roundedAmount, 0));
2215
2216 player:SetCharacterData("Cash", cash, true);
2217 player:SetSharedVar("Cash", cash);
2218
2219 if (roundedAmount < 0) then
2220 roundedAmount = math.abs(roundedAmount);
2221
2222 if (!bNoMsg) then
2223 if (reason) then
2224 Clockwork.hint:Send(
2225 player, "Your character has lost the sum of "..Clockwork.kernel:FormatCash(roundedAmount).." ("..reason..").", 4, negativeHintColor
2226 );
2227 else
2228 Clockwork.hint:Send(
2229 player, "Your character has lost the sum of "..Clockwork.kernel:FormatCash(roundedAmount)..".", 4, negativeHintColor
2230 );
2231 end;
2232 end;
2233 elseif (roundedAmount > 0) then
2234 if (!bNoMsg) then
2235 if (reason) then
2236 Clockwork.hint:Send(
2237 player, "Your character has gained the sum of "..Clockwork.kernel:FormatCash(roundedAmount).." ("..reason..").", 4, positiveHintColor
2238 );
2239 else
2240 Clockwork.hint:Send(
2241 player, "Your character has gained the sum of "..Clockwork.kernel:FormatCash(roundedAmount)..".", 4, positiveHintColor
2242 );
2243 end;
2244 end;
2245 end;
2246
2247 Clockwork.plugin:Call("PlayerCashUpdated", player, roundedAmount, reason, bNoMsg);
2248 end;
2249end;
2250
2251-- A function to show cinematic text to a player.
2252function Clockwork.player:CinematicText(player, text, color, barLength, hangTime)
2253 Clockwork.datastream:Start(player, "CinematicText", {
2254 text = text,
2255 color = color,
2256 barLength = barLength,
2257 hangTime = hangTime
2258 });
2259end;
2260
2261-- A function to show cinematic text to each player.
2262function Clockwork.player:CinematicTextAll(text, color, hangTime)
2263 local playerList = _player.GetAll();
2264
2265 for k, v in pairs(playerList) do
2266 if (v:HasInitialized()) then
2267 self:CinematicText(v, text, color, hangTime);
2268 end;
2269 end;
2270end;
2271
2272-- A function to find a player by an identifier.
2273function Clockwork.player:FindByID(identifier)
2274 local playerList = _player.GetAll();
2275
2276 for k, v in pairs(playerList) do
2277 if (v:HasInitialized() and (v:SteamID() == identifier or v:UniqueID() == identifier
2278 or string.find(string.lower(v:Name()), string.lower(identifier), 1, true))) then
2279 return v;
2280 end;
2281 end;
2282end;
2283
2284-- A function to get if a player is protected.
2285function Clockwork.player:IsProtected(identifier)
2286 local steamID = nil;
2287 local ownerSteamID = Clockwork.config:Get("owner_steamid"):Get();
2288 local bSuccess, value = pcall(IsValid, identifier);
2289
2290 if (!bSuccess or value == false) then
2291 local playerObj = self:FindByID(identifier);
2292
2293 if (IsValid(playerObj)) then
2294 steamID = playerObj:SteamID();
2295 end;
2296 else
2297 steamID = identifier:SteamID();
2298 end;
2299
2300 if (steamID and steamID == ownerSteamID) then
2301 return true;
2302 end;
2303
2304 return false;
2305end;
2306
2307-- A function to notify each player in a radius.
2308function Clockwork.player:NotifyInRadius(text, class, position, radius)
2309 local listeners = {};
2310 local playerList = _player.GetAll();
2311
2312 for k, v in pairs(playerList) do
2313 if (v:HasInitialized()) then
2314 if (position:Distance(v:GetPos()) <= radius) then
2315 listeners[#listeners + 1] = v;
2316 end;
2317 end;
2318 end;
2319
2320 self:Notify(listeners, text, class);
2321end;
2322
2323-- A function to notify each player.
2324function Clockwork.player:NotifyAll(text, class)
2325 self:Notify(nil, text, true);
2326end;
2327
2328-- A function to notify a player.
2329function Clockwork.player:Notify(player, text, class)
2330 if (type(player) == "table") then
2331 for k, v in pairs(player) do
2332 self:Notify(v, text, class);
2333 end;
2334 elseif (class == true) then
2335 Clockwork.chatBox:Add(player, nil, "notify_all", text);
2336 elseif (!class) then
2337 Clockwork.chatBox:Add(player, nil, "notify", text);
2338 else
2339 Clockwork.datastream:Start(player, "Notification", {text = text, class = class});
2340 end;
2341end;
2342
2343Clockwork.player:AddToMetaTable("Player", "Notify");
2344
2345-- A function to set a player's weapons list from a table.
2346function Clockwork.player:SetWeapons(player, weapons, bForceReturn)
2347 for k, v in pairs(weapons) do
2348 if (!player:HasWeapon(v.weaponData["class"])) then
2349 if (!v.teamIndex or player:Team() == v.teamIndex) then
2350 player:Give(
2351 v.weaponData["class"], v.weaponData["itemTable"], bForceReturn
2352 );
2353 end;
2354 end;
2355 end;
2356end;
2357
2358-- A function to give ammo to a player from a table.
2359function Clockwork.player:GiveAmmo(player, ammo)
2360 for k, v in pairs(ammo) do player:GiveAmmo(v, k); end;
2361end;
2362
2363-- A function to set a player's ammo list from a table.
2364function Clockwork.player:SetAmmo(player, ammo)
2365 for k, v in pairs(ammo) do player:SetAmmo(v, k); end;
2366end;
2367
2368-- A function to get a player's ammo list as a table.
2369function Clockwork.player:GetAmmo(player, bDoStrip)
2370 local spawnAmmo = self:GetSpawnAmmo(player);
2371 local ammo = {
2372 ["sniperpenetratedround"] = player:GetAmmoCount("sniperpenetratedround"),
2373 ["striderminigun"] = player:GetAmmoCount("striderminigun"),
2374 ["helicoptergun"] = player:GetAmmoCount("helicoptergun"),
2375 ["combinecannon"] = player:GetAmmoCount("combinecannon"),
2376 ["smg1_grenade"] = player:GetAmmoCount("smg1_grenade"),
2377 ["gaussenergy"] = player:GetAmmoCount("gaussenergy"),
2378 ["sniperround"] = player:GetAmmoCount("sniperround"),
2379 ["airboatgun"] = player:GetAmmoCount("airboatgun"),
2380 ["ar2altfire"] = player:GetAmmoCount("ar2altfire"),
2381 ["rpg_round"] = player:GetAmmoCount("rpg_round"),
2382 ["xbowbolt"] = player:GetAmmoCount("xbowbolt"),
2383 ["buckshot"] = player:GetAmmoCount("buckshot"),
2384 ["alyxgun"] = player:GetAmmoCount("alyxgun"),
2385 ["grenade"] = player:GetAmmoCount("grenade"),
2386 ["thumper"] = player:GetAmmoCount("thumper"),
2387 ["gravity"] = player:GetAmmoCount("gravity"),
2388 ["battery"] = player:GetAmmoCount("battery"),
2389 ["pistol"] = player:GetAmmoCount("pistol"),
2390 ["slam"] = player:GetAmmoCount("slam"),
2391 ["smg1"] = player:GetAmmoCount("smg1"),
2392 ["357"] = player:GetAmmoCount("357"),
2393 ["ar2"] = player:GetAmmoCount("ar2")
2394 };
2395
2396 Clockwork.plugin:Call("GetPlayerAmmo", player, ammo);
2397
2398 if (spawnAmmo) then
2399 for k, v in pairs(spawnAmmo) do
2400 if (ammo[k]) then
2401 ammo[k] = math.max(ammo[k] - v, 0);
2402 end;
2403 end;
2404 end;
2405
2406 if (bDoStrip) then
2407 player:RemoveAllAmmo();
2408 end;
2409
2410 return ammo;
2411end;
2412
2413-- A function to get a player's weapons list as a table.
2414function Clockwork.player:GetWeapons(player, bDoKeep)
2415 local weapons = {};
2416
2417 for k, v in pairs(player:GetWeapons()) do
2418 local itemTable = Clockwork.item:GetByWeapon(v);
2419 local teamIndex = player:Team();
2420 local class = v:GetClass();
2421
2422 if (!self:GetSpawnWeapon(player, class)) then
2423 teamIndex = nil;
2424 end;
2425
2426 weapons[#weapons + 1] = {
2427 weaponData = {
2428 itemTable = itemTable,
2429 class = class
2430 },
2431 teamIndex = teamIndex
2432 };
2433
2434 if (!bDoKeep) then
2435 player:StripWeapon(class);
2436 end;
2437 end;
2438
2439 return weapons;
2440end;
2441
2442-- A function to get the total weight of a player's equipped weapons.
2443function Clockwork.player:GetEquippedWeight(player)
2444 local weight = 0;
2445
2446 for k, v in pairs(player:GetWeapons()) do
2447 local itemTable = Clockwork.item:GetByWeapon(v);
2448
2449 if (itemTable) then
2450 weight = weight + itemTable("weight");
2451 end;
2452 end;
2453
2454 return weight;
2455end;
2456
2457-- A function to get the total space of a player's equipped weapons.
2458function Clockwork.player:GetEquippedSpace(player)
2459 local space = 0;
2460
2461 for k, v in pairs(player:GetWeapons()) do
2462 local itemTable = Clockwork.item:GetByWeapon(v);
2463
2464 if (itemTable) then
2465 space = space + itemTable("space");
2466 end;
2467 end;
2468
2469 return space;
2470end;
2471
2472-- A function to get a player's holstered weapon.
2473function Clockwork.player:GetHolsteredWeapon(player)
2474 for k, v in pairs(player:GetWeapons()) do
2475 local itemTable = Clockwork.item:GetByWeapon(v);
2476 local class = v:GetClass();
2477
2478 if (itemTable) then
2479 if (self:GetWeaponClass(player) != class) then
2480 return class;
2481 end;
2482 end;
2483 end;
2484end;
2485
2486-- A function to check whether a player is ragdolled.
2487function Clockwork.player:IsRagdolled(player, exception, bNoEntity)
2488 if (player:GetRagdollEntity() or bNoEntity) then
2489 local ragdolled = player:GetSharedVar("IsRagdoll");
2490
2491 if (ragdolled == exception) then
2492 return false;
2493 else
2494 return (ragdolled != RAGDOLL_NONE);
2495 end;
2496 end;
2497end;
2498
2499-- A function to set a player's unragdoll time.
2500function Clockwork.player:SetUnragdollTime(player, delay)
2501 player.cwRagdollPaused = nil;
2502
2503 if (delay) then
2504 self:SetAction(player, "unragdoll", delay, 2, function()
2505 if (IsValid(player) and player:Alive()) then
2506 self:SetRagdollState(player, RAGDOLL_NONE);
2507 end;
2508 end);
2509 else
2510 self:SetAction(player, "unragdoll", false);
2511 end;
2512end;
2513
2514-- A function to pause a player's unragdoll time.
2515function Clockwork.player:PauseUnragdollTime(player)
2516 if (!player.cwRagdollPaused) then
2517 local unragdollTime = self:GetUnragdollTime(player);
2518 local curTime = CurTime();
2519
2520 if (player:IsRagdolled()) then
2521 if (unragdollTime > 0) then
2522 player.cwRagdollPaused = unragdollTime - curTime;
2523 self:SetAction(player, "unragdoll", false);
2524 end;
2525 end;
2526 end;
2527end;
2528
2529-- A function to start a player's unragdoll time.
2530function Clockwork.player:StartUnragdollTime(player)
2531 if (player.cwRagdollPaused) then
2532 if (player:IsRagdolled()) then
2533 self:SetUnragdollTime(player, player.cwRagdollPaused);
2534
2535 player.cwRagdollPaused = nil;
2536 end;
2537 end;
2538end;
2539
2540-- A function to get a player's unragdoll time.
2541function Clockwork.player:GetUnragdollTime(player)
2542 local action, actionDuration, startActionTime = self:GetAction(player);
2543
2544 if (action == "unragdoll") then
2545 return startActionTime + actionDuration;
2546 else
2547 return 0;
2548 end;
2549end;
2550
2551-- A function to get a player's ragdoll state.
2552function Clockwork.player:GetRagdollState(player)
2553 return player:GetSharedVar("IsRagdoll");
2554end;
2555
2556-- A function to get a player's ragdoll entity.
2557function Clockwork.player:GetRagdollEntity(player)
2558 if (player.cwRagdollTab) then
2559 if (IsValid(player.cwRagdollTab.entity)) then
2560 return player.cwRagdollTab.entity;
2561 end;
2562 end;
2563end;
2564
2565-- A function to get a player's ragdoll table.
2566function Clockwork.player:GetRagdollTable(player)
2567 return player.cwRagdollTab;
2568end;
2569
2570-- A function to do a player's ragdoll decay check.
2571function Clockwork.player:DoRagdollDecayCheck(player, ragdoll)
2572 local index = ragdoll:EntIndex();
2573
2574 Clockwork.kernel:CreateTimer("DecayCheck"..index, 60, 0, function()
2575 local ragdollIsValid = IsValid(ragdoll);
2576 local playerIsValid = IsValid(player);
2577
2578 if (!playerIsValid and ragdollIsValid) then
2579 if (!Clockwork.entity:IsDecaying(ragdoll)) then
2580 local decayTime = Clockwork.config:Get("body_decay_time"):Get();
2581
2582 if (decayTime > 0 and Clockwork.plugin:Call("PlayerCanRagdollDecay", player, ragdoll, decayTime)) then
2583 Clockwork.entity:Decay(ragdoll, decayTime);
2584 end;
2585 else
2586 Clockwork.kernel:DestroyTimer("DecayCheck"..index);
2587 end;
2588 elseif (!ragdollIsValid) then
2589 Clockwork.kernel:DestroyTimer("DecayCheck"..index);
2590 end;
2591 end);
2592end;
2593
2594-- A function to set a player's ragdoll immunity.
2595function Clockwork.player:SetRagdollImmunity(player, delay)
2596 if (delay) then
2597 player:GetRagdollTable().immunity = CurTime() + delay;
2598 else
2599 player:GetRagdollTable().immunity = 0;
2600 end;
2601end;
2602
2603-- A function to set a player's ragdoll state.
2604function Clockwork.player:SetRagdollState(player, state, delay, decay, force, multiplier, velocityCallback)
2605 if (state == RAGDOLL_KNOCKEDOUT or state == RAGDOLL_FALLENOVER) then
2606 if (player:IsRagdolled()) then
2607 if (Clockwork.plugin:Call("PlayerCanRagdoll", player, state, delay, decay, player.cwRagdollTab)) then
2608 self:SetUnragdollTime(player, delay);
2609 player:SetSharedVar("IsRagdoll", state);
2610 player.cwRagdollTab.delay = delay;
2611 player.cwRagdollTab.decay = decay;
2612 Clockwork.plugin:Call("PlayerRagdolled", player, state, player.cwRagdollTab);
2613 end;
2614 elseif (Clockwork.plugin:Call("PlayerCanRagdoll", player, state, delay, decay)) then
2615 local velocity = player:GetVelocity() + (player:GetAimVector() * 128);
2616 local ragdoll = ents.Create("prop_ragdoll");
2617
2618 ragdoll:SetMaterial(player:GetMaterial());
2619 ragdoll:SetAngles(player:GetAngles());
2620 ragdoll:SetColor(player:GetColor());
2621 ragdoll:SetModel(player:GetModel());
2622 ragdoll:SetSkin(player:GetSkin());
2623 ragdoll:SetPos(player:GetPos());
2624 ragdoll:Spawn();
2625
2626 player.cwRagdollTab = {};
2627 player.cwRagdollTab.eyeAngles = player:EyeAngles();
2628 player.cwRagdollTab.immunity = CurTime() + Clockwork.config:Get("ragdoll_immunity_time"):Get();
2629 player.cwRagdollTab.moveType = MOVETYPE_WALK;
2630 player.cwRagdollTab.entity = ragdoll;
2631 player.cwRagdollTab.health = player:Health();
2632 player.cwRagdollTab.armor = player:Armor();
2633 player.cwRagdollTab.delay = delay;
2634 player.cwRagdollTab.decay = decay;
2635
2636 if (!player:IsOnGround()) then
2637 player.cwRagdollTab.immunity = 0;
2638 end;
2639
2640 if (IsValid(ragdoll)) then
2641 local headIndex = ragdoll:LookupBone("ValveBiped.Bip01_Head1");
2642
2643 ragdoll:SetCollisionGroup(COLLISION_GROUP_WEAPON);
2644
2645 for i = 1, ragdoll:GetPhysicsObjectCount() do
2646 local physicsObject = ragdoll:GetPhysicsObjectNum(i);
2647 local boneIndex = ragdoll:TranslatePhysBoneToBone(i);
2648 local position, angle = player:GetBonePosition(boneIndex);
2649
2650 if (IsValid(physicsObject)) then
2651 physicsObject:SetPos(position);
2652 physicsObject:SetAngles(angle);
2653
2654 if (!velocityCallback) then
2655 if (boneIndex == headIndex) then
2656 physicsObject:SetVelocity(velocity * 1.5);
2657 else
2658 physicsObject:SetVelocity(velocity);
2659 end;
2660
2661 if (force) then
2662 if (boneIndex == headIndex) then
2663 physicsObject:ApplyForceCenter(force * 1.5);
2664 else
2665 physicsObject:ApplyForceCenter(force);
2666 end;
2667 end;
2668 else
2669 velocityCallback(physicsObject, boneIndex, ragdoll, velocity, force);
2670 end;
2671 end;
2672 end;
2673 end;
2674
2675 if (player:Alive()) then
2676 if (IsValid(player:GetActiveWeapon())) then
2677 player.cwRagdollTab.weapon = self:GetWeaponClass(player);
2678 end;
2679
2680 player.cwRagdollTab.weapons = self:GetWeapons(player, true);
2681
2682 if (delay) then
2683 self:SetUnragdollTime(player, delay);
2684 end;
2685 end;
2686
2687 if (player:InVehicle()) then
2688 player:ExitVehicle();
2689 player.cwRagdollTab.eyeAngles = Angle(0, 0, 0);
2690 end;
2691
2692 if (player:IsOnFire()) then
2693 ragdoll:Ignite(8, 0);
2694 end;
2695
2696 player:Spectate(OBS_MODE_CHASE);
2697 player:RunCommand("-duck");
2698 player:RunCommand("-voicerecord");
2699 player:SetMoveType(MOVETYPE_OBSERVER);
2700 player:StripWeapons(true);
2701 player:SpectateEntity(ragdoll);
2702 player:CrosshairDisable();
2703
2704 if (player:FlashlightIsOn()) then
2705 player:Flashlight(false);
2706 end;
2707
2708 player.cwRagdollPaused = nil;
2709
2710 player:SetSharedVar("IsRagdoll", state);
2711 player:SetDTEntity(0, ragdoll);
2712
2713 if (state != RAGDOLL_FALLENOVER) then
2714 self:GiveDeathCode(player);
2715 end;
2716
2717 Clockwork.entity:SetPlayer(ragdoll, player);
2718 self:DoRagdollDecayCheck(player, ragdoll);
2719
2720 Clockwork.plugin:Call("PlayerRagdolled", player, state, player.cwRagdollTab);
2721 end;
2722 elseif (state == RAGDOLL_NONE or state == RAGDOLL_RESET) then
2723 if (player:IsRagdolled(nil, true)) then
2724 local ragdollTable = player:GetRagdollTable();
2725
2726 if (Clockwork.plugin:Call("PlayerCanUnragdoll", player, state, ragdollTable)) then
2727 player:UnSpectate();
2728 player:CrosshairEnable();
2729
2730 if (state != RAGDOLL_RESET) then
2731 self:LightSpawn(player, nil, nil, true);
2732 end;
2733
2734 if (state != RAGDOLL_RESET) then
2735 if (IsValid(ragdollTable.entity)) then
2736 local velocity = ragdollTable.entity:GetVelocity();
2737 local position = Clockwork.entity:GetPelvisPosition(ragdollTable.entity);
2738
2739 if (position) then
2740 self:SetSafePosition(player, position, ragdollTable.entity);
2741 end;
2742
2743 player:SetSkin(ragdollTable.entity:GetSkin());
2744 player:SetColor(ragdollTable.entity:GetColor());
2745 player:SetMaterial(ragdollTable.entity:GetMaterial());
2746
2747 if (!ragdollTable.model) then
2748 player:SetModel(ragdollTable.entity:GetModel());
2749 else
2750 player:SetModel(ragdollTable.model);
2751 end;
2752
2753 if (!ragdollTable.skin) then
2754 player:SetSkin(ragdollTable.entity:GetSkin());
2755 else
2756 player:SetSkin(ragdollTable.skin);
2757 end;
2758
2759 player:SetVelocity(velocity);
2760 end;
2761
2762 player:SetArmor(ragdollTable.armor);
2763 player:SetHealth(ragdollTable.health);
2764 player:SetMoveType(ragdollTable.moveType);
2765 player:SetEyeAngles(ragdollTable.eyeAngles);
2766 end;
2767
2768 if (IsValid(ragdollTable.entity)) then
2769 Clockwork.kernel:DestroyTimer("DecayCheck"..ragdollTable.entity:EntIndex());
2770
2771 if (ragdollTable.decay) then
2772 if (Clockwork.plugin:Call("PlayerCanRagdollDecay", player, ragdollTable.entity, ragdollTable.decay)) then
2773 Clockwork.entity:Decay(ragdollTable.entity, ragdollTable.decay);
2774 end;
2775 else
2776 ragdollTable.entity:Remove();
2777 end;
2778 end;
2779
2780 if (state != RAGDOLL_RESET) then
2781 self:SetWeapons(player, ragdollTable.weapons, true);
2782
2783 if (ragdollTable.weapon) then
2784 player:SelectWeapon(ragdollTable.weapon);
2785 end;
2786 end;
2787
2788 self:SetUnragdollTime(player, false);
2789 player:SetSharedVar("IsRagdoll", RAGDOLL_NONE);
2790 player:SetDTEntity(0, NULL);
2791 Clockwork.plugin:Call("PlayerUnragdolled", player, state, ragdollTable);
2792
2793 player.cwRagdollPaused = nil;
2794 player.cwRagdollTab = {};
2795 end;
2796 end;
2797 end;
2798end;
2799
2800-- A function to make a player drop their weapons.
2801function Clockwork.player:DropWeapons(player)
2802 local ragdollEntity = player:GetRagdollEntity();
2803
2804 if (player:IsRagdolled()) then
2805 local ragdollWeapons = player:GetRagdollWeapons();
2806
2807 for k, v in pairs(ragdollWeapons) do
2808 local itemTable = v.weaponData["itemTable"];
2809
2810 if (itemTable and Clockwork.plugin:Call("PlayerCanDropWeapon", player, itemTable, NULL, true)) then
2811 local info = {
2812 itemTable = itemTable,
2813 position = ragdollEntity:GetPos() + Vector(0, 0, math.random(1, 48)),
2814 angles = Angle(0, 0, 0)
2815 };
2816
2817 player:TakeItem(info.itemTable);
2818 ragdollWeapons[k] = nil;
2819
2820 if (Clockwork.plugin:Call("PlayerAdjustDropWeaponInfo", player, info)) then
2821 local entity = Clockwork.entity:CreateItem(player, info.itemTable, info.position, info.angles);
2822
2823 if (IsValid(entity)) then
2824 Clockwork.plugin:Call("PlayerDropWeapon", player, info.itemTable, entity, NULL);
2825 end;
2826 end;
2827 end;
2828 end;
2829 else
2830 for k, v in pairs(player:GetWeapons()) do
2831 local itemTable = Clockwork.item:GetByWeapon(v);
2832
2833 if (itemTable and Clockwork.plugin:Call("PlayerCanDropWeapon", player, itemTable, v, true)) then
2834 local info = {
2835 itemTable = itemTable,
2836 position = player:GetPos() + Vector(0, 0, math.random(1, 48)),
2837 angles = Angle(0, 0, 0)
2838 };
2839
2840 if (Clockwork.plugin:Call("PlayerAdjustDropWeaponInfo", player, info)) then
2841 local entity = Clockwork.entity:CreateItem(
2842 player, info.itemTable, info.position, info.angles
2843 );
2844
2845 if (IsValid(entity)) then
2846 Clockwork.plugin:Call("PlayerDropWeapon", player, info.itemTable, entity, v);
2847 player:StripWeapon(v:GetClass());
2848 player:TakeItem(info.itemTable, true);
2849 end;
2850 end;
2851 end;
2852 end;
2853 end;
2854end;
2855
2856-- A function to lightly spawn a player.
2857function Clockwork.player:LightSpawn(player, weapons, ammo, bForceReturn)
2858 if (player:IsRagdolled() and !bForceReturn) then
2859 self:SetRagdollState(player, RAGDOLL_NONE);
2860 end;
2861
2862 player.cwLightSpawn = true;
2863
2864 local moveType = player:GetMoveType();
2865 local material = player:GetMaterial();
2866 local position = player:GetPos();
2867 local angles = player:EyeAngles();
2868 local weapon = player:GetActiveWeapon();
2869 local health = player:Health();
2870 local armor = player:Armor();
2871 local model = player:GetModel();
2872 local color = player:GetColor();
2873 local skin = player:GetSkin();
2874
2875 if (ammo) then
2876 if (type(ammo) != "table") then
2877 ammo = self:GetAmmo(player, true);
2878 end;
2879 end;
2880
2881 if (weapons) then
2882 if (type(weapons) != "table") then
2883 weapons = self:GetWeapons(player);
2884 end;
2885
2886 if (IsValid(weapon)) then
2887 weapon = weapon:GetClass();
2888 end;
2889 end;
2890
2891 player.cwSpawnCallback = function(player, gamemodeHook)
2892 if (weapons) then
2893 Clockwork:PlayerLoadout(player);
2894
2895 self:SetWeapons(player, weapons, bForceReturn);
2896
2897 if (type(weapon) == "string") then
2898 player:SelectWeapon(weapon);
2899 end;
2900 end;
2901
2902 if (ammo) then
2903 self:GiveAmmo(player, ammo);
2904 end;
2905
2906 player:SetPos(position);
2907 player:SetSkin(skin);
2908 player:SetModel(model);
2909 player:SetColor(color);
2910 player:SetArmor(armor);
2911 player:SetHealth(health);
2912 player:SetMaterial(material);
2913 player:SetMoveType(moveType);
2914 player:SetEyeAngles(angles);
2915
2916 if (gamemodeHook) then
2917 special = special or false;
2918
2919 Clockwork.plugin:Call("PostPlayerLightSpawn", player, weapons, ammo, special);
2920 end;
2921
2922 player:ResetSequence(
2923 player:GetSequence()
2924 );
2925 end;
2926
2927 player:Spawn();
2928end;
2929
2930-- A function to convert a table to camel case.
2931function Clockwork.player:ConvertToCamelCase(baseTable)
2932 local newTable = {};
2933
2934 for k, v in pairs(baseTable) do
2935 local key = Clockwork.kernel:SetCamelCase(string.gsub(k, "_", ""), true);
2936
2937 if (key and key != "") then
2938 newTable[key] = v;
2939 end;
2940 end;
2941
2942 return newTable;
2943end;
2944
2945-- A function to get a player's characters.
2946function Clockwork.player:GetCharacters(player, Callback)
2947 if (!IsValid(player)) then return; end;
2948
2949 local charactersTable = Clockwork.config:Get("mysql_characters_table"):Get();
2950 local schemaFolder = Clockwork.kernel:GetSchemaFolder();
2951 local queryObj = Clockwork.database:Select(charactersTable);
2952 queryObj:AddWhere("_Schema = ?", schemaFolder);
2953 queryObj:AddWhere("_SteamID = ?", player:SteamID());
2954 queryObj:SetCallback(function(result)
2955 if (!IsValid(player)) then return; end;
2956
2957 if (Clockwork.database:IsResult(result)) then
2958 local characters = {};
2959
2960 for k, v in pairs(result) do
2961 characters[k] = self:ConvertToCamelCase(v);
2962 end;
2963
2964 Callback(characters);
2965 else
2966 Callback();
2967 end;
2968 end);
2969 queryObj:Pull();
2970end;
2971
2972-- A function to add a character to the character screen.
2973function Clockwork.player:CharacterScreenAdd(player, character)
2974 local info = {
2975 name = character.name,
2976 model = character.model,
2977 banned = character.data["CharBanned"],
2978 faction = character.faction,
2979 characterID = character.characterID
2980 };
2981
2982 if (character.data["PhysDesc"]) then
2983 if (string.len(character.data["PhysDesc"]) > 64) then
2984 info.details = string.sub(character.data["PhysDesc"], 1, 64).."...";
2985 else
2986 info.details = character.data["PhysDesc"];
2987 end;
2988 end;
2989
2990 if (character.data["CharBanned"]) then
2991 info.details = "This character is banned.";
2992 end;
2993
2994 Clockwork.plugin:Call("PlayerAdjustCharacterScreenInfo", player, character, info);
2995 Clockwork.datastream:Start(player, "CharacterAdd", info);
2996end;
2997
2998-- A function to convert a character's MySQL variables to Lua variables.
2999function Clockwork.player:ConvertCharacterMySQL(baseTable)
3000 baseTable.recognisedNames = self:ConvertCharacterRecognisedNamesString(baseTable.recognisedNames);
3001 baseTable.characterID = tonumber(baseTable.characterID);
3002 baseTable.attributes = self:ConvertCharacterDataString(baseTable.attributes);
3003 baseTable.inventory = Clockwork.inventory:ToLoadable(
3004 self:ConvertCharacterDataString(baseTable.inventory)
3005 );
3006 baseTable.cash = tonumber(baseTable.cash);
3007 baseTable.ammo = self:ConvertCharacterDataString(baseTable.ammo);
3008 baseTable.data = self:ConvertCharacterDataString(baseTable.data);
3009 baseTable.key = tonumber(baseTable.key);
3010end;
3011
3012-- A function to get a player's character ID.
3013function Clockwork.player:GetCharacterID(player)
3014 local character = player:GetCharacter();
3015
3016 if (character) then
3017 for k, v in pairs(player:GetCharacters()) do
3018 if (v == character) then
3019 return k;
3020 end;
3021 end;
3022 end;
3023end;
3024
3025-- A function to load a player's character.
3026function Clockwork.player:LoadCharacter(player, characterID, tMergeCreate, Callback, bForce)
3027 local character = {};
3028 local unixTime = os.time();
3029
3030 if (tMergeCreate) then
3031 character = {};
3032 character.name = name;
3033 character.data = {};
3034 character.ammo = {};
3035 character.cash = Clockwork.config:Get("default_cash"):Get();
3036 character.model = "models/police.mdl";
3037 character.flags = "b";
3038 character.schema = Clockwork.kernel:GetSchemaFolder();
3039 character.gender = GENDER_MALE;
3040 character.faction = FACTION_CITIZEN;
3041 character.steamID = player:SteamID();
3042 character.steamName = player:SteamName();
3043 character.inventory = {};
3044 character.attributes = {};
3045 character.onNextLoad = "";
3046 character.lastPlayed = unixTime;
3047 character.timeCreated = unixTime;
3048 character.characterID = characterID;
3049 character.recognisedNames = {};
3050
3051 if (!player.cwCharacterList[characterID]) then
3052 table.Merge(character, tMergeCreate);
3053
3054 if (character and type(character) == "table") then
3055 character.inventory = {};
3056 Clockwork.plugin:Call(
3057 "GetPlayerDefaultInventory", player, character, character.inventory
3058 );
3059
3060 if (!bForce) then
3061 local fault = Clockwork.plugin:Call("PlayerCanCreateCharacter", player, character, characterID);
3062
3063 if (fault == false or type(fault) == "string") then
3064 return self:SetCreateFault(player, fault or "You cannot create this character!");
3065 end;
3066 end;
3067
3068 self:SaveCharacter(player, true, character, function(key)
3069 player.cwCharacterList[characterID] = character;
3070 player.cwCharacterList[characterID].key = key;
3071
3072 Clockwork.plugin:Call("PlayerCharacterCreated", player, character);
3073 self:CharacterScreenAdd(player, character);
3074
3075 if (Callback) then
3076 Callback();
3077 end;
3078 end);
3079 end;
3080 end;
3081 else
3082 character = player.cwCharacterList[characterID];
3083
3084 if (character) then
3085 if (player:GetCharacter()) then
3086 self:SaveCharacter(player);
3087 self:UpdateCharacter(player);
3088
3089 Clockwork.plugin:Call("PlayerCharacterUnloaded", player);
3090 end;
3091
3092 player.cwCharacter = character;
3093
3094 if (player:Alive()) then
3095 player:KillSilent();
3096 end;
3097
3098 if (self:SetBasicSharedVars(player)) then
3099 Clockwork.plugin:Call("PlayerCharacterLoaded", player);
3100 player:SaveCharacter();
3101 end;
3102 end;
3103 end;
3104end;
3105
3106-- A function to set a player's basic shared variables.
3107function Clockwork.player:SetBasicSharedVars(player)
3108 local gender = player:GetGender();
3109 local faction = player:GetFaction();
3110
3111 player:SetDTString(2, player:GetFlags());
3112 player:SetSharedVar("Model", self:GetDefaultModel(player));
3113 player:SetDTString(0, player:Name());
3114 player:SetDTInt(0, player:GetCharacterKey());
3115
3116 if (Clockwork.faction.stored[faction]) then
3117 player:SetDTInt(2, Clockwork.faction.stored[faction].index);
3118 end;
3119
3120 if (gender == GENDER_MALE) then
3121 player:SetDTInt(1, 2);
3122 else
3123 player:SetDTInt(1, 1);
3124 end;
3125
3126 return true;
3127end;
3128
3129-- A function to get the character's ammo as a string.
3130function Clockwork.player:GetCharacterAmmoString(player, character, bRawTable)
3131 local ammo = table.Copy(character.ammo);
3132
3133 for k, v in pairs(self:GetAmmo(player)) do
3134 if (v > 0) then
3135 ammo[k] = v;
3136 end;
3137 end;
3138
3139 if (!bRawTable) then
3140 return Clockwork.json:Encode(ammo);
3141 else
3142 return ammo;
3143 end;
3144end;
3145
3146-- A function to get the character's data as a string.
3147function Clockwork.player:GetCharacterDataString(player, character, bRawTable)
3148 local data = table.Copy(character.data);
3149 Clockwork.plugin:Call("PlayerSaveCharacterData", player, data);
3150
3151 if (!bRawTable) then
3152 return Clockwork.json:Encode(data);
3153 else
3154 return data;
3155 end;
3156end;
3157
3158-- A function to get the character's recognised names as a string.
3159function Clockwork.player:GetCharacterRecognisedNamesString(player, character)
3160 local recognisedNames = {};
3161
3162 for k, v in pairs(character.recognisedNames) do
3163 if (v == RECOGNISE_SAVE) then
3164 recognisedNames[#recognisedNames + 1] = k;
3165 end;
3166 end;
3167
3168 return Clockwork.json:Encode(recognisedNames);
3169end;
3170
3171-- A function to get the character's inventory as a string.
3172function Clockwork.player:GetCharacterInventoryString(player, character, bRawTable)
3173 local inventory = Clockwork.inventory:CreateDuplicate(character.inventory);
3174 Clockwork.plugin:Call("PlayerAddToSavedInventory", player, character, function(itemTable)
3175 Clockwork.inventory:AddInstance(inventory, itemTable);
3176 end);
3177
3178 if (!bRawTable) then
3179 return Clockwork.json:Encode(Clockwork.inventory:ToSaveable(inventory));
3180 else
3181 return inventory;
3182 end;
3183end;
3184
3185-- A function to convert a character's recognised names string to a table.
3186function Clockwork.player:ConvertCharacterRecognisedNamesString(data)
3187 local bSuccess, value = pcall(Clockwork.json.Decode, Clockwork.json, data);
3188
3189 if (bSuccess and value != nil) then
3190 local recognisedNames = {};
3191
3192 for k, v in pairs(value) do
3193 recognisedNames[v] = RECOGNISE_SAVE;
3194 end;
3195
3196 return recognisedNames;
3197 else
3198 return {};
3199 end;
3200end;
3201
3202-- A function to convert a character's data string to a table.
3203function Clockwork.player:ConvertCharacterDataString(data)
3204 local bSuccess, value = pcall(Clockwork.json.Decode, Clockwork.json, data);
3205
3206 if (bSuccess and value != nil) then
3207 return value;
3208 else
3209 return {};
3210 end;
3211end;
3212
3213-- A function to load a player's data.
3214function Clockwork.player:LoadData(player, Callback)
3215 local playersTable = Clockwork.config:Get("mysql_players_table"):Get();
3216 local schemaFolder = Clockwork.kernel:GetSchemaFolder();
3217 local unixTime = os.time();
3218 local steamID = player:SteamID();
3219
3220 local queryObj = Clockwork.database:Select(playersTable);
3221 queryObj:AddWhere("_Schema = ?", schemaFolder);
3222 queryObj:AddWhere("_SteamID = ?", steamID);
3223 queryObj:SetCallback(function(result)
3224 if (!IsValid(player) or player.cwData) then
3225 return;
3226 end;
3227
3228 local ownerSteamID = Clockwork.config:Get("owner_steamid"):Get();
3229 local onNextPlay = "";
3230
3231 if (Clockwork.database:IsResult(result)) then
3232 player.cwTimeJoined = tonumber(result[1]._TimeJoined);
3233 player.cwLastPlayed = tonumber(result[1]._LastPlayed);
3234 player.cwUserGroup = result[1]._UserGroup;
3235 player.cwData = Clockwork.player:ConvertDataString(player, result[1]._Data);
3236
3237 local bSuccess, value = pcall(Clockwork.json.Decode, Clockwork.json, result[1]._Donations);
3238
3239 if (bSuccess and value != nil) then
3240 player.cwDonations = value;
3241 else
3242 player.cwDonations = {};
3243 end;
3244
3245 onNextPlay = result[1]._OnNextPlay;
3246 else
3247 player.cwTimeJoined = unixTime;
3248 player.cwLastPlayed = unixTime;
3249 player.cwDonations = {};
3250 player.cwUserGroup = "user";
3251 player.cwData = Clockwork.player:SaveData(player, true);
3252 end;
3253
3254 if (string.lower(steamID) == string.lower(ownerSteamID)) then
3255 player.cwUserGroup = "superadmin";
3256 end;
3257
3258 if (!player.cwUserGroup or player.cwUserGroup == "") then
3259 player.cwUserGroup = "user";
3260 end;
3261
3262 if (!Clockwork.config:Get("use_own_group_system"):Get()
3263 and player.cwUserGroup != "user") then
3264 player:SetUserGroup(player.cwUserGroup);
3265 end;
3266
3267 Clockwork.plugin:Call("PlayerRestoreData", player, player.cwData);
3268
3269 if (Callback and IsValid(player)) then
3270 Callback(player);
3271 end;
3272
3273 if (onNextPlay != "") then
3274 local updateObj = Clockwork.database:Update(playersTable);
3275 updateObj:SetValue("_OnNextPlay", "");
3276 updateObj:SetValue("_SteamID", steamID);
3277 updateObj:SetValue("_Schema", schemaFolder);
3278 updateObj:Push();
3279
3280 PLAYER = player;
3281 RunString(onNextPlay);
3282 PLAYER = nil;
3283 end;
3284 end);
3285 queryObj:Pull();
3286
3287 timer.Simple(2, function()
3288 if (IsValid(player) and !player.cwData) then
3289 self:LoadData(player, Callback);
3290 end;
3291 end);
3292end;
3293
3294-- A function to save a players's data.
3295function Clockwork.player:SaveData(player, bCreate)
3296 if (!bCreate) then
3297 local schemaFolder = Clockwork.kernel:GetSchemaFolder();
3298 local steamName = Clockwork.database:Escape(player:SteamName());
3299 local ipAddress = player:IPAddress();
3300 local userGroup = player:GetClockworkUserGroup();
3301 local steamID = player:SteamID();
3302 local data = table.Copy(player.cwData);
3303
3304 Clockwork.plugin:Call("PlayerSaveData", player, data);
3305
3306 local playersTable = Clockwork.config:Get("mysql_players_table"):Get();
3307 local queryObj = Clockwork.database:Update(playersTable);
3308 queryObj:AddWhere("_Schema = ?", schemaFolder);
3309 queryObj:AddWhere("_SteamID = ?", steamID);
3310 queryObj:SetValue("_LastPlayed", os.time());
3311 queryObj:SetValue("_SteamName", steamName);
3312 queryObj:SetValue("_IPAddress", ipAddress);
3313 queryObj:SetValue("_UserGroup", userGroup);
3314 queryObj:SetValue("_SteamID", steamID);
3315 queryObj:SetValue("_Schema", schemaFolder);
3316 queryObj:SetValue("_Data", Clockwork.json:Encode(data));
3317 queryObj:Push();
3318 else
3319 local playersTable = Clockwork.config:Get("mysql_players_table"):Get();
3320 local queryObj = Clockwork.database:Insert(playersTable);
3321 queryObj:SetValue("_Data", "");
3322 queryObj:SetValue("_Schema", Clockwork.kernel:GetSchemaFolder());
3323 queryObj:SetValue("_SteamID", player:SteamID());
3324 queryObj:SetValue("_Donations", "");
3325 queryObj:SetValue("_UserGroup", "user");
3326 queryObj:SetValue("_IPAddress", player:IPAddress());
3327 queryObj:SetValue("_SteamName", player:SteamName());
3328 queryObj:SetValue("_OnNextPlay", "");
3329 queryObj:SetValue("_LastPlayed", os.time());
3330 queryObj:SetValue("_TimeJoined", os.time());
3331 queryObj:Push();
3332
3333 return {};
3334 end;
3335end;
3336
3337-- A function to update a player's character.
3338function Clockwork.player:UpdateCharacter(player)
3339 player.cwCharacter.inventory = self:GetCharacterInventoryString(player, player.cwCharacter, true);
3340 player.cwCharacter.ammo = self:GetCharacterAmmoString(player, player.cwCharacter, true);
3341 player.cwCharacter.data = self:GetCharacterDataString(player, player.cwCharacter, true);
3342end;
3343
3344-- A function to save a player's character.
3345function Clockwork.player:SaveCharacter(player, bCreate, character, Callback)
3346 if (bCreate) then
3347 local charactersTable = Clockwork.config:Get("mysql_characters_table"):Get();
3348 local values = "";
3349 local amount = 1;
3350 local keys = "";
3351
3352 if (!character or type(character) != "table") then
3353 character = player:GetCharacter();
3354 end;
3355
3356 local queryObj = Clockwork.database:Insert(charactersTable);
3357 for k, v in pairs(character) do
3358 local tableKey = "_"..Clockwork.kernel:SetCamelCase(k, false);
3359
3360 if (k == "recognisedNames") then
3361 queryObj:SetValue(tableKey, Clockwork.json:Encode(character.recognisedNames));
3362 elseif (k == "attributes") then
3363 queryObj:SetValue(tableKey, Clockwork.json:Encode(character.attributes));
3364 elseif (k == "inventory") then
3365 queryObj:SetValue(tableKey, Clockwork.json:Encode(Clockwork.inventory:ToSaveable(character.inventory)));
3366 elseif (k == "ammo") then
3367 queryObj:SetValue(tableKey, Clockwork.json:Encode(character.ammo));
3368 elseif (k == "data") then
3369 queryObj:SetValue(tableKey, Clockwork.json:Encode(v));
3370 else
3371 queryObj:SetValue(tableKey, v);
3372 end;
3373 end;
3374 queryObj:SetCallback(function(result, status, lastID)
3375 if (Callback and tonumber(lastID)) then
3376 Callback(tonumber(lastID));
3377 end;
3378 end);
3379 queryObj:SetFlag(2);
3380 queryObj:Push();
3381 elseif (player:HasInitialized()) then
3382 local currentCharacter = player:GetCharacter();
3383 local charactersTable = Clockwork.config:Get("mysql_characters_table"):Get();
3384 local schemaFolder = Clockwork.kernel:GetSchemaFolder();
3385 local unixTime = os.time();
3386 local steamID = player:SteamID();
3387
3388 if (!character) then
3389 character = player:GetCharacter();
3390 end;
3391
3392 local queryObj = Clockwork.database:Update(charactersTable);
3393 queryObj:AddWhere("_Schema = ?", schemaFolder);
3394 queryObj:AddWhere("_SteamID = ?", steamID);
3395 queryObj:AddWhere("_CharacterID = ?", character.characterID);
3396 queryObj:SetValue("_RecognisedNames", self:GetCharacterRecognisedNamesString(player, character));
3397 queryObj:SetValue("_Attributes", Clockwork.json:Encode(character.attributes));
3398 queryObj:SetValue("_LastPlayed", unixTime);
3399 queryObj:SetValue("_SteamName", player:SteamName());
3400 queryObj:SetValue("_Faction", character.faction);
3401 queryObj:SetValue("_Gender", character.gender);
3402 queryObj:SetValue("_Schema", character.schema);
3403 queryObj:SetValue("_Model", character.model);
3404 queryObj:SetValue("_Flags", character.flags);
3405 queryObj:SetValue("_Cash", character.cash);
3406 queryObj:SetValue("_Name", character.name);
3407
3408 if (currentCharacter == character) then
3409 queryObj:SetValue("_Inventory", self:GetCharacterInventoryString(player, character));
3410 queryObj:SetValue("_Ammo", self:GetCharacterAmmoString(player, character));
3411 queryObj:SetValue("_Data", self:GetCharacterDataString(player, character));
3412 else
3413 queryObj:SetValue("_Inventory", Clockwork.json:Encode(Clockwork.inventory:ToSaveable(character.inventory)));
3414 queryObj:SetValue("_Ammo", Clockwork.json:Encode(character.ammo));
3415 queryObj:SetValue("_Data", Clockwork.json:Encode(character.data));
3416 end;
3417 queryObj:Push();
3418
3419 --[[ Save the player's data after pushing the update. --]]
3420 Clockwork.player:SaveData(player);
3421 end;
3422end;
3423
3424-- A function to get the class of a player's active weapon.
3425function Clockwork.player:GetWeaponClass(player, safe)
3426 if (IsValid(player:GetActiveWeapon())) then
3427 return player:GetActiveWeapon():GetClass();
3428 else
3429 return safe;
3430 end;
3431end;
3432
3433-- A function to get a player's wages.
3434function Clockwork.player:GetWages(player)
3435 return player:GetSharedVar("Wages");
3436end;