Class PulseAmmo : Ammo { Default { Tag "Pulse Cell"; Inventory.PickupMessage "You picked up a Pulse Cell."; Inventory.Amount 25; Inventory.MaxAmount 200; Ammo.BackpackAmount 40; 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_Matrix4.GetAxes(target.pitch,target.angle,target.roll); Vector3 origin = x*ofs.x+y*ofs.y+z*ofs.z+(0,0,target.player.viewz); SetOrigin(target.Vec2OffsetZ(origin.x,origin.y,origin.z),true); bInvisible = (players[consoleplayer].camera != target); if ( level.frozen || globalfreeze ) 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 : DynamicLight { double lifetime; Default { DynamicLight.Type "Point"; ReactionTime 20; Args 64,255,0,30; } override void PostBeginPlay() { Super.PostBeginPlay(); lifetime = 1.0; } override void Tick() { Super.Tick(); if ( globalfreeze || level.frozen ) return; args[LIGHT_RED] = int(64*lifetime); args[LIGHT_GREEN] = int(255*lifetime); lifetime -= 1./ReactionTime; if ( lifetime <= 0 ) Destroy(); } } Class PulseBall : Actor { Default { Obituary "%o ate %k's burning plasma death."; DamageType 'Pulsed'; RenderStyle "Add"; DamageFunction 20; PROJECTILE; +EXPLODEONWATER; +SKYEXPLODE; +FORCEXYBILLBOARD; Scale 0.19; Speed 22; Radius 2; Height 2; } override void PostBeginPlay() { A_PlaySound("pulse/fly",CHAN_BODY,0.8,true,8.0); let l = Spawn("PulseBallLight",pos); l.target = self; } action void A_BallExp() { A_SetScale(0.45); A_PlaySound("pulse/hit",CHAN_BODY); A_SprayDecal("BoltScorch"); Spawn("PulseExplLight",pos); int numpt = Random[Pulse](20,40); 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 PulseGun : UTWeapon { int clipcount; double sangle; Actor beam; Property ClipCount : clipcount; override void PostRender( double lbottom ) { if ( !flak_pulsereload ) return; Screen.DrawText(confont,Font.CR_GREEN,Screen.GetWidth()*0.01,lbottom-Screen.GetHeight()*0.01-confont.GetHeight(),String.Format("Clip: %2d / 50",clipcount)); } action void A_Reloading() { Weapon weap = Weapon(invoker); if ( !weap ) return; invoker.clipcount = Min(50,weap.Ammo1.Amount); A_PlaySound("pulse/reload",CHAN_WEAPON); } action void A_DrainAmmo() { Weapon weap = Weapon(invoker); if ( !weap ) return; if ( weap.Ammo1.Amount <= 0 ) return; 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); UTMainHandler.DoSwing(self,(FRandom[Pulse](-1,-1),FRandom[Pulse](-1,1)),0.1,-0.02,3,SWING_Spring,0,2); A_AlertMonsters(); Vector3 x, y, z; [x, y, z] = dt_Matrix4.GetAxes(pitch,angle,roll); Vector3 origin = Vec2OffsetZ(0,0,player.viewz)+10.0*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; i0)?Min(50,weap.Ammo1.Amount):50; invoker.FireEffect(); UTMainHandler.DoFlash(self,Color(32,128,255,128),1); UTMainHandler.DoSwing(self,(FRandom[Pulse](-1,-1),FRandom[Pulse](-1,1)),0.3,-0.1,2,SWING_Spring,0,3); 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_Matrix4.GetAxes(pitch,angle,roll); Vector3 origin = Vec2OffsetZ(0,0,player.viewz)+10.0*x+3.0*y-1.8*z; origin += y*cos(invoker.sangle)*2.0+z*sin(invoker.sangle)*2.0; 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.0,-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 A_Jump(255,"Reload"); A_WeaponReady(WRF_ALLOWRELOAD); } else A_WeaponReady(); return A_JumpIf(!Random[Pulse](0,300),1); } Wait; PGNI ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 { A_CheckReload(); A_WeaponReady(WRF_ALLOWRELOAD); } Goto Idle; Fire: PGNI A 0 A_PlaySound("pulse/fire",CHAN_WEAPON,1.0,true); Hold: PGNF A 1 A_PulseFire(); PGNF BCDEF 1; PNGF G 0 A_PulseRefire(1); Goto Release; PGNF G 1 A_PulseFire(); PGNF HIJKL 1; PNGF M 0 A_PulseRefire(1); Goto Release; PGNF N 1 A_PulseFire(); PGNF OPQRS 1; PNGF T 0 A_PulseRefire(1); Goto Release; PGNF U 1 A_PulseFire(); PGNF VWXYZ 1; PGF2 A 0 A_PulseRefire(1); Goto Release; PGF2 A 1 A_PulseFire(); PGF2 BCDEF 1; PGF2 G 0 A_PulseRefire(1); Goto Release; PGF2 H 1 A_PulseFire(); PGF2 IJKLM 1; PGF2 N 0 A_PulseRefire(); Goto Release; Release: PGNC A 0 A_PlaySound("pulse/down",CHAN_WEAPON); PGNC ABCDEFGHIJKLMNOPQRSTUVWXY 1 A_PulseRefire(null,true); PGNC Y 0; Goto Idle; AltFire: PGBS ABCDE 1; PGBL A 0 A_StartBeam(); AltHold: PGBL A 1 A_DrainAmmo(); PGBL B 0 A_PulseRefire(1); Goto AltRelease; PGBL B 1; PGBL C 0 A_PulseRefire(1); Goto AltRelease; PGBL C 1; PGBL D 0 A_PulseRefire(1); Goto AltRelease; PGBL D 1; PGBL E 0 A_PulseRefire(1); Goto AltRelease; PGBL E 1; PGBL F 0 A_PulseRefire(1); Goto AltRelease; PGBL F 1; PGBL G 0 A_PulseRefire(1); Goto AltRelease; PGBL G 1; PGBL H 0 A_PulseRefire(1); Goto AltRelease; PGBL H 1; PGBL I 0 A_PulseRefire(1); Goto AltRelease; PGBL I 1; PGBL J 0 A_PulseRefire(1); Goto AltRelease; PGBL J 1; PGBL A 0 A_PulseRefire(); AltRelease: PGBE A 0 A_StopBeam(); PGBE ABCDE 1 A_PulseRefire(null,true); Goto Idle; Reload: PGNI A 1; PGNI A 0 A_JumpIf(invoker.clipcount >= Min(50,invoker.Ammo1.Amount),"Idle"); PGNR A 1 A_Reloading(); PGNR BCDEFGHIJKLMNOPQRSTUVWXYZ 1; PGR2 ABCDEFGHIJKLMNOPQRSTUVWX 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; } }