diff --git a/src/lua_baselib.c b/src/lua_baselib.c index c1fd87af3..840863eb0 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1809,9 +1809,10 @@ static int lib_pFadeLight(lua_State *L) INT16 tag = (INT16)luaL_checkinteger(L, 1); INT32 destvalue = (INT32)luaL_checkinteger(L, 2); INT32 speed = (INT32)luaL_checkinteger(L, 3); + boolean ticbased = lua_optboolean(L, 4); NOHUD INLEVEL - P_FadeLight(tag, destvalue, speed); + P_FadeLight(tag, destvalue, speed, ticbased); return 0; } diff --git a/src/p_lights.c b/src/p_lights.c index 8aa2eedca..95171155e 100644 --- a/src/p_lights.c +++ b/src/p_lights.c @@ -13,6 +13,7 @@ /// Fire flicker, light flash, strobe flash, lightning flash, glow, and fade. #include "doomdef.h" +#include "doomstat.h" // gametic #include "p_local.h" #include "r_state.h" #include "z_zone.h" @@ -322,40 +323,57 @@ glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector, return g; } -/** Fades all the lights in sectors with a particular tag to a new +/** Fades all the lights in specified sector to a new * value. * - * \param tag Tag to look for sectors by. + * \param sector Target sector * \param destvalue The final light value in these sectors. * \param speed Speed of the fade; the change to the ligh * level in each sector per tic. - * \todo Calculate speed better so that it is possible to specify - * the time for completion of the fade, and all lights fade - * in this time regardless of initial values. + * \param ticbased Use a specific duration for the fade, defined by speed * \sa T_LightFade */ -void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed) +void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean ticbased) +{ + lightlevel_t *ll; + + P_RemoveLighting(sector); // remove the old lighting effect first + + if ((ticbased && !speed) || sector->lightlevel == destvalue) // set immediately + { + sector->lightlevel = destvalue; + return; + } + + ll = Z_Calloc(sizeof (*ll), PU_LEVSPEC, NULL); + ll->thinker.function.acp1 = (actionf_p1)T_LightFade; + sector->lightingdata = ll; // set it to the lightlevel_t + + P_AddThinker(&ll->thinker); // add thinker + + ll->sector = sector; + ll->sourcelevel = sector->lightlevel; + ll->destlevel = destvalue; + + if (ticbased) + { + ll->ticbased = true; + ll->timer = ll->speed = abs(speed); // use ll->speed for total duration + } + else + { + ll->ticbased = false; + ll->timer = -1; + ll->speed = abs(speed); + } +} + +void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased) { INT32 i; - lightlevel_t *ll; - sector_t *sector; - // search all sectors for ones with tag for (i = -1; (i = P_FindSectorFromTag(tag, i)) >= 0 ;) - { - sector = §ors[i]; - - P_RemoveLighting(sector); // remove the old lighting effect first - ll = Z_Calloc(sizeof (*ll), PU_LEVSPEC, NULL); - ll->thinker.function.acp1 = (actionf_p1)T_LightFade; - sector->lightingdata = ll; // set it to the lightlevel_t - - P_AddThinker(&ll->thinker); // add thinker - - ll->sector = sector; - ll->destlevel = destvalue; - ll->speed = speed; - } + P_FadeLightBySector(§ors[i], destvalue, speed, ticbased); } /** Fades the light level in a sector to a new value. @@ -365,18 +383,37 @@ void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed) */ void T_LightFade(lightlevel_t *ll) { + if (ll->ticbased) + { + if (--ll->timer <= 0) + { + ll->sector->lightlevel = ll->destlevel; // set to dest lightlevel + P_RemoveLighting(ll->sector); // clear lightingdata, remove thinker + } + else + { + INT16 delta = abs(ll->destlevel - ll->sourcelevel); + fixed_t factor = min(FixedDiv(ll->speed - ll->timer, ll->speed), 1*FRACUNIT); + if (ll->destlevel < ll->sourcelevel) + ll->sector->lightlevel = max(min(ll->sector->lightlevel, ll->sourcelevel - (INT16)FixedMul(delta, factor)), ll->destlevel); + else if (ll->destlevel > ll->sourcelevel) + ll->sector->lightlevel = min(max(ll->sector->lightlevel, ll->sourcelevel + (INT16)FixedMul(delta, factor)), ll->destlevel); + } + return; + } + if (ll->sector->lightlevel < ll->destlevel) { // increase the lightlevel if (ll->sector->lightlevel + ll->speed >= ll->destlevel) { // stop changing light level - ll->sector->lightlevel = (INT16)ll->destlevel; // set to dest lightlevel + ll->sector->lightlevel = ll->destlevel; // set to dest lightlevel P_RemoveLighting(ll->sector); // clear lightingdata, remove thinker } else - ll->sector->lightlevel = (INT16)(ll->sector->lightlevel + (INT16)ll->speed); // move lightlevel + ll->sector->lightlevel += ll->speed; // move lightlevel } else { @@ -384,11 +421,11 @@ void T_LightFade(lightlevel_t *ll) if (ll->sector->lightlevel - ll->speed <= ll->destlevel) { // stop changing light level - ll->sector->lightlevel = (INT16)ll->destlevel; // set to dest lightlevel + ll->sector->lightlevel = ll->destlevel; // set to dest lightlevel P_RemoveLighting(ll->sector); // clear lightingdata, remove thinker } else - ll->sector->lightlevel = (INT16)(ll->sector->lightlevel - (INT16)ll->speed); // move lightlevel + ll->sector->lightlevel -= ll->speed; // move lightlevel } } diff --git a/src/p_saveg.c b/src/p_saveg.c index 42757faf2..574f871bb 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1559,8 +1559,11 @@ static void SaveLightlevelThinker(const thinker_t *th, const UINT8 type) const lightlevel_t *ht = (const void *)th; WRITEUINT8(save_p, type); WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT32(save_p, ht->destlevel); - WRITEINT32(save_p, ht->speed); + WRITEINT16(save_p, ht->sourcelevel); + WRITEINT16(save_p, ht->destlevel); + WRITEINT16(save_p, ht->speed); + WRITEUINT8(save_p, (UINT8)ht->ticbased); + WRITEINT32(save_p, ht->timer); } // @@ -2532,8 +2535,11 @@ static inline void LoadLightlevelThinker(actionf_p1 thinker) lightlevel_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; ht->sector = LoadSector(READUINT32(save_p)); - ht->destlevel = READINT32(save_p); - ht->speed = READINT32(save_p); + ht->sourcelevel = READINT16(save_p); + ht->destlevel = READINT16(save_p); + ht->speed = READINT16(save_p); + ht->ticbased = (boolean)READUINT8(save_p); + ht->timer = READINT32(save_p); if (ht->sector) ht->sector->lightingdata = ht; P_AddThinker(&ht->thinker); diff --git a/src/p_spec.c b/src/p_spec.c index 40be3c7fb..85790041f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2778,7 +2778,16 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 420: // Fade light levels in tagged sectors to new value - P_FadeLight(line->tag, line->frontsector->lightlevel, P_AproxDistance(line->dx, line->dy)>>FRACBITS); + P_FadeLight(line->tag, + (line->flags & ML_DONTPEGBOTTOM) ? max(sides[line->sidenum[0]].textureoffset>>FRACBITS, 0) : line->frontsector->lightlevel, + // failsafe: if user specifies Back Y Offset and NOT Front Y Offset, use the Back Offset + // to be consistent with other light and fade specials + (line->flags & ML_DONTPEGBOTTOM) ? + ((line->sidenum[1] != 0xFFFF && !(sides[line->sidenum[0]].rowoffset>>FRACBITS)) ? + max(min(sides[line->sidenum[1]].rowoffset>>FRACBITS, 255), 0) + : max(min(sides[line->sidenum[0]].rowoffset>>FRACBITS, 255), 0)) + : abs(P_AproxDistance(line->dx, line->dy))>>FRACBITS), + (line->flags & ML_EFFECT4)); break; case 421: // Stop lighting effect in tagged sectors diff --git a/src/p_spec.h b/src/p_spec.h index e0bcc18eb..69087d6c4 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -136,8 +136,13 @@ typedef struct { thinker_t thinker; ///< Thinker in use for the effect. sector_t *sector; ///< Sector where action is taking place. - INT32 destlevel; ///< Light level we're fading to. - INT32 speed; ///< Speed at which to change light level. + INT16 sourcelevel; ///< Light level we're fading from. + INT16 destlevel; ///< Light level we're fading to. + INT16 speed; ///< Speed at which to change light level. OR: Tic-based duration + + // Tic-based behavior + boolean ticbased; ///< Tic-based logic + INT32 timer; ///< Tic-based timer } lightlevel_t; #define GLOWSPEED 8 @@ -156,7 +161,8 @@ strobe_t * P_SpawnAdjustableStrobeFlash(sector_t *minsector, sector_t *maxsector void T_Glow(glow_t *g); glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector, INT32 length); -void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed); +void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean ticbased); +void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased); void T_LightFade(lightlevel_t *ll); typedef enum