Class RifleAmmo : Ammo { Default { Tag "Box of Rifle Rounds"; Inventory.PickupMessage "You picked up a Box of Rifle Rounds."; Inventory.Amount 10; Inventory.MaxAmount 50; Ammo.BackpackAmount 20; Ammo.BackpackMaxAmount 100; Ammo.DropAmount 5; } States { Spawn: SBOX A -1; Stop; } } Class RifleAmmo2 : RifleAmmo { Default { Tag "Rifle Round"; Inventory.PickupMessage "You got a Rifle Round."; Inventory.Amount 1; Ammo.DropAmount 1; } States { Spawn: SRND A -1; Stop; } } Class SniperLight : EnforcerLight { Default { args 255,224,64,120; } } Class SniperRifle : UTWeapon { double sniperzoom; TextureID reticle; override void PostBeginPlay() { Super.PostBeginPlay(); reticle = TexMan.CheckForTexture("RReticle",Texman.Type_Any); } override void PreRender( double lbottom ) { if ( sniperzoom <= 1.0 ) return; Screen.DrawTexture(reticle,false,320,240,DTA_VirtualWidth,640,DTA_VirtualHeight,480,DTA_RenderStyle,(1|2<<8|1<<16)); Screen.DrawText(confont,Font.CR_DARKGREEN,192,160,String.Format("X%.1f",sniperzoom),DTA_Clean,true); } action void A_SniperFire( bool zoomed = false ) { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( weap.Ammo1.Amount <= 0 ) return; if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return; invoker.FireEffect(); UTMainHandler.DoFlash(self,Color(32,0,0,255),1); A_PlaySound("sniper/fire",CHAN_WEAPON); A_AlertMonsters(); if ( zoomed ) A_QuakeEx(2,2,2,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.09); else { A_QuakeEx(3,3,3,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.12); A_Overlay(-2,"MuzzleFlash"); A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true); A_OverlayRenderstyle(-2,STYLE_Add); } let l = Spawn("SniperLight",pos); l.target = self; Vector3 x, y, z; [x, y, z] = Matrix4.GetAxes(pitch,angle,roll); Vector3 origin = Vec2OffsetZ(0,0,player.viewz)+10.0*x; if ( !zoomed ) origin = origin+y*4.0-z*2.0; FLineTraceData d; LineTrace(angle,10000,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d); if ( d.HitType == TRACE_HitActor ) { int dmg = Random[Sniper](45,60); if ( d.HitLocation.z >= (d.HitActor.pos.z+d.HitActor.height*0.8) ) dmg = d.HitActor.DamageMobj(invoker,self,dmg+70,'Decapitated'); else dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot'); if ( d.HitActor.bNOBLOOD ) { let p = Spawn("BulletImpact",d.HitLocation); p.scale *= 1.5; p.angle = atan2(d.HitDir.y,d.HitDir.x)+180; p.pitch = asin(d.HitDir.z); } else { d.HitActor.TraceBleed(dmg,self); d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg); } } else if ( d.HitType != TRACE_HitNone ) { Vector3 hitnormal = -d.HitDir; if ( d.HitType == TRACE_HitFloor ) hitnormal = d.HitSector.floorplane.Normal; else if ( d.HitType == TRACE_HitCeiling ) hitnormal = d.HitSector.ceilingplane.Normal; else if ( d.HitType == TRACE_HitWall ) { hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit(); if ( !d.LineSide ) hitnormal *= -1; } let p = Spawn("BulletImpact",d.HitLocation+hitnormal*0.01); p.scale *= 1.5; p.angle = atan2(hitnormal.y,hitnormal.x); p.pitch = asin(-hitnormal.z); if ( d.HitLine ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation); } origin += x*8.0+y*6.0-z*9.0; let c = Spawn("UTCasing",origin); c.scale *= 1.25; c.vel = x*FRandom[Junk](-2,2)+y*FRandom[Junk](3,6)+z*FRandom[Junk](3,5); } Default { Tag "Sniper Rifle"; Obituary "%k put a bullet through %o's head."; Inventory.PickupMessage "You got the Sniper Rifle."; Weapon.UpSound "sniper/select"; Weapon.SlotNumber 0; Weapon.SelectionOrder 5; Weapon.AmmoType "RifleAmmo"; Weapon.AmmoUse 1; Weapon.AmmoType2 "RifleAmmo"; Weapon.AmmoUse2 1; Weapon.AmmoGive 8; } States { Spawn: SRFP A -1; Stop; SRFP B -1; Stop; Select: SRFS A 1 A_Raise(int.max); Wait; Ready: SRFS A 1 { A_ZoomFactor(invoker.sniperzoom=1.0,ZOOM_INSTANT); A_WeaponReady(WRF_NOFIRE); } SRFS BCDEFGHIJKLMNOPQ 1 A_WeaponReady(WRF_NOFIRE); Idle: SRFI A 1 { A_CheckReload(); A_WeaponReady(); } Wait; ZoomedIdle: TNT1 A 1 { A_CheckReload(); A_WeaponReady(); } Wait; Fire: SRFI A 0 A_JumpIf(invoker.sniperzoom>1.0,"ZoomedFire"); SRFI A 0 { A_SniperFire(); return A_Jump(256,1,11,21,31,41); } Goto Idle; SRF1 ABCDEFGHIJ 2; Goto Idle; SRF2 ABCDEFGHIJ 2; Goto Idle; SRF3 ABCDEFGHIJ 2; Goto Idle; SRF4 ABCDEFGHIJ 2; Goto Idle; SRF5 ABCDEFGHIJ 2; Goto Idle; ZoomedFire: TNT1 A 20 A_SniperFire(true); Goto ZoomedIdle; AltFire: SRFI A 0 A_JumpIf(invoker.sniperzoom>1.0,"AltHold2"); AltHold: TNT1 A 1 { if ( invoker.sniperzoom <= 8.0 ) A_ZoomFactor(invoker.sniperzoom*=1.1); invoker.sniperzoom = min(invoker.sniperzoom,8.1); } TNT1 A 0 A_Refire("AltHold"); Goto ZoomedIdle; AltHold2: SRFI A 1 A_ZoomFactor(invoker.sniperzoom=1.0,ZOOM_INSTANT); SRFI A 0 A_Refire("AltHold2"); Goto Idle; Deselect: SRFD A 0 A_ZoomFactor(invoker.sniperzoom=1.0,ZOOM_INSTANT); SRFD ABCDEFG 1; SRFD G 1 A_Lower(int.max); Wait; MuzzleFlash: SMUZ A 3 Bright; Stop; } }