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