// player effects // drop from monsters when using "Demoslayer" fun option // heals up to 100 HP when touched Class SlayerOrb : Actor abstract { Class tclass; Property TrailClass : tclass; Default { RenderStyle "Add"; Radius 4; Height 8; Scale .5; BounceFactor .75; WallBounceFactor .75; Gravity .35; PROJECTILE; +THRUACTORS; -NOGRAVITY; +NOTELEPORT; +DONTSPLASH; +BOUNCEONWALLS; +BOUNCEONFLOORS; +BOUNCEONCEILINGS; +CANBOUNCEWATER; +FORCEXYBILLBOARD; } virtual void PickedUp( int np, PlayerPawn mo ) { } override void Tick() { Vector3 oldp = pos; Super.Tick(); if ( !isFrozen() ) { let t = Spawn(tclass,pos); t.scale *= abs(scale.x); t.alpha *= alpha; scale *= .995; alpha = abs(scale.x)*2.; if ( abs(scale.x) < .1 ) { Destroy(); return; } } int np = -1; double mdist = 1000.; for ( int i=0; i mdist ) continue; mdist = dist; np = i; } if ( np == -1 ) return; let mo = players[np].mo; if ( (GetAge() > 5) && SWWMUtility.BoxIntersect(self,mo,pad:8) ) { PickedUp(np,mo); Destroy(); return; } if ( isFrozen() ) return; Vector3 dirto = level.Vec3Diff(pos,mo.Vec3Offset(0,0,mo.Height/2)); double distto = dirto.length(); dirto /= distto; double fact = ((1000.-distto)/1000.)**2.; vel *= 1.-.05*fact; vel += (dirto+(0,0,.1))*fact*2.; } override void PostBeginPlay() { Super.PostBeginPlay(); SpriteOffset = (0,-4); Scale.x *= RandomPick[Junk](-1,-1); Scale.y *= RandomPick[Junk](-1,-1); } } Class HealthOrb : SlayerOrb { Default { SlayerOrb.TrailClass "HealthOrbTrail"; } override void PickedUp( int np, PlayerPawn mo ) { int flg = CHANF_OVERLAP|CHANF_MAYBE_LOCAL; if ( mo.CheckLocalView() ) flg |= CHANF_NOPAUSE; mo.A_StartSound("misc/health_pkup",CHAN_ITEM,flg); int hp = int(ceil(abs(scale.x*10))); mo.GiveBody(hp,100); SWWMHandler.HealthFlash(np); SWWMScoreObj.Spawn(hp,mo.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+mo.Height/2),ST_Health); } States { Spawn: BLPF E -1 Bright; Stop; } } Class ArmorOrb : SlayerOrb { Default { SlayerOrb.TrailClass "ArmorOrbTrail"; } override void PickedUp( int np, PlayerPawn mo ) { int flg = CHANF_OVERLAP|CHANF_MAYBE_LOCAL; if ( mo.CheckLocalView() ) flg |= CHANF_NOPAUSE; mo.A_StartSound("misc/armor_pkup",CHAN_ITEM,flg); int hp = int(ceil(abs(scale.x*10))); let n = mo.FindInventory("ArmorNugget"); if ( !n ) { n = Inventory(Spawn("ArmorNugget")); n.AttachToOwner(mo); SWWMLoreLibrary.Add(mo.player,"Nugget"); n.Amount = 0; } if ( n.Amount < 100 ) n.Amount = min(n.Amount+hp,100); SWWMHandler.ArmorFlash(np); SWWMScoreObj.Spawn(hp,mo.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+mo.Height/2),ST_Armor); } States { Spawn: BLPF D -1 Bright; Stop; } } Class SlayerOrbTrail : Actor abstract { Default { RenderStyle "Add"; Radius .1; Height 0.; Scale .25; Alpha .5; +FORCEXYBILLBOARD; +NOGRAVITY; +NOBLOCKMAP; +DONTSPLASH; +NOTELEPORT; +NOINTERACTION; } override void Tick() { if ( isFrozen() ) return; alpha *= .9; scale *= 1.05; if ( alpha < .05 ) Destroy(); } override void PostBeginPlay() { Super.PostBeginPlay(); SpriteOffset = (0,-4); } } Class HealthOrbTrail : SlayerOrbTrail { States { Spawn: BLPS E -1 Bright; Stop; } } Class ArmorOrbTrail : SlayerOrbTrail { States { Spawn: BLPS D -1 Bright; Stop; } } Class DashTrail : Actor { Default { RenderStyle "Add"; Radius .1; Height 0.; Scale 0.3; +NOGRAVITY; +NOBLOCKMAP; +DONTSPLASH; +NOTELEPORT; +NOINTERACTION; FloatBobPhase 0; } override void PostBeginPlay() { Super.PostBeginPlay(); SetState(FindState("Spawn")+Random[ExploS](0,7)); let t = Spawn("DashTrail2",level.Vec3Offset(pos,vel*.3)); t.target = target; 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; } override void Tick() { Super.Tick(); // hack if ( target && (players[consoleplayer].Camera == target) ) Warp(target,pos.x,pos.y,pos.z,0,WARPF_ABSOLUTEPOSITION|WARPF_COPYINTERPOLATION); } States { Spawn: JFLB ABCDEFGH 1 Bright { A_FadeOut(.2); A_SetScale(scale.x*.95); } Loop; } } Class DashTrail2 : Actor { Default { RenderStyle "Add"; Radius .1; Height 0.; Scale 0.2; Alpha 0.4; +NOGRAVITY; +NOBLOCKMAP; +DONTSPLASH; +NOTELEPORT; +NOINTERACTION; FloatBobPhase 0; } override void PostBeginPlay() { Super.PostBeginPlay(); SetState(FindState("Spawn")+Random[ExploS](0,7)); } override void Tick() { Super.Tick(); // hack if ( target && (players[consoleplayer].Camera == target) ) Warp(target,pos.x,pos.y,pos.z,0,WARPF_ABSOLUTEPOSITION|WARPF_COPYINTERPOLATION); } 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 : Actor { Default { RenderStyle "Add"; Radius 16; Height 8; +NOBLOCKMAP; +NOGRAVITY; +DONTSPLASH; +NOTELEPORT; +NOINTERACTION; } 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; } 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 += (4000./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) ) Spawn("InvisibleSplasher",Vec3Offset(0,0,2)); 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 : Actor { Default { +NOGRAVITY; +NOBLOCKMAP; +NOTELEPORT; +NODAMAGETHRUST; +FORCERADIUSDMG; +NOINTERACTION; Radius .1; Height 0.; } 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,'GroundPound',target); for ( int i=0; i<360; i+=5 ) { Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,3); let s = Spawn("SWWMSmoke",Vec3Angle(4,i,8)); s.vel = pvel+(cos(i),sin(i),0)*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 = (cos(i),sin(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 rgb; str.Split(rgb,",",0); tagcolor = Color(255,rgb[0].ToInt(),rgb[1].ToInt(),rgb[2].ToInt()); } else tagcolor = Color(255,32,48,24); } bool doselflight = swwm_selflight; bool curactive = doselflight&&activelight(); // 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 if ( curactive && !oldactive ) target.A_AttachLight('DemoSelfLight',DynamicLight.PointLight,Color(112,144,176),200,0,DynamicLight.LF_DONTLIGHTSELF|DynamicLight.LF_ATTENUATE|DynamicLight.LF_SPOT,(5,0,target.player?(target.player.viewz-target.pos.z):(target.height*.93)),0,15,60,180); else if ( !curactive && oldactive ) target.A_AttachLight('DemoSelfLight',DynamicLight.PointLight,0,0,0); oldactive = curactive; bool curglow = doselflight&&(!(target.bINVISIBLE||(target.alpha <= double.epsilon))); if ( curglow && !oldglow ) target.A_AttachLight('DemoSelfLight2',DynamicLight.PointLight,tagcolor,80,0,DynamicLight.LF_DONTLIGHTSELF|DynamicLight.LF_ATTENUATE,(0,0,target.height/2)); else if ( !curglow && oldglow ) target.A_AttachLight('DemoSelfLight2',DynamicLight.PointLight,0,0,0); oldglow = curglow; } }