From 2bd1cb0657d822e98ca35db8386fb6bdd098a073 Mon Sep 17 00:00:00 2001 From: Marisa the Magician Date: Sat, 29 Jul 2023 13:15:34 +0200 Subject: [PATCH] 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. --- language.version | 4 +- zscript/dlc1/swwm_mister_fx.zsc | 24 ++--- zscript/handler/swwm_handler_debugrender.zsc | 6 +- zscript/handler/swwm_handler_worldthings.zsc | 18 ++-- zscript/handler/swwm_handler_worldtick.zsc | 30 +++--- zscript/items/swwm_ammoextra.zsc | 12 ++- zscript/items/swwm_lamp.zsc | 6 +- zscript/items/swwm_powerups.zsc | 6 +- zscript/items/swwm_powerups_vip.zsc | 4 +- zscript/player/swwm_player_tick.zsc | 21 ++--- zscript/utility/swwm_utility_blast.zsc | 93 +------------------ zscript/weapons/swwm_baseweapon_melee.zsc | 10 +- zscript/weapons/swwm_blazeit_fx.zsc | 18 ++-- .../weapons/swwm_deathlydeathcannon_fx.zsc | 6 +- zscript/weapons/swwm_deepdarkimpact.zsc | 8 +- zscript/weapons/swwm_sparkyboi_fx.zsc | 46 ++++----- zscript/weapons/swwm_splode_fx.zsc | 21 +++-- 17 files changed, 113 insertions(+), 220 deletions(-) diff --git a/language.version b/language.version index 97a60dcc9..caf47edea 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -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-"; +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-"; diff --git a/zscript/dlc1/swwm_mister_fx.zsc b/zscript/dlc1/swwm_mister_fx.zsc index 2ede28567..aaa61cd81 100644 --- a/zscript/dlc1/swwm_mister_fx.zsc +++ b/zscript/dlc1/swwm_mister_fx.zsc @@ -1036,14 +1036,18 @@ Class MisterGrenade : Actor if ( bNoProx ) return; // "safe delay" for main grenade if ( !bAMBUSH && (ReactionTime > default.ReactionTime-20) ) return; - let bt = BlockThingsIterator.Create(self,120); - while ( bt.Next() ) + bool breakout = false; + foreach ( s:level.Sectors ) { - 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; + 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; } } @@ -1129,13 +1133,11 @@ Class MisterGrenade : Actor } // gather seekable targets Array candidates; - let bt = BlockThingsIterator.Create(self,2000); let tt = new("TargetTracer"); tt.target = target; - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - 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; + if ( (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 diff --git a/zscript/handler/swwm_handler_debugrender.zsc b/zscript/handler/swwm_handler_debugrender.zsc index 372bd47b3..e6f9de77b 100644 --- a/zscript/handler/swwm_handler_debugrender.zsc +++ b/zscript/handler/swwm_handler_debugrender.zsc @@ -3,7 +3,6 @@ extend Class SWWMHandler { ui SWWMProjectionData projdata; - transient ui ThinkerIterator dbgti; private ui void DrawWorldLine( RenderEvent e, Vector3 apos, Vector3 bpos, Color col ) { @@ -103,10 +102,7 @@ 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); - if ( !dbgti ) dbgti = ThinkerIterator.Create("Actor"); - else dbgti.Reinit(); - Actor a; - while ( a = Actor(dbgti.Next()) ) + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { if ( (a == players[consoleplayer].Camera) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue; if ( a.bINVISIBLE && !(a is 'DynamicLight') ) continue; diff --git a/zscript/handler/swwm_handler_worldthings.zsc b/zscript/handler/swwm_handler_worldthings.zsc index ef7ef9189..036679120 100644 --- a/zscript/handler/swwm_handler_worldthings.zsc +++ b/zscript/handler/swwm_handler_worldthings.zsc @@ -178,14 +178,18 @@ extend Class SWWMHandler // copies the floatbob of overlapping identical items, so it doesn't look weird private void CopyFloatBob( Actor a ) { - let bt = BlockThingsIterator.Create(a,16); - while ( bt.Next() ) + bool breakout = false; + foreach ( s:level.Sectors ) { - 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; + 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; } } diff --git a/zscript/handler/swwm_handler_worldtick.zsc b/zscript/handler/swwm_handler_worldtick.zsc index 75519cb01..a1b2f3a70 100644 --- a/zscript/handler/swwm_handler_worldtick.zsc +++ b/zscript/handler/swwm_handler_worldtick.zsc @@ -98,11 +98,9 @@ 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; - while ( a = Actor(cti.Next()) ) + // 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 ) { if ( !a.player && !a.bISMONSTER ) continue; // ignore the dead @@ -206,12 +204,12 @@ extend Class SWWMHandler } mapclearagain++; if ( !iwantdie ) return; - let ti = ThinkerIterator.Create("SWWMStats",Thinker.STAT_STATIC); - SWWMStats s; - while ( s = SWWMStats(ti.Next()) ) + for ( int i=0; i 0 ) - return; + if ( !playeringame[i] ) continue; + let demo = Demolitionist(players[i].mo); + if ( !demo || !demo.mystats ) continue; + if ( demo.mystats.deaths > 0 ) return; } SWWMUtility.MarkAchievement("wantdie",players[consoleplayer]); } @@ -279,11 +277,9 @@ extend Class SWWMHandler } // update trackers for anything around the player double viewdist = SWWMStatusBar.MAPVIEWDIST*swwm_mm_zoom; - BlockThingsIterator bt = BlockThingsIterator.Create(players[consoleplayer].Camera,viewdist); - while ( bt.Next() ) + // 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 ) { - 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; @@ -325,19 +321,15 @@ 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 viewdist ) continue; diff --git a/zscript/items/swwm_ammoextra.zsc b/zscript/items/swwm_ammoextra.zsc index a4130b16c..f45f5e642 100644 --- a/zscript/items/swwm_ammoextra.zsc +++ b/zscript/items/swwm_ammoextra.zsc @@ -523,15 +523,19 @@ 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; - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; ) { - let t = bt.Thing; - if ( !t || (t == self) || !(t is 'HammerspaceEmbiggener') || !(t.spawnpoint ~== spawnpoint) ) continue; + let next = t.snext; + if ( (t == self) || !(t is 'HammerspaceEmbiggener') || !(t.spawnpoint ~== spawnpoint) ) + { + t = next; + continue; + } tamount += HammerspaceEmbiggener(t).Amount; t.ClearCounters(); t.Destroy(); + t = next; } if ( tamount <= 1 ) return; tamount -= tamount%2; // always even numbered diff --git a/zscript/items/swwm_lamp.zsc b/zscript/items/swwm_lamp.zsc index 3b3c892bf..16e2c66b3 100644 --- a/zscript/items/swwm_lamp.zsc +++ b/zscript/items/swwm_lamp.zsc @@ -58,12 +58,10 @@ Class LampMoth : Actor if ( !lamp ) { // look for nearby lamps - let bi = BlockThingsIterator.Create(self,250); double mindist = 62500.; - while ( bi.Next() ) + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { - if ( !bi.Thing || !(bi.Thing is 'CompanionLamp') ) continue; - Actor a = bi.Thing; + if ( !(a is 'CompanionLamp') ) continue; double dist = Distance3DSquared(a); if ( (a.frame == 0) || (dist > mindist) && !CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; mindist = dist; diff --git a/zscript/items/swwm_powerups.zsc b/zscript/items/swwm_powerups.zsc index 2fbe1f8db..c8cf7eb11 100644 --- a/zscript/items/swwm_powerups.zsc +++ b/zscript/items/swwm_powerups.zsc @@ -310,11 +310,9 @@ Class GhostTarget : Actor } if ( isFrozen() ) return; if ( diedie ) A_FadeOut(.05); - let bt = BlockThingsIterator.Create(self,300); - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - let t = bt.Thing; - if ( !t || !t.bIsMonster || t.player || !t.IsHostile(master) || (t.target != self) ) continue; + if ( !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 diff --git a/zscript/items/swwm_powerups_vip.zsc b/zscript/items/swwm_powerups_vip.zsc index 082a8930a..5f6aa0799 100644 --- a/zscript/items/swwm_powerups_vip.zsc +++ b/zscript/items/swwm_powerups_vip.zsc @@ -510,9 +510,7 @@ Class Mykradvo : Inventory { targets.Clear(); // search all actively hostile enemies within 50m - let ti = ThinkerIterator.Create("Actor"); - Actor a; - while ( a=Actor(ti.Next()) ) + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { // must be an active, shootable live monster if ( !a.bISMONSTER || !a.bSHOOTABLE || a.bDORMANT || (a.Health <= 0) ) continue; diff --git a/zscript/player/swwm_player_tick.zsc b/zscript/player/swwm_player_tick.zsc index 2bf04bc32..bfd978895 100644 --- a/zscript/player/swwm_player_tick.zsc +++ b/zscript/player/swwm_player_tick.zsc @@ -5,18 +5,15 @@ extend Class Demolitionist { if ( player.cmd.buttons&BT_USER3 ) { - let bt = BlockThingsIterator.Create(self,800); - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor i=s.thinglist; i; i=i.snext ) { - let i = bt.Thing; - if ( !i || (!(i is 'Inventory') && !(i is 'Chancebox') && !(i is 'SWWMRespawnTimer')) ) continue; + if ( !(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; @@ -53,11 +50,9 @@ extend Class Demolitionist } if ( (magitem_cnt < 8) && !swwm_usetopickup ) { - let bt = BlockThingsIterator.Create(self,500); - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - 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) ) + if ( !(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 cls = i.GetClass(); @@ -87,7 +82,6 @@ extend Class Demolitionist magitem = nmi; magitem_cnt++; } - bt.Destroy(); } SWWMMagItem itm = magitem; SWWMMagItem prev = null, next; @@ -529,14 +523,13 @@ 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; - while ( (spd > 0) && bi.Next() ) + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { - a = bi.Thing; - if ( !a || (a == self) || (!a.bSOLID && !a.bSHOOTABLE) || a.bTHRUACTORS || a.bCORPSE || !CanCollideWith(a,false) || !a.CanCollideWith(self,true) ) continue; + if ( spd <= 0 ) break; + if ( (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); diff --git a/zscript/utility/swwm_utility_blast.zsc b/zscript/utility/swwm_utility_blast.zsc index 494bc163e..1eed42a3b 100644 --- a/zscript/utility/swwm_utility_blast.zsc +++ b/zscript/utility/swwm_utility_blast.zsc @@ -63,17 +63,12 @@ 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; - Array washit; - washit.Clear(); - while ( bi.Next() ) + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { - Actor a = bi.Thing; - washit.Push(a); // early checks for self and ignored actor (usually the instigator) - if ( !a || (a == ignoreme) || (a == Source) ) + if ( (a == ignoreme) || (a == Source) ) continue; // can't be affected if ( !a.bSHOOTABLE && !a.bVULNERABLE ) @@ -141,90 +136,6 @@ 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 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")); diff --git a/zscript/weapons/swwm_baseweapon_melee.zsc b/zscript/weapons/swwm_baseweapon_melee.zsc index 5a388405c..6ef9ddcf1 100644 --- a/zscript/weapons/swwm_baseweapon_melee.zsc +++ b/zscript/weapons/swwm_baseweapon_melee.zsc @@ -111,11 +111,9 @@ Class ParryField : SWWMNonInteractiveActor } SetOrigin(SWWMUtility.GetFireOffset(master,20,0,0),false); let raging = RagekitPower(master.FindInventory("RagekitPower")); - let s = Demolitionist(master).mystats; + let st = Demolitionist(master).mystats; // check for projectiles to deflect - let ti = ThinkerIterator.Create("Actor"); - Actor a; - while ( a = Actor(ti.Next()) ) + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { 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); @@ -179,13 +177,13 @@ Class ParryField : SWWMNonInteractiveActor if ( !critsnd ) { A_StartSound("misc/soulsparry",CHAN_ITEM,CHANF_OVERLAP,1.,.5); - if ( s ) s.pparries++; + if ( st ) st.pparries++; } critsnd = true; if ( (a is 'LostSoul') && (master.player.ReadyWeapon is 'SilverBullet') ) SWWMUtility.MarkAchievement("baseball",master.player); } - if ( s ) s.parries++; + if ( st ) st.parries++; SWWMUtility.AchievementProgressInc("parry",1,master.player); } if ( --special1 <= 0 ) Destroy(); diff --git a/zscript/weapons/swwm_blazeit_fx.zsc b/zscript/weapons/swwm_blazeit_fx.zsc index ab62e2b7a..cf47b3ad2 100644 --- a/zscript/weapons/swwm_blazeit_fx.zsc +++ b/zscript/weapons/swwm_blazeit_fx.zsc @@ -266,14 +266,18 @@ Class HellblazerMissile : Actor return; } // proximity check - let bt = BlockThingsIterator.Create(self,200); - while ( bt.Next() ) + bool checked = false; + foreach ( s:level.Sectors ) { - 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; + 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; } } diff --git a/zscript/weapons/swwm_deathlydeathcannon_fx.zsc b/zscript/weapons/swwm_deathlydeathcannon_fx.zsc index 45accfc6a..54dedc63c 100644 --- a/zscript/weapons/swwm_deathlydeathcannon_fx.zsc +++ b/zscript/weapons/swwm_deathlydeathcannon_fx.zsc @@ -465,13 +465,11 @@ Class YnykronImpact : SWWMNonInteractiveActor let s = Spawn("YnykronImpactArm",pos); s.target = target; } - let bt = BlockThingsIterator.Create(self,rad+200); Array candidates; candidates.Clear(); - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - 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 ( !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)); diff --git a/zscript/weapons/swwm_deepdarkimpact.zsc b/zscript/weapons/swwm_deepdarkimpact.zsc index fadd3737c..fdf2f529b 100644 --- a/zscript/weapons/swwm_deepdarkimpact.zsc +++ b/zscript/weapons/swwm_deepdarkimpact.zsc @@ -211,10 +211,8 @@ 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 ti = ThinkerIterator.Create("Actor"); - Actor m; - let s = Demolitionist(self).mystats; - while ( m = Actor(ti.Next()) ) + let st = Demolitionist(self).mystats; + foreach ( s:level.Sectors ) for ( Actor m=s.thinglist; m; m=m.snext ) { if ( !SWWMUtility.ValidProjectile(m) ) continue; Vector3 rdir = level.Vec3Diff(origin,m.pos); @@ -235,7 +233,7 @@ Class DeepImpact : SWWMWeapon pb.AttachToOwner(m); pb.bAMBUSH = true; } - if ( s ) s.parries++; + if ( st ) st.parries++; SWWMUtility.AchievementProgressInc("parry",1,player); } int numpt = Random[Impact](7,12); diff --git a/zscript/weapons/swwm_sparkyboi_fx.zsc b/zscript/weapons/swwm_sparkyboi_fx.zsc index f033fbe1c..637fe9e30 100644 --- a/zscript/weapons/swwm_sparkyboi_fx.zsc +++ b/zscript/weapons/swwm_sparkyboi_fx.zsc @@ -192,12 +192,10 @@ Class BigBiospark : Actor if ( !(special2%5) ) { double closest = double.infinity; - let bt = BlockThingsIterator.Create(self,8000); - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - let t = bt.Thing; double dist; - 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; + 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; Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2)).unit(); if ( dist > closest ) continue; closest = dist; @@ -222,11 +220,9 @@ Class BigBiospark : Actor angle = atan2(dir.y,dir.x); pitch = asin(-dir.z); // deal (proper) radius damage - let bt2 = BlockThingsIterator.Create(self,500); - while ( bt2.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - let t = bt2.Thing; - if ( !t || !t.bSHOOTABLE ) continue; + if ( !t.bSHOOTABLE ) continue; if ( SWWMUtility.SphereIntersect(t,pos,40) ) { t.DamageMobj(self,target,4+special1,'Biospark'); @@ -465,12 +461,10 @@ Class BiosparkBall : Actor if ( !(special2%5) ) { double closest = double.infinity; - let bt = BlockThingsIterator.Create(self,500); - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - let t = bt.Thing; double dist; - 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; + 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; 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; @@ -497,13 +491,17 @@ Class BiosparkBall : Actor return; } // proximity check - let bt = BlockThingsIterator.Create(self,100); - while ( bt.Next() ) + bool checked = false; + foreach ( s:level.Sectors ) { - 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; + 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; } } override void OnDestroy() @@ -1055,12 +1053,10 @@ Class BiosparkBeam : SWWMNonInteractiveActor } nextpos = t.Results.HitPos; double closest = double.infinity; - let bt = BlockThingsIterator.Create(self,500); - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - let t = bt.Thing; double dist; - 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; + 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; Vector3 dirto = level.Vec3Diff(nextpos,t.Vec3Offset(0,0,t.height/2)); if ( dir dot dirto < .2 ) continue; if ( dist > closest ) continue; @@ -1362,12 +1358,10 @@ Class BiosparkArc : SWWMNonInteractiveActor else { double closest = double.infinity; - let bt = BlockThingsIterator.Create(self,1500); - while ( bt.Next() ) + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) { - let t = bt.Thing; double dist; - 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; + 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; Vector3 dirto = level.Vec3Diff(nextpos,t.Vec3Offset(0,0,t.height/2)); if ( dir dot dirto < .2 ) continue; if ( dist > closest ) continue; diff --git a/zscript/weapons/swwm_splode_fx.zsc b/zscript/weapons/swwm_splode_fx.zsc index e9217a24c..57f0e3ca9 100644 --- a/zscript/weapons/swwm_splode_fx.zsc +++ b/zscript/weapons/swwm_splode_fx.zsc @@ -245,15 +245,20 @@ Class ExplodiumMagHitbox : Actor return; } SetOrigin(target.Vec3Offset(0,0,-height*.5),false); - let bt = BlockThingsIterator.Create(self,128); - while ( bt.Next() ) + bool breakout = false; + foreach ( s:level.Sectors ) { - 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; + 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 )