1. SHELL_9MM = 1 -- pistol shells
  2. SHELL_57 = 2 -- bigger pistol shells? maybe for desert eagle?
  3. SHELL_556 = 3 -- AK47, etc. shells
  4. SHELL_762NATO = 4 -- M4, etc. shells
  5. SHELL_SHOTGUN = 5 -- all shotguns
  6. SHELL_338MAG = 6 -- AWP/scout shells
  7. SHELL_50CAL = 7 -- this is the default hl2 rifle shell. it looks roughly like a 50
  8.  
  9. if ( SERVER ) then
  10. AddCSLuaFile( "shared.lua" )
  11. AddCSLuaFile( "cl_viewmodel.lua" )
  12.  
  13. SWEP.AutoSwitchFrom = false
  14. SWEP.AutoSwitchTo = false
  15. SWEP.Weight = 5
  16.  
  17. resource.AddFile("materials/gmod/scope.vtf")
  18. resource.AddFile("materials/gmod/scope.vmt")
  19. resource.AddFile("materials/gmod/scope-refract.vtf")
  20. resource.AddFile("materials/gmod/scope-refract.vmt")
  21. end
  22.  
  23. if ( CLIENT ) then
  24. include( "cl_viewmodel.lua" )
  25.  
  26. SWEP.BobScale = 1
  27. SWEP.SwayScale = 1
  28. SWEP.BounceWeaponIcon = false
  29. SWEP.DrawAmmo = false
  30. SWEP.DrawCrosshair = false
  31. SWEP.DrawWeaponInfoBox = false
  32. SWEP.UseCustomCrosshair = false
  33. SWEP.AccurateCrosshair = false
  34. SWEP.PrintName = "BlackOps Base"
  35. SWEP.RenderGroup = RENDERGROUP_OPAQUE
  36. SWEP.Slot = 0
  37. SWEP.SlotPos = 0
  38. SWEP.SpeechBubbleLid = surface.GetTextureID( "gui/speech_lid" )
  39. SWEP.WepSelectIcon = surface.GetTextureID( "weapons/swep" )
  40. SWEP.CSMuzzleFlashes = true
  41.  
  42. surface.CreateFont( "csd", ScreenScale( 60 ), 500, true, true, "CSSelectIcons" )
  43. surface.CreateFont( "csd", ScreenScale( 30 ), 500, true, true, "CSKillIcons" )
  44. surface.CreateFont( "HL2MPTypeDeath", ScreenScale( 60 ), 500, true, true, "HL2MPTypeSelect" )
  45.  
  46. SWEP.IconLetter = "e"
  47. SWEP.IconSelectFont = "CSSelectIcons"
  48. SWEP.IconFont = "CSKillIcons"
  49. end
  50.  
  51. SWEP.Category = "BlackOps"
  52. SWEP.Spawnable = false
  53. SWEP.AdminSpawnable = false
  54. SWEP.AnimPrefix = "python"
  55. SWEP.Author = "BlackOps"
  56. --SWEP.Base = "bo_base"
  57. SWEP.Contact = ""
  58. SWEP.Instructions = ""
  59. SWEP.Purpose = ""
  60. SWEP.ViewModel = ""
  61. SWEP.WorldModel = ""
  62. SWEP.ViewModelFlip = false
  63. SWEP.ViewModelFOV = 70
  64. SWEP.HoldType = "ar2"
  65.  
  66. --SWEP.Folder --returns the folder of the sweps
  67. --SWEP.Owner --returns the owner of the swep
  68. --SWEP.Weapon --returns the weapon entity
  69.  
  70. SWEP.Primary.Sound = Sound( "Weapon_AK47.Single" )
  71. SWEP.Primary.Recoil = 1.20
  72. SWEP.Primary.Damage = { 8, 14 }
  73. SWEP.Primary.BulletForce = 1
  74. SWEP.Primary.NumShots = 1
  75. SWEP.Primary.Cone = 0.03
  76. SWEP.Primary.ClipSize = 60
  77. SWEP.Primary.Delay = 0.085
  78. SWEP.Primary.DefaultClip = 999
  79. SWEP.Primary.Automatic = true
  80. SWEP.Primary.Ammo = "smg1"
  81. SWEP.Primary.ShellType = SHELL_9MM
  82.  
  83. SWEP.Secondary.ClipSize = 1
  84. SWEP.Secondary.DefaultClip = 1
  85. SWEP.Secondary.Automatic = false
  86. SWEP.Secondary.Ammo = "none"
  87.  
  88. SWEP.IronSightsPos = Vector(0,0,0)
  89. SWEP.IronSightsAng = Vector(0,0,0)
  90. SWEP.RunArmOffset = Vector(0,0,0)
  91. SWEP.RunArmAngle = Vector(0,0,0)
  92.  
  93. SWEP.CanSprintAndShoot = false
  94. SWEP.CanIronSight = true
  95.  
  96. SWEP.SprayTime = 0.2
  97. SWEP.SprayAccuracy = 0.5
  98.  
  99. SWEP.RunBob = 2.0
  100. SWEP.RunSway = 2.0
  101. SWEP.IronBob = 0.1
  102. SWEP.IronSway = 0.3
  103.  
  104. function SWEP:Initialize()
  105.  
  106. if ( SERVER ) then
  107. self:SetWeaponHoldType( self.HoldType )
  108. self:SetNPCMinBurst( 30 )
  109. self:SetNPCMaxBurst( 30 )
  110. self:SetNPCFireRate( 0.01 )
  111. end
  112.  
  113. self.Weapon:SetNetworkedBool( "Ironsights", false )
  114.  
  115. end
  116.  
  117. function SWEP:SetIronsights( b )
  118.  
  119. self.Weapon:SetNetworkedBool( "Ironsights", b )
  120.  
  121. if b == true then
  122. self.Owner:SetFOV(65,0.15)
  123. else
  124. self.Owner:SetFOV(0,0.15)
  125. end
  126.  
  127. end
  128.  
  129. function SWEP:Reload()
  130. if self.Owner:GetActiveWeapon():Clip1() == self.Primary.ClipSize then return end
  131. if self.Reloading or self.Owner:GetAmmoCount(self.Primary.Ammo) == 0 then return end
  132. if self.Weapon:Clip1() < self.Primary.ClipSize then
  133. self.Weapon:DefaultReload(ACT_VM_RELOAD)
  134. self:SetIronsights( false )
  135. end
  136. end
  137.  
  138. function SWEP:Deploy()
  139.  
  140. self:SetIronsights( false )
  141.  
  142. self.Weapon:SendWeaponAnim(ACT_VM_DRAW)
  143. return true
  144.  
  145. end
  146.  
  147. function SWEP:OnRestore()
  148.  
  149. self.NextSecondaryAttack = 0
  150. self:SetIronsights( false )
  151.  
  152. end
  153.  
  154. function SWEP:CanShootWeapon()
  155.  
  156. if( self.Owner:IsNPC() ) then
  157. return true
  158. end
  159.  
  160. if( self.CanSprintAndShoot == false ) then
  161. if( self.Owner:KeyDown( IN_SPEED ) ) then return false end
  162. if ( self.LastSprintTime && CurTime() - self.LastSprintTime < 0.1 ) then return false end
  163. end
  164.  
  165. return true
  166.  
  167. end
  168.  
  169. function SWEP:Think()
  170. if ( self.Owner && self.Owner:KeyDown( IN_SPEED ) ) then
  171. self.LastSprintTime = CurTime()
  172. self:SetIronsights( false )
  173. end
  174. self:GetStanceAccuracyBonus()
  175. end
  176.  
  177. function SWEP:GetStanceAccuracyBonus()
  178.  
  179. if( self.Owner:IsNPC() ) then
  180. return 0.8;
  181. end
  182.  
  183. if( self.ConstantAccuracy ) then
  184. return 1.0;
  185. end
  186.  
  187. local LastAccuracy = self.LastAccuracy or 0;
  188. local Accuracy = 1.0;
  189. local LastShoot = self.Weapon:GetNWFloat( "LastShootTime", 0 );
  190.  
  191. local speed = self.Owner:GetVelocity():Length()
  192. -- 200 walk, 500 sprint, 705 noclip
  193. local speedperc = math.Clamp( math.abs( speed / 2000 ), 0, 1 );
  194.  
  195. if( CurTime() <= LastShoot + self.SprayTime ) then
  196. --print ( CurTime() - LastShoot )
  197. Accuracy = Accuracy * self.SprayAccuracy;
  198. --Accuracy = Accuracy * ( CurTime() - LastShoot ) / (self.SprayAccuracy/2)
  199. end
  200.  
  201. if( speed > 10 ) then -- moving
  202. Accuracy = Accuracy * ( ( ( 1 - speedperc ) + 0.1 ) / 1.5 );
  203. end
  204.  
  205. if( self.Owner:KeyDown( IN_DUCK ) == true || self.Weapon:GetNetworkedBool( "Ironsights", false ) == true) then -- ducking moving forward
  206. Accuracy = Accuracy * 1.50;
  207. end
  208.  
  209. if( self.Owner:KeyDown( IN_LEFT ) or self.Owner:KeyDown( IN_RIGHT ) ) then -- just strafing
  210. Accuracy = Accuracy * 0.95;
  211. end
  212.  
  213. if( !self.Owner:OnGround() ) then
  214. Accuracy = Accuracy * 0.5;
  215. end
  216.  
  217. if( LastAccuracy != 0 ) then
  218. if( Accuracy > LastAccuracy ) then
  219. Accuracy = math.Approach( self.LastAccuracy, Accuracy, FrameTime() * 2 )
  220. else
  221. Accuracy = math.Approach( self.LastAccuracy, Accuracy, FrameTime() * -2 )
  222. end
  223. end
  224.  
  225. self.LastAccuracy = Accuracy;
  226.  
  227. return Accuracy * 2;
  228.  
  229. end
  230.  
  231. --bullet stuff
  232. function SWEP:SecondaryAttack()
  233.  
  234. if ( !self:CanShootWeapon() and !self.CanIronSight) then return end
  235.  
  236. self.Weapon:SetNextSecondaryFire( CurTime() + 0.3 )
  237.  
  238. if SERVER then
  239. bIronsights = !self.Weapon:GetNetworkedBool( "Ironsights", false )
  240. self:SetIronsights( bIronsights )
  241. end
  242. if ( CLIENT || SinglePlayer()) then
  243. self.Weapon:EmitSound(Sound("npc/metropolice/gear"..math.random(1,6)..".wav"),30,math.random(75,100)) --Sexy ironsight sound
  244. end
  245.  
  246. end
  247.  
  248. function SWEP:PrimaryAttack()
  249. if ( !self:CanShootWeapon() ) then return end
  250. if ( !self:CanPrimaryAttack() ) then return end
  251.  
  252. self.Weapon:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
  253.  
  254. self.Weapon:ShootBullet( self.Primary.NumShots, self.Primary.Cone/self:GetStanceAccuracyBonus() )
  255. self.Weapon:TakePrimaryAmmo( 1 )
  256.  
  257. if IsFirstTimePredicted() and self.Owner:IsValid() then --Predict that motha' fucka'
  258.  
  259. self.Owner:ViewPunchReset()
  260.  
  261. self.Weapon:EmitSound( self.Primary.Sound, 100, math.random(95,105) )
  262.  
  263. local bonus = self:GetStanceAccuracyBonus()
  264.  
  265. if ( CLIENT || SinglePlayer()) then
  266. local eyeang = self.Owner:EyeAngles()
  267. eyeang.pitch = eyeang.pitch - self.Primary.Recoil/bonus/1.5
  268. eyeang.yaw = eyeang.yaw - math.Rand(-1,1)*self.Primary.Recoil/bonus/1.5
  269.  
  270. self.Owner:SetEyeAngles( eyeang )
  271. end
  272.  
  273. if self.Weapon:GetNetworkedBool( "Ironsights", false ) == false then
  274. self.Owner:ViewPunch( Angle( -self.Primary.Recoil/bonus, math.Rand(-1,1)*self.Primary.Recoil, 0))
  275. else
  276. self.Owner:ViewPunch( Angle( -self.Primary.Recoil/bonus/2, math.Rand(-1,1)*self.Primary.Recoil/2, 0))
  277. end
  278. end
  279.  
  280. if ( (SinglePlayer() && SERVER) || CLIENT ) then
  281. self.Weapon:SetNetworkedFloat( "LastShootTime", CurTime() )
  282. end
  283.  
  284. end
  285.  
  286. function SWEP:ShootBullet( num_bullets, aimcone )
  287.  
  288. if self.Weappon:GetNetworkedBoool( "Ironsights", false ) == false then
  289. self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
  290. end
  291.  
  292. self.Owner:MuzzleFlash()
  293. self.Owner:SetAnimation( PLAYER_ATTACK1 )
  294.  
  295. if !IsFirstTimePredicted() then return end
  296.  
  297. local effectdata = EffectData()
  298. effectdata:SetOrigin( self.Owner:GetShootPos() )
  299. effectdata:SetEntity( self.Weapon )
  300. effectdata:SetStart( self.Owner:GetShootPos() )
  301. effectdata:SetNormal( self.Owner:GetAimVector() )
  302. effectdata:SetAttachment( 1 )
  303. util.Effect( "gunsmoke", effectdata ) --Was ugly
  304.  
  305. if SERVER and self.Primary.ShellType then
  306. local effectdata = EffectData()
  307. effectdata:SetEntity( self.Weapon )
  308. effectdata:SetAttachment( self.Weapon:LookupAttachment( "2" ) ) -- what attachment should the bullet come from?
  309. effectdata:SetScale( self.Primary.ShellType )
  310. util.Effect( "weapon_shell", effectdata, true, true )
  311. end
  312.  
  313. if self.MuzzleEffect and self.MuzzleEffect != nil then
  314. local effectdata = EffectData()
  315. effectdata:SetOrigin( self.Owner:GetShootPos() )
  316. effectdata:SetEntity( self.Weapon )
  317. effectdata:SetStart( self.Owner:GetShootPos() )
  318. effectdata:SetNormal( self.Owner:GetAimVector() )
  319. effectdata:SetAttachment( 1 )
  320. util.Effect( self.MuzzleEffect, effectdata )
  321. end
  322.  
  323. local bullet = {}
  324. bullet.Num = num_bullets
  325. bullet.Src = self.Owner:GetShootPos()
  326. bullet.Dir = self.Owner:GetAimVector()
  327. bullet.Spread = Vector( aimcone, aimcone, 0 )
  328. bullet.Tracer = 5
  329. bullet.Force = self.Primary.BulletForce
  330. if type( self.Primary.Damage ) == "table" then
  331. bullet.Damage = math.random( self.Primary.Damage[1], self.Primary.Damage[2] )
  332. else
  333. bullet.Damage = self.Primary.Damage
  334. end
  335. bullet.AmmoType = self.Primary.Ammo
  336. bullet.Callback = function ( attacker, tr, dmginfo )
  337. self.Weapon:BulletCallback( attacker, tr, dmginfo, 0 )
  338. end
  339.  
  340. self.Owner:FireBullets( bullet )
  341. end
  342.  
  343. function SWEP:BulletCallback( attacker, tr, dmginfo, bounce )
  344.  
  345. if( !self or !ValidEntity( self.Weapon ) ) then return end
  346.  
  347. self.Weapon:BulletPenetration( attacker, tr, dmginfo, bounce + 1 );
  348.  
  349. return { damage = true, effect = true, effects = true };
  350.  
  351. end
  352.  
  353. function SWEP:GetPenetrationDistance( mat_type )
  354.  
  355. --[[if ( mat_type == MAT_PLASTIC || mat_type == MAT_WOOD || mat_type == MAT_FLESH || mat_type == MAT_ALIENFLESH || mat_type == MAT_GLASS || mat_type == MAT_DIRT || mat_type == MAT_FOLIAGE || mat_type == MAT_VENT ) then
  356. return 128
  357. end]]
  358.  
  359. if( mat_type == MAT_GLASS || mat_type == MAT_VENT || mat_type == MAT_FOLIAGE ) then
  360. return 32
  361. elseif( mat_type == MAT_PLASTIC || mat_type == MAT_FLESH || mat_type == MAT_ALIENFLESH ) then
  362. return 24
  363. elseif( mat_type == MAT_WOOD || mat_type == MAT_DIRT ) then
  364. return 16
  365. elseif( mat_type == MAT_METAL ) then
  366. return 8
  367. end
  368.  
  369. return 24
  370.  
  371. end
  372.  
  373. function SWEP:GetDecalType( mat_type )
  374. if ( mat_type == MAT_WOOD ) then
  375. return "Impact.Wood"
  376. elseif ( mat_type == MAT_FLESH ) then
  377. return "Impact.BloodyFlesh"
  378. elseif ( mat_type == MAT_ALIENFLESH ) then
  379. return "Impact.Antlion"
  380. elseif ( mat_type == MAT_GLASS ) then
  381. return "Impact.Glass"
  382. elseif ( mat_type == MAT_METAL or mat_type == MAT_VENT ) then
  383. return "Impact.Metal"
  384. elseif ( mat_type == MAT_SAND or mat_type == MAT_FOLIAGE ) then
  385. return "Impact.Sand"
  386. end
  387.  
  388. return "Impact.Concrete"
  389. end
  390.  
  391. function SWEP:GetPenetrationDamageLoss( mat_type, distance, damage )
  392.  
  393. if( mat_type == MAT_GLASS || mat_type == MAT_VENT || mat_type == MAT_FOLIAGE ) then
  394. return damage - ( distance * 0.45 )
  395. elseif( mat_type == MAT_PLASTIC || mat_type == MAT_FLESH || mat_type == MAT_ALIENFLESH || mat_type == 45 ) then
  396. return damage - ( distance * 0.55 )
  397. elseif( mat_type == MAT_WOOD || mat_type == MAT_DIRT ) then
  398. return damage - ( distance * 0.65 )
  399. end
  400.  
  401. return damage - ( distance * 0.75 )
  402. end
  403.  
  404. function SWEP:BulletPenetration( attacker, tr, dmginfo, bounce )
  405.  
  406. if ( !self or !ValidEntity( self.Weapon ) ) then return end
  407.  
  408. if ( bounce > 5 ) then return false end
  409.  
  410. local PeneDir = tr.Normal * self:GetPenetrationDistance( tr.MatType )
  411.  
  412. local PeneTrace = {}
  413. PeneTrace.endpos = tr.HitPos
  414. PeneTrace.start = tr.HitPos + PeneDir
  415. PeneTrace.mask = MASK_SHOT
  416. PeneTrace.filter = { self.Owner }
  417.  
  418. local PeneTrace = util.TraceLine( PeneTrace )
  419.  
  420. if ( PeneTrace.StartSolid || PeneTrace.Fraction >= 1.0 || tr.Fraction <= 0.0 ) then return false end
  421.  
  422. local distance = ( PeneTrace.HitPos - tr.HitPos ):Length();
  423. local new_damage = self:GetPenetrationDamageLoss( tr.MatType, distance, dmginfo:GetDamage() );
  424.  
  425. --print( "Distance = ", distance, "Original Damage = ", dmginfo:GetDamage(), "New Damage = ",new_damage )
  426.  
  427. if( new_damage > 0 ) then
  428. local bullet =
  429. {
  430. Num = 1,
  431. Src = PeneTrace.HitPos,
  432. Dir = tr.Normal,
  433. Spread = Vector( 0, 0, 0 ),
  434. Tracer = 0,
  435. Force = 5,
  436. Damage = new_damage,
  437. AmmoType = "Pistol",
  438. }
  439.  
  440. bullet.Callback = function( a, b, c ) if ( self.BulletCallback ) then return self:BulletCallback( a, b, c, bounce + 1 ) end end
  441.  
  442. util.Decal(self:GetDecalType( PeneTrace.MatType ), PeneTrace.HitPos + PeneTrace.HitNormal, PeneTrace.HitPos - PeneTrace.HitNormal)
  443.  
  444. timer.Simple( 0, attacker.FireBullets, attacker, bullet, true )
  445. end
  446. end
  447.  
  448. function SWEP:DrawHUD( )
  449. local pos = LocalPlayer():GetShootPos()
  450. local ang = LocalPlayer():GetAimVector()
  451. local tracedata = {}
  452. tracedata.start = pos
  453. tracedata.endpos = pos+(ang*99999999)
  454. tracedata.filter = LocalPlayer()
  455. local trace = util.TraceLine(tracedata)
  456. local scrnpos = trace.HitPos:ToScreen()
  457.  
  458. local x = scrnpos.x
  459. local y = scrnpos.y
  460.  
  461. // No crosshair when ironsights is on
  462. if ( self.Weapon:GetNetworkedBool( "Ironsights" ) ) then return true end
  463.  
  464. //local scale = ( 10 + (self.Primary.Cone * ( 260 * (ScrH()/720) ) ) * (1/self:GetStanceAccuracyBonus())) * 0.5;
  465. local scale = 10 * self.Primary.Cone * (1/self:GetStanceAccuracyBonus())
  466.  
  467. // Scale the size of the crosshair according to how long ago we fired our weapon
  468. local LastShootTime = self.Weapon:GetNetworkedFloat( "LastShootTime", 0 )
  469. --local LastShootTime = self.LastAttack
  470. scale = scale * (2 - math.Clamp( (CurTime() - LastShootTime) * 5, 0.0, 1.0 ))
  471.  
  472. surface.SetDrawColor( 0, 255, 0, 255 )
  473.  
  474. // Draw an awesome crosshair
  475. local gap = 40 * scale
  476. local length = gap + 20 * scale
  477. surface.DrawLine( x - length, y, x - gap, y )
  478. surface.DrawLine( x + length, y, x + gap, y )
  479. surface.DrawLine( x, y - length, x, y - gap )
  480. surface.DrawLine( x, y + length, x, y + gap )
  481. end
  482.  
  483. function SWEP:DrawWeaponSelection( x, y, wide, tall, alpha )
  484.  
  485. local txt = self.IconLetter or "e"
  486. local font = self.IconSelectFont or "CSSelectIcons"
  487.  
  488. draw.SimpleText( txt, font, x + wide/2, y + tall*0.2, Color( 255, 210, 0, 255 ), TEXT_ALIGN_CENTER )
  489. draw.SimpleText( txt, font, x + wide/2 + math.Rand(-4, 4), y + tall*0.2+ math.Rand(-14, 14), Color( 255, 210, 0, math.Rand(10, 120) ), TEXT_ALIGN_CENTER )
  490. draw.SimpleText( txt, font, x + wide/2 + math.Rand(-4, 4), y + tall*0.2+ math.Rand(-9, 9), Color( 255, 210, 0, math.Rand(10, 120) ), TEXT_ALIGN_CENTER )
  491.  
  492. end
  493.  
  494. function SWEP:DoDrawCrosshair( x, y )
  495. return true
  496. end