Class PulseAmmo : Ammo { Default { Tag "$T_PULSEAMMO"; Inventory.PickupMessage "$I_PULSEAMMO"; Inventory.Amount 25; Inventory.MaxAmount 200; Ammo.BackpackAmount 10; Ammo.BackpackMaxAmount 400; Ammo.DropAmount 10; } States { Spawn: PAMO A -1; Stop; } } Class PulseSpark : Actor { Default { RenderStyle "Add"; Radius 2; Height 2; +NOBLOCKMAP; +NOGRAVITY; +MISSILE; +FORCEXYBILLBOARD; +THRUACTORS; +ROLLSPRITE; +ROLLCENTER; +NOTELEPORT; +DONTSPLASH; +CANBOUNCEWATER; -BOUNCEAUTOOFF; BounceType "Doom"; BounceFactor 1.0; WallBounceFactor 1.0; Scale 0.03; } override void PostBeginPlay() { Super.PostBeginPlay(); if ( !bAMBUSH ) { roll = FRandom[Pulse](0,360); let s = Spawn(GetClass(),pos); s.bAMBUSH = true; s.vel = vel; s.scale = scale; s.roll = roll; } } States { Spawn: PSPK A 1 Bright { A_FadeOut(FRandom[Pulse](0.0,0.15)); vel *= 0.96; } Wait; } } Class ViewPulseSpark : PulseSpark { Vector3 ofs, vvel; override void PostBeginPlay() { Actor.PostBeginPlay(); scale *= FRandom[Puff](0.4,0.9); alpha *= FRandom[Puff](0.5,2.0); roll = FRandom[Pulse](0,360); } override void Tick() { Actor.Tick(); if ( !target || !target.player ) { Destroy(); return; } Vector3 x, y, z; [x, y, z] = dt_CoordUtil.GetAxes(target.pitch,target.angle,target.roll); Vector3 origin = level.Vec3Offset(target.Vec2OffsetZ(0,0,target.player.viewz),x*ofs.x+y*ofs.y+z*ofs.z); SetOrigin(origin,true); bInvisible = (players[consoleplayer].camera != target); if ( isFrozen() ) return; ofs += vvel; vvel *= 0.9; scale *= 0.8; if ( scale.x <= 0.01 ) Destroy(); } States { Spawn: PSPK A 1 Bright A_FadeOut(FRandom[Pulse](0.0,0.15)); Wait; } } Class PulseBallLight : DynamicLight { double pulseofs; Default { DynamicLight.Type "Point"; Args 64,255,0,10; } override void PostBeginPlay() { Super.PostBeginPlay(); pulseofs = FRandom[Pulse](0,360); } override void Tick() { Super.Tick(); if ( !target || target.InStateSequence(target.CurState,target.ResolveState("Death")) ) { Destroy(); return; } SetOrigin(target.pos,true); args[LIGHT_INTENSITY] = 10+int(sin(gametic*80+pulseofs)*5); } } Class PulseExplLight : PaletteLight { Default { Tag "ExplGreen"; ReactionTime 20; Args 0,0,0,30; } } Class PulseBall : Actor { Default { Obituary "$O_PULSEGUN"; DamageType 'Pulsed'; RenderStyle "Add"; DamageFunction 20; PROJECTILE; +EXPLODEONWATER; +SKYEXPLODE; +FORCEXYBILLBOARD; Scale 0.19; Speed 22; Radius 2; Height 2; } override void PostBeginPlay() { A_StartSound("pulse/fly",CHAN_BODY,CHANF_LOOPING,.8,8.); let l = Spawn("PulseBallLight",pos); l.target = self; } action void A_BallExp() { A_SetScale(0.45); A_StartSound("pulse/hit"); A_SprayDecal("BoltScorch"); Spawn("PulseExplLight",pos); int numpt = Random[Pulse](20,40); for ( int i=0; i ShootThroughList; override ETraceStatus TraceCallback() { if ( Results.HitType == TRACE_HitActor ) { if ( Results.HitActor == ignore ) return TRACE_Skip; if ( Results.HitActor.bSHOOTABLE ) return TRACE_Stop; return TRACE_Skip; } else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) ) { if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&Line.ML_BlockHitscan) ) return TRACE_Stop; ShootThroughList.Push(Results.HitLine); return TRACE_Skip; } return TRACE_Stop; } } Class PulseBoltCap : Actor { override void OnDestroy() { Super.OnDestroy(); if ( tracer ) tracer.Destroy(); } override void Tick() { Super.Tick(); if ( bAMBUSH ) return; if ( !tracer ) { tracer = Spawn(GetClass(),pos); tracer.bAMBUSH = true; } tracer.SetOrigin(pos,true); } Default { RenderStyle "Add"; Radius 0.1; Height 0; +NOGRAVITY; +NOCLIP; +DONTSPLASH; +FORCEXYBILLBOARD; +NOTELEPORT; Scale 0.3; } States { Spawn: PCAP ABCD 1 Bright; Loop; } } Class PulseBoltHit : Actor { override void OnDestroy() { Super.OnDestroy(); if ( tracer ) tracer.Destroy(); } override void Tick() { Super.Tick(); if ( bAMBUSH ) return; if ( !tracer ) { tracer = Spawn(GetClass(),pos); tracer.bAMBUSH = true; } } Default { RenderStyle "Add"; Radius 0.1; Height 0; +NOGRAVITY; +NOCLIP; +DONTSPLASH; +FORCEXYBILLBOARD; +NOTELEPORT; Scale 0.3; } States { Spawn: PHIT ABCD 1 Bright; Loop; } } Class PulseBolt : Actor { const beamsize = 81.0; PulseBoltTracer t; double accdamage; int lasthit; Actor damagedactor; Actor weffect; int position; PulseBolt next; override void OnDestroy() { Super.OnDestroy(); if ( next ) next.Destroy(); if ( weffect ) weffect.Destroy(); } override void PostBeginPlay() { Super.PostBeginPlay(); t = new("PulseBoltTracer"); t.ignore = target; let l = Spawn("PulseBoltLight",pos); l.target = self; } void CheckBeam( Vector3 x ) { t.ShootThroughList.Clear(); t.Trace(pos,cursector,x,beamsize,0); for ( int i=0; i 0.17 ) { t.Results.HitActor.DamageMobj(self,target,int(72*accdamage),'zapped',DMG_USEANGLE,atan2(x.y,x.x)); accdamage = 0; } } Vector3 norm = -x; if ( t.Results.HitType == TRACE_HitWall ) { norm = (t.Results.HitLine.delta.y,-t.Results.HitLine.delta.x,0).unit(); if ( t.Results.Side ) norm *= -1; t.Results.HitLine.RemoteActivate(tracer,t.Results.Side,SPAC_Impact,t.Results.HitPos); } else if ( t.Results.HitType == TRACE_HitFloor ) { if ( t.Results.ffloor ) norm = -t.Results.ffloor.top.Normal; else norm = t.Results.HitSector.floorplane.Normal; } else if ( t.Results.HitType == TRACE_HitCeiling ) { if ( t.Results.ffloor ) norm = -t.Results.ffloor.bottom.Normal; else norm = t.Results.HitSector.ceilingplane.Normal; } int numpt = Random[Pulse](10,20)*!Random[Pulse](0,2); for ( int i=0; i= 9 ) { int numpt = Random[Pulse](5,10)*!Random[Pulse](0,5); for ( int i=0; i 4 ) frame = 0; CheckBeam((cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch))); } } Class PulseMag : UTCasing { Default { BounceSound "enforcer/bounce"; } override void PostBeginPlay() { Super.PostBeginPlay(); heat = 0.; } States { Death: PCAS A -1 { pitch = Normalize180(pitch); if ( abs(deltaangle(pitch,0)) < 35 ) pitch = 0; else pitch = (pitch>0)?90:-90; angle = FRandom[Junk](0,360); } Stop; } } Class PulseGun : UTWeapon { int clipcount; bool ClipOut; double sangle; Actor beam; transient ui Font usmf; Property ClipCount : clipcount; PulseGunLED ammoled; override void DoEffect() { Super.DoEffect(); if ( !ammoled ) { let ti = ThinkerIterator.Create("PulseGunLED"); while ( ammoled=PulseGunLED(ti.Next()) ) break; if ( !ammoled ) ammoled = PulseGunLED(Spawn("PulseGunLED")); } if ( !Owner || !Owner.player || (Owner != players[consoleplayer].Camera) ) return; ammoled.mygun = self; //TexMan.SetCameraToTexture(ammoled,"PAmmoLed",90); } override int, int, bool, bool GetClipAmount() { if ( !flak_pulsereload ) return Super.GetClipAmount(); return ClipOut?-1:ClipCount, -1, (ClipCount<10), false; } action void A_DrainAmmo() { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( (weap.Ammo1.Amount <= 0) || !(player.cmd.buttons&BT_ALTATTACK) || (flak_pulsereload && (invoker.clipcount <= 0)) ) { player.SetPSprite(PSP_WEAPON,ResolveState("AltRelease")); return; } if ( invoker.special1 > 0 ) { invoker.special1--; return; } invoker.special1 = 9; if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return; invoker.clipcount--; if ( !flak_pulsereload && (invoker.clipcount <= 0) ) invoker.clipcount = min(invoker.default.clipcount,weap.Ammo1.Amount); invoker.FireEffect(); UTMainHandler.DoFlash(self,Color(32,128,255,128),1); A_AlertMonsters(); Vector3 x, y, z; [x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll); Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+4.1*y-2.7*z); for ( int i=0; i<4; i++ ) { let s = Spawn("UTViewSmoke",origin); UTViewSmoke(s).ofs = (10,4.1,-2.7); s.scale *= 1.8; s.target = self; s.SetShade("206010"); s.A_SetRenderStyle(0.4,STYLE_AddShaded); UTViewSmoke(s).vvel += (FRandom[Pulse](0.2,0.6),FRandom[Pulse](-0.2,0.2),FRandom[Pulse](-0.2,0.2)); } int numpt = Random[Pulse](8,16); for ( int i=0; i 0 ) { invoker.special1--; return; } invoker.special1 = 5; if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return; invoker.clipcount--; if ( !flak_pulsereload && (invoker.clipcount <=0) ) invoker.clipcount = (weap.Ammo1.Amount>0)?Min(50,weap.Ammo1.Amount):50; invoker.FireEffect(); UTMainHandler.DoFlash(self,Color(32,128,255,128),1); A_AlertMonsters(); A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.05); A_Overlay(-2,"MuzzleFlash"); A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true); A_OverlayRenderstyle(-2,STYLE_Add); Vector3 x, y, z; double a; [x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll); Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-1.8*z); origin = level.Vec3Offset(origin,y*cos(invoker.sangle)*2+z*sin(invoker.sangle)*2); invoker.sangle += 100; Actor p = Spawn("PulseBall",origin); p.angle = angle; p.pitch = BulletSlope(); p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed; p.target = self; for ( int i=0; i<8; i++ ) { let s = Spawn("UTViewSmoke",origin); UTViewSmoke(s).ofs = (10,3,-1.8); s.scale *= 1.8; s.target = self; s.SetShade("206010"); s.A_SetRenderStyle(0.4,STYLE_AddShaded); UTViewSmoke(s).vvel += (FRandom[Pulse](0.4,0.8),FRandom[Pulse](-0.2,0.2),FRandom[Pulse](-0.2,0.2)); } int numpt = Random[Pulse](8,16); for ( int i=0; i 0) ) return ResolveState("Reload"); A_WeaponReady(WRF_ALLOWRELOAD); } else A_WeaponReady(); return A_JumpIf(!Random[Pulse](0,300),1); } Wait; PGNI ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 { A_CheckReload(); if ( flak_pulsereload ) { if ( (invoker.clipcount <= 0) && (invoker.Ammo1.Amount > 0) ) return ResolveState("Reload"); A_WeaponReady(WRF_ALLOWRELOAD); } else A_WeaponReady(); return ResolveState(null); } Goto Idle; Fire: PGNI A 0 { invoker.special1 = 0; A_StartSound("pulse/fire",CHAN_WEAPON,CHANF_LOOPING); } PGNF ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 A_PulseFire(); PGF2 ABCDEFGHIJKLMN 1 A_PulseFire(); Goto Fire+1; Release: PGNC A 0 A_StartSound("pulse/down",CHAN_WEAPON); PGNC ABCDEFGHIJKLMNOPQRSTUVWXY 1 A_PulseRefire(); PGNC Y 0; Goto Idle; AltFire: PGBS ABCDE 1; Goto AltHold; AltHold: PGBL A 0 A_StartBeam(); PGBL ABCDEFGHIJ 1 A_DrainAmmo(); Goto AltHold+1; AltRelease: PGBE A 0 A_StopBeam(); PGBE ABCDE 1 A_PulseRefire(); Goto Idle; Reload: PGNI A 1; PGNI A 0 A_JumpIf(invoker.clipcount >= Min(invoker.default.clipcount,invoker.Ammo1.Amount),"Idle"); PGNR A 1 { A_StartSound("pulse/reload",CHAN_WEAPONMISC); if ( self is 'UTPlayer' ) UTPlayer(self).PlayReloading(); } PGNR BCDEFGHIJKLMNO 1; PGNR P 1 { invoker.clipout = true; invoker.clipcount = 0; } PGNR QRSTUVWXYZ 1; PGR2 A 1 { Vector3 x, y, z, origin; [x,y,z] = dt_CoordUtil.GetAxes(pitch,angle,roll); origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),x*4.-y*6.-z*8.); let c = Spawn("PulseMag",origin); c.angle = angle; c.pitch = pitch; c.vel = vel*.5+x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](-.5,.5)-z*FRandom[Junk](1,2); } PGR2 BCD 1; PGR2 E 1 { invoker.clipout = false; invoker.clipcount = Min(invoker.default.clipcount,invoker.Ammo1.Amount); } PGR2 FGHIJKLMNOPQRSTUVWX 1; Goto Idle; Deselect: PGNS W 1 A_StopSound(CHAN_WEAPON); PGNS VTSQPNMKJHGEDBA 1; PGNS A 1 A_Lower(int.max); Wait; Select: PGNS A 1 A_Raise(int.max); Wait; MuzzleFlash: PMUZ A 2 Bright; Stop; } }