// Explodium Gun projectiles and effects Class ExplodiumCasing : SWWMCasing {} Class ExplodiumMag : SWWMCasing { Default { Mass 10; BounceFactor 0.4; WallBounceFactor 0.4; BounceSound "explodium/mag"; } override void PostBeginPlay() { Super.PostBeginPlay(); heat = 0; } States { Death: XZW1 BC -1 { bINTERPOLATEANGLES = false; pitch = roll = 0; angle = FRandom[Junk](0,360); frame = RandomPick[Junk](1,2); } Stop; } } Class ExplodiumMagArm : Actor { Default { Obituary "$O_EXPLODIUM"; DamageType "Explodium"; PROJECTILE; +THRUACTORS; +BOUNCEONWALLS; +BOUNCEONFLOORS; +BOUNCEONCEILINGS; +CANBOUNCEWATER; +NODAMAGETHRUST; +FORCERADIUSDMG; -NOGRAVITY; +NOFRICTION; Gravity 0.35; BounceFactor 1.0; Radius 2; Height 4; } override void PostBeginPlay() { Super.PostBeginPlay(); reactiontime = Random[ExploS](10,15); double ang, pt; ang = FRandom[ExploS](0,360); pt = FRandom[ExploS](-90,90); vel = SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[ExploS](8.,20.); } States { Spawn: TNT1 A 1 { Spawn("ExplodiumMagTrail",pos); if ( !(ReactionTime%2) ) { int nhit, nkill; [nhit, nkill] = SWWMUtility.DoExplosion(self,3+reactiontime/2,3000+500*reactiontime,40+3*reactiontime,20,DE_COUNTENEMIES); if ( target && special1 ) SWWMUtility.AchievementProgressInc("grenade",nkill,target.player); } Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](1,5); let s = Spawn("SWWMHalfSmoke",pos); s.vel = pvel+vel*.2; s.SetShade(Color(1,1,1)*Random[ExploS](64,224)); s.special1 = Random[ExploS](1,3); s.scale *= 2.4; s.alpha *= 0.1+.4*(ReactionTime/15.); A_CountDown(); } Wait; } } Class ExplodiumMagTrail : SWWMNonInteractiveActor { Default { RenderStyle "Add"; +FORCEXYBILLBOARD; Scale 1.1; } States { Spawn: XEX1 ADGJMPSVY\ 1 Bright; Stop; } } Class ExplodiumMagProj : Actor { Mixin SWWMMissileFix; double pitchvel, anglevel; Vector3 cvel; Default { Obituary "$O_EXPLODIUM"; DamageType "Explodium"; Radius 2; Height 4; Gravity 0.5; Speed 30; PROJECTILE; -NOGRAVITY; +ROLLSPRITE; +ROLLCENTER; +INTERPOLATEANGLES; +NODAMAGETHRUST; +FORCERADIUSDMG; +FORCEXYBILLBOARD; +BOUNCEONFLOORS; +BOUNCEONCEILINGS; +BOUNCEONWALLS; +ALLOWBOUNCEONACTORS; +DONTBOUNCEONSHOOTABLES; +CANBOUNCEWATER; +DONTBOUNCEONSKY; +USEBOUNCESTATE; BounceFactor 0.4; WallBounceFactor 0.4; } override void PostBeginPlay() { Super.PostBeginPlay(); pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1); } void A_BlowUp() { bool isplanted = (self is 'ExplodiumMagAttach'); angle = atan2(cvel.y,cvel.x); pitch = asin(-cvel.z); bNOGRAVITY = true; A_SetRenderStyle(1.,STYLE_Add); Scale *= 2.+.2*special1; A_AlertMonsters(swwm_uncapalert?0:6000,AMF_EMITFROMTARGET); int nhit, nkill; [nhit, nkill] = SWWMUtility.DoExplosion(self,20+25*special1,80000+8000*special1,90+10*special1,60,DE_EXTRAZTHRUST|DE_COUNTENEMIES); if ( target && isplanted ) SWWMUtility.AchievementProgressInc("grenade",nkill,target.player); A_QuakeEx(9,9,9,30,0,400+80*special1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:300,rollintensity:2.); A_StartSound("explodium/maghit",CHAN_VOICE,attenuation:.35); A_StartSound("explodium/maghit",CHAN_WEAPON,attenuation:.2); A_SprayDecal("BigRocketBlast",172); Scale *= FRandom[ExploS](0.8,1.1); Scale.x *= RandomPick[ExploS](-1,1); Scale.y *= RandomPick[ExploS](-1,1); int numpt = Random[ExploS](16,24); for ( int i=0; i 4) && (vel.unit() dot cvel > 0.) ) { bHITOWNER = true; A_StartSound("explodium/mag"); return; } // ensure we can leave a decal angle += 180; pitch = -pitch; ExplodeMissile(); } States { Spawn: XZW1 A 1 { pitch += pitchvel; angle += anglevel; if ( vel.length() > 0. ) cvel = vel.unit(); } Wait; Bounce: XZW1 A 0 A_CheckBounce(); Goto Spawn; Death: TNT1 A 0 A_BlowUp(); XEX1 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright; Stop; } } Class ExplodiumMagHitbox : Actor { Default { Radius 2; Height 4; +NOGRAVITY; +DONTSPLASH; +NOTELEPORT; +SHOOTABLE; +NOBLOOD; } override void Tick() { if ( !target || target.bKILLED ) { Destroy(); return; } SetOrigin(target.Vec3Offset(0,0,-height*.5),false); let bt = BlockThingsIterator.Create(self,128); while ( bt.Next() ) { if ( !bt.Thing || (bt.Thing == self) || !bt.Thing.bSHOOTABLE || (bt.Thing == target.target) || bt.Thing.IsFriend(target.target) || !SWWMUtility.BoxIntersect(self,bt.Thing) ) continue; target.bKILLED = true; target.SetStateLabel("Detonate"); Destroy(); break; } } override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle ) { if ( target && !target.bKILLED ) { target.bKILLED = true; target.SetStateLabel("Detonate"); Destroy(); } return 0; } } Class ExplodiumMagAttach : ExplodiumMagProj { Line atline; int atside; int atpart; int atplane; Sector atsector; double atz; Vector3 normal; Actor hitbox; default { +MOVEWITHSECTOR; +EXPLODEONWATER; -BOUNCEONFLOORS; -BOUNCEONCEILINGS; -BOUNCEONWALLS; -ALLOWBOUNCEONACTORS; -DONTBOUNCEONSHOOTABLES; -CANBOUNCEWATER; -USEBOUNCESTATE; Speed 15; } override int SpecialMissileHit( Actor victim ) { if ( victim is 'ExplodiumMagHitbox' ) return 1; return -1; } override void Tick() { Super.Tick(); if ( freezetics > 0 ) return; if ( isFrozen() ) return; if ( bKILLED ) return; if ( atline ) // attempt to follow the movement of the line { if ( atpart == 1 ) { if ( atline.flags&Line.ML_DONTPEGTOP ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(1)),true); else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[!atside].sector.GetPlaneTexZ(1)),true); } else if ( atpart == -1 ) { if ( atline.flags&Line.ML_DONTPEGBOTTOM ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(0)),true); else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[!atside].sector.GetPlaneTexZ(0)),true); } else if ( atline.flags&Line.ML_DONTPEGBOTTOM ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(0)),true); else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(1)),true); if ( (pos.z > ceilingz) || (pos.z < floorz) ) bKILLED = true; } else if ( atsector ) // attempt to follow the movement of the plane { SetOrigin(Vec2OffsetZ(0,0,atz+atsector.GetPlaneTexZ(atplane)),true); if ( ceilingz-floorz <= 2 ) bKILLED = true; } if ( bKILLED ) SetStateLabel("Detonate"); } void A_Attach() { F3DFloor ff; A_NoGravity(); A_Stop(); if ( BlockingFloor ) { // find closest 3d floor for its normal for ( int i=0; i (pos.z+height) ) atpart = -1; // lower else { atpart = 0; // check if we're touching a 3d floor line Sector backsector = atline.sidedef[!atside].sector; for ( int i=0; i (pos.z+height) ) continue; if ( backsector.Get3DFloor(i).top.ZAtPoint(pos.xy) < pos.z ) continue; ff = backsector.Get3DFloor(i); break; } // attach to it if ( ff ) { atline = ff.master; atside = 0; } } if ( atpart == 1 ) { if ( atline.flags&Line.ML_DONTPEGTOP ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(1); else atz = pos.z-atline.sidedef[!atside].sector.GetPlaneTexZ(1); } else if ( atpart == -1 ) { if ( atline.flags&Line.ML_DONTPEGBOTTOM ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(0); else atz = pos.z-atline.sidedef[!atside].sector.GetPlaneTexZ(0); } else if ( atline.flags&Line.ML_DONTPEGBOTTOM ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(0); else atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(1); angle = atan2(normal.y,normal.x)+180; pitch = 0; } else { bKILLED = true; SetStateLabel("Detonate"); return; } let b = Spawn("ExplodiumMagHitbox",pos); b.target = self; A_StartSound("explodium/jamitin",CHAN_BODY,CHANF_DEFAULT,.65,2.5); } States { Spawn: XZW1 A -1; Stop; Death: XZW1 A -1 A_Attach(); Stop; Detonate: XZW1 # 2; TNT1 A 0 { cvel = SWWMUtility.Vec3FromAngles(angle,pitch); A_BlowUp(); } XEX1 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright; Stop; } } Class ExploLight : PaletteLight { Default { ReactionTime 15; } } Class ExploLight2 : PaletteLight { Default { ReactionTime 30; Args 0,0,0,120; } } Class ExplodiumBulletImpact : SWWMNonInteractiveActor { Default { Obituary "$O_EXPLODIUM"; DamageType "Explodium"; RenderStyle "Add"; Scale 1.2; +NODAMAGETHRUST; +FORCERADIUSDMG; +FORCEXYBILLBOARD; } override void PostBeginPlay() { Super.PostBeginPlay(); A_AlertMonsters(swwm_uncapalert?0:3000,AMF_EMITFROMTARGET); SWWMUtility.DoExplosion(self,25,40000,70,40,DE_EXTRAZTHRUST); A_QuakeEx(4,4,4,10,0,250,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:150,rollintensity:0.2); A_StartSound("explodium/hit",CHAN_VOICE,attenuation:.6); A_StartSound("explodium/hit",CHAN_WEAPON,attenuation:.3); A_SprayDecal("RocketBlast",-172); Scale *= FRandom[ExploS](0.8,1.1); Scale.x *= RandomPick[ExploS](-1,1); Scale.y *= RandomPick[ExploS](-1,1); int numpt = Random[ExploS](10,20); for ( int i=0; i