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

@ -1,3 +1,3 @@
[default]
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r835 \cu(Sat 29 Jul 13:15:34 CEST 2023)\c-";
SWWM_SHORTVER="\cw1.3pre r835 \cu(2023-07-29 13:15:34)\c-";
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r834 \cu(Sat 29 Jul 12:25:53 CEST 2023)\c-";
SWWM_SHORTVER="\cw1.3pre r834 \cu(2023-07-29 12:25:53)\c-";

View file

@ -1036,18 +1036,14 @@ Class MisterGrenade : Actor
if ( bNoProx ) return;
// "safe delay" for main grenade
if ( !bAMBUSH && (ReactionTime > default.ReactionTime-20) ) return;
bool breakout = false;
foreach ( s:level.Sectors )
let bt = BlockThingsIterator.Create(self,120);
while ( bt.Next() )
{
for ( Actor t=s.thinglist; t; t=t.snext )
{
if ( !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),bAMBUSH?80:120) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
special1++;
tracer = t;
breakout = true;
break;
}
if ( breakout ) break;
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),bAMBUSH?80:120) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
special1++;
tracer = t;
break;
}
}
@ -1133,11 +1129,13 @@ Class MisterGrenade : Actor
}
// gather seekable targets
Array<Actor> candidates;
let bt = BlockThingsIterator.Create(self,2000);
let tt = new("TargetTracer");
tt.target = target;
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
while ( bt.Next() )
{
if ( (t == tracer) || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
let t = bt.Thing;
if ( !t || (t == tracer) || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
// don't seek if enemy is too close to shooter
if ( target && SWWMUtility.SphereIntersect(t,target.pos,250) ) continue;
// don't seek if shooter is between us and the enemy

View file

@ -3,6 +3,7 @@
extend Class SWWMHandler
{
ui SWWMProjectionData projdata;
transient ui ThinkerIterator dbgti;
private ui void DrawWorldLine( RenderEvent e, Vector3 apos, Vector3 bpos, Color col )
{
@ -102,7 +103,10 @@ extend Class SWWMHandler
if ( !swwm_debugview ) return;
// prepare projection data, we're going to need this
SWWMUtility.PrepareProjData(projdata,e.ViewPos,e.ViewAngle,e.ViewPitch,e.ViewRoll,players[consoleplayer].fov);
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
if ( !dbgti ) dbgti = ThinkerIterator.Create("Actor");
else dbgti.Reinit();
Actor a;
while ( a = Actor(dbgti.Next()) )
{
if ( (a == players[consoleplayer].Camera) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue;
if ( a.bINVISIBLE && !(a is 'DynamicLight') ) continue;

View file

@ -178,18 +178,14 @@ extend Class SWWMHandler
// copies the floatbob of overlapping identical items, so it doesn't look weird
private void CopyFloatBob( Actor a )
{
bool breakout = false;
foreach ( s:level.Sectors )
let bt = BlockThingsIterator.Create(a,16);
while ( bt.Next() )
{
for ( Actor t=s.thinglist; t; t=t.snext )
{
if ( (t == a) || !(t is 'Inventory') || !(t.spawnpoint ~== a.spawnpoint) ) continue;
a.floatbobphase = t.floatbobphase;
a.angle = t.angle; // also copy angle
breakout = true;
break;
}
if ( breakout ) break;
let t = bt.Thing;
if ( !t || (t == a) || !(t is 'Inventory') || !(t.spawnpoint ~== a.spawnpoint) ) continue;
a.floatbobphase = t.floatbobphase;
a.angle = t.angle; // also copy angle
break;
}
}

View file

@ -98,9 +98,11 @@ extend Class SWWMHandler
}
bool enteredcombat = false;
// add new entries
if ( !cti ) cti = ThinkerIterator.Create("Actor");
else cti.Reinit();
Actor a, keyactor = null;
bool bossfound = false;
// we can use this instead of a thinker iterator as only actors that EXIST physically could count as combatants
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
while ( a = Actor(cti.Next()) )
{
if ( !a.player && !a.bISMONSTER ) continue;
// ignore the dead
@ -204,12 +206,12 @@ extend Class SWWMHandler
}
mapclearagain++;
if ( !iwantdie ) return;
for ( int i=0; i<MAXPLAYERS; i++ )
let ti = ThinkerIterator.Create("SWWMStats",Thinker.STAT_STATIC);
SWWMStats s;
while ( s = SWWMStats(ti.Next()) )
{
if ( !playeringame[i] ) continue;
let demo = Demolitionist(players[i].mo);
if ( !demo || !demo.mystats ) continue;
if ( demo.mystats.deaths > 0 ) return;
if ( s.deaths > 0 )
return;
}
SWWMUtility.MarkAchievement("wantdie",players[consoleplayer]);
}
@ -277,9 +279,11 @@ extend Class SWWMHandler
}
// update trackers for anything around the player
double viewdist = SWWMStatusBar.MAPVIEWDIST*swwm_mm_zoom;
// still about as expensive as using a BlockThingsIterator, but without the need to allocate one every tic
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
BlockThingsIterator bt = BlockThingsIterator.Create(players[consoleplayer].Camera,viewdist);
while ( bt.Next() )
{
let a = bt.Thing;
if ( !a ) continue;
Vector2 rv = a.pos.xy-players[consoleplayer].Camera.pos.xy;
if ( max(abs(rv.x)-a.radius,abs(rv.y)-a.radius) > viewdist )
continue;
@ -321,15 +325,19 @@ extend Class SWWMHandler
continue;
SWWMSimpleTracker.Track(self,a);
}
bt.Destroy();
// oh boy here we go
int thisgroup = players[consoleplayer].Camera.CurSector.portalgroup;
for ( int i=0; i<level.GetPortalGroupCount(); i++ )
{
if ( i == thisgroup ) continue;
Vector2 relpos = players[consoleplayer].Camera.pos.xy+level.GetDisplacement(thisgroup,i);
// still about as expensive as using a BlockThingsIterator, but without the need to allocate one every tic
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
if ( bt ) bt.Destroy();
bt = BlockThingsIterator.CreateFromPos(relpos.x,relpos.y,players[consoleplayer].Camera.pos.z,players[consoleplayer].Camera.pos.z+players[consoleplayer].Camera.height,viewdist,false);
while ( bt.Next() )
{
let a = bt.Thing;
if ( !a ) continue;
Vector2 rv = a.pos.xy-relpos;
if ( max(abs(rv.x)-a.radius,abs(rv.y)-a.radius) > viewdist )
continue;

View file

@ -523,19 +523,15 @@ Class HammerspaceEmbiggener : Inventory
// since backpacks are taller in Doom
if ( gameinfo.gametype&GAME_DoomChex )
A_SetSize(-1,26);
let bt = BlockThingsIterator.Create(self,16);
int tamount = Amount;
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; )
while ( bt.Next() )
{
let next = t.snext;
if ( (t == self) || !(t is 'HammerspaceEmbiggener') || !(t.spawnpoint ~== spawnpoint) )
{
t = next;
continue;
}
let t = bt.Thing;
if ( !t || (t == self) || !(t is 'HammerspaceEmbiggener') || !(t.spawnpoint ~== spawnpoint) ) continue;
tamount += HammerspaceEmbiggener(t).Amount;
t.ClearCounters();
t.Destroy();
t = next;
}
if ( tamount <= 1 ) return;
tamount -= tamount%2; // always even numbered

View file

@ -58,10 +58,12 @@ Class LampMoth : Actor
if ( !lamp )
{
// look for nearby lamps
let bi = BlockThingsIterator.Create(self,250);
double mindist = 62500.;
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
while ( bi.Next() )
{
if ( !(a is 'CompanionLamp') ) continue;
if ( !bi.Thing || !(bi.Thing is 'CompanionLamp') ) continue;
Actor a = bi.Thing;
double dist = Distance3DSquared(a);
if ( (a.frame == 0) || (dist > mindist) && !CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
mindist = dist;

View file

@ -310,9 +310,11 @@ Class GhostTarget : Actor
}
if ( isFrozen() ) return;
if ( diedie ) A_FadeOut(.05);
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
let bt = BlockThingsIterator.Create(self,300);
while ( bt.Next() )
{
if ( !t.bIsMonster || t.player || !t.IsHostile(master) || (t.target != self) ) continue;
let t = bt.Thing;
if ( !t || !t.bIsMonster || t.player || !t.IsHostile(master) || (t.target != self) ) continue;
if ( SWWMUtility.BoxIntersect(self,t,pad:16) || t.CheckMeleeRange() )
{
// they found out, there's no one here

View file

@ -510,7 +510,9 @@ Class Mykradvo : Inventory
{
targets.Clear();
// search all actively hostile enemies within 50m
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
let ti = ThinkerIterator.Create("Actor");
Actor a;
while ( a=Actor(ti.Next()) )
{
// must be an active, shootable live monster
if ( !a.bISMONSTER || !a.bSHOOTABLE || a.bDORMANT || (a.Health <= 0) ) continue;

View file

@ -5,15 +5,18 @@ extend Class Demolitionist
{
if ( player.cmd.buttons&BT_USER3 )
{
foreach ( s:level.Sectors ) for ( Actor i=s.thinglist; i; i=i.snext )
let bt = BlockThingsIterator.Create(self,800);
while ( bt.Next() )
{
if ( !(i is 'Inventory') && !(i is 'Chancebox') && !(i is 'SWWMRespawnTimer') ) continue;
let i = bt.Thing;
if ( !i || (!(i is 'Inventory') && !(i is 'Chancebox') && !(i is 'SWWMRespawnTimer')) ) continue;
if ( (i is 'Inventory') && (i.bINVISIBLE || !i.bSPECIAL || Inventory(i).Owner) ) continue;
if ( (i is 'Chancebox') && (i.CurState != i.SpawnState) ) continue;
if ( !SWWMUtility.SphereIntersect(i,pos,800) ) continue;
if ( !level.allmap && !i.CheckSight(self,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
SWWMItemSense.Spawn(self,i);
}
bt.Destroy();
}
SWWMItemsense itm = itemsense;
SWWMItemsense prev = null, next;
@ -50,9 +53,11 @@ extend Class Demolitionist
}
if ( (magitem_cnt < 8) && !swwm_usetopickup )
{
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
let bt = BlockThingsIterator.Create(self,500);
while ( bt.Next() )
{
if ( !(t is 'Inventory') || !t.bSPECIAL || !t.bDROPPED || t.bINVISIBLE || Inventory(t).Owner || !SWWMUtility.SphereIntersect(t,pos,500) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
let t = bt.Thing;
if ( !t || !(t is 'Inventory') || !t.bSPECIAL || !t.bDROPPED || t.bINVISIBLE || Inventory(t).Owner || !SWWMUtility.SphereIntersect(t,pos,500) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
continue;
let i = Inventory(t);
Class<Inventory> cls = i.GetClass();
@ -82,6 +87,7 @@ extend Class Demolitionist
magitem = nmi;
magitem_cnt++;
}
bt.Destroy();
}
SWWMMagItem itm = magitem;
SWWMMagItem prev = null, next;
@ -523,13 +529,14 @@ extend Class Demolitionist
Vector3 viewdir = SWWMUtility.Vec3FromAngles(angle,pitch);
// look for things we could potentially bump into
bool bumped = false;
let bi = BlockThingsIterator.Create(self,500);
let raging = RagekitPower(FindInventory("RagekitPower"));
double maxmass = max(mass*spd/40.,200);
if ( raging ) maxmass *= 2;
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
while ( (spd > 0) && bi.Next() )
{
if ( spd <= 0 ) break;
if ( (a == self) || (!a.bSOLID && !a.bSHOOTABLE) || a.bTHRUACTORS || a.bCORPSE || !CanCollideWith(a,false) || !a.CanCollideWith(self,true) ) continue;
a = bi.Thing;
if ( !a || (a == self) || (!a.bSOLID && !a.bSHOOTABLE) || a.bTHRUACTORS || a.bCORPSE || !CanCollideWith(a,false) || !a.CanCollideWith(self,true) ) continue;
if ( !SWWMUtility.ExtrudeIntersect(self,a,dir*(spd+radius),8) ) continue;
if ( (a.pos.z <= a.floorz) && (a.height <= MaxStepHeight) ) continue;
Vector3 diff = level.Vec3Diff(pos,a.pos);

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"));

View file

@ -111,9 +111,11 @@ Class ParryField : SWWMNonInteractiveActor
}
SetOrigin(SWWMUtility.GetFireOffset(master,20,0,0),false);
let raging = RagekitPower(master.FindInventory("RagekitPower"));
let st = Demolitionist(master).mystats;
let s = Demolitionist(master).mystats;
// check for projectiles to deflect
foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext )
let ti = ThinkerIterator.Create("Actor");
Actor a;
while ( a = Actor(ti.Next()) )
{
if ( (justparried.Find(a) < justparried.Size()) || !(SWWMUtility.ValidProjectile(a) || a.bSKULLFLY) || a.bTHRUACTORS || (level.Vec3Diff(a.pos,pos).length() > 80) ) continue;
if ( a is 'Whirlwind' ) SWWMUtility.MarkAchievement("tornado",master.player);
@ -177,13 +179,13 @@ Class ParryField : SWWMNonInteractiveActor
if ( !critsnd )
{
A_StartSound("misc/soulsparry",CHAN_ITEM,CHANF_OVERLAP,1.,.5);
if ( st ) st.pparries++;
if ( s ) s.pparries++;
}
critsnd = true;
if ( (a is 'LostSoul') && (master.player.ReadyWeapon is 'SilverBullet') )
SWWMUtility.MarkAchievement("baseball",master.player);
}
if ( st ) st.parries++;
if ( s ) s.parries++;
SWWMUtility.AchievementProgressInc("parry",1,master.player);
}
if ( --special1 <= 0 ) Destroy();

View file

@ -266,18 +266,14 @@ Class HellblazerMissile : Actor
return;
}
// proximity check
bool checked = false;
foreach ( s:level.Sectors )
let bt = BlockThingsIterator.Create(self,200);
while ( bt.Next() )
{
for ( Actor t=s.thinglist; t; t=t.snext )
{
if ( !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;
checked = true;
break;
}
if ( checked ) break;
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;
}
}

View file

@ -465,11 +465,13 @@ Class YnykronImpact : SWWMNonInteractiveActor
let s = Spawn("YnykronImpactArm",pos);
s.target = target;
}
let bt = BlockThingsIterator.Create(self,rad+200);
Array<Actor> candidates;
candidates.Clear();
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
while ( bt.Next() )
{
if ( !t.bSHOOTABLE || !SWWMUtility.SphereIntersect(t,pos,rad) || (!SWWMUtility.SphereIntersect(t,pos,100) && !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) ) continue;
let t = bt.Thing;
if ( !t || !t.bSHOOTABLE || !SWWMUtility.SphereIntersect(t,pos,rad) || (!SWWMUtility.SphereIntersect(t,pos,100) && !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) ) continue;
if ( YnykronShot(master) && (YnykronShot(master).hitlist.Find(t) < YnykronShot(master).hitlist.Size()) )
continue;
Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.Height/2));

View file

@ -211,8 +211,10 @@ Class DeepImpact : SWWMWeapon
let p = SWWMPuff.Setup(avgpos,avgdir,invoker,self,l.a);
l.a.DamageMobj(p,self,int(dmg/250.),'Push',DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
}
let st = Demolitionist(self).mystats;
foreach ( s:level.Sectors ) for ( Actor m=s.thinglist; m; m=m.snext )
let ti = ThinkerIterator.Create("Actor");
Actor m;
let s = Demolitionist(self).mystats;
while ( m = Actor(ti.Next()) )
{
if ( !SWWMUtility.ValidProjectile(m) ) continue;
Vector3 rdir = level.Vec3Diff(origin,m.pos);
@ -233,7 +235,7 @@ Class DeepImpact : SWWMWeapon
pb.AttachToOwner(m);
pb.bAMBUSH = true;
}
if ( st ) st.parries++;
if ( s ) s.parries++;
SWWMUtility.AchievementProgressInc("parry",1,player);
}
int numpt = Random[Impact](7,12);

View file

@ -192,10 +192,12 @@ Class BigBiospark : Actor
if ( !(special2%5) )
{
double closest = double.infinity;
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
let bt = BlockThingsIterator.Create(self,8000);
while ( bt.Next() )
{
let t = bt.Thing;
double dist;
if ( !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3DSquared(t)) > 64000000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3DSquared(t)) > 64000000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2)).unit();
if ( dist > closest ) continue;
closest = dist;
@ -220,9 +222,11 @@ Class BigBiospark : Actor
angle = atan2(dir.y,dir.x);
pitch = asin(-dir.z);
// deal (proper) radius damage
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
let bt2 = BlockThingsIterator.Create(self,500);
while ( bt2.Next() )
{
if ( !t.bSHOOTABLE ) continue;
let t = bt2.Thing;
if ( !t || !t.bSHOOTABLE ) continue;
if ( SWWMUtility.SphereIntersect(t,pos,40) )
{
t.DamageMobj(self,target,4+special1,'Biospark');
@ -461,10 +465,12 @@ Class BiosparkBall : Actor
if ( !(special2%5) )
{
double closest = double.infinity;
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
let bt = BlockThingsIterator.Create(self,500);
while ( bt.Next() )
{
let t = bt.Thing;
double dist;
if ( !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3DSquared(t)) > 250000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3DSquared(t)) > 250000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2)).unit();
if ( dir dot dirto < .5 ) continue; // don't seek stuff that's behind us
if ( dist > closest ) continue;
@ -491,17 +497,13 @@ Class BiosparkBall : Actor
return;
}
// proximity check
bool checked = false;
foreach ( s:level.Sectors )
let bt = BlockThingsIterator.Create(self,100);
while ( bt.Next() )
{
for ( Actor t=s.thinglist; t; t=t.snext )
{
if ( !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),16) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
deto++;
checked = true;
break;
}
if ( checked ) break;
let t = bt.Thing;
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || (target && t.IsFriend(target)) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),16) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
deto++;
break;
}
}
override void OnDestroy()
@ -1053,10 +1055,12 @@ Class BiosparkBeam : SWWMNonInteractiveActor
}
nextpos = t.Results.HitPos;
double closest = double.infinity;
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
let bt = BlockThingsIterator.Create(self,500);
while ( bt.Next() )
{
let t = bt.Thing;
double dist;
if ( (!(t is 'BiosparkHitbox') && (!t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)))) || ((dist=Distance3DSquared(t)) > 250000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
if ( !t || (!(t is 'BiosparkHitbox') && (!t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)))) || ((dist=Distance3DSquared(t)) > 250000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
Vector3 dirto = level.Vec3Diff(nextpos,t.Vec3Offset(0,0,t.height/2));
if ( dir dot dirto < .2 ) continue;
if ( dist > closest ) continue;
@ -1358,10 +1362,12 @@ Class BiosparkArc : SWWMNonInteractiveActor
else
{
double closest = double.infinity;
foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext )
let bt = BlockThingsIterator.Create(self,1500);
while ( bt.Next() )
{
let t = bt.Thing;
double dist;
if ( !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3DSquared(t)) > 2250000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain') && !t.player) || (t.Health <= 0) || (target && t.IsFriend(target)) || ((dist=Distance3DSquared(t)) > 2250000) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
Vector3 dirto = level.Vec3Diff(nextpos,t.Vec3Offset(0,0,t.height/2));
if ( dir dot dirto < .2 ) continue;
if ( dist > closest ) continue;

View file

@ -245,20 +245,15 @@ Class ExplodiumMagHitbox : Actor
return;
}
SetOrigin(target.Vec3Offset(0,0,-height*.5),false);
bool breakout = false;
foreach ( s:level.Sectors )
let bt = BlockThingsIterator.Create(self,128);
while ( bt.Next() )
{
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;
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 )