diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 575e16d2b..2d6e9d878 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -1689,6 +1689,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticleEx) PARAM_FLOAT (startroll) PARAM_FLOAT (rollvel) PARAM_FLOAT (rollacc) + PARAM_FLOAT (fadeoutstep) startalpha = clamp(startalpha, 0., 1.); fadestep = clamp(fadestep, -1.0, 1.0); @@ -1729,7 +1730,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticleEx) style = STYLE_None; } - P_SpawnParticle(self->Level, self->Vec3Offset(pos), vel, acc, color, startalpha, lifetime, size, fadestep, sizestep, flags, texid, ERenderStyle(style), startroll, rollvel, rollacc); + P_SpawnParticle(self->Level, self->Vec3Offset(pos), vel, acc, color, startalpha, lifetime, size, fadestep, sizestep, flags, texid, ERenderStyle(style), startroll, rollvel, rollacc, fadeoutstep); } return 0; } diff --git a/src/playsim/p_effect.cpp b/src/playsim/p_effect.cpp index 5ad982159..4cfe0c14c 100644 --- a/src/playsim/p_effect.cpp +++ b/src/playsim/p_effect.cpp @@ -301,6 +301,18 @@ void P_ThinkParticles (FLevelLocals *Level) } particle->alpha -= particle->fadestep; + if ( (!!(particle->flags & SPF_FADE_IN_OUT) && particle->alpha >= 1.0) + || (!!(particle->flags & SPF_FADE_IN_HOLD_OUT) && (particle->ttl * fabs(particle->fadeoutstep)) <= std::min(1.0f, fabs(particle->alpha))) + ) { // [Jay] if SPF_FADE_IN_HOLD_OUT, hold until the fade out would line up with ttl + particle->alpha = std::min(1.0f, fabs(particle->alpha)); + particle->fadestep = particle->fadeoutstep; + particle->flags &= ~(SPF_FADE_IN_OUT|SPF_FADE_IN_HOLD_OUT); + } + + // It looks really glitchy if the alpha is allowed to overshoot + if (particle->alpha > 1.0) + particle->alpha = 1.0; + particle->size += particle->sizestep; if (particle->alpha <= 0 || --particle->ttl <= 0 || (particle->size <= 0)) { // The particle has expired, so free it @@ -345,7 +357,7 @@ void P_ThinkParticles (FLevelLocals *Level) } 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) + double fadestep, double sizestep, int flags, FTextureID texture, ERenderStyle style, double startroll, double rollvel, double rollacc, double fadeoutstep) { particle_t *particle = NewParticle(Level, !!(flags & SPF_REPLACE)); @@ -356,8 +368,21 @@ void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &v particle->Acc = FVector3(accel); particle->color = ParticleColor(color); particle->alpha = float(startalpha); - if ((fadestep < 0 && !(flags & SPF_NEGATIVE_FADESTEP)) || fadestep <= -1.0) particle->fadestep = FADEFROMTTL(lifetime); - else particle->fadestep = float(fadestep); + if ((flags & SPF_FADE_IN_OUT) || (flags & SPF_FADE_IN_HOLD_OUT)) + particle->fadeoutstep = fadeoutstep; + if ((fadestep < 0 && !(flags & SPF_NEGATIVE_FADESTEP)) || fadestep <= -1.0) + { + particle->fadestep = FADEFROMTTL(lifetime); + if (flags & SPF_FADE_IN_OUT) + particle->fadestep *= (float)-2; + else if (flags & SPF_FADE_IN_HOLD_OUT) + particle->fadestep *= (float)-3; + particle->fadeoutstep = -particle->fadestep; + } + else + { + particle->fadestep = float(fadestep); + } particle->ttl = lifetime; particle->size = size; particle->sizestep = sizestep; diff --git a/src/playsim/p_effect.h b/src/playsim/p_effect.h index b23efb01b..c722ab01e 100644 --- a/src/playsim/p_effect.h +++ b/src/playsim/p_effect.h @@ -79,6 +79,8 @@ enum EParticleFlags SPF_ROLLCENTER = 1 << 13, SPF_STRETCHPIXELS = 1 << 14, SPF_ALLOWSHADERS = 1 << 15, + SPF_FADE_IN_OUT = 1 << 16, + SPF_FADE_IN_HOLD_OUT = 1 << 17, }; class DVisualThinker; @@ -96,12 +98,14 @@ struct particle_t ERenderStyle style; //+4 = 88 float Roll, RollVel, RollAcc; //+12 = 100 uint16_t tnext, snext, tprev; //+6 = 106 - uint16_t flags; //+2 = 108 - // uint32_t padding; //+4 = 112 + // uint16_t padding; //+2 = 108 + uint32_t flags; //+4 = 112 FStandaloneAnimation animData; //+16 = 128 + float fadeoutstep; //+4 = 132 + // float padding2; //+4 = 136 }; -static_assert(sizeof(particle_t) == 128, "Only LP64/LLP64 is supported"); +static_assert(sizeof(particle_t) == 136, "Only LP64/LLP64 is supported"); const uint16_t NO_PARTICLE = 0xffff; @@ -134,13 +138,14 @@ struct FSpawnParticleParams double startalpha; double fadestep; + double fadeoutstep; double startroll; double rollvel; double rollacc; }; -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 = 0, FTextureID texture = FNullTextureID(), ERenderStyle style = STYLE_None, double startroll = 0, double rollvel = 0, double rollacc = 0); +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 = 0, FTextureID texture = FNullTextureID(), ERenderStyle style = STYLE_None, double startroll = 0, double rollvel = 0, double rollacc = 0, double fadeoutstep = 0); void P_InitEffects (void); diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index d5b72c5ad..a66d281a9 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -2205,6 +2205,7 @@ DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, vel); DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, accel); DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, startalpha); DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, fadestep); +DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, fadeoutstep); DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, startroll); DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, rollvel); DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, rollacc); @@ -2215,7 +2216,7 @@ static void SpawnParticle(FLevelLocals *Level, FSpawnParticleParams *params) params->color, params->startalpha, params->lifetime, params->size, params->fadestep, params->sizestep, params->flags, params->texture, ERenderStyle(params->style), - params->startroll, params->rollvel, params->rollacc); + params->startroll, params->rollvel, params->rollacc, params->fadeoutstep); } DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnParticle, SpawnParticle) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index a3a34a963..3c9bbc6d0 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1285,7 +1285,7 @@ class Actor : Thinker native native void A_FadeTo(double target, double amount = 0.1, int flags = 0); native void A_SpawnDebris(class spawntype, bool transfer_translation = false, double mult_h = 1, double mult_v = 1); native void A_SpawnParticle(color color1, int flags = 0, int lifetime = TICRATE, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0); - native void A_SpawnParticleEx(color color1, TextureID texture, int style = STYLE_None, int flags = 0, int lifetime = TICRATE, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0, double startroll = 0, double rollvel = 0, double rollacc = 0); + native void A_SpawnParticleEx(color color1, TextureID texture, int style = STYLE_None, int flags = 0, int lifetime = TICRATE, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0, double startroll = 0, double rollvel = 0, double rollacc = 0, double fadeoutstepf = 0); native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); native void A_DropInventory(class itemtype, int amount = -1); native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0, double alpha2 = 0.); diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 226468c98..1ca6e0312 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -726,6 +726,8 @@ enum EParticleFlags SPF_ROLLCENTER = 1 << 13, SPF_STRETCHPIXELS = 1 << 14, SPF_ALLOWSHADERS = 1 << 15, + SPF_FADE_IN_OUT = 1 << 16, + SPF_FADE_IN_HOLD_OUT = 1 << 17, SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG }; diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index a863e5ad1..82e1fe34f 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -473,6 +473,7 @@ struct FSpawnParticleParams native double startalpha; native double fadestep; + native double fadeoutstep; // unlike fadestep, this is always expected to be a positive value. native double startroll; native double rollvel; diff --git a/wadsrc/static/zscript/visualthinker.zs b/wadsrc/static/zscript/visualthinker.zs index a926243b6..4f57d3672 100644 --- a/wadsrc/static/zscript/visualthinker.zs +++ b/wadsrc/static/zscript/visualthinker.zs @@ -12,7 +12,7 @@ Class VisualThinker : Thinker native native TranslationID Translation; native int16 LightLevel; - native uint16 Flags; + native uint Flags; native int VisualThinkerFlags; FlagDef FlipOffsetX : VisualThinkerFlags, 0;