From 2a9e28d94920f80e5dafa5fd105a43c7d53e5b47 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Thu, 10 Nov 2022 18:59:30 -0600 Subject: [PATCH] Added PS_REPLACE flag for A_SpawnParticle(Ex). - When used, new particles that spawn when the limit is reached will replace the oldest particle. --- src/g_levellocals.h | 1 + src/playsim/p_effect.cpp | 77 +++++++++++++++++++++++++----- src/playsim/p_effect.h | 34 ++++++------- wadsrc/static/zscript/constants.zs | 1 + 4 files changed, 80 insertions(+), 33 deletions(-) diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 65748470a8..8d9c92d7e7 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -654,6 +654,7 @@ public: DSeqNode *SequenceListHead; // [RH] particle globals + uint32_t OldestParticle; // [MC] Oldest particle for replacing with PS_REPLACE uint32_t ActiveParticles; uint32_t InactiveParticles; TArray Particles; diff --git a/src/playsim/p_effect.cpp b/src/playsim/p_effect.cpp index 64564e9acf..899c4ba005 100644 --- a/src/playsim/p_effect.cpp +++ b/src/playsim/p_effect.cpp @@ -99,15 +99,57 @@ static const struct ColorList { {NULL, 0, 0, 0 } }; -inline particle_t *NewParticle (FLevelLocals *Level) +inline particle_t *NewParticle (FLevelLocals *Level, bool replace = false) { particle_t *result = nullptr; - if (Level->InactiveParticles != NO_PARTICLE) + // [MC] Thanks to RaveYard and randi for helping me with this addition. + // Array's filled up + if (Level->InactiveParticles == NO_PARTICLE) { - result = &Level->Particles[Level->InactiveParticles]; - Level->InactiveParticles = result->tnext; - result->tnext = Level->ActiveParticles; - Level->ActiveParticles = uint32_t(result - Level->Particles.Data()); + if (replace) + { + result = &Level->Particles[Level->OldestParticle]; + + // There should be NO_PARTICLE for the oldest's tnext + if (result->tprev != NO_PARTICLE) + { + // tnext: youngest to oldest + // tprev: oldest to youngest + + // 2nd oldest -> oldest + particle_t *nbottom = &Level->Particles[result->tprev]; + nbottom->tnext = NO_PARTICLE; + + // now oldest becomes youngest + Level->OldestParticle = result->tprev; + result->tnext = Level->ActiveParticles; + result->tprev = NO_PARTICLE; + Level->ActiveParticles = uint32_t(result - Level->Particles.Data()); + + // youngest -> 2nd youngest + particle_t* ntop = &Level->Particles[result->tnext]; + ntop->tprev = Level->ActiveParticles; + } + } + return result; + } + + // Array isn't full. + uint32_t current = Level->ActiveParticles; + result = &Level->Particles[Level->InactiveParticles]; + Level->InactiveParticles = result->tnext; + result->tnext = current; + result->tprev = NO_PARTICLE; + Level->ActiveParticles = uint32_t(result - Level->Particles.Data()); + + if (current != NO_PARTICLE) // More than one active particles + { + particle_t* next = &Level->Particles[current]; + next->tprev = Level->ActiveParticles; + } + else // Just one active particle + { + Level->OldestParticle = Level->ActiveParticles; } return result; } @@ -139,11 +181,16 @@ void P_ClearParticles (FLevelLocals *Level) { int i = 0; memset (Level->Particles.Data(), 0, Level->Particles.Size() * sizeof(particle_t)); + Level->OldestParticle = NO_PARTICLE; Level->ActiveParticles = NO_PARTICLE; Level->InactiveParticles = 0; for (auto &p : Level->Particles) + { + p.tprev = i - 1; p.tnext = ++i; + } Level->Particles.Last().tnext = NO_PARTICLE; + Level->Particles.Data()->tprev = NO_PARTICLE; } // Group particles by subsectors. Because particles are always @@ -212,16 +259,13 @@ void P_InitEffects () void P_ThinkParticles (FLevelLocals *Level) { - int i; - particle_t *particle, *prev; - - i = Level->ActiveParticles; - prev = NULL; + int i = Level->ActiveParticles; + particle_t *particle = nullptr, *prev = nullptr; while (i != NO_PARTICLE) { particle = &Level->Particles[i]; i = particle->tnext; - if (!particle->notimefreeze && Level->isFrozen()) + if (Level->isFrozen() && !particle->notimefreeze) { prev = particle; continue; @@ -237,6 +281,12 @@ void P_ThinkParticles (FLevelLocals *Level) prev->tnext = i; else Level->ActiveParticles = i; + + if (i != NO_PARTICLE) + { + particle_t *next = &Level->Particles[i]; + next->tprev = particle->tprev; + } particle->tnext = Level->InactiveParticles; Level->InactiveParticles = (int)(particle - Level->Particles.Data()); continue; @@ -283,12 +333,13 @@ enum PSFlag PS_FULLBRIGHT = 1, PS_NOTIMEFREEZE = 1 << 5, PS_ROLL = 1 << 6, + PS_REPLACE = 1 << 7, }; void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size, double fadestep, double sizestep, int flags, FTextureID texture, ERenderStyle style, double startroll, double rollvel, double rollacc) { - particle_t *particle = NewParticle(Level); + particle_t *particle = NewParticle(Level, !!(flags & PS_REPLACE)); if (particle) { diff --git a/src/playsim/p_effect.h b/src/playsim/p_effect.h index 233d2f0951..11e25f42ef 100644 --- a/src/playsim/p_effect.h +++ b/src/playsim/p_effect.h @@ -52,26 +52,20 @@ struct FLevelLocals; struct particle_t { - DVector3 Pos; - DVector3 Vel; - DVector3 Acc; - double size; - double sizestep; - subsector_t * subsector; - int32_t ttl; - uint8_t bright; - bool notimefreeze; - float fadestep; - float alpha; - int color; - uint16_t tnext; - uint16_t snext; - FTextureID texture; - ERenderStyle style; - double Roll; - double RollVel; - double RollAcc; - bool doRoll; + DVector3 Pos; + DVector3 Vel; + DVector3 Acc; + double size, sizestep; + float fadestep, alpha; + subsector_t* subsector; + int32_t ttl; + int color; + FTextureID texture; + ERenderStyle style; + double Roll, RollVel, RollAcc; + uint16_t tnext, snext, tprev; + uint8_t bright; + bool notimefreeze, doRoll; }; const uint16_t NO_PARTICLE = 0xffff; diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index fcb1b62200..efdfd5d61d 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -690,6 +690,7 @@ enum EParticleFlags SPF_RELANG = 1 << 4, SPF_NOTIMEFREEZE = 1 << 5, SPF_ROLL = 1 << 6, + SPF_REPLACE = 1 << 7, SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG };