// Dr. Locke's Mighty Wolf Breath Airgun aka "Deep Impact" Airblaster (from SWWM series) // Slot 1, replaces Fist, Staff, Hexen starting weapons Class DeepTracer : LineTracer { Actor ignoreme; Array hitlist; Array hitdist; Array hitposx, hitposy, hitposz; override ETraceStatus TraceCallback() { if ( Results.HitType == TRACE_HitActor ) { if ( Results.HitActor == ignoreme ) return TRACE_Skip; if ( Results.HitActor.bSHOOTABLE ) { hitlist.Push(Results.HitActor); hitdist.Push(Results.Distance); hitposx.Push(Results.HitPos.x); hitposy.Push(Results.HitPos.y); hitposz.Push(Results.HitPos.z); return TRACE_Skip; } return TRACE_Skip; } else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) ) { if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) ) return TRACE_Stop; return TRACE_Skip; } return TRACE_Stop; } } Class THitList { Actor a; int nhits; Vector3 avgdir; double avgdist; Vector3 avgpos; } Class DeepImpact : SWWMWeapon { int clipcount; double charge; bool charging; int wastecycle; // for easter egg transient ui SmoothDynamicValueInterpolator ChargeInter; transient int failtime; Property ClipCount : clipcount; override void HudTick() { Super.HudTick(); if ( !ChargeInter ) ChargeInter = SmoothDynamicValueInterpolator.Create(clipcount,.5); ChargeInter.Update(clipcount); } override bool ReportHUDAmmo() { return (ClipCount>0); } action void A_BeginCharge() { invoker.charge = 0; A_StartSound("deepimpact/charge",CHAN_WEAPONEXTRA); A_QuakeEx(2,2,2,35,0,1,"",QF_RELATIVE|QF_SCALEUP,rollIntensity:.2); A_AlertMonsters(swwm_uncapalert?0:100); } action void A_ChargeUp() { invoker.charge += 1./GameTicRate; A_WeaponOffset(FRandom[Impact](-1,1)*invoker.charge,32+FRandom[Impact](-1,1)*invoker.charge); if ( invoker.charge >= (invoker.clipcount*.01) ) { A_WeaponOffset(0,32); player.SetPSprite(PSP_WEAPON,ResolveState("AltRelease")); } } override Vector3 GetTraceOffset( int index ) { return (10.,2.,-3.); } action void A_DryFire() { let weap = Weapon(invoker); if ( !weap ) return; A_StartSound("deepimpact/dryfire",CHAN_WEAPON,CHANF_OVERLAP,.5); A_AlertMonsters(swwm_uncapalert?0:70); Vector3 x = SWWMUtility.GetPlayerViewDir(self); Vector3 origin = SWWMUtility.GetFireOffset(self,10,2,-3); int numpt = Random[Impact](5,7); for ( int i=0; i list; list.Clear(); int rings = 1; int wallhits = 0; Vector3 hitnormal; Vector3 wnorm = (0,0,0); for ( double i=0; i<.35; i+=.05 ) { for ( int j=0; j<360; j+=(360/rings) ) { dir = SWWMUtility.ConeSpread(x,y,z,j,i); t.hitlist.Clear(); t.hitdist.Clear(); t.hitposx.Clear(); t.hitposy.Clear(); t.hitposz.Clear(); t.Trace(origin,level.PointInSector(origin.xy),dir,250-i*150,0); SWWMBulletTrail.DoTrail(self,origin,dir,250-i*150,0); for ( int k=0; k 0 ) { wnorm /= wallhits; if ( (pos.z > floorz) && TestMobjZ() ) wnorm *= 2.4; SWWMUtility.DoKnockback(self,wnorm.unit(),wnorm.length()*5000000.); } foreach ( l:list ) { if ( !l.a ) continue; Vector3 avgdir = l.avgdir/l.nhits; double avgdist = l.avgdist/l.nhits; Vector3 avgpos = l.avgpos/l.nhits; double dmg = 5000.*(1.-clamp(avgdist/250.,0.,1.)); SWWMUtility.DoKnockback(l.a,avgdir,dmg*35.); let p = SWWMPuff.Setup(avgpos,avgdir,invoker,self,l.a); l.a.DamageMobj(p,self,int(dmg/250.),'Push',DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF); } let ti = ThinkerIterator.Create("Actor"); Actor m; let s = Demolitionist(self).mystats; while ( m = Actor(ti.Next()) ) { if ( !SWWMUtility.ValidProjectile(m) ) continue; Vector3 rdir = level.Vec3Diff(origin,m.pos); double rdist = rdir.length(); if ( rdist <= 0. ) continue; rdir /= rdist; if ( LineTrace(atan2(rdir.y,rdir.x),rdist,asin(-rdir.z),TRF_THRUACTORS|TRF_ABSPOSITION,origin.z,origin.x,origin.y) || (rdist > 250) || (rdir dot x < .75) ) continue; m.speed = m.vel.length(); m.vel = m.speed*1.5*(-m.vel.unit()*.3+rdir+x*.2).unit(); Vector3 ndir = m.vel.unit(); m.angle = atan2(ndir.y,ndir.x); m.pitch = asin(-ndir.z); if ( m.bSEEKERMISSILE && (m.target != self) ) m.tracer = m.target; m.target = self; if ( !m.FindInventory("ParriedBuff") ) { let pb = Inventory(Spawn("ParriedBuff")); pb.AttachToOwner(m); pb.bAMBUSH = true; } if ( s ) s.parries++; SWWMUtility.AchievementProgressInc("parry",1,player); } int numpt = Random[Impact](7,12); for ( int i=0; i=invoker.default.clipcount,"NoReload"); XZW2 A 2 A_StartSound("deepimpact/reloadbeg",CHAN_WEAPON,CHANF_OVERLAP); XZW3 HIJ 2; ReloadHold: XZW3 K 2 A_Crank(); XZW3 LM 2; XZW3 NOPQ 3; XZW3 K 0 A_JumpIf((player.cmd.buttons&(BT_RELOAD|BT_ALTATTACK))&&(invoker.clipcount