// player effects // simple object for moving a dropped item towards the player Class SWWMMagItem play { SWWMMagItem next; Inventory item; Demolitionist target; bool Tick() { if ( !target || (target.Health <= 0) ) return true; if ( !item || item.Owner || !item.bSPECIAL || item.bINVISIBLE || !SWWMUtility.SphereIntersect(target,item.pos,800) || !target.CheckSight(item,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) return true; Class cls = item.GetClass(); if ( item is 'Ammo' ) cls = Ammo(item).GetParentAmmo(); else if ( item is 'MaGammo' ) cls = MagAmmo(item).GetParentMagAmmo(); let oi = target.FindInventory(cls); if ( !item.bALWAYSPICKUP && oi && (oi.Amount >= oi.MaxAmount) ) return true; if ( (item is 'SWWMWeapon') && SWWMWeapon(item).HasSwapWeapon(target) && swwm_swapweapons ) return true; if ( (item is 'SWWMDualWeaponGiver') && SWWMDualWeaponGiver(item).HasSwapWeapon(target) && swwm_swapweapons ) return true; Vector3 dirto = level.Vec3Diff(item.pos,target.Vec3Offset(0,0,target.height/2)); double dist = dirto.length(); if ( SWWMUtility.BoxIntersect(item,target) ) { item.Touch(target); return false; } dirto /= dist; double fact = clamp(dist/800.,0.,1.)**.5; item.vel *= .75; item.vel += dirto*SWWMUtility.Lerp(8.,1.,fact); item.A_SoundVolume(CHAN_AMBEXTRA,1.-.8*fact); item.A_SoundPitch(CHAN_AMBEXTRA,SWWMUtility.Lerp(2.,.5,fact)); return false; } override void OnDestroy() { if ( !item ) return; if ( item.bSPECIAL ) item.bNOGRAVITY = item.default.bNOGRAVITY; item.A_StopSound(CHAN_AMBEXTRA); } } Class DashTrail : SWWMNonInteractiveActor { Mixin SWWMMinimalMovingWaterTick; Default { RenderStyle "Add"; Scale .3; +MASTERNOSEE; +FORCEXYBILLBOARD; } override void PostBeginPlay() { Super.PostBeginPlay(); SetState(FindState("Spawn")+Random[ExploS](0,7)); if ( waterlevel > 0 ) return; let t = Spawn("DashTrail2",level.Vec3Offset(pos,vel*.3)); t.master = master; t.vel = vel*1.2; let s = Spawn("SWWMSmoke",level.Vec3Offset(pos,vel*1.6)); s.vel = vel*.8; s.SetShade(Color(1,1,1)*Random[ExploS](64,128)); s.special1 = Random[ExploS](2,4); s.scale *= 1.4; s.alpha *= .3; } States { Spawn: JFLB ABCDEFGH 1 Bright { A_FadeOut(.2); A_SetScale(scale.x*.95); } Loop; } } Class DashTrail2 : SWWMNonInteractiveActor { Mixin SWWMMinimalMovingWaterTick; Default { RenderStyle "Add"; Scale .2; Alpha .4; +MASTERNOSEE; +FORCEXYBILLBOARD; } override void PostBeginPlay() { Super.PostBeginPlay(); SetState(FindState("Spawn")+Random[ExploS](0,7)); } States { Spawn: JFLR ABCDEFGH 1 Bright { A_FadeOut(.02); A_SetScale(scale.x*1.04); if ( waterlevel > 0 ) { let b = Spawn("SWWMBubble",pos); b.vel = vel; b.scale *= scale.x; Destroy(); } } Loop; } } Class DemolitionistRadiusShockwaveTail : SWWMNonInteractiveActor { Mixin SWWMMinimalMovingTick; Default { RenderStyle "Add"; } States { Spawn: XZW1 A 1 { pitch = min(85,(pitch+2)*1.05); A_FadeOut(.02); A_SetScale(scale.x*1.08,scale.y); vel *= .98; } Wait; } } Class DemolitionistRadiusShockwave : Actor { Actor lasthit; Default { RenderStyle "Add"; Speed 15; DamageFunction int(200*alpha); DamageType "GroundPound"; Radius 16; Height 8; Alpha .4; XScale .65; YScale 3.; PROJECTILE; +DONTSPLASH; +STEPMISSILE; +NOEXPLODEFLOOR; +FLATSPRITE; +RIPPER; +BLOODLESSIMPACT; -NOGRAVITY; +NOFRICTION; } override int DoSpecialDamage( Actor target, int damage, Name damagetype ) { if ( target == lasthit ) return 0; lasthit = target; if ( damage <= 0 ) return damage; if ( (target.mass < LARGE_MASS) && !target.bDONTTHRUST ) { target.vel.xy += vel.xy.unit()*(30000./max(50,target.mass))*alpha; if ( (target.pos.z <= floorz) || !target.TestMobjZ() ) target.vel.z += (8000./max(50,target.mass))*alpha; } return damage; } States { Spawn: XZW1 A 1 { SetZ(floorz); pitch = min(85,(pitch+2)*1.05); if ( !Random[ExploS](0,3) ) { let p = Spawn("InvisibleSplasher",Vec3Offset(0,0,2)); p.target = target; } let s = Spawn("DemolitionistRadiusShockwaveTail",pos); s.vel = vel*.35; s.scale = scale; s.alpha = alpha*.4; s.angle = angle; s.pitch = pitch; s.roll = roll; A_FadeOut(.015); A_SetScale(scale.x*1.08,scale.y); vel *= .98; } Wait; Death: XZW1 A 1 { SetZ(floorz); A_FadeOut(.05); A_SetScale(scale.x*1.1,scale.y*.97); } Wait; } } Class DemolitionistShockwave : SWWMNonInteractiveActor { Default { +NODAMAGETHRUST; +FORCERADIUSDMG; } override void PostBeginPlay() { Super.PostBeginPlay(); A_QuakeEx(7,7,7,30,0,300+min(special1,50)*4,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:200,rollIntensity:1.5); if ( target.player != players[consoleplayer] ) { A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,attenuation:.3); A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,attenuation:.2,pitch:.7); A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,attenuation:.1,pitch:.4); } SWWMUtility.DoExplosion(self,40+min(special1,120),100000+min(special1*2000,150000),100+min(special1*2,130),80,DE_BLAST|DE_EXTRAZTHRUST|DE_NONEXPLOSIVE,'GroundPound',target); for ( int i=0; i<360; i+=5 ) { Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](1,3); let s = Spawn("SWWMSmoke",Vec3Angle(4,i,8)); s.vel = pvel+SWWMUtility.AngleToVector3(i,7.); s.SetShade(Color(1,1,1)*Random[ExploS](64,224)); s.special1 = Random[ExploS](1,4); s.scale *= 1.5; s.alpha *= .4; } if ( pos.z > floorz+16 ) return; for ( int i=0; i<360; i+=5 ) { let r = Spawn("DemolitionistRadiusShockwave",Vec3Angle(5,i)); r.target = target; r.angle = i; r.vel.xy = AngleToVector(i,r.speed+min(special1*.15,30)); r.alpha *= .1+min(special1*.03,.9); } int numpt = Random[ExploS](10,20); for ( int i=0; i= litecolor.Size()) ) idx = 0; bool curactive = !(target.bINVISIBLE || (target.alpha <= double.epsilon)); // setting the pitch to a value outside [-90,90] makes it auto-update to the actor's own pitch // this is undocumented and it's very great and nice and fine that such a thing had to be found out purely by chance // how very wonderful /s double curheight = target.player?(target.player.viewz-target.pos.z):(target.height*.93); if ( curactive && (!oldactive || (idx != oldcolor) || (curheight != oldheight)) ) { target.A_AttachLight('DemoSelfLight',DynamicLight.PointLight,Color(255,112,144,176),200,0,DynamicLight.LF_DONTLIGHTSELF|DynamicLight.LF_ATTENUATE|DynamicLight.LF_SPOT,(5,0,curheight),0,15,60,180); target.A_AttachLight('DemoSelfLight2',DynamicLight.PointLight,litecolor[idx],80,0,DynamicLight.LF_DONTLIGHTSELF|DynamicLight.LF_ATTENUATE,(0,0,target.height/2)); } else if ( !curactive && oldactive ) { target.A_AttachLight('DemoSelfLight',DynamicLight.PointLight,0,0,0); target.A_AttachLight('DemoSelfLight2',DynamicLight.PointLight,0,0,0); } oldactive = curactive; oldcolor = idx; oldheight = curheight; } }