Class URifleAmmo : Ammo { Default { Tag "$T_RIFLEAMMO"; Inventory.Icon "I_RifleA"; Inventory.PickupMessage ""; Inventory.Amount 8; Inventory.MaxAmount 50; Ammo.BackpackAmount 4; Ammo.BackpackMaxAmount 100; Ammo.DropAmount 8; +INVENTORY.IGNORESKILL; } override String PickupMessage() { if ( PickupMsg.Length() > 0 ) return Super.PickupMessage(); return String.Format("%s%d%s",StringTable.Localize("$I_RIFLEAMMOL"),Amount,StringTable.Localize("$I_RIFLEAMMOR")); } States { Spawn: SBOX A -1; Stop; } } Class URifleAmmo2 : URifleAmmo { Default { Tag "$T_RIFLEAMMO2"; Inventory.PickupMessage "$I_RIFLEAMMO2"; Inventory.Amount 1; Ammo.DropAmount 1; +INVENTORY.IGNORESKILL; } States { Spawn: SRND A -1; Stop; } } Class URifle : UnrealWeapon { double sniperzoom; ui TextureID reticle; transient ui Font zfont; bool bLightOn; UFlashLight1 lt[2]; override void PreRender( double lbottom ) { if ( sniperzoom <= 1. ) return; if ( reticle.IsNull() ) reticle = TexMan.CheckForTexture("UReticle",Texman.Type_Any); Screen.DrawTexture(reticle,false,320,320,DTA_VirtualWidth,640,DTA_VirtualHeight,640,DTA_LegacyRenderStyle,STYLE_Stencil,DTA_FillColor,Color(255,0,0)); if ( !zfont ) zfont = Font.GetFont('UTFont40'); Screen.DrawText(zfont,Font.CR_UNTRANSLATED,700,700,String.Format("X%.1f",sniperzoom),DTA_VirtualWidth,1280,DTA_VirtualHeight,960,DTA_LegacyRenderStyle,STYLE_Stencil,DTA_FillColor,Color(255,0,0)); } override void DetachFromOwner() { Super.DetachFromOwner(); PlayerInfo p = players[consoleplayer]; if ( p.Camera == Owner ) Shader.SetEnabled(p,"URifleScope",false); bLightOn = false; if ( lt[0] ) lt[0].Destroy(); if ( lt[1] ) lt[1].Destroy(); } override void RenderOverlay( RenderEvent e ) { PlayerInfo p = players[consoleplayer]; if ( (p.Camera != Owner) || (sniperzoom <= 1.) ) Shader.SetEnabled(p,"URifleScope",false); else Shader.SetEnabled(p,"URifleScope",CVar.GetCVar('sting_zoomshader',p).GetBool()); } override void DoEffect() { Super.DoEffect(); bALT_AMMO_OPTIONAL = !sting_rifle; if ( sniperzoom > 1.0 ) crosshair = 99; else crosshair = 0; } action void A_ToggleLight() { invoker.bLightOn = !invoker.bLightOn; A_StartSound(invoker.bLightOn?"lite/pickup":"lite/off",CHAN_ITEM); if ( invoker.bLightOn ) { if ( !invoker.lt[0] ) invoker.lt[0] = UFlashLight1(Spawn("UFlashLight1",pos)); invoker.lt[0].target = self; invoker.lt[0].master = invoker; invoker.lt[0].basecolor[0] = 255; invoker.lt[0].basecolor[1] = 224; invoker.lt[0].basecolor[2] = 192; invoker.lt[0].args[3] = 480; invoker.lt[0].SpotInnerAngle = 2; invoker.lt[0].SpotOuterAngle = 9; if ( !invoker.lt[1] ) invoker.lt[1] = UFlashLight1(Spawn("UFlashLight2",pos)); invoker.lt[1].target = self; invoker.lt[1].master = invoker; invoker.lt[1].basecolor[0] = 128; invoker.lt[1].basecolor[1] = 112; invoker.lt[1].basecolor[2] = 96; invoker.lt[1].args[3] = 500; invoker.lt[1].SpotOuterAngle = 15; } else { if ( invoker.lt[0] ) invoker.lt[0].Destroy(); if ( invoker.lt[1] ) invoker.lt[1].Destroy(); } } action void A_RifleFire( bool zoomed = false, bool alt = false ) { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( weap.Ammo1.Amount <= 0 ) return; if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return; if ( self is 'UTPlayer' ) UTPlayer(self).PlayAttacking3(); invoker.FireEffect(); UTMainHandler.DoFlash(self,Color(32,0,0,255),1); if ( alt ) A_StartSound("rifle/fire",CHAN_WEAPON,CHANF_OVERLAP,Dampener.Active(self)?.3:1.,pitch:FRandom[Sniper](0.9,1.1)); else A_StartSound("rifle/fire",CHAN_WEAPON,CHANF_OVERLAP,Dampener.Active(self)?.3:1.); if ( !Dampener.Active(self) ) A_AlertMonsters(); if ( zoomed ) A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.09); else { A_QuakeEx(2,2,2,3,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] = dt_CoordUtil.GetAxes(pitch,angle,roll); Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x); if ( !zoomed ) origin = level.Vec3Offset(origin,y*3-z*2); FLineTraceData d; double pt = BulletSlope(); LineTrace(angle,10000,pt,TRF_ABSPOSITION,origin.z,origin.x,origin.y,d); UTBulletTrail.DoTrail(self,origin,(cos(angle)*cos(pt),sin(angle)*cos(pt),-sin(pt)),10000,alt?3:1); if ( d.HitType == TRACE_HitActor ) { int dmg = 45; if ( d.HitLocation.z >= (d.HitActor.pos.z+d.HitActor.height*0.81) ) { dmg = d.HitActor.DamageMobj(invoker,self,100,'Decapitated',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); UTMainHandler.DoKnockback(d.HitActor,d.HitDir,35000); } else { dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); UTMainHandler.DoKnockback(d.HitActor,d.HitDir,30000); } 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 ) { if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.top.Normal; else hitnormal = d.HitSector.floorplane.Normal; } else if ( d.HitType == TRACE_HitCeiling ) { if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.bottom.Normal; else 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); } for ( int i=0; i<24; i++ ) { let s = Spawn("UTStaticViewSmoke",origin); UTViewSmoke(s).ofs = (10,3,-2); UTViewSmoke(s).vvel += (FRandom[Sniper](-0.05,0.15),FRandom[Sniper](-1.2,1.2),FRandom[Sniper](-0.1,0.1)); s.target = self; s.scale *= 1.8; s.alpha *= 0.3; } origin = level.Vec3Offset(origin,x*4+y*6-z*10); let c = Spawn("UCasing",origin); c.scale *= 1.25; c.angle = angle; c.pitch = pitch; c.vel = x*FRandom[Junk](-1.5,1.5)+y*FRandom[Junk](2,4)+z*FRandom[Junk](2,3); } override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack ) { if ( mod == 'Decapitated' ) return StringTable.Localize("$O_SNIPERDECAP"); return Obituary; } Default { Tag "$T_RIFLE"; Obituary "$O_SNIPER"; Inventory.PickupMessage "$I_RIFLE"; Weapon.UpSound "rifle/select"; Weapon.SlotNumber 9; Weapon.SelectionOrder 900; Weapon.SlotPriority 1; Weapon.AmmoType "URifleAmmo"; Weapon.AmmoUse 1; Weapon.AmmoType2 "URifleAmmo"; Weapon.AmmoUse2 1; Weapon.AmmoGive 8; Weapon.Kickback 250; UTWeapon.DropAmmo 4; +NOEXTREMEDEATH; } States { Spawn: SRFP A -1; Stop; SRFP B -1; Stop; Select: SRFS A 1 A_Raise(int.max); Wait; Ready: SRFS A 0 A_ZoomFactor(invoker.sniperzoom=1.0,ZOOM_INSTANT); SRFS ABCDEFGHIJKLMNOPQRST 1 A_WeaponReady(WRF_NOFIRE); Idle: SRFI A 1 { A_CheckReload(); A_WeaponReady(sting_riflel?(WRF_ALLOWZOOM|WRF_ALLOWRELOAD):WRF_ALLOWZOOM); } Wait; ZoomedIdle: TNT1 A 1 { A_CheckReload(); A_WeaponReady(sting_riflel?(WRF_ALLOWZOOM|WRF_ALLOWRELOAD):WRF_ALLOWZOOM); } Wait; Fire: SRFF A 0 A_JumpIf(invoker.sniperzoom>1.0,"ZoomedFire"); SRFF A 0 A_RifleFire(); SRFF ABCDEFGHIJ 2; Goto Idle; ZoomedFire: TNT1 A 20 A_RifleFire(true); Goto ZoomedIdle; AltFire: SRFF A 0 A_JumpIf(!sting_rifle,"Zoom"); SRFF A 0 A_JumpIf(invoker.sniperzoom>1.0,"ZoomedAltFire"); SRFF A 0 A_RifleFire(false,true); SRFF ABCDEFG 1; SRFF A 0 A_JumpIfNoAmmo("AltFireEnd"); SRFF A 0 A_RifleFire(false,true); SRFF ABCDEFG 1; SRFF A 0 A_JumpIfNoAmmo("AltFireEnd"); SRFF A 0 A_RifleFire(false,true); SRFF ABCDEFG 1; AltFireEnd: SRFF HIJ 1; SRFI A 3; Goto Idle; ZoomedAltFire: TNT1 A 7 A_RifleFire(true,true); TNT1 A 0 A_JumpIfNoAmmo("ZoomedAltFireEnd"); TNT1 A 7 A_RifleFire(true,true); TNT1 A 0 A_JumpIfNoAmmo("ZoomedAltFireEnd"); TNT1 A 7 A_RifleFire(true,true); ZoomedAltFireEnd: TNT1 A 6; Goto ZoomedIdle; Reload: SRFI A 0 A_JumpIf(invoker.sniperzoom>1.0,"ZoomedReload"); SRFI A 8 A_ToggleLight(); Goto Idle; ZoomedReload: TNT1 A 8 A_ToggleLight(); Goto Idle; Zoom: SRSU A 0 A_JumpIf(invoker.sniperzoom>1.0,"ZoomOut"); SRSU A 0 A_StartSound("rifle/scopeon",CHAN_WEAPONMISC,volume:.5); SRSU ABCDEFGHIJKLMN 1; SRSI A 0; Goto ZoomHold; ZoomHold: 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_JumpIf(player.cmd.buttons&(BT_ALTATTACK|BT_ZOOM),"ZoomHold"); Goto ZoomedIdle; ZoomOut: SRSD A 0 A_ZoomFactor(invoker.sniperzoom=1.0,ZOOM_INSTANT); SRSD A 0 A_StartSound("rifle/scopeoff",CHAN_WEAPONMISC,volume:.5); SRSI A 1; SRSD ABCDEFGHIJKLMNO 1; Goto Idle; Deselect: SRFD A 0 A_JumpIf(invoker.sniperzoom<=1.0,"Deselect2"); SRSD A 0 A_ZoomFactor(invoker.sniperzoom=1.0,ZOOM_INSTANT); SRSD A 0 A_StartSound("rifle/scopeoff",CHAN_WEAPONMISC,volume:.5); SRSI A 1; SRSD ABCDEFGHIJKLMNO 1; Deselect2: SRFD A 0 { A_ZoomFactor(invoker.sniperzoom=1.0,ZOOM_INSTANT); if ( invoker.bLightOn ) A_ToggleLight(); } SRFD ABCDEFG 1; SRFD H 1 A_Lower(int.max); Wait; MuzzleFlash: SMUZ A 3 Bright; Stop; } }