Revert "Replace usage of ThinkerIterator and BlockThingsIterator in various places where we can instead loop through sector thing lists."

This reverts commit 2bd1cb0657.
This commit is contained in:
Mari the Deer 2023-07-29 13:48:33 +02:00
commit 3b10e684b6
17 changed files with 220 additions and 113 deletions

View file

@ -63,12 +63,17 @@ extend Class SWWMUtility
else brange = 1./(ExplosionRadius-FullDamageRadius);
Actor Instigator = realsource?realsource:(flags&DE_NOTMISSILE)?Source:Source.target;
int dflg = ((flags&DE_NONEXPLOSIVE)?0:DMG_EXPLOSION)|dmgflags;
BlockThingsIterator bi = BlockThingsIterator.Create(Source,ExplosionRadius);
int nhit = 0, nkill = 0;
bool haskilled = false;
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
Array<Actor> washit;
washit.Clear();
while ( bi.Next() )
{
Actor a = bi.Thing;
washit.Push(a);
// early checks for self and ignored actor (usually the instigator)
if ( (a == ignoreme) || (a == Source) )
if ( !a || (a == ignoreme) || (a == Source) )
continue;
// can't be affected
if ( !a.bSHOOTABLE && !a.bVULNERABLE )
@ -136,6 +141,90 @@ extend Class SWWMUtility
if ( (flags&DE_COUNTFHKILLS) && (oldhp < basehp) ) continue; // was not at full health
if ( (!a || (a.Health <= 0)) && (!(flags&DE_COUNTENEMIES) || hostile) && (!(flags&DE_COUNTSTEALTH) || inactive) ) nkill++;
}
// traverse portals (needed since BlockThingsIterator can't properly cross sector portals in both vertical directions)
int thisgroup = Source.CurSector.portalgroup;
for ( int i=0; i<level.GetPortalGroupCount(); i++ )
{
if ( i == thisgroup ) continue;
Vector2 relpos = Source.pos.xy+level.GetDisplacement(thisgroup,i);
bi = BlockThingsIterator.CreateFromPos(relpos.x,relpos.y,Source.pos.z,Source.pos.z+Source.height,ExplosionRadius,false);
while ( bi.Next() )
{
Actor a = bi.Thing;
// early exit for already processed actors
if ( washit.Find(a) < washit.Size() )
continue;
washit.Push(a);
// early checks for self and ignored actor (usually the instigator)
if ( !a || (a == ignoreme) || (a == Source) )
continue;
// can't be affected
if ( !a.bSHOOTABLE && !a.bVULNERABLE )
continue;
// no blasting if no radius dmg (unless forced)
if ( a.bNORADIUSDMG && !Source.bFORCERADIUSDMG )
continue;
// check the DONTHARMCLASS/DONTHARMSPECIES flags
if ( !a.player && ((Source.bDONTHARMCLASS && (a.GetClass() == Source.GetClass())) || (Source.bDONTHARMSPECIES && (a.GetSpecies() == Source.GetSpecies()))) )
continue;
// check friendliness
if ( (flags&DE_NOHURTFRIEND) && Instigator && Instigator.IsFriend(a) )
continue;
// can we see it
if ( !(flags&DE_THRUWALLS) && !Source.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
continue;
// intersecting?
if ( !SphereIntersect(a,Source.pos,ExplosionRadius) )
continue;
// calculate factor
Vector3 dir;
if ( flags&DE_CENTERHEIGHT ) dir = level.Vec3Diff(Source.Vec3Offset(0,0,Source.Height/2),a.Vec3Offset(0,0,a.Height/2));
else dir = level.Vec3Diff(Source.pos,a.Vec3Offset(0,0,a.Height/2));
double dist = dir.length();
// intersecting, randomize direction
if ( dir.length() <= double.epsilon )
{
double ang = FRandom[DoBlast](0,360);
double pt = FRandom[DoBlast](-90,90);
dir = Vec3FromAngles(ang,pt);
}
else dir /= dist;
dist = clamp(dist-FullDamageRadius,0,min(dist,ExplosionRadius));
double damagescale;
if ( ExplosionRadius == FullDamageRadius ) damagescale = 1.;
else damagescale = 1.-clamp((dist-a.Radius)*brange,0.,1.);
double mm = MomentumTransfer*damagescale;
// no knockback if massive/unpushable
if ( (abs(mm) > 0.) && !a.bDORMANT && !a.bDONTTHRUST && (a.Mass < Actor.LARGE_MASS) )
{
Vector3 Momentum = dir*mm;
if ( (a.pos.z <= a.floorz) || !a.TestMobjZ() )
Momentum.z = max(Momentum.z,(flags&DE_EXTRAZTHRUST?.4:.1)*Momentum.length());
Momentum /= GameTicRate*max(50,a.Mass); // prevent tiny things from getting yeeted at warp speed
a.vel += Momentum;
if ( (flags&DE_BLAST) && a.bCANBLAST && !a.bDONTBLAST ) a.bBLASTED = true;
}
// hit it
bool inactive = (!a.player&&!a.target);
bool hostile = (Instigator&&a.IsHostile(Instigator)&&(a.bISMONSTER||a.player));
if ( (!(flags&DE_COUNTENEMIES) || hostile) && (!(flags&DE_COUNTSTEALTH) || inactive) ) nhit++;
int dmg = int(Damage*damagescale);
if ( flags&DE_QUADRAVOL )
{
OnFire.Apply(a,Instigator,dmg); // ignite
continue;
}
if ( dmg <= 0 ) continue; // no harm
int oldhp = a.Health;
int basehp = a.GetSpawnHealth();
int ndmg = a.DamageMobj(realinflictor?realinflictor:Source,Instigator,dmg,(DamageType=='')?Source.DamageType:DamageType,dflg,atan2(-dir.y,-dir.x));
if ( (ndmg > 0) && a && !(flags&DE_NOBLEED) ) a.TraceBleed(ndmg,Source);
if ( (flags&DE_HOWL) && a && (a.Health > 0) && a.bISMONSTER && !Random[DoBlast](0,3) ) a.Howl();
if ( hostile && (!a || (a.Health <= 0)) ) haskilled = true;
if ( (flags&DE_COUNTFHKILLS) && (oldhp < basehp) ) continue; // was not at full health
if ( (!a || (a.Health <= 0)) && (!(flags&DE_COUNTENEMIES) || hostile) && (!(flags&DE_COUNTSTEALTH) || inactive) ) nkill++;
}
}
if ( (Instigator is 'Demolitionist') && haskilled && !(flags&DE_NONEXPLOSIVE) )
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));