swwmgz_m/zscript/weapons/swwm_splode_fx.zsc
Marisa the Magician e5e6ce619c Fix severe performance issues in large maps.
So... Remember that one decision I made about avoiding BlockThingsIterator as
much as possible? Turns out that was a stupid idea. There ARE situations where
it's better to iterate sector thinglists, yes, especially for things that are
NOT part of the blockmap, but in other cases, the excess allocations of new
iterators are a reasonable price to pay for the lower perf impact in extreme
cases, such as maps that have a gazillion sectors with gazillions of things in
them (I'm looking at you, UDMF mappers).
As a compromise, at least, in situations where the thinglists are needed, I did
add a sort of micro-optimization by implementing code to check if a bounding
box is inside a sector (would be nice if this was part of GZDoom itself, tho).
2023-12-19 11:46:29 +01:00

542 lines
13 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);
let bt = BlockThingsIterator.Create(self,256);
while ( bt.Next() )
{
let t = bt.Thing;
if ( !t || (t == self) || !t.bSHOOTABLE || (t == target.target) || t.IsFriend(target.target) || !SWWMUtility.BoxIntersect(self,t) )
continue;
target.bKILLED = true;
target.SetStateLabel("Detonate");
Destroy();
break;
}
bt.Destroy();
}
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;
}
}