// basic effects // imitates UE1 light type LT_TexturePaletteOnce/LT_TexturePaletteLoop Class PaletteLight : PointLight { Color pal[256]; bool IsLooping; int InitialReactionTime; Default { Tag "Explosion"; Args 0,0,0,80; ReactionTime 15; } private void UpdateLight() { int index = clamp(255-((255*ReactionTime)/InitialReactionTime),0,255); args[LIGHT_RED] = pal[index].r; args[LIGHT_GREEN] = pal[index].g; args[LIGHT_BLUE] = pal[index].b; } override void PostBeginPlay() { Super.PostBeginPlay(); String palname = GetTag(); int sep = palname.IndexOf(","); int palnum = 0; if ( sep != -1 ) { String palnumstr = palname.Mid(sep+1); palnum = palnumstr.ToInt()*768; palname.Truncate(sep); } int lump = Wads.CheckNumForFullname(String.Format("palettes/%s.pal",palname)); String paldat = Wads.ReadLump(lump); for ( int i=0; i<256; i++ ) { pal[i].r = paldat.ByteAt(palnum++); pal[i].g = paldat.ByteAt(palnum++); pal[i].b = paldat.ByteAt(palnum++); } if ( ReactionTime < 0 ) { ReactionTime = abs(ReactionTime)-1; IsLooping = true; } InitialReactionTime = ReactionTime; UpdateLight(); } override void Tick() { Super.Tick(); if ( isFrozen() || (freezetics > 0) ) return; ReactionTime--; if ( ReactionTime < 0 ) { if ( !IsLooping ) { Destroy(); return; } else ReactionTime = abs(InitialReactionTime); } if ( target ) SetOrigin(target.pos,true); UpdateLight(); } } // Generic smoke, lightweight tick Class SWWMSmoke : SWWMNonInteractiveActor { Default { RenderStyle "Shaded"; StencilColor "FFFFFF"; Speed 1; +FORCEXYBILLBOARD; +ROLLSPRITE; +ROLLCENTER; Scale .3; } override void PostBeginPlay() { double ang, pt; scale *= FRandom[Puff](.5,1.5); alpha = min(1.,alpha*FRandom[Puff](.5,1.5)); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[Puff](.2,.8)*speed; roll = Frandom[Puff](0,360); scale.x *= RandomPick[Puff](-1,1); scale.y *= RandomPick[Puff](-1,1); } override void Tick() { prev = pos; // for interpolation if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; vel *= .96; vel.z += .01; // linetrace-based movement (hopefully more reliable than traditional methods) Vector3 dir = vel; double spd = vel.length(); dir /= spd; double dist = spd; FLineTraceData d; Vector3 newpos = pos; newpos.z = clamp(newpos.z,floorz,ceilingz); int nstep = 0; while ( dist > 0 ) { // safeguard, too many bounces if ( nstep > MAXBOUNCEPERTIC ) { Destroy(); return; } double ang = atan2(dir.y,dir.x); double pt = asin(-dir.z); LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN|TRF_ABSPOSITION,newpos.z,newpos.x,newpos.y,d); if ( d.HitType != TRACE_HitNone ) { Vector3 hitnormal = SWWMUtility.GetLineTraceHitNormal(d); dist -= d.Distance; // should only happen if we bounced dir = d.HitDir-(FRandom[Puff](1.,1.2)*hitnormal*(d.HitDir dot hitnormal)); vel = dir*spd; newpos = d.HitLocation+dir; } else { dist = 0.; newpos = level.Vec3Offset(newpos,dir*spd); } nstep++; } newpos.z = clamp(newpos.z,floorz,ceilingz); SetOrigin(newpos,true); UpdateWaterLevel(); if ( (waterlevel > 0) && !bAMBUSH ) { let b = Spawn("SWWMBubble",pos); b.scale *= abs(scale.x); b.vel = vel; Destroy(); return; } if ( !CheckNoDelay() || (tics == -1) ) return; if ( tics > 0 ) tics--; while ( !tics ) { if ( !SetState(CurState.NextState) ) return; } } States { Spawn: XSMK ABCDEFGHIJKLMNOPQRST 1 A_SetTics(1+special1); Stop; } } // strictly non-colliding smoke, much lighter tick, used for heavier effects Class SWWMHalfSmoke : SWWMNonInteractiveActor { Default { RenderStyle "Shaded"; StencilColor "FFFFFF"; Speed 1; +FORCEXYBILLBOARD; +ROLLSPRITE; +ROLLCENTER; Scale 0.3; } override void PostBeginPlay() { double ang, pt; scale *= FRandom[Puff](0.5,1.5); alpha *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[Puff](0.2,0.8)*speed; roll = Frandom[Puff](0,360); scale.x *= RandomPick[Puff](-1,1); scale.y *= RandomPick[Puff](-1,1); } override void Tick() { prev = pos; // for interpolation if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; vel *= 0.96; vel.z += 0.01; SetOrigin(level.Vec3Offset(pos,vel),true); UpdateWaterLevel(); if ( (waterlevel > 0) && !bAMBUSH ) { let b = Spawn("SWWMBubble",pos); b.scale *= abs(scale.x); b.vel = vel; Destroy(); return; } if ( !CheckNoDelay() || (tics == -1) ) return; if ( tics > 0 ) tics--; while ( !tics ) { if ( !SetState(CurState.NextState) ) return; } } States { Spawn: XSMK ABCDEFGHIJKLMNOPQRST 1 A_SetTics(1+special1); Stop; } } Class SWWMSmallSmoke : SWWMHalfSmoke { override void PostBeginPlay() { double ang, pt; scale *= FRandom[Puff](0.1,0.3); alpha *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[Puff](0.04,0.16); roll = Frandom[Puff](0,360); scale.x *= RandomPick[Puff](-1,1); scale.y *= RandomPick[Puff](-1,1); } States { Spawn: QSM6 ABCDEFGHIJKLMNOPQR 1 A_SetTics(1+special1); Stop; } } Class SWWMBubble : SWWMNonInteractiveActor { Default { RenderStyle "Add"; +FORCEXYBILLBOARD; Scale 0.5; } override void PostBeginPlay() { double ang, pt; scale *= FRandom[Puff](0.5,1.5); ang = FRandom[Puff](0,360); pt = FRandom[Puff](-90,90); vel += SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[Puff](0.2,0.8); if ( waterlevel <= 0 ) Destroy(); SetState(ResolveState("Spawn")+Random[Puff](0,19)); } override void Tick() { prev = pos; if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; vel *= 0.96; vel.z += 0.05; // linetrace-based movement (hopefully more reliable than traditional methods) Vector3 dir = vel; double spd = vel.length(); dir /= spd; double dist = spd; FLineTraceData d; Vector3 newpos = pos; newpos.z = clamp(newpos.z,floorz,ceilingz); int nstep = 0; while ( dist > 0 ) { // safeguard, too many bounces if ( nstep > MAXBOUNCEPERTIC ) { Destroy(); return; } double ang = atan2(dir.y,dir.x); double pt = asin(-dir.z); LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN|TRF_ABSPOSITION,newpos.z,newpos.x,newpos.y,d); if ( d.HitType != TRACE_HitNone ) { Vector3 hitnormal = SWWMUtility.GetLineTraceHitNormal(d); dist -= d.Distance; // should only happen if we bounced dir = d.HitDir-(FRandom[Puff](1.,1.2)*hitnormal*(d.HitDir dot hitnormal)); vel = dir*spd; newpos = d.HitLocation+dir; } else { dist = 0.; newpos = level.Vec3Offset(newpos,dir*spd); } nstep++; } newpos.z = clamp(newpos.z,floorz,ceilingz); SetOrigin(newpos,true); UpdateWaterLevel(); if ( (waterlevel <= 0) || !Random[Puff](0,100) ) Destroy(); if ( !CheckNoDelay() || (tics == -1) ) return; if ( tics > 0 ) tics--; while ( !tics ) { if ( !SetState(CurState.NextState) ) return; } } States { Spawn: XBUB ABCDEFGHIJKLMNOPQRST 1; Loop; } } Class SWWMSparkTrail : SWWMNonInteractiveActor { Default { RenderStyle "Add"; +FORCEXYBILLBOARD; } override void Tick() { if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; A_SetScale(scale.x*.9,scale.y); A_FadeOut(.06); } States { Spawn: XZW1 A -1 Bright; Stop; } } Class SWWMSpark : SWWMNonInteractiveActor { bool dead; Sector tracksector; int trackplane; Default { RenderStyle "Add"; +FORCEXYBILLBOARD; Gravity .2; Scale .05; } override void Tick() { prev = pos; if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; if ( dead ) { // do nothing but follow floor movement if ( tracksector ) { double trackz; if ( trackplane ) trackz = tracksector.ceilingplane.ZAtPoint(pos.xy); else trackz = tracksector.floorplane.ZAtPoint(pos.xy); if ( trackz != pos.z ) SetZ(trackz); } } else { vel.z -= GetGravity(); // linetrace-based movement (hopefully more reliable than traditional methods) Vector3 dir = vel; double spd = vel.length(); dir /= spd; double dist = spd; FLineTraceData d; Vector3 newpos = pos; newpos.z = clamp(newpos.z,floorz,ceilingz); int nstep = 0; while ( dist > 0 ) { Vector3 oldpos = newpos; // safeguard, too many bounces if ( nstep > MAXBOUNCEPERTIC ) { Destroy(); return; } double ang = atan2(dir.y,dir.x); double pt = asin(-dir.z); LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN|TRF_ABSPOSITION,newpos.z,newpos.x,newpos.y,d); if ( d.HitType != TRACE_HitNone ) { Vector3 hitnormal = SWWMUtility.GetLineTraceHitNormal(d); dist -= d.Distance; // should only happen if we bounced dir = d.HitDir-(2*hitnormal*(d.HitDir dot hitnormal)); spd *= .4; dist *= .4; vel = dir*spd; newpos = d.HitLocation+dir; } else { dist = 0.; newpos = level.Vec3Offset(newpos,dir*spd); } if ( ((spd < 1.) || (dir.z <= 0.)) && ((d.HitType == TRACE_HitFloor) || (newpos.z <= floorz)) ) { // lose speed and die if ( d.Hit3DFloor ) { newpos.z = d.Hit3DFloor.top.ZAtPoint(newpos.xy); tracksector = d.Hit3DFloor.model; trackplane = 1; } else { // hacky workaround if ( !d.HitSector ) d.HitSector = floorsector; newpos.z = d.HitSector.floorplane.ZAtPoint(newpos.xy); tracksector = d.HitSector; trackplane = 0; } vel = (0,0,0); pitch = 0; roll = 0; dead = true; SetStateLabel("Death"); break; } nstep++; } newpos.z = clamp(newpos.z,floorz,ceilingz); Vector3 taildir = level.Vec3Diff(newpos,pos); double taillen = taildir.length(); if ( (taillen > 0.) && (alpha > .3) && (waterlevel <= 0) ) { taildir /= taillen; let t = Spawn("SWWMSparkTrail",newpos); t.alpha = alpha*.3; t.speed = taillen; [t.angle, t.pitch, t.scale.y] = SWWMUtility.CalcYBeam(taildir,taillen); } SetOrigin(newpos,true); if ( (pos.z <= floorz) && GetFloorTerrain().IsLiquid ) { Destroy(); return; } } UpdateWaterLevel(); if ( waterlevel > 0 ) { let b = Spawn("SWWMBubble",pos); b.vel = vel; b.scale *= 0.3; Destroy(); return; } if ( !CheckNoDelay() || (tics == -1) ) return; if ( tics > 0 ) tics--; while ( !tics ) { if ( !SetState(CurState.NextState) ) return; } } States { Spawn: BLPF A 1 Bright A_FadeOut(0.01); Wait; Death: BLPF A 1 Bright A_FadeOut(0.05); Wait; } } Class SWWMChip : SWWMNonInteractiveActor { SWWMChip prevchip, nextchip; bool killme; double anglevel, pitchvel, rollvel; bool dead; Sector tracksector; int trackplane; Default { +INTERPOLATEANGLES; +ROLLSPRITE; +ROLLCENTER; +FORCEXYBILLBOARD; Gravity .35; Scale .2; } override void PostBeginPlay() { anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); frame = Random[Junk](0,7); scale *= Frandom[Junk](0.8,1.2); SWWMHandler.QueueChip(self); } override void OnDestroy() { SWWMHandler.DeQueueChip(self); Super.OnDestroy(); } override void Tick() { prev = pos; // for interpolation if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; if ( dead ) { // do nothing but follow floor movement if ( tracksector ) { double trackz; if ( trackplane ) trackz = tracksector.ceilingplane.ZAtPoint(pos.xy); else trackz = tracksector.floorplane.ZAtPoint(pos.xy); if ( trackz != pos.z ) { SetZ(trackz); UpdateWaterLevel(false); } } } else { if ( waterlevel <= 0 ) vel.z -= GetGravity(); // linetrace-based movement (hopefully more reliable than traditional methods) Vector3 dir = vel; double spd = vel.length(); dir /= spd; double dist = spd; FLineTraceData d; Vector3 newpos = pos; newpos.z = clamp(newpos.z,floorz,ceilingz); int nstep = 0; while ( dist > 0 ) { // safeguard, too many bounces if ( nstep > MAXBOUNCEPERTIC ) { Destroy(); return; } double ang = atan2(dir.y,dir.x); double pt = asin(-dir.z); LineTrace(ang,dist,pt,TRF_THRUACTORS|TRF_THRUHITSCAN|TRF_ABSPOSITION,newpos.z,newpos.x,newpos.y,d); if ( d.HitType != TRACE_HitNone ) { Vector3 hitnormal = SWWMUtility.GetLineTraceHitNormal(d); dist -= d.Distance; // should only happen if we bounced dir = d.HitDir-(2*hitnormal*(d.HitDir dot hitnormal)); spd *= .3; dist *= .3; vel = dir*spd; newpos = d.HitLocation+dir; SetStateLabel("Bounce"); } else { dist = 0.; newpos = level.Vec3Offset(newpos,dir*spd); } newpos.z = clamp(newpos.z,floorz,ceilingz); if ( ((spd < 1.) || (dir.z <= 0.)) && ((d.HitType == TRACE_HitFloor) || (newpos.z <= floorz)) ) { // lose speed and die if ( d.Hit3DFloor ) { newpos.z = d.Hit3DFloor.top.ZAtPoint(newpos.xy); tracksector = d.Hit3DFloor.model; trackplane = 1; } else { // hacky workaround if ( !d.HitSector ) d.HitSector = floorsector; newpos.z = d.HitSector.floorplane.ZAtPoint(newpos.xy); tracksector = d.HitSector; trackplane = 0; } vel = (0,0,0); dead = true; SetStateLabel("Death"); break; } nstep++; } SetOrigin(newpos,true); UpdateWaterLevel(); if ( (pos.z <= floorz) && GetFloorTerrain().IsLiquid ) { Destroy(); return; } } if ( killme ) A_FadeOut(.01); if ( waterlevel > 0 ) { vel *= .99; if ( pos.z > floorz ) vel.z -= gravity*.01; anglevel *= .98; pitchvel *= .98; rollvel *= .98; } if ( !CheckNoDelay() || (tics == -1) ) return; if ( tics > 0 ) tics--; while ( !tics ) { if ( !SetState(CurState.NextState) ) return; } } States { Spawn: XZW1 # 1 { angle += anglevel; pitch += pitchvel; roll += rollvel; } Loop; Bounce: XZW1 # 0 { anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); } Goto Spawn; Death: XZW1 # -1; Stop; } } Class PoofLight : PaletteLight { Default { Tag "Yellow"; ReactionTime 5; Args 0,0,0,60; } } Class PoofLight2 : PaletteLight { Default { Tag "Yellow"; ReactionTime 20; Args 0,0,0,90; } } Class SWWMItemFog : SWWMNonInteractiveActor { Default { RenderStyle "Add"; +ROLLSPRITE; +ROLLCENTER; +FORCEXYBILLBOARD; } States { Spawn: BLPF A 2 Bright NoDelay { // offset up SetOrigin(Vec3Offset(0,0,16),false); roll = FRandom[ExploS](0,360); scale *= FRandom[ExploS](0.9,1.1); scale.x *= RandomPick[ExploS](-1,1); scale.y *= RandomPick[ExploS](-1,1); int numpt = Random[ExploS](8,12); if ( bAMBUSH ) numpt *= 2; for ( int i=0; i 0 ) { freezetics--; return; } if ( isFrozen() ) return; A_SetScale(scale.x*specialf1); A_FadeOut(specialf2); if ( vel != (0,0,0) ) { prev = pos; SetOrigin(level.Vec3Offset(pos,vel),true); vel *= .98; } } States { Spawn: BLPF C -1 Bright; Stop; } } Class SWWMTeleportDest : SWWMNonInteractiveActor { FSpawnParticleParams flare; override void PostBeginPlay() { special1 = Random[ExploS](0,10); } override void Tick() { if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; if ( (level.maptime+special1)%10 ) return; if ( !flare.texture ) { flare.color1 = "88 AA FF"; flare.texture = TexMan.CheckForTexture("graphics/Particles/xflare.png"); flare.style = STYLE_AddShaded; flare.flags = SPF_FULLBRIGHT; flare.fadestep = -1; } double dist = Distance3DSquared(players[consoleplayer].Camera); if ( dist >= 250000. ) return; double alph = clamp((250000.-dist)/250000.,0.,1.); flare.pos = pos+(0,0,28); int numpt = Random[ExploS](0,2); for ( int i=0; i 0 ) { freezetics--; return; } if ( isFrozen() ) return; if ( (level.maptime+special1)%5 ) return; Vector3 apos, bpos; apos.xy = tline.v1.p; bpos.xy = tline.v2.p; apos.z = max(tline.frontsector.floorplane.ZAtPoint(apos.xy),tline.backsector.floorplane.ZAtPoint(apos.xy)); bpos.z = max(tline.frontsector.floorplane.ZAtPoint(bpos.xy),tline.backsector.floorplane.ZAtPoint(bpos.xy)); int numpt = Random[ExploS](0,2); numpt *= int(clamp((apos-bpos).length()/32,1,8)); if ( !flare.texture ) { flare.color1 = "88 AA FF"; flare.texture = TexMan.CheckForTexture("graphics/Particles/xflare.png"); flare.style = STYLE_AddShaded; flare.flags = SPF_FULLBRIGHT; flare.fadestep = -1; } for ( int i=0; i= 250000. ) continue; double alph = clamp((250000.-dist)/250000.,0.,1.); double ang = FRandom[ExploS](0,360); double pt = FRandom[ExploS](-90,90); Vector3 pvel = SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[ExploS](.0,.3); flare.lifetime = Random[ExploS](120,240); flare.size = FRandom[ExploS](2.,4.); flare.sizestep = FRandom[ExploS](-.02,-.01); flare.pos = ppos; flare.vel = pvel; flare.accel = (0,0,FRandom[ExploS](.05,.1)); flare.startalpha = FRandom[ExploS](.15,.3)*alph; level.SpawnParticle(flare); } } } Class SWWMTeleportFog : SWWMNonInteractiveActor { Default { RenderStyle "Add"; +FORCEXYBILLBOARD; } override void PostBeginPlay() { Super.PostBeginPlay(); A_StartSound("misc/teleport",CHAN_VOICE); Spawn("TeleLight",pos); } States { Spawn: TNT1 A 1 { int numpt = int(Random[ExploS](6,12)*alpha); for ( int i=0; i= 160000000. ) alpha = 1.; else alpha = AlphaCubeRoot(clamp(max(0,camdist-40000.)/160000000.,0.,1.)); alpha *= FRandom[ClientSparkles](.9,1.); } // nearby sparkles if ( camdist >= 250000. ) return; double alph = clamp((250000.-camdist)/250000.,0.,1.); if ( !flare.texture ) { flare.color1 = Color(Args[1]*85,Args[2]*85,Args[3]*85); flare.texture = TexMan.CheckForTexture("graphics/Particles/xflare.png"); flare.style = STYLE_AddShaded; flare.flags = SPF_FULLBRIGHT; flare.lifetime = 30; flare.accel = (0,0,.05); flare.fadestep = -1; } flare.startalpha = alph; int numpt = Random[ClientSparkles](1,3); for ( int i=0; i WaterHitList; Array ShootThroughList; static play void DoTrail( Actor target, Vector3 pos, Vector3 dir, double dist, int bubblechance, bool smoky = false ) { let t = new("SWWMBulletTrail"); t.WaterHitList.Clear(); t.ShootThroughList.Clear(); t.Trace(pos,level.PointInSector(pos.xy),dir,dist,0,ignore:target); foreach ( l:t.ShootThroughList ) { // have to do both separately, for whatever reason l.Activate(target,0,SPAC_PCross); l.Activate(target,0,SPAC_Impact); } foreach ( w:t.WaterHitList ) { let b = Actor.Spawn("InvisibleSplasher",w.hitpos); b.target = target; b.A_CheckTerrain(); } for ( int i=5; i 0 ) { freezetics--; return; } Update(); } default { RenderStyle "Shaded"; StencilColor "000000"; } States { Spawn: XZW1 A -1; Stop; } } // Terrain FX (cheap) Class SWWMBaseSplash : SWWMNonInteractiveActor abstract { TextureID pufftex[8]; FSpawnParticleParams puff; abstract void DoSplash(); void Splash() { puff.style = STYLE_Shaded; puff.fadestep = -1; puff.pos = pos; for ( int i=0; i<8; i++ ) pufftex[i] = TexMan.CheckForTexture("graphics/Particles/xpuff"..i..".png"); DoSplash(); } States { Spawn: TNT1 A 1 NoDelay Splash(); Stop; } } Class SWWMWaterSplash : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 60; puff.startalpha = .5; double ang, pt, str; Vector3 dir; for ( int i=0; i<60; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-60); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](2.,12.); dir *= str*.25; dir.z += 1.; puff.color1 = SWWMUtility.LerpColor("40 60 FF","A0 C0 FF",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:1200,AMF_EMITFROMTARGET); } } Class SWWMWaterSplash2 : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 50; puff.startalpha = .5; double ang, pt, str; Vector3 dir; for ( int i=0; i<15; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-30); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](1.,6.); dir *= str*.25; dir.z += .35; puff.color1 = SWWMUtility.LerpColor("40 60 FF","A0 C0 FF",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:300,AMF_EMITFROMTARGET); } } Class SWWMBloodSplash : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 60; puff.startalpha = .5; double ang, pt, str; Vector3 dir; for ( int i=0; i<60; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-60); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](2.,12.); dir *= str*.25; dir.z += 1.; puff.color1 = SWWMUtility.LerpColor("80 00 00","60 00 00",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+.5; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:1200,AMF_EMITFROMTARGET); } } Class SWWMBloodSplash2 : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 50; puff.startalpha = .5; double ang, pt, str; Vector3 dir; for ( int i=0; i<15; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-30); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](1.,6.); dir *= str*.25; dir.z += .35; puff.color1 = SWWMUtility.LerpColor("80 00 00","60 00 00",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+.5; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:300,AMF_EMITFROMTARGET); } } Class SWWMSludgeSplash : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 40; puff.startalpha = .8; double ang, pt, str; Vector3 dir; for ( int i=0; i<60; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-60); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](2.,8.); dir *= str*.25; dir.z += .4; puff.color1 = SWWMUtility.LerpColor("40 50 40","30 30 30",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+2.; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:1200,AMF_EMITFROMTARGET); } } Class SWWMSludgeSplash2 : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 30; puff.startalpha = .8; double ang, pt, str; Vector3 dir; for ( int i=0; i<15; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-30); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](1.,4.); dir *= str*.25; dir.z += .15; puff.color1 = SWWMUtility.LerpColor("40 50 40","30 30 30",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+2.; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:300,AMF_EMITFROMTARGET); } } Class SWWMMudSplash : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 40; puff.startalpha = .8; double ang, pt, str; Vector3 dir; for ( int i=0; i<60; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-60); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](2.,8.); dir *= str*.25; dir.z += .4; puff.color1 = SWWMUtility.LerpColor("50 40 20","30 20 10",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+2.; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:1200,AMF_EMITFROMTARGET); } } Class SWWMMudSplash2 : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 30; puff.startalpha = .8; double ang, pt, str; Vector3 dir; for ( int i=0; i<15; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-30); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](1.,4.); dir *= str*.25; dir.z += .15; puff.color1 = SWWMUtility.LerpColor("50 40 20","30 20 10",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+2.; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:300,AMF_EMITFROMTARGET); } } Class SWWMSlimeSplash : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 40; puff.startalpha = .8; puff.style = STYLE_AddShaded; puff.flags = SPF_FULLBRIGHT; double ang, pt, str; Vector3 dir; for ( int i=0; i<60; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-60); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](2.,8.); dir *= str*.25; dir.z += .4; puff.color1 = SWWMUtility.LerpColor("00 FF 00","00 80 00",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+2.; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:1200,AMF_EMITFROMTARGET); } } Class SWWMSlimeSplash2 : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 30; puff.startalpha = .8; puff.style = STYLE_AddShaded; puff.flags = SPF_FULLBRIGHT; double ang, pt, str; Vector3 dir; for ( int i=0; i<15; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-30); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](1.,4.); dir *= str*.25; dir.z += .15; puff.color1 = SWWMUtility.LerpColor("00 FF 00","00 80 00",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+2.; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } A_AlertMonsters(swwm_uncapalert?0:300,AMF_EMITFROMTARGET); } } Class SWWMLavaSplash : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 40; puff.startalpha = .8; puff.style = STYLE_AddShaded; puff.flags = SPF_FULLBRIGHT; double ang, pt, str; Vector3 dir; for ( int i=0; i<60; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-60); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](2.,12.); dir *= str*.35; dir.z += .6; puff.color1 = SWWMUtility.LerpColor("FF C0 40","FF 40 20",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+1.; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } let s = Spawn("SWWMSizzleSmoke",pos); s.target = target; } } Class SWWMLavaSplash2 : SWWMBaseSplash { override void DoSplash() { puff.lifetime = 30; puff.startalpha = .8; puff.style = STYLE_AddShaded; puff.flags = SPF_FULLBRIGHT; double ang, pt, str; Vector3 dir; for ( int i=0; i<15; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-30); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](1.,6.); dir *= str*.35; dir.z += .2; puff.color1 = SWWMUtility.LerpColor("FF C0 40","FF 40 20",FRandom[ExploS](0.,1.)); puff.texture = pufftex[Random[ExploS](0,7)]; puff.size = str+1.; puff.sizestep = -.02*str; puff.vel = dir; puff.accel = (0,0,-.03*str); level.SpawnParticle(puff); } let s = Spawn("SWWMSizzleSmoke2",pos); s.target = target; } } Class SWWMSizzleSmoke : SWWMBaseSplash { override void DoSplash() { double ang, pt, str; Vector3 dir; for ( int i=0; i<2; i++ ) { ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-30); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](.5,2.); let s = Spawn("SWWMSmallSmoke",pos); s.vel = dir*str+(0,0,.4); s.SetShade(Color(1,1,1)*Random[ExploS](192,224)); s.scale *= 40.; s.A_SetRenderStyle(s.alpha*.4,STYLE_AddShaded); s.special1 = Random[ExploS](0,2); } A_AlertMonsters(swwm_uncapalert?0:1200,AMF_EMITFROMTARGET); } } Class SWWMSizzleSmoke2 : SWWMBaseSplash { override void DoSplash() { double ang, pt, str; Vector3 dir; ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,-30); dir = SWWMUtility.Vec3FromAngles(ang,pt); str = FRandom[ExploS](.25,1.); let s = Spawn("SWWMSmallSmoke",pos); s.vel = dir*str+(0,0,.15); s.SetShade(Color(1,1,1)*Random[ExploS](192,224)); s.scale *= 20.; s.A_SetRenderStyle(s.alpha*.3,STYLE_AddShaded); s.special1 = Random[ExploS](0,1); A_AlertMonsters(swwm_uncapalert?0:300,AMF_EMITFROMTARGET); } } // Hexen thing Class SWWMCrushedSpike : Actor { Default { Radius 20; Height 16; +SOLID; +FLOORCLIP; +NOTELEPORT; } States { Spawn: TSPK X -1; Stop; } }