diff --git a/language.version b/language.version index 224095c0a..3d56dbce6 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r811 \cu(Sat 29 Jul 15:01:17 CEST 2023)\c-"; -SWWM_SHORTVER="\cw1.3pre r811 \cu(2023-07-29 15:01:17)\c-"; +SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r812 \cu(Sat 29 Jul 15:02:24 CEST 2023)\c-"; +SWWM_SHORTVER="\cw1.3pre r812 \cu(2023-07-29 15:02:24)\c-"; diff --git a/zscript/dlc1/swwm_mister_fx.zsc b/zscript/dlc1/swwm_mister_fx.zsc index 87880e2c3..87fe1a41f 100644 --- a/zscript/dlc1/swwm_mister_fx.zsc +++ b/zscript/dlc1/swwm_mister_fx.zsc @@ -1044,14 +1044,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; } } @@ -1137,13 +1141,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 bd6439ef8..a7705b019 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 ) { @@ -105,10 +104,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 6d995f375..ee2199261 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 24aa0e96a..243334a5f 100644 --- a/zscript/items/swwm_powerups.zsc +++ b/zscript/items/swwm_powerups.zsc @@ -309,12 +309,10 @@ Class GhostTarget : Actor return; } if ( isFrozen() ) return; - if ( diedie ) A_FadeOut(.02); - let bt = BlockThingsIterator.Create(self,300); - while ( bt.Next() ) + if ( diedie ) A_FadeOut(.05); + 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 3a832ac88..622c44beb 100644 --- a/zscript/items/swwm_powerups_vip.zsc +++ b/zscript/items/swwm_powerups_vip.zsc @@ -516,9 +516,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 3069ab0ad..b690333a3 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; @@ -531,14 +525,15 @@ 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() ) + Array hitlist; + hitlist.Clear(); + // gather first + 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 ( (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); @@ -559,6 +554,11 @@ extend Class Demolitionist if ( dir dot bnorm > -.6 ) continue; } if ( !CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; + hitlist.Push(a); + } + foreach ( a:hitlist ) + { + if ( spd <= 0 ) break; // large monsters will stop the player (unless hit from above if we're going at ground pound speed) A_QuakeEx(4,4,4,10,0,128,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D); A_AlertMonsters(swwm_uncapalert?0:800); diff --git a/zscript/utility/swwm_utility_blast.zsc b/zscript/utility/swwm_utility_blast.zsc index 494bc163e..d741e7e42 100644 --- a/zscript/utility/swwm_utility_blast.zsc +++ b/zscript/utility/swwm_utility_blast.zsc @@ -63,17 +63,15 @@ 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() ) + Array hitlist; + hitlist.Clear(); + // gather first + 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 ) @@ -93,6 +91,10 @@ extend Class SWWMUtility // intersecting? if ( !SphereIntersect(a,Source.pos,ExplosionRadius) ) continue; + hitlist.Push(a); + } + foreach ( a:hitlist ) + { // 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)); @@ -141,90 +143,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 aa812c35f..9c6289f47 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 082803eb9..2bd5eea66 100644 --- a/zscript/weapons/swwm_blazeit_fx.zsc +++ b/zscript/weapons/swwm_blazeit_fx.zsc @@ -265,14 +265,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 f3453fb71..9332c0f40 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 18dda72e9..a48b82ed2 100644 --- a/zscript/weapons/swwm_deepdarkimpact.zsc +++ b/zscript/weapons/swwm_deepdarkimpact.zsc @@ -210,10 +210,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); @@ -234,7 +232,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 a0de3b942..87707cf08 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,16 @@ 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() ) + Array hitlist; + hitlist.Clear(); + // gather first + foreach ( s:level.Sectors ) for ( Actor t=s.thinglist; t; t=t.snext ) + { + if ( !t.bSHOOTABLE || !SWWMUtility.SphereIntersect(t,pos,120) ) continue; + hitlist.Push(t); + } + foreach ( t:hitlist ) { - let t = bt2.Thing; - if ( !t || !t.bSHOOTABLE ) continue; if ( SWWMUtility.SphereIntersect(t,pos,40) ) { t.DamageMobj(self,target,4+special1,'Biospark'); @@ -234,13 +237,10 @@ Class BigBiospark : Actor t.Howl(); Health--; } - if ( SWWMUtility.SphereIntersect(t,pos,120) ) - { - Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2)); - double dist = dirto.length(); - dirto /= dist; - if ( dist > 4. ) SWWMUtility.DoKnockback(t,-dirto,clamp(120.-dist,0.,120.)*100); - } + Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2)); + double dist = dirto.length(); + dirto /= dist; + if ( dist > 4. ) SWWMUtility.DoKnockback(t,-dirto,clamp(120.-dist,0.,120.)*100); } Health -= 3; if ( bMISSILEMORE ) Health--; @@ -464,12 +464,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; @@ -496,13 +494,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() @@ -1063,12 +1065,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; @@ -1377,12 +1377,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 bd365a774..4d8c05df6 100644 --- a/zscript/weapons/swwm_splode_fx.zsc +++ b/zscript/weapons/swwm_splode_fx.zsc @@ -248,15 +248,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 )