Class PulseAmmo : Ammo { int OldSkin; void A_CheckSkin() { switch ( flak_oldpulse ) { case 1: if ( OldSkin != 1 ) A_ChangeModel("",1,"","",1,"models/222","JPammo_01.png"); OldSkin = 1; break; case 2: if ( OldSkin != 2 ) A_ChangeModel("",1,"","",1,"models/322","JPammo_01.png"); OldSkin = 2; break; default: if ( OldSkin != 0 ) A_ChangeModel("",1,"","",1,"models","JPammo_01.png"); OldSkin = 0; break; } } 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 A_CheckSkin(); Wait; } } Class PulseSpark : Actor { Default { RenderStyle "Add"; Radius 2; Height 2; +NOBLOCKMAP; +NOGRAVITY; +MISSILE; +FORCEXYBILLBOARD; +THRUACTORS; +ROLLSPRITE; +ROLLCENTER; +NOTELEPORT; +DONTSPLASH; +CANBOUNCEWATER; -BOUNCEAUTOOFF; +NOFRICTION; 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_Utility.GetAxes(target.angle,target.pitch,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; +NOFRICTION; 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(dt_Utility.Vec3FromAngle(angle,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; Property ClipCount : clipcount; transient ui Canvas AmmoLed; ui TextureID LedFont, LedBase, CountBar; int OldSkin; override void Tick() { Super.Tick(); switch ( flak_oldpulse ) { case 1: if ( OldSkin != 1 ) { A_ChangeModel("",1,"","",1,"models/222","JPulsePickup_01.png"); A_ChangeModel("",0,"","",2,"models/222","JPulseGun_02.png",CMDL_USESURFACESKIN); A_ChangeModel("",0,"","",3,"models/222","JPulseGun_03.png",CMDL_USESURFACESKIN); } OldSkin = 1; break; case 2: if ( OldSkin != 2 ) { A_ChangeModel("",1,"","",1,"models/322","JPulsePickup_01.png"); A_ChangeModel("",0,"","",2,"models/322","JPulseGun_02.png",CMDL_USESURFACESKIN); A_ChangeModel("",0,"","",3,"models/322","JPulseGun_03.png",CMDL_USESURFACESKIN); } OldSkin = 2; break; default: if ( OldSkin != 1 ) { A_ChangeModel("",1,"","",1,"models","JPulsePickup_01.png"); A_ChangeModel("",0,"","",2,"models","JPulseGun_02.png",CMDL_USESURFACESKIN); A_ChangeModel("",0,"","",3,"models","JPulseGun_03.png",CMDL_USESURFACESKIN); } OldSkin = 0; break; } } override void RenderOverlay( RenderEvent e ) { Vector2 fnt[] = { (0,1), (49,1), (98,1), (147,1), (196,1), (0,87), (49,87), (98,87), (147,87), (196,87) }; if ( !AmmoLed ) AmmoLed = TexMan.GetCanvas("PAmmoLed"); if ( !LedFont ) LedFont = TexMan.CheckForTexture("models/LEDFont.png",TexMan.Type_Any); if ( !LedBase ) LedBase = TexMan.CheckForTexture("models/AmmoLedBase.png",TexMan.Type_Any); if ( !CountBar ) CountBar = TexMan.CheckForTexture("models/AmmoCountBar.png",TexMan.Type_Any); AmmoLed.DrawTexture(LedBase,false,0,0); int amo = flak_pulsereload?ClipCount:Ammo1.Amount; int mamo = flak_pulsereload?default.ClipCount:Ammo1.MaxAmount; int dg3 = (amo/100)%10; int dg2 = (amo/10)%10; int dg1 = amo%10; AmmoLed.DrawTexture(LedFont,false,56,14,DTA_SrcX,fnt[dg3].x,DTA_SrcY,fnt[dg3].y,DTA_SrcWidth,48,DTA_SrcHeight,85,DTA_DestWidth,48,DTA_DestHeight,85,DTA_Color,(amo<10)?0xFFFF0000:0xFF0000FF); AmmoLed.DrawTexture(LedFont,false,104,14,DTA_SrcX,fnt[dg2].x,DTA_SrcY,fnt[dg2].y,DTA_SrcWidth,48,DTA_SrcHeight,85,DTA_DestWidth,48,DTA_DestHeight,85,DTA_Color,(amo<10)?0xFFFF0000:0xFF0000FF); AmmoLed.DrawTexture(LedFont,false,152,14,DTA_SrcX,fnt[dg1].x,DTA_SrcY,fnt[dg1].y,DTA_SrcWidth,48,DTA_SrcHeight,85,DTA_DestWidth,48,DTA_DestHeight,85,DTA_Color,(amo<10)?0xFFFF0000:0xFF0000FF); AmmoLed.DrawTexture(CountBar,false,30,100,DTA_DestWidth,(min(amo,mamo)*196)/mamo,DTA_DestHeight,10); } 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_Utility.GetAxes(angle,pitch,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_Utility.GetAxes(angle,pitch,roll); Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-1.8*z); origin = level.Vec3Offset(origin,dt_Utility.CircleOffset(y,z,invoker.sangle,2)); invoker.sangle += 100; Actor p = Spawn("PulseBall",origin); p.angle = angle; p.pitch = BulletSlope(); p.vel = dt_Utility.Vec3FromAngle(p.angle,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_Utility.GetAxes(angle,pitch,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; } }