From 09f5bfd2f6601d85a69ac83b7e7397ab88dc7ffd Mon Sep 17 00:00:00 2001 From: Marisa the Magician Date: Sat, 29 Jul 2023 14:44:34 +0200 Subject: [PATCH] Retire the "suckables list" + some fixes. --- language.version | 4 +- zscript/handler/swwm_handler_process.zsc | 19 -- zscript/handler/swwm_handler_worldthings.zsc | 25 --- zscript/handler/swwm_handler_worldtick.zsc | 92 ++------- zscript/items/swwm_powerups.zsc | 10 +- zscript/player/swwm_player.zsc | 4 - zscript/player/swwm_player_tick.zsc | 3 + zscript/swwm_gesture.zsc | 22 +- .../weapons/swwm_deathlydeathcannon_altfx.zsc | 193 +++++++++--------- 9 files changed, 138 insertions(+), 234 deletions(-) diff --git a/language.version b/language.version index 3d56dbce6..e7ae00d29 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -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-"; +SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r813 \cu(Sat 29 Jul 15:03:26 CEST 2023)\c-"; +SWWM_SHORTVER="\cw1.3pre r813 \cu(2023-07-29 15:03:26)\c-"; diff --git a/zscript/handler/swwm_handler_process.zsc b/zscript/handler/swwm_handler_process.zsc index ef8e0e69e..e95739e77 100644 --- a/zscript/handler/swwm_handler_process.zsc +++ b/zscript/handler/swwm_handler_process.zsc @@ -228,25 +228,6 @@ extend Class SWWMHandler } } } - else if ( e.Name ~== "swwmtrimsuckables" ) - { - if ( multiplayer && (e.player != Net_Arbitrator) ) - { - if ( e.player == consoleplayer ) - Console.Printf("Only the net arbitrator can call this event."); - return; - } - int n = 0; - for ( int i=0; i alreadygold; - // attempt to optimize Ynykron singularity suction - Array suckableactors; - - // for displaying beam-type projectiles - Array beams; - // legendary monster markers (for the "has mutated" message) Array legtrack; @@ -214,20 +208,6 @@ extend Class SWWMHandler // for gibber throttling if ( e.Thing is 'mkBloodDrop' ) blods_realcnt--; else if ( e.Thing is 'mkFlyingGib' ) meats_realcnt--; - if ( e.Thing.default.bSHOOTABLE || (e.Thing is 'Inventory') || SWWMUtility.ValidProjectile(e.Thing) ) - { - // remove from suckables - int pos = suckableactors.Find(e.Thing); - if ( pos < suckableactors.Size() ) - suckableactors.Delete(pos); - } - else if ( SWWMUtility.IsBeamProj(e.Thing) ) - { - // remove from beams - int pos = beams.Find(e.Thing); - if ( pos < beams.Size() ) - beams.Delete(pos); - } if ( profiling ) ProfileTock(PT_WORLDTHINGDESTROYED); } @@ -389,11 +369,6 @@ extend Class SWWMHandler let hp = Actor.Spawn("HeadpatTracker",e.Thing.pos); hp.target = e.Thing; } - // Ynykron vortex optimization (faster than a thinker iterator) - if ( e.Thing.bSHOOTABLE || (e.Thing is 'Inventory') || SWWMUtility.ValidProjectile(e.Thing) ) - SuckableActors.Push(e.Thing); - else if ( SWWMUtility.IsBeamProj(e.Thing) ) - Beams.Push(e.Thing); // vanilla blood color changes if ( (e.Thing.GetClass() == "BaronOfHell") || (e.Thing.GetClass() == "HellKnight") || (e.Thing.GetClass() == "Bishop") || (e.Thing.GetClass() == "Korax") ) { diff --git a/zscript/handler/swwm_handler_worldtick.zsc b/zscript/handler/swwm_handler_worldtick.zsc index a1b2f3a70..1ec816325 100644 --- a/zscript/handler/swwm_handler_worldtick.zsc +++ b/zscript/handler/swwm_handler_worldtick.zsc @@ -278,16 +278,31 @@ 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 + int thisgroup = players[consoleplayer].Camera.CurSector.portalgroup; foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { - Vector2 rv = a.pos.xy-players[consoleplayer].Camera.pos.xy; + Vector2 rv; + if ( s.portalgroup != thisgroup ) + { + Vector2 relpos = players[consoleplayer].Camera.pos.xy+level.GetDisplacement(thisgroup,s.portalgroup); + rv = a.pos.xy-relpos; + } + else rv = a.pos.xy-players[consoleplayer].Camera.pos.xy; + double rad; + bool isproj = a.bMISSILE; + if ( SWWMUtility.IsBeamProj(a) ) + { + isproj = true; + rad = SWWMUtility.IsYBeam(a)?(a.scale.y*cos(a.pitch-90)):(a.speed*cos(a.pitch)); + } + else rad = a.radius; if ( max(abs(rv.x)-a.radius,abs(rv.y)-a.radius) > viewdist ) continue; if ( a == players[consoleplayer].Camera ) continue; if ( a is 'GhostTarget' ) continue; - if ( !a.player && !a.bSOLID && !a.bSHOOTABLE && !a.bISMONSTER && !a.bFRIENDLY && !(a is 'Inventory') && !(a is 'Chancebox') ) + if ( !a.player && !a.bSOLID && !a.bSHOOTABLE && !a.bISMONSTER && !a.bFRIENDLY && !(a is 'Inventory') && !(a is 'Chancebox') && !isproj ) continue; if ( !level.allmap && !(deathmatch && (a is 'Inventory') && !a.bDROPPED) && !(a.IsFriend(players[consoleplayer].mo) && !(a.player && (a.player.mo != a))) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; @@ -297,81 +312,10 @@ extend Class SWWMHandler continue; if ( (a is 'Chancebox') && (a.CurState != a.SpawnState) ) continue; - SWWMSimpleTracker.Track(self,a); - } - // we need to refer to the suckables array to find missiles - foreach ( a:suckableactors ) - { - if ( !a || !a.bMISSILE ) 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; - if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) + if ( isproj && !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; SWWMSimpleTracker.Track(self,a); } - foreach ( a:beams ) - { - if ( !a ) continue; - Vector2 rv = a.pos.xy-players[consoleplayer].Camera.pos.xy; - double rad = SWWMUtility.IsYBeam(a)?(a.scale.y*cos(a.pitch-90)):(a.speed*cos(a.pitch)); - if ( max(abs(rv.x)-rad,abs(rv.y)-rad) > viewdist ) - continue; - if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) - continue; - SWWMSimpleTracker.Track(self,a); - } - // oh boy here we go - int thisgroup = players[consoleplayer].Camera.CurSector.portalgroup; - for ( int i=0; i viewdist ) - continue; - if ( a == players[consoleplayer].Camera ) - continue; - if ( a is 'GhostTarget' ) - continue; - if ( !a.player && !a.bSOLID && !a.bSHOOTABLE && !a.bISMONSTER && !a.bFRIENDLY && !(a is 'Inventory') && !(a is 'Chancebox') ) - continue; - if ( !level.allmap && !(deathmatch && (a is 'Inventory') && !a.bDROPPED) && !a.IsFriend(players[consoleplayer].mo) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) - continue; - if ( a.bKILLED || (a.Health <= 0) || a.bUnmorphed ) - continue; - if ( (a is 'Inventory') && (!a.bSPECIAL || Inventory(a).Owner) ) - continue; - if ( (a is 'Chancebox') && (a.CurState != a.SpawnState) ) - continue; - SWWMSimpleTracker.Track(self,a); - } - // we need to refer to the suckables array to find missiles - foreach ( a:suckableactors ) - { - if ( !a || !a.bMISSILE ) continue; - Vector2 rv = a.pos.xy-relpos; - if ( max(abs(rv.x)-a.radius,abs(rv.y)-a.radius) > viewdist ) - continue; - if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) - continue; - SWWMSimpleTracker.Track(self,a); - } - foreach ( a:beams ) - { - if ( !a ) continue; - Vector2 rv = a.pos.xy-relpos; - double rad = SWWMUtility.IsYBeam(a)?(a.scale.y*cos(a.pitch-90)):(a.speed*cos(a.pitch)); - if ( max(abs(rv.x)-rad,abs(rv.y)-rad) > viewdist ) - continue; - if ( !level.allmap && !(a.target && a.target.IsFriend(players[consoleplayer].mo)) && !a.CheckSight(players[consoleplayer].Camera,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) - continue; - SWWMSimpleTracker.Track(self,a); - } - } SWWMSimpleTracker trk = strackers; SWWMSimpleTracker prev = null, next; while ( trk ) diff --git a/zscript/items/swwm_powerups.zsc b/zscript/items/swwm_powerups.zsc index 243334a5f..d7676d445 100644 --- a/zscript/items/swwm_powerups.zsc +++ b/zscript/items/swwm_powerups.zsc @@ -323,10 +323,9 @@ Class GhostTarget : Actor // player made noise or is visible again if ( !master || (LastHeard == master) || !master.FindInventory("GhostPower") ) { - let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); - if ( hnd ) foreach ( a:hnd.suckableactors ) + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { - if ( !a || !a.bISMONSTER || a.player || !a.IsHostile(master) || (a.Health <= 0) ) continue; + if ( !a.bISMONSTER || a.player || !a.IsHostile(master) || (a.Health <= 0) ) continue; if ( a.target == self ) a.target = master; } Destroy(); @@ -384,11 +383,10 @@ Class GhostPower : Powerup Super.DoEffect(); if ( !Owner ) return; // are any enemies targetting us? if so, make them focus on a fake target located where we currently are standing - let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); Actor gt = null; - if ( hnd ) foreach ( a:hnd.suckableactors ) + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { - if ( !a || !a.bISMONSTER || a.player || !a.IsHostile(Owner) || (a.Health <= 0) ) continue; + if ( !a.bISMONSTER || a.player || !a.IsHostile(Owner) || (a.Health <= 0) ) continue; // make them forget the ghost if we make noise if ( (a.LastHeard == Owner) && (a.target is 'GhostTarget') && (a.target.master == Owner) ) { diff --git a/zscript/player/swwm_player.zsc b/zscript/player/swwm_player.zsc index 4370247c4..3eacd5e8a 100644 --- a/zscript/player/swwm_player.zsc +++ b/zscript/player/swwm_player.zsc @@ -773,10 +773,6 @@ Class Demolitionist : PlayerPawn player.SetPSprite(PSP_WEAPON,player.ReadyWeapon.ResolveState("Deselect")); } } - // re-add ourselves to the "suckable list" (otherwise the Ynykron Singularity won't hurt us) - if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); - if ( hnd && (hnd.SuckableActors.Find(self) >= hnd.SuckableActors.Size()) ) - hnd.SuckableActors.Push(self); } override bool PreTeleport( Vector3 destpos, double destangle, int flags ) diff --git a/zscript/player/swwm_player_tick.zsc b/zscript/player/swwm_player_tick.zsc index b690333a3..4611d2a14 100644 --- a/zscript/player/swwm_player_tick.zsc +++ b/zscript/player/swwm_player_tick.zsc @@ -559,6 +559,9 @@ extend Class Demolitionist foreach ( a:hitlist ) { if ( spd <= 0 ) break; + // we have to recalculate these + Vector3 diff = level.Vec3Diff(pos,a.pos); + Vector3 dirto = diff.unit(); // 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/swwm_gesture.zsc b/zscript/swwm_gesture.zsc index 69b39e182..299eb76a7 100644 --- a/zscript/swwm_gesture.zsc +++ b/zscript/swwm_gesture.zsc @@ -69,16 +69,20 @@ Class SWWMGesture : SWWMWeapon private void CheckWave() { - let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); - if ( !hnd ) return; - foreach ( a:hnd.suckableactors ) + bool breakout = false; + foreach ( s:level.Sectors ) { - if ( !a || (a.Health > 0) || (a.tics == -1) || !(a.bISMONSTER || a.player) || !a.IsHostile(Owner) ) continue; - // check if we can see it - if ( !SWWMUtility.InPlayerFOV(Owner.player,a) ) continue; - // someone's dying - SWWMUtility.MarkAchievement("wave",Owner.player); - break; + for ( Actor a=s.thinglist; a; a=a.snext ) + { + if ( (a.Health > 0) || (a.tics == -1) || !(a.bISMONSTER || a.player) || !a.IsHostile(Owner) ) continue; + // check if we can see it + if ( !SWWMUtility.InPlayerFOV(Owner.player,a) ) continue; + // someone's dying + SWWMUtility.MarkAchievement("wave",Owner.player); + breakout = true; + break; + } + if ( breakout ) break; } } diff --git a/zscript/weapons/swwm_deathlydeathcannon_altfx.zsc b/zscript/weapons/swwm_deathlydeathcannon_altfx.zsc index 3abed7e20..1d1204b47 100644 --- a/zscript/weapons/swwm_deathlydeathcannon_altfx.zsc +++ b/zscript/weapons/swwm_deathlydeathcannon_altfx.zsc @@ -1090,109 +1090,112 @@ Class YnykronSingularity : SWWMNonInteractiveActor beamers[i].master = self; } // suck in reachable targets - let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); - if ( hnd ) + Array candidates; + candidates.Clear(); + // gather first + foreach ( s:level.Sectors ) for ( Actor a=s.thinglist; a; a=a.snext ) { - foreach ( a:hnd.SuckableActors ) + if ( !a.bSHOOTABLE && !(a is 'Inventory') && !SWWMUtility.ValidProjectile(a) ) + continue; + if ( a.bDORMANT || (a.Health <= 0) || (a == self) || !SWWMUtility.SphereIntersect(a,pos,20000.*scale.x) || !CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) + continue; + if ( (a is 'Inventory') && !a.bDROPPED ) // must be a dropped pickup + continue; + if ( a.player && (a.player.cheats&CF_NOCLIP2) ) // for safety + continue; + if ( (a is 'YnykronSingularity') && a.bNOBLOCKMAP ) // dead singularity, ignore + continue; + candidates.Push(a); + } + foreach ( a:candidates ) + { + double capmass = a.mass; + // succ + if ( SWWMUtility.SphereIntersect(a,pos,32.*scale.x) ) { - if ( !a ) continue; - if ( a.bDORMANT || (a.Health <= 0) || (a == self) || !SWWMUtility.SphereIntersect(a,pos,20000.*scale.x) || !CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) - continue; - if ( (a is 'Inventory') && !a.bDROPPED ) // must be a dropped pickup - continue; - if ( a.player && (a.player.cheats&CF_NOCLIP2) ) // for safety - continue; - if ( (a is 'YnykronSingularity') && a.bNOBLOCKMAP ) // dead singularity, ignore - continue; - double capmass = a.mass; - // succ - if ( SWWMUtility.SphereIntersect(a,pos,32.*scale.x) ) + // merge with other vortices + if ( a is 'YnykronSingularity' ) { - // merge with other vortices - if ( a is 'YnykronSingularity' ) + critmass += YnykronSingularity(a).critmass; + specialf2 += a.specialf2; + a.Destroy(); + continue; + } + // don't delet inventory + if ( a is 'Inventory' ) + continue; + // delet missile + if ( a.bMISSILE ) + { + specialf2 += 5.; + a.Destroy(); + continue; + } + // voodoo dolls just get erased (how convenient) + // otherwise instantly vaporize the poor sap + if ( a.player && (a.player.mo != a) ) a.Destroy(); + else if ( a.CountInv("GrilledCheeseSandwich") > 0 ) + { + // force use the sandwich, warp to safe spot + let gc = GrilledCheeseSandwich(a.FindInventory("GrilledCheeseSandwich")); + gc.SafeTeleport(true); + a.A_StartSound(gc.UseSound,CHAN_ITEMEXTRA); + gc.DoTheThing(true); + gc.Amount--; + } + else if ( !a.FindInventory("GrilledCheeseSafeguard") ) + a.DamageMobj(self,target,int.max,'Ynykron',DMG_FORCED|DMG_THRUSTLESS); + if ( a && (a.Health <= 0) ) + { + if ( a.player ) { - critmass += YnykronSingularity(a).critmass; - specialf2 += a.specialf2; - a.Destroy(); - continue; - } - // don't delet inventory - if ( a is 'Inventory' ) - continue; - // delet missile - if ( a.bMISSILE ) - { - specialf2 += 5.; - a.Destroy(); - continue; - } - // voodoo dolls just get erased (how convenient) - // otherwise instantly vaporize the poor sap - if ( a.player && (a.player.mo != a) ) a.Destroy(); - else if ( a.CountInv("GrilledCheeseSandwich") > 0 ) - { - // force use the sandwich, warp to safe spot - let gc = GrilledCheeseSandwich(a.FindInventory("GrilledCheeseSandwich")); - gc.SafeTeleport(true); - a.A_StartSound(gc.UseSound,CHAN_ITEMEXTRA); - gc.DoTheThing(true); - gc.Amount--; - } - else if ( !a.FindInventory("GrilledCheeseSafeguard") ) - a.DamageMobj(self,target,int.max,'Ynykron',DMG_FORCED|DMG_THRUSTLESS); - if ( a && (a.Health <= 0) ) - { - if ( a.player ) + if ( a == target ) { - if ( a == target ) - { - SWWMUtility.MarkAchievement("oopsie",a.player); - target = PlayerGone.FeckOff(a); - } - else PlayerGone.FeckOff(a); + SWWMUtility.MarkAchievement("oopsie",a.player); + target = PlayerGone.FeckOff(a); } - if ( a.FindState("YnykronAltDeath",true) ) - a.SetStateLabel("YnykronAltDeath"); // dedicated state - else - { - // poof away manually - a.bINVISIBLE = true; - a.A_ChangeLinkFlags(false); // remove from blockmap, should guarantee archviles not raising this - IDontFeelSoGood.DeletThis(a,true); // ensures corpse is deleted too - } - if ( target && a.FindInventory("EndgameBossMarker") ) - SWWMUtility.MarkAchievement("ligma",target.player); + else PlayerGone.FeckOff(a); } - if ( !a || (a.Health <= 0) ) - specialf2 += min(100.,capmass*.6); // partial absorption - continue; - } - capmass = max(50.,a.mass); - Vector3 dirto = level.Vec3Diff(a.Vec3Offset(0,0,a.Height/2),pos); - double dist = dirto.length(); - dirto /= dist; - // rip - if ( a && a.bSHOOTABLE && SWWMUtility.SphereIntersect(a,pos,200.*scale.x) ) - a.DamageMobj(self,target,int(clamp(10.-dist*.05,0.,5.)),'YnykronAlt',DMG_FORCED|DMG_THRUSTLESS); - if ( !a ) continue; - // weak gravitational force as per v-field (approximate) - double grav = (3.*YNON_CONST*specialf2*capmass)/(dist**.5); - // strong gravitational force as per u-field (approximate) - grav += (4.*AXAN_CONST*specialf2*capmass)/(dist**2.); - // account for ground friction - if ( a.pos.z <= a.floorz ) - { - double frict, movef; - [frict, movef] = a.GetFriction(); - grav *= movef; - if ( !a.player ) dirto.z += .1; - } - if ( a.mass < LARGE_MASS ) - { - // v-force field compression (very rough approximation) - a.vel *= max(.0,1.-.03*(grav*grav)/(MION_CONST*MION_CONST)); - a.vel += dirto*grav/(capmass*GameTicRate); + if ( a.FindState("YnykronAltDeath",true) ) + a.SetStateLabel("YnykronAltDeath"); // dedicated state + else + { + // poof away manually + a.bINVISIBLE = true; + a.A_ChangeLinkFlags(false); // remove from blockmap, should guarantee archviles not raising this + IDontFeelSoGood.DeletThis(a,true); // ensures corpse is deleted too + } + if ( target && a.FindInventory("EndgameBossMarker") ) + SWWMUtility.MarkAchievement("ligma",target.player); } + if ( !a || (a.Health <= 0) ) + specialf2 += min(100.,capmass*.6); // partial absorption + continue; + } + capmass = max(50.,a.mass); + Vector3 dirto = level.Vec3Diff(a.Vec3Offset(0,0,a.Height/2),pos); + double dist = dirto.length(); + dirto /= dist; + // rip + if ( a && a.bSHOOTABLE && SWWMUtility.SphereIntersect(a,pos,200.*scale.x) ) + a.DamageMobj(self,target,int(clamp(10.-dist*.05,0.,5.)),'YnykronAlt',DMG_FORCED|DMG_THRUSTLESS); + if ( !a ) continue; + // weak gravitational force as per v-field (approximate) + double grav = (3.*YNON_CONST*specialf2*capmass)/(dist**.5); + // strong gravitational force as per u-field (approximate) + grav += (4.*AXAN_CONST*specialf2*capmass)/(dist**2.); + // account for ground friction + if ( a.pos.z <= a.floorz ) + { + let [frict, movef] = a.GetFriction(); + grav *= movef; + if ( !a.player ) dirto.z += .1; + } + if ( a.mass < LARGE_MASS ) + { + // v-force field compression (very rough approximation) + a.vel *= max(.0,1.-.03*(grav*grav)/(MION_CONST*MION_CONST)); + a.vel += dirto*grav/(capmass*GameTicRate); } } // push away from nearby geometry