· 8 years ago · Jun 03, 2018, 08:22 PM
1-- //Variables that are used on both client and server
2SWEP.Category = ""
3SWEP.Gun = ""
4SWEP.Author = "Generic Default, Worshipper, Clavus, and Bob"
5SWEP.Contact = ""
6SWEP.Purpose = ""
7SWEP.Instructions = ""
8SWEP.MuzzleAttachment = "1" -- Should be "1" for CSS models or "muzzle" for hl2 models
9SWEP.DrawCrosshair = true -- Hell no, crosshairs r 4 nubz!
10SWEP.ViewModelFOV = 65 -- How big the gun will look
11SWEP.ViewModelFlip = true -- True for CSS models, False for HL2 models
12
13SWEP.Spawnable = false
14SWEP.AdminSpawnable = false
15
16SWEP.Primary.Sound = Sound("") -- Sound of the gun
17SWEP.Primary.Round = ("") -- What kind of bullet?
18SWEP.Primary.Cone = 0.2 -- Accuracy of NPCs
19SWEP.Primary.Recoil = 10
20SWEP.Primary.Damage = 10
21SWEP.Primary.Spread = .01 --define from-the-hip accuracy (1 is terrible, .0001 is exact)
22SWEP.Primary.NumShots = 1
23SWEP.Primary.RPM = 0 -- This is in Rounds Per Minute
24SWEP.Primary.ClipSize = 0 -- Size of a clip
25SWEP.Primary.DefaultClip = 0 -- Default number of bullets in a clip
26SWEP.Primary.KickUp = 0 -- Maximum up recoil (rise)
27SWEP.Primary.KickDown = 0 -- Maximum down recoil (skeet)
28SWEP.Primary.KickHorizontal = 0 -- Maximum side recoil (koolaid)
29SWEP.Primary.Automatic = true -- Automatic/Semi Auto
30SWEP.Primary.Ammo = "none" -- What kind of ammo
31
32-- SWEP.Secondary.ClipSize = 0 -- Size of a clip
33-- SWEP.Secondary.DefaultClip = 0 -- Default number of bullets in a clip
34-- SWEP.Secondary.Automatic = false -- Automatic/Semi Auto
35SWEP.Secondary.Ammo = ""
36--//HAHA! GOTCHA, YA BASTARD!
37
38-- SWEP.Secondary.IronFOV = 0 -- How much you 'zoom' in. Less is more!
39
40SWEP.Penetration = true
41SWEP.Ricochet = false
42SWEP.MaxRicochet = 1
43SWEP.RicochetCoin = 1
44SWEP.BoltAction = false
45SWEP.Scoped = false
46SWEP.ShellTime = .35
47SWEP.Tracer = 0
48SWEP.CanBeSilenced = false
49SWEP.Silenced = false
50SWEP.NextSilence = 0
51SWEP.SelectiveFire = false
52SWEP.NextFireSelect = 0
53SWEP.OrigCrossHair = true
54
55local PainMulti = 1
56
57if GetConVar("M9KDamageMultiplier") == nil then
58 PainMulti = 1
59 print("M9KDamageMultiplier is missing! You may have hit the lua limit! Reverting multiplier to 1.")
60else
61 PainMulti = GetConVar("M9KDamageMultiplier"):GetFloat()
62 if PainMulti < 0 then
63 PainMulti = PainMulti * -1
64 print("Your damage multiplier was in the negatives. It has been reverted to a positive number. Your damage multiplier is now "..PainMulti)
65 end
66end
67
68function NewM9KDamageMultiplier(cvar, previous, new)
69 print("multiplier has been changed ")
70 if GetConVar("M9KDamageMultiplier") == nil then
71 PainMulti = 1
72 print("M9KDamageMultiplier is missing! You may have hit the lua limit! Reverting multiplier to 1, you will notice no changes.")
73 else
74 PainMulti = GetConVar("M9KDamageMultiplier"):GetFloat()
75 if PainMulti < 0 then
76 PainMulti = PainMulti * -1
77 print("Your damage multiplier was in the negatives. It has been reverted to a positive number. Your damage multiplier is now "..PainMulti)
78 end
79 end
80end
81cvars.AddChangeCallback("M9KDamageMultiplier", NewM9KDamageMultiplier)
82
83function NewDefClips(cvar, previous, new)
84 print("Default clip multiplier has changed. A server restart will be required for these changes to take effect.")
85end
86cvars.AddChangeCallback("M9KDefaultClip", NewDefClips)
87
88if GetConVar("M9KDefaultClip") == nil then
89 print("M9KDefaultClip is missing! You may have hit the lua limit!")
90else
91 if GetConVar("M9KDefaultClip"):GetInt() >= 0 then
92 print("M9K Weapons will now spawn with "..GetConVar("M9KDefaultClip"):GetFloat().." clips.")
93 else
94 print("Default clips will be not be modified")
95 end
96end
97
98SWEP.IronSightsPos = Vector (2.4537, 1.0923, 0.2696)
99SWEP.IronSightsAng = Vector (0.0186, -0.0547, 0)
100
101SWEP.VElements = {}
102SWEP.WElements = {}
103
104function SWEP:Initialize()
105 self.Reloadaftershoot = 0 -- Can't reload when firing
106 self:SetHoldType(self.HoldType)
107 self.OrigCrossHair = self.DrawCrosshair
108 if SERVER and self.Owner:IsNPC() then
109 self:SetNPCMinBurst(3)
110 self:SetNPCMaxBurst(10) -- None of this really matters but you need it here anyway
111 self:SetNPCFireRate(1/(self.Primary.RPM/60))
112 -- //self:SetCurrentWeaponProficiency( WEAPON_PROFICIENCY_VERY_GOOD )
113 end
114
115 if CLIENT then
116
117 -- // Create a new table for every weapon instance
118 self.VElements = table.FullCopy( self.VElements )
119 self.WElements = table.FullCopy( self.WElements )
120 self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
121
122 self:CreateModels(self.VElements) -- create viewmodels
123 self:CreateModels(self.WElements) -- create worldmodels
124
125 -- // init view model bone build function
126 if IsValid(self.Owner) and self.Owner:IsPlayer() then
127 if self.Owner:Alive() then
128 local vm = self.Owner:GetViewModel()
129 if IsValid(vm) then
130 self:ResetBonePositions(vm)
131 -- // Init viewmodel visibility
132 if (self.ShowViewModel == nil or self.ShowViewModel) then
133 vm:SetColor(Color(255,255,255,255))
134 else
135 -- // 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
136 vm:SetMaterial("Debug/hsv")
137 end
138 end
139
140 end
141 end
142
143 end
144
145 if CLIENT then
146 local oldpath = "vgui/hud/name" -- the path goes here
147 local newpath = string.gsub(oldpath, "name", self.Gun)
148 self.WepSelectIcon = surface.GetTextureID(newpath)
149 end
150
151end
152
153function SWEP:Equip()
154 self:SetHoldType(self.HoldType)
155end
156
157function SWEP:Deploy()
158 self:SetIronsights(false, self.Owner) -- Set the ironsight false
159 self:SetHoldType(self.HoldType)
160
161 if self.Silenced then
162 self.Weapon:SendWeaponAnim( ACT_VM_DRAW_SILENCED )
163 else
164 self.Weapon:SendWeaponAnim( ACT_VM_DRAW )
165 end
166
167 self.Weapon:SetNWBool("Reloading", false)
168
169 if !self.Owner:IsNPC() and self.Owner != nil then
170 if self.ResetSights and self.Owner:GetViewModel() != nil then
171 self.ResetSights = CurTime() + self.Owner:GetViewModel():SequenceDuration()
172 end
173 end
174 return true
175end
176
177function SWEP:Holster()
178
179 if CLIENT and IsValid(self.Owner) and not self.Owner:IsNPC() then
180 local vm = self.Owner:GetViewModel()
181 if IsValid(vm) then
182 self:ResetBonePositions(vm)
183 end
184 end
185
186 return true
187end
188
189function SWEP:OnRemove()
190
191 if CLIENT and IsValid(self.Owner) and not self.Owner:IsNPC() then
192 local vm = self.Owner:GetViewModel()
193 if IsValid(vm) then
194 self:ResetBonePositions(vm)
195 end
196 end
197
198end
199
200function SWEP:GetCapabilities()
201 return CAP_WEAPON_RANGE_ATTACK1, CAP_INNATE_RANGE_ATTACK1
202end
203
204function SWEP:Precache()
205 util.PrecacheSound(self.Primary.Sound)
206 util.PrecacheModel(self.ViewModel)
207 util.PrecacheModel(self.WorldModel)
208end
209
210function SWEP:PrimaryAttack()
211 OkaySoFar = true
212 if not IsValid(self) then
213 OkaySoFar = false
214 else if not IsValid(self.Weapon) then
215 OkaySoFar = false
216 else if not IsValid(self.Owner) then
217 OkaySoFar = false
218 end end end
219
220 if not OkaySoFar then return end
221
222 if self:CanPrimaryAttack() and self.Owner:IsPlayer() then
223 if !self.Owner:KeyDown(IN_SPEED) and !self.Owner:KeyDown(IN_RELOAD) then
224 self:ShootBulletInformation()
225 self.Weapon:TakePrimaryAmmo(1)
226
227 if self.Silenced then
228 self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK_SILENCED )
229 self.Weapon:EmitSound(self.Primary.SilencedSound)
230 else
231 self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
232 self.Weapon:EmitSound(self.Primary.Sound)
233 end
234
235 local fx = EffectData()
236 fx:SetEntity(self.Weapon)
237 fx:SetOrigin(self.Owner:GetShootPos())
238 fx:SetNormal(self.Owner:GetAimVector())
239 fx:SetAttachment(self.MuzzleAttachment)
240 if GetConVar("M9KGasEffect") != nil then
241 if GetConVar("M9KGasEffect"):GetBool() then
242 util.Effect("perp_m9k_rg_muzzle_rifle",fx)
243 end
244 end
245 self.Owner:SetAnimation( PLAYER_ATTACK1 )
246 self.Owner:MuzzleFlash()
247 self.Weapon:SetNextPrimaryFire(CurTime()+1/(self.Primary.RPM/60))
248 self:CheckWeaponsAndAmmo()
249 self.RicochetCoin = (math.random(1,4))
250 if self.BoltAction then self:BoltBack() end
251 end
252 elseif self:CanPrimaryAttack() and self.Owner:IsNPC() then
253 self:ShootBulletInformation()
254 self.Weapon:TakePrimaryAmmo(1)
255 self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
256 self.Weapon:EmitSound(self.Primary.Sound)
257 self.Owner:SetAnimation( PLAYER_ATTACK1 )
258 self.Owner:MuzzleFlash()
259 self.Weapon:SetNextPrimaryFire(CurTime()+1/(self.Primary.RPM/60))
260 self.RicochetCoin = (math.random(1,4))
261 end
262end
263
264function SWEP:CheckWeaponsAndAmmo()
265 if SERVER and self.Weapon != nil and (GetConVar("M9KWeaponStrip"):GetBool()) then
266 if self.Weapon:Clip1() == 0 && self.Owner:GetAmmoCount( self.Weapon:GetPrimaryAmmoType() ) == 0 then
267 timer.Simple(.1, function() if SERVER then if not IsValid(self) then return end
268 if self.Owner == nil then return end
269 self.Owner:StripWeapon(self.Gun)
270 end end)
271 end
272 end
273end
274
275
276/*---------------------------------------------------------
277 Name: SWEP:ShootBulletInformation()
278 Desc: This func add the damage, the recoil, the number of shots and the cone on the bullet.
279-----------------------------------------------------*/
280function SWEP:ShootBulletInformation()
281
282 local CurrentDamage
283 local CurrentRecoil
284 local CurrentCone
285 local basedamage
286
287 if (self:GetIronsights() == true) and self.Owner:KeyDown(IN_ATTACK2) then
288 CurrentCone = self.Primary.IronAccuracy
289 else
290 CurrentCone = self.Primary.Spread
291 end
292 local damagedice = math.Rand(.85,1.3)
293
294 basedamage = PainMulti * self.Primary.Damage
295 CurrentDamage = basedamage * damagedice
296 CurrentRecoil = self.Primary.Recoil
297
298 -- //Player is aiming
299 if (self:GetIronsights() == true) and self.Owner:KeyDown(IN_ATTACK2) then
300 self:ShootBullet(CurrentDamage, CurrentRecoil / 6, self.Primary.NumShots, CurrentCone)
301 -- //Player is not aiming
302 else
303 if IsValid(self) then
304 if IsValid(self.Weapon) then
305 if IsValid(self.Owner) then
306 self:ShootBullet(CurrentDamage, CurrentRecoil, self.Primary.NumShots, CurrentCone)
307 end
308 end
309 end
310 end
311
312end
313
314/*---------------------------------------------------------
315 Name: SWEP:ShootBullet()
316 Desc: A convenience func to shoot bullets.
317-----------------------------------------------------*/
318local TracerName = "Tracer"
319
320function SWEP:ShootBullet(damage, recoil, num_bullets, aimcone)
321
322 num_bullets = num_bullets or 1
323 aimcone = aimcone or 0
324
325 self:ShootEffects()
326
327 if self.Tracer == 1 then
328 TracerName = "Ar2Tracer"
329 elseif self.Tracer == 2 then
330 TracerName = "AirboatGunHeavyTracer"
331 else
332 TracerName = "Tracer"
333 end
334
335 local bullet = {}
336 bullet.Num = num_bullets
337 bullet.Src = self.Owner:GetShootPos() -- Source
338 bullet.Dir = self.Owner:GetAimVector() -- Dir of bullet
339 bullet.Spread = Vector(aimcone, aimcone, 0) -- Aim Cone
340 bullet.Tracer = 3 -- Show a tracer on every x bullets
341 bullet.TracerName = TracerName
342 bullet.Force = damage * 0.25 -- Amount of force to give to phys objects
343 bullet.Damage = damage
344 bullet.Callback = function(attacker, tracedata, dmginfo)
345 return self:RicochetCallback(0, attacker, tracedata, dmginfo)
346 end
347 if IsValid(self) then
348 if IsValid(self.Weapon) then
349 if IsValid(self.Owner) then
350 self.Owner:FireBullets(bullet)
351 end
352 end
353 end
354 -- //if SERVER and !self.Owner:IsNPC() then
355 -- // local anglo = Angle(math.Rand(-self.Primary.KickDown,-self.Primary.KickUp), math.Rand(-self.Primary.KickHorizontal,self.Primary.KickHorizontal), 0)
356 -- // self.Owner:ViewPunch(anglo)
357
358 -- // local eyes = self.Owner:EyeAngles()
359 -- // eyes.pitch = eyes.pitch + anglo.pitch
360 -- // eyes.yaw = eyes.yaw + anglo.yaw
361 -- // if game.SinglePlayer() then self.Owner:SetEyeAngles(eyes) end
362 -- //end
363
364 local anglo1 = Angle(math.Rand(-self.Primary.KickDown,-self.Primary.KickUp), math.Rand(-self.Primary.KickHorizontal,self.Primary.KickHorizontal), 0)
365 self.Owner:ViewPunch(anglo1)
366
367 if SERVER and game.SinglePlayer() and !self.Owner:IsNPC() then
368 local offlineeyes = self.Owner:EyeAngles()
369 offlineeyes.pitch = offlineeyes.pitch + anglo1.pitch
370 offlineeyes.yaw = offlineeyes.yaw + anglo1.yaw
371 if GetConVar("M9KDynamicRecoil"):GetBool() then
372 self.Owner:SetEyeAngles(offlineeyes)
373 end
374 end
375
376 if CLIENT and !game.SinglePlayer() and !self.Owner:IsNPC() then
377 local anglo = Angle(math.Rand(-self.Primary.KickDown,-self.Primary.KickUp), math.Rand(-self.Primary.KickHorizontal,self.Primary.KickHorizontal), 0)
378
379 local eyes = self.Owner:EyeAngles()
380 eyes.pitch = eyes.pitch + (anglo.pitch/3)
381 eyes.yaw = eyes.yaw + (anglo.yaw/3)
382 --if GetConVar("M9KDynamicRecoil"):GetBool() then
383 self.Owner:SetEyeAngles(eyes)
384 -- end
385 end
386
387 local trace = {};
388 trace.start = self.Owner:GetShootPos();
389 trace.endpos = trace.start + (self.Owner:GetAimVector() * 1000000);
390
391 local traceRes = util.TraceLine(trace);
392 local dir = (traceRes.HitPos - trace.start):Normalize();
393 local hitPosition = traceRes.HitPos;
394 if (CLIENT) then
395 for k, v in pairs(player.GetAll()) do
396 if (!v:Alive()) then
397 local playerRagdoll = v:GetRagdollEntity()
398
399 if (playerRagdoll) then
400 for _, ent in pairs(ents.FindInSphere(traceRes.HitPos, 25)) do
401 if ent == playerRagdoll then
402 RunConsoleCommand('perp_m_k', v:UniqueID());
403 end
404 end
405 end
406 end
407 end
408 end
409end
410
411/*---------------------------------------------------------
412 Name: SWEP:RicochetCallback()
413-----------------------------------------------------*/
414
415function SWEP:RicochetCallback(bouncenum, attacker, tr, dmginfo)
416
417 if not IsFirstTimePredicted() then
418 return {damage = false, effects = false}
419 end
420
421 local PenetrationChecker = false
422
423 if GetConVar("M9KDisablePenetration") == nil then
424 PenetrationChecker = false
425 else
426 PenetrationChecker = GetConVar("M9KDisablePenetration"):GetBool()
427 end
428
429 if PenetrationChecker then return {damage = true, effects = DoDefaultEffect} end
430
431 bulletmiss = {}
432 bulletmiss[1]=Sound("weapons/fx/nearmiss/bulletLtoR03.wav")
433 bulletmiss[2]=Sound("weapons/fx/nearmiss/bulletLtoR04.wav")
434 bulletmiss[3]=Sound("weapons/fx/nearmiss/bulletLtoR06.wav")
435 bulletmiss[4]=Sound("weapons/fx/nearmiss/bulletLtoR07.wav")
436 bulletmiss[5]=Sound("weapons/fx/nearmiss/bulletLtoR09.wav")
437 bulletmiss[6]=Sound("weapons/fx/nearmiss/bulletLtoR10.wav")
438 bulletmiss[7]=Sound("weapons/fx/nearmiss/bulletLtoR13.wav")
439 bulletmiss[8]=Sound("weapons/fx/nearmiss/bulletLtoR14.wav")
440
441 local DoDefaultEffect = true
442 if (tr.HitSky) then return end
443
444 // -- Can we go through whatever we hit?
445 if (self.Penetration) and (self:BulletPenetrate(bouncenum, attacker, tr, dmginfo)) then
446 return {damage = true, effects = DoDefaultEffect}
447 end
448
449 // -- Your screen will shake and you'll hear the savage hiss of an approaching bullet which passing if someone is shooting at you.
450 if (tr.MatType != MAT_METAL) then
451 if (SERVER) then
452 util.ScreenShake(tr.HitPos, 5, 0.1, 0.5, 64)
453 sound.Play(table.Random(bulletmiss), tr.HitPos, 75, math.random(75,150), 1)
454 end
455
456 if self.Tracer == 0 or self.Tracer == 1 or self.Tracer == 2 then
457 local effectdata = EffectData()
458 effectdata:SetOrigin(tr.HitPos)
459 effectdata:SetNormal(tr.HitNormal)
460 effectdata:SetScale(20)
461 util.Effect("AR2Impact", effectdata)
462 elseif self.Tracer == 3 then
463 local effectdata = EffectData()
464 effectdata:SetOrigin(tr.HitPos)
465 effectdata:SetNormal(tr.HitNormal)
466 effectdata:SetScale(20)
467 util.Effect("StunstickImpact", effectdata)
468 end
469
470 return
471 end
472
473 return {damage = true, effects = DoDefaultEffect}
474 /*
475 if (self.Ricochet == false) then return {damage = true, effects = DoDefaultEffect} end
476
477 if self.Primary.Ammo == "SniperPenetratedRound" then -- .50 Ammo
478 self.MaxRicochet = 12
479 elseif self.Primary.Ammo == "pistol" then -- pistols
480 self.MaxRicochet = 2
481 elseif self.Primary.Ammo == "357" then -- revolvers with big ass bullets
482 self.MaxRicochet = 4
483 elseif self.Primary.Ammo == "smg1" then -- smgs
484 self.MaxRicochet = 5
485 elseif self.Primary.Ammo == "ar2" then -- assault rifles
486 self.MaxRicochet = 8
487 elseif self.Primary.Ammo == "buckshot" then -- shotguns
488 self.MaxRicochet = 1
489 elseif self.Primary.Ammo == "slam" then -- secondary shotguns
490 self.MaxRicochet = 1
491 elseif self.Primary.Ammo == "AirboatGun" then -- metal piercing shotgun pellet
492 self.MaxRicochet = 8
493 end
494
495 if (bouncenum > self.MaxRicochet) then return end
496
497 // -- Bounce vector
498 local trace = {}
499 trace.start = tr.HitPos
500 trace.endpos = trace.start + (tr.HitNormal * 16384)
501
502 local trace = util.TraceLine(trace)
503
504 local DotProduct = tr.HitNormal:Dot(tr.Normal * -1)
505
506 local ricochetbullet = {}
507 ricochetbullet.Num = 1
508 ricochetbullet.Src = tr.HitPos + (tr.HitNormal * 5)
509 ricochetbullet.Dir = ((2 * tr.HitNormal * DotProduct) + tr.Normal) + (VectorRand() * 0.05)
510 ricochetbullet.Spread = Vector(0, 0, 0)
511 ricochetbullet.Tracer = 1
512 ricochetbullet.TracerName = "perp_m9k_effect_mad_ricochet_trace"
513 ricochetbullet.Force = dmginfo:GetDamage() * 0.15
514 ricochetbullet.Damage = dmginfo:GetDamage() * 0.5
515 ricochetbullet.Callback = function(a, b, c)
516 if (self.Ricochet) then
517 local impactnum
518 if tr.MatType == MAT_GLASS then impactnum = 0 else impactnum = 1 end
519 return self:RicochetCallback(bouncenum + impactnum, a, b, c) end
520 end
521
522 timer.Simple(0, function() attacker:FireBullets(ricochetbullet) end)
523
524 return {damage = true, effects = DoDefaultEffect}
525*/
526end
527
528
529/*---------------------------------------------------------
530 Name: SWEP:BulletPenetrate()
531-----------------------------------------------------*/
532function SWEP:BulletPenetrate(bouncenum, attacker, tr, paininfo)
533
534 local MaxPenetration
535
536 if self.Primary.Ammo == "SniperPenetratedRound" then -- .50 Ammo
537 MaxPenetration = 20
538 elseif self.Primary.Ammo == "pistol" then -- pistols
539 MaxPenetration = 9
540 elseif self.Primary.Ammo == "357" then -- revolvers with big ass bullets
541 MaxPenetration = 12
542 elseif self.Primary.Ammo == "smg1" then -- smgs
543 MaxPenetration = 14
544 elseif self.Primary.Ammo == "ar2" then -- assault rifles
545 MaxPenetration = 16
546 elseif self.Primary.Ammo == "buckshot" then -- shotguns
547 MaxPenetration = 5
548 elseif self.Primary.Ammo == "slam" then -- secondary shotguns
549 MaxPenetration = 5
550 elseif self.Primary.Ammo == "AirboatGun" then -- metal piercing shotgun pellet
551 MaxPenetration = 17
552 else
553 MaxPenetration = 14
554 end
555
556 local DoDefaultEffect = true
557 // -- Don't go through metal, sand or player
558
559 if self.Primary.Ammo == "pistol" or
560 self.Primary.Ammo == "buckshot" or
561 self.Primary.Ammo == "slam" then self.Ricochet = true
562 else
563 if self.RicochetCoin == 1 then
564 self.Ricochet = true
565 elseif self.RicochetCoin >= 2 then
566 self.Ricochet = false
567 end
568 end
569
570 if self.Primary.Ammo == "SniperPenetratedRound" then self.Ricochet = true end
571
572 if self.Primary.Ammo == "SniperPenetratedRound" then -- .50 Ammo
573 self.MaxRicochet = 10
574 elseif self.Primary.Ammo == "pistol" then -- pistols
575 self.MaxRicochet = 2
576 elseif self.Primary.Ammo == "357" then -- revolvers with big ass bullets
577 self.MaxRicochet = 5
578 elseif self.Primary.Ammo == "smg1" then -- smgs
579 self.MaxRicochet = 4
580 elseif self.Primary.Ammo == "ar2" then -- assault rifles
581 self.MaxRicochet = 5
582 elseif self.Primary.Ammo == "buckshot" then -- shotguns
583 self.MaxRicochet = 0
584 elseif self.Primary.Ammo == "slam" then -- secondary shotguns
585 self.MaxRicochet = 0
586 elseif self.Primary.Ammo == "AirboatGun" then -- metal piercing shotgun pellet
587 self.MaxRicochet = 8
588 end
589
590 if (tr.MatType == MAT_METAL and self.Ricochet == true and self.Primary.Ammo != "SniperPenetratedRound" ) then return false end
591
592 // -- Don't go through more than 3 times
593 if (bouncenum > self.MaxRicochet) then return false end
594
595 // -- Direction (and length) that we are going to penetrate
596 local PenetrationDirection = tr.Normal * MaxPenetration
597
598 if (tr.MatType == MAT_GLASS or tr.MatType == MAT_PLASTIC or tr.MatType == MAT_WOOD or tr.MatType == MAT_FLESH or tr.MatType == MAT_ALIENFLESH) then
599 PenetrationDirection = tr.Normal * (MaxPenetration * 2)
600 end
601
602 local trace = {}
603 trace.endpos = tr.HitPos
604 trace.start = tr.HitPos + PenetrationDirection
605 trace.mask = MASK_SHOT
606 trace.filter = {self.Owner}
607
608 local trace = util.TraceLine(trace)
609
610 // -- Bullet didn't penetrate.
611 if (trace.StartSolid or trace.Fraction >= 1.0 or tr.Fraction <= 0.0) then return false end
612
613 // -- Damage multiplier depending on surface
614 local fDamageMulti = 0.5
615
616 if self.Primary.Ammo == "SniperPenetratedRound" then
617 fDamageMulti = 1
618 elseif(tr.MatType == MAT_CONCRETE or tr.MatType == MAT_METAL) then
619 fDamageMulti = 0.3
620 elseif (tr.MatType == MAT_WOOD or tr.MatType == MAT_PLASTIC or tr.MatType == MAT_GLASS) then
621 fDamageMulti = 0.8
622 elseif (tr.MatType == MAT_FLESH or tr.MatType == MAT_ALIENFLESH) then
623 fDamageMulti = 0.9
624 end
625
626 local damagedice = math.Rand(.85,1.3)
627 local newdamage = self.Primary.Damage * damagedice
628
629 // -- Fire bullet from the exit point using the original trajectory
630 local penetratedbullet = {}
631 penetratedbullet.Num = 1
632 penetratedbullet.Src = trace.HitPos
633 penetratedbullet.Dir = tr.Normal
634 penetratedbullet.Spread = Vector(0, 0, 0)
635 penetratedbullet.Tracer = 2
636 penetratedbullet.TracerName = "perp_m9k_effect_mad_penetration_trace"
637 penetratedbullet.Force = 5
638 penetratedbullet.Damage = paininfo:GetDamage() * fDamageMulti
639 penetratedbullet.Callback = function(a, b, c) if (self.Ricochet) then
640 local impactnum
641 if tr.MatType == MAT_GLASS then impactnum = 0 else impactnum = 1 end
642 return self:RicochetCallback(bouncenum + impactnum, a,b,c) end end
643
644 timer.Simple(0, function() if attacker != nil then attacker:FireBullets(penetratedbullet) end end)
645
646 return true
647end
648
649
650function SWEP:SecondaryAttack()
651 return false
652end
653
654function SWEP:Reload()
655 if not IsValid(self) then return end if not IsValid(self.Owner) then return end
656
657 if self.Owner:IsNPC() then
658 self.Weapon:DefaultReload(ACT_VM_RELOAD)
659 return end
660
661 if self.Owner:KeyDown(IN_USE) then return end
662
663 if self.Silenced then
664 self.Weapon:DefaultReload(ACT_VM_RELOAD_SILENCED)
665 else
666 self.Weapon:DefaultReload(ACT_VM_RELOAD)
667 end
668
669 if !self.Owner:IsNPC() then
670 if self.Owner:GetViewModel() == nil then self.ResetSights = CurTime() + 3 else
671 self.ResetSights = CurTime() + self.Owner:GetViewModel():SequenceDuration()
672 end
673 end
674
675 if SERVER and self.Weapon != nil then
676 if ( self.Weapon:Clip1() < self.Primary.ClipSize ) and !self.Owner:IsNPC() then
677 -- //When the current clip < full clip and the rest of your ammo > 0, then
678 self.Owner:SetFOV( 0, 0.3 )
679 -- //Zoom = 0
680 self:SetIronsights(false)
681 -- //Set the ironsight to false
682 self.Weapon:SetNWBool("Reloading", true)
683 end
684 local waitdammit = (self.Owner:GetViewModel():SequenceDuration())
685 timer.Simple(waitdammit + .1,
686 function()
687 if self.Weapon == nil then return end
688 self.Weapon:SetNWBool("Reloading", false)
689 if self.Owner:KeyDown(IN_ATTACK2) and self.Weapon:GetClass() == self.Gun then
690 if CLIENT then return end
691 if self.Scoped == false then
692 self.Owner:SetFOV( self.Secondary.IronFOV, 0.3 )
693 self.IronSightsPos = self.SightsPos -- Bring it up
694 self.IronSightsAng = self.SightsAng -- Bring it up
695 self:SetIronsights(true, self.Owner)
696 self.DrawCrosshair = false
697 else return end
698 elseif self.Owner:KeyDown(IN_SPEED) and self.Weapon:GetClass() == self.Gun then
699 if self.Weapon:GetNextPrimaryFire() <= (CurTime() + .03) then
700 self.Weapon:SetNextPrimaryFire(CurTime()+0.3) -- Make it so you can't shoot for another quarter second
701 end
702 self.IronSightsPos = self.RunSightsPos -- Hold it down
703 self.IronSightsAng = self.RunSightsAng -- Hold it down
704 self:SetIronsights(true, self.Owner) -- Set the ironsight true
705 self.Owner:SetFOV( 0, 0.3 )
706 else return end
707 end)
708 end
709end
710
711function SWEP:PostReloadScopeCheck()
712 if self.Weapon == nil then return end
713 self.Weapon:SetNWBool("Reloading", false)
714 if self.Owner:KeyDown(IN_ATTACK2) and self.Weapon:GetClass() == self.Gun then
715 if CLIENT then return end
716 if self.Scoped == false then
717 self.Owner:SetFOV( self.Secondary.IronFOV, 0.3 )
718 self.IronSightsPos = self.SightsPos -- Bring it up
719 self.IronSightsAng = self.SightsAng -- Bring it up
720 self:SetIronsights(true, self.Owner)
721 self.DrawCrosshair = false
722 else return end
723 elseif self.Owner:KeyDown(IN_SPEED) and self.Weapon:GetClass() == self.Gun then
724 if self.Weapon:GetNextPrimaryFire() <= (CurTime() + .03) then
725 self.Weapon:SetNextPrimaryFire(CurTime()+0.3) -- Make it so you can't shoot for another quarter second
726 end
727 self.IronSightsPos = self.RunSightsPos -- Hold it down
728 self.IronSightsAng = self.RunSightsAng -- Hold it down
729 self:SetIronsights(true, self.Owner) -- Set the ironsight true
730 self.Owner:SetFOV( 0, 0.3 )
731 else return end
732end
733
734function SWEP:Silencer()
735
736 if self.NextSilence > CurTime() then return end
737
738 if self.Weapon != nil then
739 self.Owner:SetFOV( 0, 0.3 )
740 self:SetIronsights(false)
741 self.Weapon:SetNWBool("Reloading", true) -- i know we're not reloading but it works
742 end
743
744 if self.Silenced then
745 self:SendWeaponAnim(ACT_VM_DETACH_SILENCER)
746 self.Silenced = false
747 elseif not self.Silenced then
748 self:SendWeaponAnim(ACT_VM_ATTACH_SILENCER)
749 self.Silenced = true
750 end
751
752 siltimer = CurTime() + (self.Owner:GetViewModel():SequenceDuration()) + 0.1
753 if self.Weapon:GetNextPrimaryFire() <= siltimer then
754 self.Weapon:SetNextPrimaryFire(siltimer)
755 end
756 self.NextSilence = siltimer
757
758 timer.Simple( ((self.Owner:GetViewModel():SequenceDuration()) + 0.1),
759 function()
760 if self.Weapon != nil then
761 self.Weapon:SetNWBool("Reloading", false)
762 if self.Owner:KeyDown(IN_ATTACK2) and self.Weapon:GetClass() == self.Gun then
763 if CLIENT then return end
764 if self.Scoped == false then
765 self.Owner:SetFOV( self.Secondary.IronFOV, 0.3 )
766 self.IronSightsPos = self.SightsPos -- Bring it up
767 self.IronSightsAng = self.SightsAng -- Bring it up
768 self:SetIronsights(true, self.Owner)
769 self.DrawCrosshair = false
770 else return end
771 elseif self.Owner:KeyDown(IN_SPEED) and self.Weapon:GetClass() == self.Gun then
772 if self.Weapon:GetNextPrimaryFire() <= (CurTime()+0.3) then
773 self.Weapon:SetNextPrimaryFire(CurTime()+0.3) -- Make it so you can't shoot for another quarter second
774 end
775 self.IronSightsPos = self.RunSightsPos -- Hold it down
776 self.IronSightsAng = self.RunSightsAng -- Hold it down
777 self:SetIronsights(true, self.Owner) -- Set the ironsight true
778 self.Owner:SetFOV( 0, 0.3 )
779 else return end
780 end
781 end)
782
783end
784
785function SWEP:SelectFireMode()
786
787 if self.Primary.Automatic then
788 self.Primary.Automatic = false
789 self.NextFireSelect = CurTime() + .5
790 if CLIENT then
791 self.Owner:PrintMessage(HUD_PRINTTALK, "Semi-automatic selected.")
792 end
793 self.Weapon:EmitSound("Weapon_AR2.Empty")
794 else
795 self.Primary.Automatic = true
796 self.NextFireSelect = CurTime() + .5
797 if CLIENT then
798 self.Owner:PrintMessage(HUD_PRINTTALK, "Automatic selected.")
799 end
800 self.Weapon:EmitSound("Weapon_AR2.Empty")
801 end
802end
803
804
805/*---------------------------------------------------------
806IronSight
807-----------------------------------------------------*/
808function SWEP:IronSight()
809
810 if not IsValid(self) then return end
811 if not IsValid(self.Owner) then return end
812
813 if !self.Owner:IsNPC() then
814 if self.ResetSights and CurTime() >= self.ResetSights then
815 self.ResetSights = nil
816
817 if self.Silenced then
818 self:SendWeaponAnim(ACT_VM_IDLE_SILENCED)
819 else
820 self:SendWeaponAnim(ACT_VM_IDLE)
821 end
822 end end
823 /*
824 if self.CanBeSilenced and self.NextSilence < CurTime() then
825 if self.Owner:KeyDown(IN_USE) and self.Owner:KeyPressed(IN_RELOAD) then
826 self:Silencer()
827 end
828 end
829 */
830 if self.SelectiveFire and self.NextFireSelect < CurTime() and not (self.Weapon:GetNWBool("Reloading")) then
831 if self.Owner:KeyDown(IN_USE) and self.Owner:KeyPressed(IN_ATTACK2) then
832 self:SelectFireMode()
833 end
834 end
835
836-- //copy this...
837 if self.Owner:KeyPressed(IN_SPEED) and not (self.Weapon:GetNWBool("Reloading")) then -- If you are running
838 if self.Weapon:GetNextPrimaryFire() <= (CurTime()+0.3) then
839 self.Weapon:SetNextPrimaryFire(CurTime()+0.3) -- Make it so you can't shoot for another quarter second
840 end
841 self.IronSightsPos = self.RunSightsPos -- Hold it down
842 self.IronSightsAng = self.RunSightsAng -- Hold it down
843 self:SetIronsights(true, self.Owner) -- Set the ironsight true
844 self.Owner:SetFOV( 0, 0.3 )
845 self.DrawCrosshair = false
846 end
847
848 if self.Owner:KeyReleased (IN_SPEED) then -- If you release run then
849 self:SetIronsights(false, self.Owner) -- Set the ironsight true
850 self.Owner:SetFOV( 0, 0.3 )
851 self.DrawCrosshair = self.OrigCrossHair
852 end -- Shoulder the gun
853
854-- //down to this
855 if !self.Owner:KeyDown(IN_USE) and !self.Owner:KeyDown(IN_SPEED) then
856 -- //If the key E (Use Key) is not pressed, then
857
858 if self.Owner:KeyPressed(IN_ATTACK2) and not (self.Weapon:GetNWBool("Reloading")) then
859 self.Owner:SetFOV( self.Secondary.IronFOV, 0.3 )
860 self.IronSightsPos = self.SightsPos -- Bring it up
861 self.IronSightsAng = self.SightsAng -- Bring it up
862 self:SetIronsights(true, self.Owner)
863 self.DrawCrosshair = false
864 -- //Set the ironsight true
865
866 if CLIENT then return end
867 end
868 end
869
870 if self.Owner:KeyReleased(IN_ATTACK2) and !self.Owner:KeyDown(IN_USE) and !self.Owner:KeyDown(IN_SPEED) then
871 -- //If the right click is released, then
872 self.Owner:SetFOV( 0, 0.3 )
873 self.DrawCrosshair = self.OrigCrossHair
874 self:SetIronsights(false, self.Owner)
875 -- //Set the ironsight false
876
877 if CLIENT then return end
878 end
879
880 if self.Owner:KeyDown(IN_ATTACK2) and !self.Owner:KeyDown(IN_USE) and !self.Owner:KeyDown(IN_SPEED) then
881 self.SwayScale = 0.05
882 self.BobScale = 0.05
883 else
884 self.SwayScale = 1.0
885 self.BobScale = 1.0
886 end
887end
888
889/*---------------------------------------------------------
890Think
891-----------------------------------------------------*/
892function SWEP:Think()
893
894self:IronSight()
895
896end
897
898/*---------------------------------------------------------
899GetViewModelPosition
900-----------------------------------------------------*/
901local IRONSIGHT_TIME = 0.3
902-- //Time to enter in the ironsight mod
903
904function SWEP:GetViewModelPosition(pos, ang)
905
906 if (not self.IronSightsPos) then return pos, ang end
907
908 local bIron = self.Weapon:GetNWBool("perp_m9k_Ironsights")
909
910 if (bIron != self.bLastIron) then
911 self.bLastIron = bIron
912 self.fIronTime = CurTime()
913
914 end
915
916 local fIronTime = self.fIronTime or 0
917
918 if (not bIron and fIronTime < CurTime() - IRONSIGHT_TIME) then
919 return pos, ang
920 end
921
922 local Mul = 1.0
923
924 if (fIronTime > CurTime() - IRONSIGHT_TIME) then
925 Mul = math.Clamp((CurTime() - fIronTime) / IRONSIGHT_TIME, 0, 1)
926
927 if not bIron then Mul = 1 - Mul end
928 end
929
930 local Offset = self.IronSightsPos
931
932 if (self.IronSightsAng) then
933 ang = ang * 1
934 ang:RotateAroundAxis(ang:Right(), self.IronSightsAng.x * Mul)
935 ang:RotateAroundAxis(ang:Up(), self.IronSightsAng.y * Mul)
936 ang:RotateAroundAxis(ang:Forward(), self.IronSightsAng.z * Mul)
937 end
938
939 local Right = ang:Right()
940 local Up = ang:Up()
941 local Forward = ang:Forward()
942
943 pos = pos + Offset.x * Right * Mul
944 pos = pos + Offset.y * Forward * Mul
945 pos = pos + Offset.z * Up * Mul
946
947 return pos, ang
948end
949
950/*---------------------------------------------------------
951SetIronsights
952-----------------------------------------------------*/
953function SWEP:SetIronsights(b)
954 self.Weapon:SetNWBool("perp_m9k_Ironsights", b)
955end
956
957function SWEP:GetIronsights()
958 return self.Weapon:GetNWBool("perp_m9k_Ironsights")
959end
960
961
962if CLIENT then
963
964 SWEP.vRenderOrder = nil
965 function SWEP:ViewModelDrawn()
966
967 if not IsValid(self) then return end
968 if not IsValid(self.Owner) then return end
969 local vm = self.Owner:GetViewModel()
970 if !IsValid(vm) then return end
971
972 if (!self.VElements) then return end
973
974 self:UpdateBonePositions(vm)
975
976 if (!self.vRenderOrder) then
977
978 -- // we build a render order because sprites need to be drawn after models
979 self.vRenderOrder = {}
980
981 for k, v in pairs( self.VElements ) do
982 if (v.type == "Model") then
983 table.insert(self.vRenderOrder, 1, k)
984 elseif (v.type == "Sprite" or v.type == "Quad") then
985 table.insert(self.vRenderOrder, k)
986 end
987 end
988
989 end
990
991 for k, name in ipairs( self.vRenderOrder ) do
992
993 local v = self.VElements[name]
994 if (!v) then self.vRenderOrder = nil break end
995 if (v.hide) then continue end
996
997 local model = v.modelEnt
998 local sprite = v.spriteMaterial
999
1000 if (!v.bone) then continue end
1001
1002 local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
1003
1004 if (!pos) then continue end
1005
1006 if (v.type == "Model" and IsValid(model)) then
1007
1008 model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
1009 ang:RotateAroundAxis(ang:Up(), v.angle.y)
1010 ang:RotateAroundAxis(ang:Right(), v.angle.p)
1011 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
1012
1013 model:SetAngles(ang)
1014 -- //model:SetModelScale(v.size)
1015 local matrix = Matrix()
1016 matrix:Scale(v.size)
1017 model:EnableMatrix( "RenderMultiply", matrix )
1018
1019 if (v.material == "") then
1020 model:SetMaterial("")
1021 elseif (model:GetMaterial() != v.material) then
1022 model:SetMaterial( v.material )
1023 end
1024
1025 if (v.skin and v.skin != model:GetSkin()) then
1026 model:SetSkin(v.skin)
1027 end
1028
1029 if (v.bodygroup) then
1030 for k, v in pairs( v.bodygroup ) do
1031 if (model:GetBodygroup(k) != v) then
1032 model:SetBodygroup(k, v)
1033 end
1034 end
1035 end
1036
1037 if (v.surpresslightning) then
1038 render.SuppressEngineLighting(true)
1039 end
1040
1041 render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
1042 render.SetBlend(v.color.a/255)
1043 model:DrawModel()
1044 render.SetBlend(1)
1045 render.SetColorModulation(1, 1, 1)
1046
1047 if (v.surpresslightning) then
1048 render.SuppressEngineLighting(false)
1049 end
1050
1051 elseif (v.type == "Sprite" and sprite) then
1052
1053 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
1054 render.SetMaterial(sprite)
1055 render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
1056
1057 elseif (v.type == "Quad" and v.draw_func) then
1058
1059 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
1060 ang:RotateAroundAxis(ang:Up(), v.angle.y)
1061 ang:RotateAroundAxis(ang:Right(), v.angle.p)
1062 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
1063
1064 cam.Start3D2D(drawpos, ang, v.size)
1065 v.draw_func( self )
1066 cam.End3D2D()
1067
1068 end
1069
1070 end
1071
1072 end
1073
1074 SWEP.wRenderOrder = nil
1075 function SWEP:DrawWorldModel()
1076
1077 if (self.ShowWorldModel == nil or self.ShowWorldModel) then
1078 self:DrawModel()
1079 end
1080
1081 if (!self.WElements) then return end
1082
1083 if (!self.wRenderOrder) then
1084
1085 self.wRenderOrder = {}
1086
1087 for k, v in pairs( self.WElements ) do
1088 if (v.type == "Model") then
1089 table.insert(self.wRenderOrder, 1, k)
1090 elseif (v.type == "Sprite" or v.type == "Quad") then
1091 table.insert(self.wRenderOrder, k)
1092 end
1093 end
1094
1095 end
1096
1097 if (IsValid(self.Owner)) then
1098 bone_ent = self.Owner
1099 else
1100 -- // when the weapon is dropped
1101 bone_ent = self
1102 end
1103
1104 for k, name in pairs( self.wRenderOrder ) do
1105
1106 local v = self.WElements[name]
1107 if (!v) then self.wRenderOrder = nil break end
1108 if (v.hide) then continue end
1109
1110 local pos, ang
1111
1112 if (v.bone) then
1113 pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
1114 else
1115 pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
1116 end
1117
1118 if (!pos) then continue end
1119
1120 local model = v.modelEnt
1121 local sprite = v.spriteMaterial
1122
1123 if (v.type == "Model" and IsValid(model)) then
1124
1125 model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
1126 ang:RotateAroundAxis(ang:Up(), v.angle.y)
1127 ang:RotateAroundAxis(ang:Right(), v.angle.p)
1128 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
1129
1130 model:SetAngles(ang)
1131 -- //model:SetModelScale(v.size)
1132 local matrix = Matrix()
1133 matrix:Scale(v.size)
1134 model:EnableMatrix( "RenderMultiply", matrix )
1135
1136 if (v.material == "") then
1137 model:SetMaterial("")
1138 elseif (model:GetMaterial() != v.material) then
1139 model:SetMaterial( v.material )
1140 end
1141
1142 if (v.skin and v.skin != model:GetSkin()) then
1143 model:SetSkin(v.skin)
1144 end
1145
1146 if (v.bodygroup) then
1147 for k, v in pairs( v.bodygroup ) do
1148 if (model:GetBodygroup(k) != v) then
1149 model:SetBodygroup(k, v)
1150 end
1151 end
1152 end
1153
1154 if (v.surpresslightning) then
1155 render.SuppressEngineLighting(true)
1156 end
1157
1158 render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
1159 render.SetBlend(v.color.a/255)
1160 model:DrawModel()
1161 render.SetBlend(1)
1162 render.SetColorModulation(1, 1, 1)
1163
1164 if (v.surpresslightning) then
1165 render.SuppressEngineLighting(false)
1166 end
1167
1168 elseif (v.type == "Sprite" and sprite) then
1169
1170 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
1171 render.SetMaterial(sprite)
1172 render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
1173
1174 elseif (v.type == "Quad" and v.draw_func) then
1175
1176 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
1177 ang:RotateAroundAxis(ang:Up(), v.angle.y)
1178 ang:RotateAroundAxis(ang:Right(), v.angle.p)
1179 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
1180
1181 cam.Start3D2D(drawpos, ang, v.size)
1182 v.draw_func( self )
1183 cam.End3D2D()
1184
1185 end
1186
1187 end
1188
1189 end
1190
1191 function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
1192
1193 local bone, pos, ang
1194 if (tab.rel and tab.rel != "") then
1195
1196 local v = basetab[tab.rel]
1197
1198 if (!v) then return end
1199
1200 -- // Technically, if there exists an element with the same name as a bone
1201 -- // you can get in an infinite loop. Let's just hope nobody's that stupid.
1202 pos, ang = self:GetBoneOrientation( basetab, v, ent )
1203
1204 if (!pos) then return end
1205
1206 pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
1207 ang:RotateAroundAxis(ang:Up(), v.angle.y)
1208 ang:RotateAroundAxis(ang:Right(), v.angle.p)
1209 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
1210
1211 else
1212
1213 bone = ent:LookupBone(bone_override or tab.bone)
1214
1215 if (!bone) then return end
1216
1217 pos, ang = Vector(0,0,0), Angle(0,0,0)
1218 local m = ent:GetBoneMatrix(bone)
1219 if (m) then
1220 pos, ang = m:GetTranslation(), m:GetAngles()
1221 end
1222
1223 if (IsValid(self.Owner) and self.Owner:IsPlayer() and
1224 ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
1225 ang.r = -ang.r --// Fixes mirrored models
1226 end
1227
1228 end
1229
1230 return pos, ang
1231 end
1232
1233 function SWEP:CreateModels( tab )
1234
1235 if (!tab) then return end
1236
1237 -- // Create the clientside models here because Garry says we can't do it in the render hook
1238 for k, v in pairs( tab ) do
1239 if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
1240 string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
1241
1242 v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
1243 if (IsValid(v.modelEnt)) then
1244 v.modelEnt:SetPos(self:GetPos())
1245 v.modelEnt:SetAngles(self:GetAngles())
1246 v.modelEnt:SetParent(self)
1247 v.modelEnt:SetNoDraw(true)
1248 v.createdModel = v.model
1249 else
1250 v.modelEnt = nil
1251 end
1252
1253 elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
1254 and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
1255
1256 local name = v.sprite.."-"
1257 local params = { ["$basetexture"] = v.sprite }
1258 -- // make sure we create a unique name based on the selected options
1259 local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
1260 for i, j in pairs( tocheck ) do
1261 if (v[j]) then
1262 params["$"..j] = 1
1263 name = name.."1"
1264 else
1265 name = name.."0"
1266 end
1267 end
1268
1269 v.createdSprite = v.sprite
1270 v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
1271
1272 end
1273 end
1274
1275 end
1276
1277 local allbones
1278 local hasGarryFixedBoneScalingYet = false
1279
1280 function SWEP:UpdateBonePositions(vm)
1281
1282 if self.ViewModelBoneMods then
1283
1284 if (!vm:GetBoneCount()) then return end
1285
1286 -- // !! WORKAROUND !! --//
1287 -- // We need to check all model names :/
1288 local loopthrough = self.ViewModelBoneMods
1289 if (!hasGarryFixedBoneScalingYet) then
1290 allbones = {}
1291 for i=0, vm:GetBoneCount() do
1292 local bonename = vm:GetBoneName(i)
1293 if (self.ViewModelBoneMods[bonename]) then
1294 allbones[bonename] = self.ViewModelBoneMods[bonename]
1295 else
1296 allbones[bonename] = {
1297 scale = Vector(1,1,1),
1298 pos = Vector(0,0,0),
1299 angle = Angle(0,0,0)
1300 }
1301 end
1302 end
1303
1304 loopthrough = allbones
1305 end
1306 //!! ----------- !! --
1307
1308 for k, v in pairs( loopthrough ) do
1309 local bone = vm:LookupBone(k)
1310 if (!bone) then continue end
1311
1312 -- // !! WORKAROUND !! --//
1313 local s = Vector(v.scale.x,v.scale.y,v.scale.z)
1314 local p = Vector(v.pos.x,v.pos.y,v.pos.z)
1315 local ms = Vector(1,1,1)
1316 if (!hasGarryFixedBoneScalingYet) then
1317 local cur = vm:GetBoneParent(bone)
1318 while(cur >= 0) do
1319 local pscale = loopthrough[vm:GetBoneName(cur)].scale
1320 ms = ms * pscale
1321 cur = vm:GetBoneParent(cur)
1322 end
1323 end
1324
1325 s = s * ms
1326 //!! ----------- !! --
1327
1328 if vm:GetManipulateBoneScale(bone) != s then
1329 vm:ManipulateBoneScale( bone, s )
1330 end
1331 if vm:GetManipulateBoneAngles(bone) != v.angle then
1332 vm:ManipulateBoneAngles( bone, v.angle )
1333 end
1334 if vm:GetManipulateBonePosition(bone) != p then
1335 vm:ManipulateBonePosition( bone, p )
1336 end
1337 end
1338 else
1339 self:ResetBonePositions(vm)
1340 end
1341
1342 end
1343
1344 function SWEP:ResetBonePositions(vm)
1345
1346 if (!vm:GetBoneCount()) then return end
1347 for i=0, vm:GetBoneCount() do
1348 vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
1349 vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
1350 vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
1351 end
1352
1353 end
1354
1355 /**************************
1356 Global utility code
1357 **************************/
1358
1359 -- // Fully copies the table, meaning all tables inside this table are copied too and so on (normal table.Copy copies only their reference).
1360 -- // Does not copy entities of course, only copies their reference.
1361 -- // WARNING: do not use on tables that contain themselves somewhere down the line or you'll get an infinite loop
1362 function table.FullCopy( tab )
1363
1364 if (!tab) then return nil end
1365
1366 local res = {}
1367 for k, v in pairs( tab ) do
1368 if (type(v) == "table") then
1369 res[k] = table.FullCopy(v) --// recursion ho!
1370 elseif (type(v) == "Vector") then
1371 res[k] = Vector(v.x, v.y, v.z)
1372 elseif (type(v) == "Angle") then
1373 res[k] = Angle(v.p, v.y, v.r)
1374 else
1375 res[k] = v
1376 end
1377 end
1378
1379 return res
1380
1381 end
1382
1383end