swwmgz_m/zscript/weapons/swwm_splode_fx.zsc
Marisa the Magician 2bd1cb0657 Replace usage of ThinkerIterator and BlockThingsIterator in various places where we can instead loop through sector thing lists.
While in the latter case this may result in longer loops, it also reduces GC thrashing by not needing to allocate an iterator every time.
This also simplifies the DoBlast code as there is no longer a need to manually traverse portals vertically.
2023-07-29 13:15:34 +02:00

545 lines
14 KiB
Text

// 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) )
{
let [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;
+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);
let [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<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](1,6);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
s.special1 = Random[ExploS](1,4);
s.scale *= 2.8;
s.alpha *= .4;
}
numpt = Random[ExploS](10,15);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](2,12);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](15,25);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](2,24);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
numpt = int(Random[ExploS](2,3)+(.6*special1));
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("ExplodiumMagArm",pos);
s.target = target;
s.special1 = isplanted;
}
Spawn("ExploLight2",pos);
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,20+15*special1,cvel);
}
void A_CheckBounce()
{
if ( (vel.length() > 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);
bool breakout = false;
foreach ( s:level.Sectors )
{
for ( Actor t=s.thinglist; t; t=t.snext )
{
if ( (t == self) || !t.bSHOOTABLE || (t == target.target) || t.IsFriend(target.target) || !SWWMUtility.BoxIntersect(self,t) )
continue;
target.bKILLED = true;
target.SetStateLabel("Detonate");
Destroy();
breakout = true;
break;
}
if ( breakout ) 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;
+SKYEXPLODE;
-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<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFLoor(i);
break;
}
if ( ff )
{
normal = -ff.top.Normal;
atsector = ff.model;
atplane = 1;
SWWMUtility.SetToSlopeSpecific(self,angle,ff.top,true);
}
else
{
normal = BlockingFloor.floorplane.Normal;
atsector = BlockingFloor;
atplane = 0;
SWWMUtility.SetToSlopeSpecific(self,angle,BlockingFloor.floorplane,false);
}
frame = 1; // on floor
SetOrigin((pos.x,pos.y,floorz)+normal*.75,true);
atz = pos.z-atsector.GetPlaneTexZ(atplane);
}
else if ( BlockingCeiling )
{
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;
}
if ( ff )
{
normal = -ff.bottom.Normal;
atsector = ff.model;
atplane = 0;
SWWMUtility.SetToSlopeSpecific(self,angle,ff.bottom,false);
}
else
{
normal = BlockingCeiling.ceilingplane.Normal;
atsector = BlockingCeiling;
atplane = 1;
SWWMUtility.SetToSlopeSpecific(self,angle,BlockingCeiling.ceilingplane,true);
}
frame = 2; // on ceiling
SetOrigin((pos.x,pos.y,ceilingz)+normal*.75,true);
atz = pos.z-atsector.GetPlaneTexZ(atplane);
}
else if ( BlockingLine && SWWMUtility.BlockingLineIsBlocking(self,Line.ML_BLOCKEVERYTHING|Line.ML_BLOCKPROJECTILE,BlockingLine) )
{
atline = BlockingLine;
normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
atside = Level.PointOnLineSide(pos.xy,BlockingLine);
if ( !atside ) normal *= -1;
Vector3 orig = (BlockingLine.v1.p.x,BlockingLine.v1.p.y,0);
Vector3 onwall = pos-(normal dot (pos-orig))*normal;
SetOrigin(onwall+normal*.75,true);
// attempt to guess line part (upper/mid/lower)
if ( !atline.sidedef[1] ) atpart = 0; // mid
else if ( atline.sidedef[!atside].sector.ceilingplane.ZAtPoint(pos.xy) < pos.z ) atpart = 1; // upper
else if ( atline.sidedef[!atside].sector.floorplane.ZAtPoint(pos.xy) > (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<backsector.Get3DFloorCount(); i++ )
{
if ( backsector.Get3DFloor(i).bottom.ZAtPoint(pos.xy) > (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<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](1,3);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
s.special1 = Random[ExploS](1,2);
s.scale *= 2.4;
s.alpha *= .4;
}
numpt = Random[ExploS](8,12);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](2,6);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](6,16);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[ExploS](0,360),FRandom[ExploS](-90,90))*FRandom[ExploS](2,12);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
Spawn("ExploLight",pos);
}
States
{
Spawn:
XEX1 ACEGIKMOQSUWY[] 1 Bright;
Stop;
}
}