Class ShockAmmo : Ammo { Default { Tag "ShockCore"; Inventory.PickupMessage "You picked up a Shock Core."; Inventory.Amount 10; Inventory.MaxAmount 50; Ammo.BackpackAmount 50; Ammo.BackpackMaxAmount 100; Ammo.DropAmount 10; } States { Spawn: SHOA A -1; Stop; } } Class ShockBeamTracer : LineTracer { Actor owner, ignore; override ETraceStatus TraceCallback() { if ( Results.HitType == TRACE_HitActor ) { if ( (Results.HitActor == owner) || (Results.HitActor == ignore) ) return TRACE_Skip; if ( Results.HitActor.bSHOOTABLE || Results.HitActor is 'ShockHitbox' ) 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; return TRACE_Skip; } return TRACE_Stop; } } Class ShockRifleWave : Actor { Default { RenderStyle "Add"; Radius 0.1; Height 0; Scale 0.7; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; } override void Tick() { Super.Tick(); if ( globalfreeze || level.frozen ) return; alpha -= 1/50.; } States { Spawn: SWAV A 50 Bright; SWAV B 0 Bright; Stop; } } Class ShockBeamRing : Actor { Default { RenderStyle "Add"; Radius 0.1; Height 0; Scale 0.5; ReactionTime 18; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; } override void Tick() { Super.Tick(); if ( globalfreeze || level.frozen ) return; alpha -= 1./ReactionTime; } States { Spawn: SRNG ABCDEFGHI 2 Bright; Stop; } } Class ShockBlastRing : ShockBeamRing { Default { Scale 3.0; ReactionTime 45; } States { Spawn: SRNG ABCDEFGHI 5 Bright; Stop; } } Class ShockBeam : Actor { ShockBeamTracer t; Vector3 tracedir; bool moving; double totaldist; Default { Obituary "%k inflicted mortal damage upon %o with the Shock Rifle"; RenderStyle "Add"; Radius 0.1; Height 0; Scale 0.4; DamageFunction Random[ASMD](30,45); +NOGRAVITY; +NOCLIP; +DONTSPLASH; +FORCEXYBILLBOARD; } override void PostBeginPlay() { Super.PostBeginPlay(); t = new("ShockBeamTracer"); t.owner = target; t.ignore = self; moving = true; } override void Tick() { Super.Tick(); if ( globalfreeze || level.frozen ) return; if ( !moving ) return; // step trace tracedir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); t.Trace(pos,cursector,tracedir,1000,0); totaldist += t.Results.Distance; // spawn particles for ( int i=0; i= 10000.0 ) { // reposition and explode on air SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true); A_SprayDecal("ShockMark",16); ExplodeMissile(t.Results.HitLine,null); moving = false; let r = Spawn("ShockBeamRing",pos); r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x); r.pitch = asin(-t.Results.HitVector.z); } else if ( t.Results.HitType == TRACE_HitNone ) { // reposition SetOrigin(t.Results.HitPos+t.Results.HitVector,true); angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x); pitch = asin(-t.Results.HitVector.z); } else if ( t.Results.HitType == TRACE_HitActor ) { // reposition and explode on actor SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true); ExplodeMissile(null,t.Results.HitActor); if ( t.Results.HitActor is 'ShockHitbox' ) { if ( target ) target.TakeInventory('ShockAmmo',2); let b = t.Results.HitActor.target; b.ExplodeMissile(null,self); b.A_Explode(Random[ASMD](150,160),250); b.A_QuakeEx(6,6,6,60,0,1200,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2); b.A_SprayDecal("BigShockMark1",100); b.A_SprayDecal("BigShockMark2",100); Spawn("ShockRifleWave",b.pos); Spawn("ShockBlastLight",b.pos); let r = Spawn("ShockBlastRing",b.pos); r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x); r.pitch = asin(-t.Results.HitVector.z); A_PlaySound("shock/blast",CHAN_WEAPON,attenuation:0.5); int numpt = Random[ASMD](200,300); for ( int i=0; i