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