swwmgz_m/zscript/weapons/swwm_blazeit_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

464 lines
11 KiB
Text

// Hellblazer projectiles and effects
Class HellblazerExplLight : PaletteLight
{
Default
{
Tag "HellExpl";
Args 0,0,0,200;
ReactionTime 25;
}
}
Class HellblazerSubExpl : SWWMNonInteractiveActor
{
Default
{
RenderStyle "Add";
Scale 2.2;
Alpha .75;
+FORCEXYBILLBOARD;
+ROLLSPRITE;
+ROLLCENTER;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
roll = FRandom[ExploS](0,360);
scale.x *= RandomPick[ExploS](-1,1);
scale.y *= RandomPick[ExploS](-1,1);
}
States
{
Spawn:
XEX0 ABCDEFGHIJKLMNOPQRS 1 Bright;
Stop;
}
}
Class HellblazerRing : SWWMNonInteractiveActor
{
Default
{
RenderStyle "Add";
Scale 2.;
+FORCEXYBILLBOARD;
}
States
{
Spawn:
XRG3 ACEGIKMOQSUW 1 Bright A_SetScale(scale.x*1.15);
Stop;
}
}
Class HellblazerArmTrail : SWWMNonInteractiveActor
{
Default
{
RenderStyle "Add";
+FORCEXYBILLBOARD;
Scale 2.5;
}
States
{
Spawn:
XEX0 ACEGIKMOQS 1 Bright;
Stop;
}
}
Class HellblazerArm : Actor
{
Default
{
Obituary "$O_HELLBLAZER";
DamageType 'Fire';
PROJECTILE;
+THRUACTORS;
+BOUNCEONWALLS;
+BOUNCEONFLOORS;
+BOUNCEONCEILINGS;
+CANBOUNCEWATER;
+NODAMAGETHRUST;
+FORCERADIUSDMG;
-NOGRAVITY;
+NOFRICTION;
Gravity 0.35;
BounceFactor 1.0;
Radius 4;
Height 4;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
reactiontime = Random[ExploS](6,8);
double ang, pt;
ang = FRandom[ExploS](0,360);
pt = FRandom[ExploS](-90,90);
vel = SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[ExploS](30.,40.);
}
States
{
Spawn:
TNT1 A 1
{
Spawn("HellblazerArmTrail",pos);
SWWMUtility.DoExplosion(self,6+reactiontime/2,3000+500*reactiontime,80+10*reactiontime);
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(4,2,1)*Random[ExploS](48,63));
s.special1 = Random[ExploS](0,2);
s.scale *= 3.;
s.alpha *= 0.1+.4*(ReactionTime/8.);
A_CountDown();
}
Wait;
}
}
Class HellblazerTrail : SWWMNonInteractiveActor
{
Default
{
RenderStyle "Add";
Scale .2;
Alpha .3;
+FORCEXYBILLBOARD;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
SetState(FindState("Spawn")+Random[ExploS](0,7));
}
States
{
Spawn:
JFLR ABCDEFGH 1 Bright
{
A_FadeOut(.06);
A_SetScale(scale.x*.95);
if ( waterlevel > 0 )
{
let b = Spawn("SWWMBubble",pos);
b.vel = vel;
b.scale *= scale.x;
Destroy();
}
}
Loop;
}
}
Class HellblazerFlare : SWWMNonInteractiveActor
{
Default
{
RenderStyle "Add";
+FORCEXYBILLBOARD;
}
override void Tick()
{
if ( !master || !master.bMISSILE )
{
Destroy();
return;
}
Vector3 traildir = -SWWMUtility.Vec3FromAngles(master.angle,master.pitch);
SetOrigin(level.Vec3Offset(master.pos,traildir*3),true);
}
States
{
Spawn:
HFLR A -1 Bright;
Stop;
}
}
// rockets
Class HellblazerMissile : Actor
{
Mixin SWWMMissileFix;
int deto, detact;
Actor seektarget;
Vector3 InitialDir, Acceleration;
Default
{
Obituary "$O_HELLBLAZER";
DamageType 'Sydon';
Radius 2;
Height 4;
Speed 50;
PROJECTILE;
+EXPLODEONWATER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
+HITTRACER;
+SKYEXPLODE;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( bNOGRAVITY )
{
A_StartSound("hellblazer/fly",CHAN_BODY,CHANF_LOOP,1.,2.);
let t = Spawn("HellblazerFlare",pos);
t.master = self;
}
}
void A_BlazerTick( Color smokecol )
{
Vector3 traildir = -SWWMUtility.Vec3FromAngles(angle,pitch);
for ( int i=0; i<3; i++ )
{
let s = Spawn("SWWMHalfSmoke",level.Vec3Offset(pos,traildir*3));
s.SetShade(smokecol*Random[Hellblazer](48,63));
s.scale *= FRandom[Hellblazer](.8,1.2);
s.special1 = Random[Hellblazer](0,2);
s.alpha *= .5;
s.vel = .3*vel + (traildir+SWWMUtility.Vec3FromAngles(FRandom[Hellblazer](0,360),FRandom[Hellblazer](-90,90))*.4).unit()*FRandom[Hellblazer](1.,2.);
}
if ( bNOGRAVITY )
{
for ( double i=0.; i<vel.length(); i+= 5. )
{
let t = Spawn("HellblazerTrail",level.Vec3Offset(pos,-vel.unit()*i+traildir*3));
t.vel = traildir*4.;
}
if ( InitialDir.length() < double.epsilon ) InitialDir = vel.unit();
vel += Acceleration/GameTicRate;
Vector3 dir = vel.unit();
if ( vel.length() > 50. ) vel = dir*50.;
}
// don't auto-detonate if we're too close to our shooter
// ensures player doesn't eat up the full brunt of the blast
if ( (deto > 1) && (!target || !SWWMUtility.SphereIntersect(target,pos,150)) )
{
ExplodeMissile();
return;
}
if ( seektarget )
{
// seek tracer
if ( SWWMUtility.SphereIntersect(seektarget,level.Vec3Offset(pos,vel),bNOGRAVITY?50:90) )
{
deto++;
tracer = seektarget;
return;
}
if ( bNOGRAVITY )
{
Vector3 SeekingDir = level.Vec3Diff(pos,seektarget.Vec3Offset(0,0,seektarget.height/2)).unit();
if ( SeekingDir dot InitialDir > -1 )
{
double MagnitudeVel = Vel.length();
SeekingDir = (SeekingDir*.25*MagnitudeVel+Vel).unit();
Vel = MagnitudeVel*SeekingDir;
Acceleration = 25*SeekingDir;
}
}
return;
}
// proximity check
let bt = BlockThingsIterator.Create(self,256);
while ( bt.Next() )
{
let t = bt.Thing;
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),bNOGRAVITY?50:90) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
deto++;
tracer = t;
break;
}
bt.Destroy();
}
void A_BlazerMissileExplode()
{
bForceXYBillboard = true;
bRollSprite = false;
A_SetRenderStyle(1.0,STYLE_Add);
A_SprayDecal("BigRocketBlast",50);
A_SetScale(4.5);
SWWMUtility.DoExplosion(self,200,320000,150,100);
A_NoGravity();
A_QuakeEx(5.,5.,5.,15,0,1500,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:500,rollIntensity:.8);
A_StopSound(CHAN_BODY);
A_StartSound("hellblazer/hit",CHAN_WEAPON,attenuation:.8);
A_StartSound("hellblazer/hit",CHAN_VOICE,attenuation:.5);
A_AlertMonsters(swwm_uncapalert?0:2500,AMF_EMITFROMTARGET);
Spawn("HellblazerExplLight",pos);
int numpt = Random[Hellblazer](12,24);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Hellblazer](0,360),FRandom[Hellblazer](-90,90))*FRandom[Hellblazer](2,8);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(4,2,1)*Random[Hellblazer](48,63));
s.special1 = Random[Hellblazer](1,4);
s.scale *= 2.8;
s.alpha *= .4;
}
numpt = Random[Hellblazer](8,12);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Hellblazer](0,360),FRandom[Hellblazer](-90,90))*FRandom[Hellblazer](4,12);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[Hellblazer](12,16);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = SWWMUtility.Vec3FromAngles(FRandom[Hellblazer](0,360),FRandom[Hellblazer](-90,90))*FRandom[Hellblazer](10,20);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
s.scale *= FRandom[Hellblazer](0.9,1.8);
}
Spawn("HellblazerRing",pos);
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,320,SWWMUtility.Vec3FromAngles(angle,pitch));
}
void A_SubExpl( double xscale = 1. )
{
if ( special1 < 15 ) SWWMUtility.DoExplosion(self,60-special1*4,3000-special1*200,100+special1*10,damagetype:'Fire');
special1++;
if ( (special1 <= 8) && !(special1%2) )
{
int numpt = Random[Hellblazer](0,8-special1);
double ang, pt;
for ( int i=0; i<numpt; i++ )
{
ang = FRandom[Hellblazer](0,360);
pt = FRandom[Hellblazer](-90,90);
FLineTraceData d;
LineTrace(ang,FRandom[Hellblazer](10,20)+10*special1*xscale,pt,TRF_THRUACTORS,data:d);
Vector3 HitNormal = SWWMUtility.GetLineTraceHitNormal(d);
let p = Spawn("HellblazerSubExpl",d.HitLocation+hitnormal*4);
p.angle = atan2(hitnormal.y,hitnormal.x);
p.pitch = asin(-hitnormal.z);
p.target = target;
p.scale *= xscale*(2-special1*.1);
p.alpha *= 1-special1*.1;
}
}
special2++;
if ( (special2 <= 6) && !(special2%3) )
{
int numpt = 5-special2/2;
for ( int i=0; i<numpt; i++ )
{
double ang = FRandom[Hellblazer](0,360);
double pt = FRandom[Hellblazer](-90,90);
let c = Spawn("HellblazerArm",pos);
c.angle = ang;
c.pitch = pt;
c.target = target;
}
}
}
States
{
Spawn:
XZW1 A 1 A_BlazerTick(Color(4,3,2));
Wait;
Death:
TNT1 A 0 A_BlazerMissileExplode();
HEXP ABCDEFGHIJKLMNOPQR 1 Bright A_SubExpl();
Stop;
}
}
// grenades
Class HellblazerMissile2 : HellblazerMissile
{
double rollvel, anglevel, pitchvel;
Vector3 oldvel;
Default
{
BounceFactor 1.;
WallBounceFactor 1.;
Gravity .35;
ReactionTime 85;
-NOGRAVITY;
-EXPLODEONWATER;
+USEBOUNCESTATE;
+BOUNCEONWALLS;
+BOUNCEONFLOORS;
+BOUNCEONCEILINGS;
+ALLOWBOUNCEONACTORS;
+DONTBOUNCEONSHOOTABLES;
+CANBOUNCEWATER;
+INTERPOLATEANGLES;
+ROLLSPRITE;
+ROLLCENTER;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
rollvel = FRandom[Hellblazer](-4,4);
anglevel = FRandom[Hellblazer](-4,4);
pitchvel = FRandom[Hellblazer](-4,4);
oldvel = vel;
}
override void Tick()
{
oldvel = vel;
Super.Tick();
if ( isFrozen() || (freezetics > 0) || !InStateSequence(CurState,FindState("Spawn")) ) return;
roll += rollvel;
angle += anglevel;
pitch += pitchvel;
ReactionTime--;
if ( ReactionTime <= 0 ) ExplodeMissile();
}
virtual void A_HandleBounce()
{
Vector3 HitNormal = SWWMUtility.GetActorHitNormal(self);
// undo the bounce, we need to hook in our own
vel = oldvel;
// re-do the bounce with our formula
Vector3 RealHitNormal = HitNormal;
HitNormal = (HitNormal+SWWMUtility.Vec3FromAngles(FRandom[Hellblazer](0,360),FRandom[Hellblazer](-90,90))*.1).unit();
if ( (HitNormal dot RealHitNormal) < 0 ) HitNormal *= -.5;
vel = FRandom[Hellblazer](.8,.9)*((vel dot HitNormal)*HitNormal*(FRandom[Hellblazer](-2.,-1.6))+vel);
if ( vel.z > 10 ) vel.z = 0.5*(10+vel.z);
bHITOWNER = true;
if ( vel.length() < 4. )
{
ClearBounce();
ExplodeMissile();
return;
}
A_StartSound("hellblazer/bounce",CHAN_ITEM);
rollvel = FRandom[Hellblazer](-16,16);
anglevel = FRandom[Hellblazer](-16,16);
pitchvel = FRandom[Hellblazer](-16,16);
// steer towards seek target
if ( seektarget )
{
Vector3 dirto = level.Vec3Diff(pos,seektarget.Vec3Offset(0,0,seektarget.Height/2));
double distto = dirto.length();
if ( distto <= 0. ) return;
dirto /= distto;
dirto.z += .1;
double spd = vel.length();
if ( spd <= 0. ) return;
vel /= spd;
vel = (vel*.3+dirto*.7)*spd;
}
}
States
{
Bounce:
XZW1 A 0 A_HandleBounce();
Goto Spawn;
}
}