· 7 years ago · Jan 07, 2019, 10:52 AM
1SWEP.Author = "Hxrmn, HOLOGRAPHICpizza, MTYLT"
2SWEP.Contact = "bllaarrgghh@gmail.com"
3SWEP.Purpose = "A Grappling Hook"
4SWEP.Instructions = "Left click to fire"
5
6SWEP.Spawnable = true
7SWEP.AdminSpawnable = false
8
9SWEP.PrintName = "Grappling Hook"
10SWEP.Slot = 0
11SWEP.SlotPos = 4
12SWEP.DrawAmmo = false
13SWEP.DrawCrosshair = true
14SWEP.ViewModel = "models/weapons/v_crossbow.mdl"
15SWEP.WorldModel = "models/weapons/w_crossbow.mdl"
16SWEP.Category = "MTYLT"
17SWEP.ViewModelFOV = 50
18
19SWEP.Primary.Sound = Sound("Grapple1")
20SWEP.Secondary.Sound = Sound("Grapple2")
21SWEP.DeployDelay = 1
22
23local sndTooFar = Sound("weapons/pistol/pistol_empty.wav")
24
25function SWEP:Initialize()
26
27 nextshottime = CurTime()
28 self:SetWeaponHoldType( "smg" )
29 self.zoomed = false
30
31end
32
33function SWEP:Think()
34
35 if (!self.Owner || self.Owner == NULL) then return end
36
37 if ( self.Owner:KeyPressed( IN_ATTACK ) ) then
38
39 self:StartAttack()
40
41 elseif ( self.Owner:KeyDown( IN_ATTACK ) && inRange ) then
42
43 self:UpdateAttack()
44
45 elseif ( self.Owner:KeyReleased( IN_ATTACK ) && inRange ) then
46
47 self:EndAttack( true )
48
49 end
50
51 --Changed from KeyDown to prevent random stuck-in-zoom bug.
52 if ( self.Owner:KeyPressed( IN_ATTACK2 ) ) then
53
54 self:Attack2()
55
56 end
57
58end
59
60function SWEP:DoTrace( endpos )
61 local trace = {}
62 trace.start = self.Owner:GetShootPos()
63 trace.endpos = trace.start + (self.Owner:GetAimVector() * 14096) --14096 is length modifier.
64 if(endpos) then trace.endpos = (endpos - self.Tr.HitNormal * 7) end
65 trace.filter = { self.Owner, self.Weapon }
66
67 self.Tr = nil
68 self.Tr = util.TraceLine( trace )
69end
70
71function SWEP:StartAttack()
72 -- Get begining and end poins of trace.
73 local gunPos = self.Owner:GetShootPos() -- Start of distance trace.
74 local disTrace = self.Owner:GetEyeTrace() -- Store all results of a trace in disTrace.
75 local hitPos = disTrace.HitPos -- Stores Hit Position of disTrace.
76
77 -- Calculate Distance
78 -- Thanks to rgovostes for this code.
79 local x = (gunPos.x - hitPos.x)^2;
80 local y = (gunPos.y - hitPos.y)^2;
81 local z = (gunPos.z - hitPos.z)^2;
82 local distance = math.sqrt(x + y + z);
83
84 -- Only latches if distance is less than distance CVAR, or CVAR negative
85 local distanceCvar = GetConVarNumber("grapple_distance")
86 inRange = false
87 if distanceCvar < 0 or distance <= distanceCvar then
88 inRange = true
89 end
90
91 if inRange then
92 if (SERVER) then
93
94 if (!self.Beam) then -- If the beam does not exist, draw the beam.
95 -- grapple_beam
96 self.Beam = ents.Create( "trace2" )
97 self.Beam:SetPos( self.Owner:GetShootPos() )
98 self.Beam:Spawn()
99 end
100
101 self.Beam:SetParent( self.Owner )
102 self.Beam:SetOwner( self.Owner )
103
104 end
105
106 self:DoTrace()
107 self.speed = 10000 -- Rope latch speed. Was 3000.
108 self.startTime = CurTime()
109 self.endTime = CurTime() + self.speed
110 self.dt = -1
111
112 if (SERVER && self.Beam) then
113 self.Beam:GetTable():SetEndPos( self.Tr.HitPos )
114 end
115
116 self:UpdateAttack()
117
118 self.Weapon:EmitSound(self.Secondary.Sound)
119 self.Weapon:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
120 else
121 -- Play a sound
122 self.Weapon:EmitSound( sndTooFar )
123 end
124end
125
126function SWEP:UpdateAttack()
127
128 self.Owner:LagCompensation( true )
129
130 if (!endpos) then endpos = self.Tr.HitPos end
131
132 if (SERVER && self.Beam) then
133 self.Beam:GetTable():SetEndPos( endpos )
134 end
135
136 lastpos = endpos
137
138
139 if ( self.Tr.Entity:IsValid() ) then
140
141 endpos = self.Tr.Entity:GetPos()
142 if ( SERVER ) then
143 self.Beam:GetTable():SetEndPos( endpos )
144 end
145
146 end
147
148 local vVel = (endpos - self.Owner:GetPos())
149 local Distance = endpos:Distance(self.Owner:GetPos())
150
151 local et = (self.startTime + (Distance/self.speed))
152 if(self.dt != 0) then
153 self.dt = (et - CurTime()) / (et - self.startTime)
154 end
155 if(self.dt < 0) then
156 self.Weapon:EmitSound(self.Primary.Sound)
157 self.dt = 0
158 end
159
160 if(self.dt == 0) then
161 zVel = self.Owner:GetVelocity().z
162 vVel = vVel:GetNormalized()*(math.Clamp(Distance,0,7))
163 if( SERVER ) then
164 local gravity = GetConVarNumber("sv_Gravity")
165 vVel:Add(Vector(0,0,(gravity/100)*1.5)) -- Player speed. DO NOT MESS WITH THIS VALUE!
166 if(zVel < 0) then
167 vVel:Sub(Vector(0,0,zVel/100))
168 end
169 self.Owner:SetVelocity(vVel)
170 end
171 end
172
173 endpos = nil
174
175 self.Owner:LagCompensation( false )
176
177end
178
179function SWEP:EndAttack( shutdownsound )
180
181 self.zoomed = false
182 self:ReloadAnimation()
183
184
185 if ( CLIENT ) then return end
186 if ( !self.Beam ) then return end
187
188 self.Beam:Remove()
189 self.Beam = nil
190
191end
192
193function SWEP:Attack2() -- Zoom.
194 if self.zoomed then
195 self.zoomed = false
196 if SERVER then
197 self.Owner:SetFOV(0, 0.1)
198 end
199 else
200 self.zoomed = true
201 if SERVER then
202 self.Owner:SetFOV(30, 0.1)
203 end
204 end
205end
206
207function SWEP:Holster()
208 self:EndAttack( false )
209 return true
210end
211
212function SWEP:OnRemove()
213 self:EndAttack( false )
214 return true
215end
216
217
218function SWEP:PrimaryAttack()
219end
220
221function SWEP:SecondaryAttack()
222end
223
224/*---------------------------------------------------------
225 Name: SWEP:IdleAnimation()
226 Desc: Are you seriously too stupid to understand the function by yourself?
227---------------------------------------------------------*/
228function SWEP:IdleAnimation(time)
229
230 self.IdleApply = true
231 self.ActionDelay = CurTime() + time
232 self.IdleDelay = CurTime() + time
233end
234
235/*---------------------------------------------------------
236 Name: SWEP:Deploy()
237 Desc: Whip mine out.
238---------------------------------------------------------*/
239function SWEP:Deploy()
240
241 self:DeployAnimation()
242
243 if (IsValid(self.Owner) and self.Owner:GetViewModel()) then
244 self:IdleAnimation(self.Owner:GetViewModel():SequenceDuration())
245 end
246
247 self.Weapon:SetNextPrimaryFire(CurTime() + self.DeployDelay + 0.05)
248 self.Weapon:SetNextSecondaryFire(CurTime() + self.DeployDelay + 0.05)
249 self.ActionDelay = (CurTime() + self.DeployDelay + 0.05)
250
251 return true
252end
253
254/*---------------------------------------------------------
255 Name: SWEP:DeployAnimation()
256---------------------------------------------------------*/
257function SWEP:DeployAnimation()
258
259 self.Weapon:SendWeaponAnim(ACT_VM_DRAW)
260end
261
262/*---------------------------------------------------------
263 Name: SWEP:ReloadAnimation()
264---------------------------------------------------------*/
265function SWEP:ReloadAnimation()
266
267 self.Weapon:SendWeaponAnim(ACT_VM_RELOAD)
268end
269
270/*---------------------------------------------------------
271 Name: YERP()
272---------------------------------------------------------*/
273SWEP.VElements = {
274 ["bolt"] = { type = "Model", model = "models/props_junk/harpoon002a.mdl", bone = "Crossbow_model.bolt", rel = "", pos = Vector(0, 0.2, 9.199), angle = Angle(90, 0, 0), size = Vector(0.25, 0.25, 0.25), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
275}
276
277SWEP.ViewModelBoneMods = {
278 ["Crossbow_model.bolt"] = { scale = Vector(0.009, 0.009, 0.009), pos = Vector(0, 0, 0), angle = Angle(0, 0, 0) }
279}
280
281/********************************************************
282 SWEP Construction Kit base code
283 Created by Clavus
284 Available for public use, thread at:
285 facepunch.com/threads/1032378
286
287
288 DESCRIPTION:
289 This script is meant for experienced scripters
290 that KNOW WHAT THEY ARE DOING. Don't come to me
291 with basic Lua questions.
292
293 Just copy into your SWEP or SWEP base of choice
294 and merge with your own code.
295
296 The SWEP.VElements, SWEP.WElements and
297 SWEP.ViewModelBoneMods tables are all optional
298 and only have to be visible to the client.
299********************************************************/
300
301function SWEP:Initialize()
302
303 // other initialize code goes here
304
305 if CLIENT then
306
307 // Create a new table for every weapon instance
308 self.VElements = table.FullCopy( self.VElements )
309 self.WElements = table.FullCopy( self.WElements )
310 self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
311
312 self:CreateModels(self.VElements) // create viewmodels
313 self:CreateModels(self.WElements) // create worldmodels
314
315 // init view model bone build function
316 if IsValid(self.Owner) then
317 local vm = self.Owner:GetViewModel()
318 if IsValid(vm) then
319 self:ResetBonePositions(vm)
320
321 // Init viewmodel visibility
322 if (self.ShowViewModel == nil or self.ShowViewModel) then
323 vm:SetColor(Color(255,255,255,255))
324 else
325 // we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
326 vm:SetColor(Color(255,255,255,1))
327 // ^ stopped working in GMod 13 because you have to do Entity:SetRenderMode(1) for translucency to kick in
328 // however for some reason the view model resets to render mode 0 every frame so we just apply a debug material to prevent it from drawing
329 vm:SetMaterial("Debug/hsv")
330 end
331 end
332 end
333
334 end
335
336end
337
338function SWEP:Holster()
339
340 if CLIENT and IsValid(self.Owner) then
341 local vm = self.Owner:GetViewModel()
342 if IsValid(vm) then
343 self:ResetBonePositions(vm)
344 end
345 end
346
347 return true
348end
349
350function SWEP:OnRemove()
351 self:Holster()
352end
353
354if CLIENT then
355
356 SWEP.vRenderOrder = nil
357 function SWEP:ViewModelDrawn()
358
359 local vm = self.Owner:GetViewModel()
360 if !IsValid(vm) then return end
361
362 if (!self.VElements) then return end
363
364 self:UpdateBonePositions(vm)
365
366 if (!self.vRenderOrder) then
367
368 // we build a render order because sprites need to be drawn after models
369 self.vRenderOrder = {}
370
371 for k, v in pairs( self.VElements ) do
372 if (v.type == "Model") then
373 table.insert(self.vRenderOrder, 1, k)
374 elseif (v.type == "Sprite" or v.type == "Quad") then
375 table.insert(self.vRenderOrder, k)
376 end
377 end
378
379 end
380
381 for k, name in ipairs( self.vRenderOrder ) do
382
383 local v = self.VElements[name]
384 if (!v) then self.vRenderOrder = nil break end
385 if (v.hide) then continue end
386
387 local model = v.modelEnt
388 local sprite = v.spriteMaterial
389
390 if (!v.bone) then continue end
391
392 local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
393
394 if (!pos) then continue end
395
396 if (v.type == "Model" and IsValid(model)) then
397
398 model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
399 ang:RotateAroundAxis(ang:Up(), v.angle.y)
400 ang:RotateAroundAxis(ang:Right(), v.angle.p)
401 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
402
403 model:SetAngles(ang)
404 //model:SetModelScale(v.size)
405 local matrix = Matrix()
406 matrix:Scale(v.size)
407 model:EnableMatrix( "RenderMultiply", matrix )
408
409 if (v.material == "") then
410 model:SetMaterial("")
411 elseif (model:GetMaterial() != v.material) then
412 model:SetMaterial( v.material )
413 end
414
415 if (v.skin and v.skin != model:GetSkin()) then
416 model:SetSkin(v.skin)
417 end
418
419 if (v.bodygroup) then
420 for k, v in pairs( v.bodygroup ) do
421 if (model:GetBodygroup(k) != v) then
422 model:SetBodygroup(k, v)
423 end
424 end
425 end
426
427 if (v.surpresslightning) then
428 render.SuppressEngineLighting(true)
429 end
430
431 render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
432 render.SetBlend(v.color.a/255)
433 model:DrawModel()
434 render.SetBlend(1)
435 render.SetColorModulation(1, 1, 1)
436
437 if (v.surpresslightning) then
438 render.SuppressEngineLighting(false)
439 end
440
441 elseif (v.type == "Sprite" and sprite) then
442
443 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
444 render.SetMaterial(sprite)
445 render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
446
447 elseif (v.type == "Quad" and v.draw_func) then
448
449 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
450 ang:RotateAroundAxis(ang:Up(), v.angle.y)
451 ang:RotateAroundAxis(ang:Right(), v.angle.p)
452 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
453
454 cam.Start3D2D(drawpos, ang, v.size)
455 v.draw_func( self )
456 cam.End3D2D()
457
458 end
459
460 end
461
462 end
463
464 SWEP.wRenderOrder = nil
465 function SWEP:DrawWorldModel()
466
467 if (self.ShowWorldModel == nil or self.ShowWorldModel) then
468 self:DrawModel()
469 end
470
471 if (!self.WElements) then return end
472
473 if (!self.wRenderOrder) then
474
475 self.wRenderOrder = {}
476
477 for k, v in pairs( self.WElements ) do
478 if (v.type == "Model") then
479 table.insert(self.wRenderOrder, 1, k)
480 elseif (v.type == "Sprite" or v.type == "Quad") then
481 table.insert(self.wRenderOrder, k)
482 end
483 end
484
485 end
486
487 if (IsValid(self.Owner)) then
488 bone_ent = self.Owner
489 else
490 // when the weapon is dropped
491 bone_ent = self
492 end
493
494 for k, name in pairs( self.wRenderOrder ) do
495
496 local v = self.WElements[name]
497 if (!v) then self.wRenderOrder = nil break end
498 if (v.hide) then continue end
499
500 local pos, ang
501
502 if (v.bone) then
503 pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
504 else
505 pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
506 end
507
508 if (!pos) then continue end
509
510 local model = v.modelEnt
511 local sprite = v.spriteMaterial
512
513 if (v.type == "Model" and IsValid(model)) then
514
515 model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
516 ang:RotateAroundAxis(ang:Up(), v.angle.y)
517 ang:RotateAroundAxis(ang:Right(), v.angle.p)
518 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
519
520 model:SetAngles(ang)
521 //model:SetModelScale(v.size)
522 local matrix = Matrix()
523 matrix:Scale(v.size)
524 model:EnableMatrix( "RenderMultiply", matrix )
525
526 if (v.material == "") then
527 model:SetMaterial("")
528 elseif (model:GetMaterial() != v.material) then
529 model:SetMaterial( v.material )
530 end
531
532 if (v.skin and v.skin != model:GetSkin()) then
533 model:SetSkin(v.skin)
534 end
535
536 if (v.bodygroup) then
537 for k, v in pairs( v.bodygroup ) do
538 if (model:GetBodygroup(k) != v) then
539 model:SetBodygroup(k, v)
540 end
541 end
542 end
543
544 if (v.surpresslightning) then
545 render.SuppressEngineLighting(true)
546 end
547
548 render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
549 render.SetBlend(v.color.a/255)
550 model:DrawModel()
551 render.SetBlend(1)
552 render.SetColorModulation(1, 1, 1)
553
554 if (v.surpresslightning) then
555 render.SuppressEngineLighting(false)
556 end
557
558 elseif (v.type == "Sprite" and sprite) then
559
560 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
561 render.SetMaterial(sprite)
562 render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
563
564 elseif (v.type == "Quad" and v.draw_func) then
565
566 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
567 ang:RotateAroundAxis(ang:Up(), v.angle.y)
568 ang:RotateAroundAxis(ang:Right(), v.angle.p)
569 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
570
571 cam.Start3D2D(drawpos, ang, v.size)
572 v.draw_func( self )
573 cam.End3D2D()
574
575 end
576
577 end
578
579 end
580
581 function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
582
583 local bone, pos, ang
584 if (tab.rel and tab.rel != "") then
585
586 local v = basetab[tab.rel]
587
588 if (!v) then return end
589
590 // Technically, if there exists an element with the same name as a bone
591 // you can get in an infinite loop. Let's just hope nobody's that stupid.
592 pos, ang = self:GetBoneOrientation( basetab, v, ent )
593
594 if (!pos) then return end
595
596 pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
597 ang:RotateAroundAxis(ang:Up(), v.angle.y)
598 ang:RotateAroundAxis(ang:Right(), v.angle.p)
599 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
600
601 else
602
603 bone = ent:LookupBone(bone_override or tab.bone)
604
605 if (!bone) then return end
606
607 pos, ang = Vector(0,0,0), Angle(0,0,0)
608 local m = ent:GetBoneMatrix(bone)
609 if (m) then
610 pos, ang = m:GetTranslation(), m:GetAngles()
611 end
612
613 if (IsValid(self.Owner) and self.Owner:IsPlayer() and
614 ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
615 ang.r = -ang.r // Fixes mirrored models
616 end
617
618 end
619
620 return pos, ang
621 end
622
623 function SWEP:CreateModels( tab )
624
625 if (!tab) then return end
626
627 // Create the clientside models here because Garry says we can't do it in the render hook
628 for k, v in pairs( tab ) do
629 if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
630 string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
631
632 v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
633 if (IsValid(v.modelEnt)) then
634 v.modelEnt:SetPos(self:GetPos())
635 v.modelEnt:SetAngles(self:GetAngles())
636 v.modelEnt:SetParent(self)
637 v.modelEnt:SetNoDraw(true)
638 v.createdModel = v.model
639 else
640 v.modelEnt = nil
641 end
642
643 elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
644 and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
645
646 local name = v.sprite.."-"
647 local params = { ["$basetexture"] = v.sprite }
648 // make sure we create a unique name based on the selected options
649 local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
650 for i, j in pairs( tocheck ) do
651 if (v[j]) then
652 params["$"..j] = 1
653 name = name.."1"
654 else
655 name = name.."0"
656 end
657 end
658
659 v.createdSprite = v.sprite
660 v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
661
662 end
663 end
664
665 end
666
667 local allbones
668 local hasGarryFixedBoneScalingYet = false
669
670 function SWEP:UpdateBonePositions(vm)
671
672 if self.ViewModelBoneMods then
673
674 if (!vm:GetBoneCount()) then return end
675
676 // !! WORKAROUND !! //
677 // We need to check all model names :/
678 local loopthrough = self.ViewModelBoneMods
679 if (!hasGarryFixedBoneScalingYet) then
680 allbones = {}
681 for i=0, vm:GetBoneCount() do
682 local bonename = vm:GetBoneName(i)
683 if (self.ViewModelBoneMods[bonename]) then
684 allbones[bonename] = self.ViewModelBoneMods[bonename]
685 else
686 allbones[bonename] = {
687 scale = Vector(1,1,1),
688 pos = Vector(0,0,0),
689 angle = Angle(0,0,0)
690 }
691 end
692 end
693
694 loopthrough = allbones
695 end
696 // !! ----------- !! //
697
698 for k, v in pairs( loopthrough ) do
699 local bone = vm:LookupBone(k)
700 if (!bone) then continue end
701
702 // !! WORKAROUND !! //
703 local s = Vector(v.scale.x,v.scale.y,v.scale.z)
704 local p = Vector(v.pos.x,v.pos.y,v.pos.z)
705 local ms = Vector(1,1,1)
706 if (!hasGarryFixedBoneScalingYet) then
707 local cur = vm:GetBoneParent(bone)
708 while(cur >= 0) do
709 local pscale = loopthrough[vm:GetBoneName(cur)].scale
710 ms = ms * pscale
711 cur = vm:GetBoneParent(cur)
712 end
713 end
714
715 s = s * ms
716 // !! ----------- !! //
717
718 if vm:GetManipulateBoneScale(bone) != s then
719 vm:ManipulateBoneScale( bone, s )
720 end
721 if vm:GetManipulateBoneAngles(bone) != v.angle then
722 vm:ManipulateBoneAngles( bone, v.angle )
723 end
724 if vm:GetManipulateBonePosition(bone) != p then
725 vm:ManipulateBonePosition( bone, p )
726 end
727 end
728 else
729 self:ResetBonePositions(vm)
730 end
731
732 end
733
734 function SWEP:ResetBonePositions(vm)
735
736 if (!vm:GetBoneCount()) then return end
737 for i=0, vm:GetBoneCount() do
738 vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
739 vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
740 vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
741 end
742
743 end
744
745 /**************************
746 Global utility code
747 **************************/
748
749 // Fully copies the table, meaning all tables inside this table are copied too and so on (normal table.Copy copies only their reference).
750 // Does not copy entities of course, only copies their reference.
751 // WARNING: do not use on tables that contain themselves somewhere down the line or you'll get an infinite loop
752 function table.FullCopy( tab )
753
754 if (!tab) then return nil end
755
756 local res = {}
757 for k, v in pairs( tab ) do
758 if (type(v) == "table") then
759 res[k] = table.FullCopy(v) // recursion ho!
760 elseif (type(v) == "Vector") then
761 res[k] = Vector(v.x, v.y, v.z)
762 elseif (type(v) == "Angle") then
763 res[k] = Angle(v.p, v.y, v.r)
764 else
765 res[k] = v
766 end
767 end
768
769 return res
770
771 end
772
773end