diff --git a/src/p_saveg.c b/src/p_saveg.c
index 8ec35a0d6..a3790d6f0 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1593,9 +1593,9 @@ static void SaveFadeThinker(const thinker_t *th, const UINT8 type)
 	WRITEINT16(save_p, ht->destvalue);
 	WRITEINT16(save_p, ht->destlightlevel);
 	WRITEINT16(save_p, ht->speed);
-	WRITEINT32(save_p, ht->duration);
+	WRITEUINT8(save_p, (UINT8)ht->ticbased);
+	WRITEINT32(save_p, ht->timer);
 	WRITEUINT32(save_p, ht->interval);
-	WRITEUINT32(save_p, (UINT32)ht->firsttic);
 	WRITEUINT8(save_p, ht->doexists);
 	WRITEUINT8(save_p, ht->dotranslucent);
 	WRITEUINT8(save_p, ht->dolighting);
@@ -2605,9 +2605,9 @@ static inline void LoadFadeThinker(actionf_p1 thinker)
 	ht->destvalue = READINT16(save_p);
 	ht->destlightlevel = READINT16(save_p);
 	ht->speed = READINT16(save_p);
-	ht->duration = READINT32(save_p);
+	ht->ticbased = (boolean)READUINT8(save_p);
+	ht->timer = READINT32(save_p);
 	ht->interval = READUINT32(save_p);
-	ht->firsttic = (tic_t)READUINT32(save_p);
 	ht->doexists = READUINT8(save_p);
 	ht->dotranslucent = READUINT8(save_p);
 	ht->dolighting = READUINT8(save_p);
diff --git a/src/p_spec.c b/src/p_spec.c
index 8b5b0c1c4..1bc60cc71 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -105,7 +105,7 @@ static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *
 static void Add_MasterDisappearer(tic_t appeartime, tic_t disappeartime, tic_t offset, INT32 line, INT32 sourceline);
 static void P_ResetFakeFloorFader(ffloor_t *rover, fade_t *data, boolean finalize);
 #define P_RemoveFakeFloorFader(l) P_ResetFakeFloorFader(l, NULL, false);
-static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 destvalue, INT16 speed, INT32 duration, UINT32 interval, tic_t firsttic,
+static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 destvalue, INT16 speed, boolean ticbased, INT32 *timer, UINT32 interval,
 	boolean doexists, boolean dotranslucent, boolean dolighting, boolean docollision, boolean doghostfade, boolean exactalpha);
 static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloornum,
 	INT16 destvalue, INT16 speed, boolean ticbased,
@@ -3368,7 +3368,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 					P_RemoveFakeFloorFader(rover);
 					P_FadeFakeFloor(rover,
 						destvalue, 0, // set alpha immediately
-						-1, 0, 0,                           // tic-based logic
+						false, NULL, 0,                           // tic-based logic
 						!(line->flags & ML_BLOCKMONSTERS),  // do not handle FF_EXISTS
 						!(line->flags & ML_NOCLIMB),        // do not handle FF_TRANSLUCENT
 						!(line->flags & ML_EFFECT2),        // do not handle lighting
@@ -7446,9 +7446,9 @@ static void P_ResetFakeFloorFader(ffloor_t *rover, fade_t *data, boolean finaliz
 						fadingdata->alpha - 1 : // trigger fade-out finish
 						fadingdata->alpha + 1, // trigger fade-in finish
 					0,
-					fadingdata->duration,
+					fadingdata->ticbased,
+					&fadingdata->timer,
 					fadingdata->interval,
-					fadingdata->firsttic,
 					fadingdata->doexists,
 					fadingdata->dotranslucent,
 					fadingdata->docollision,
@@ -7467,10 +7467,9 @@ static void P_ResetFakeFloorFader(ffloor_t *rover, fade_t *data, boolean finaliz
 	}
 }
 
-static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 destvalue, INT16 speed, INT32 duration, UINT32 interval, tic_t firsttic,
+static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 destvalue, INT16 speed, boolean ticbased, INT32 *timer, UINT32 interval,
 	boolean doexists, boolean dotranslucent, boolean dolighting, boolean docollision, boolean doghostfade, boolean exactalpha)
 {
-	boolean ticbased = (duration > -1);
 	boolean stillfading = false;
 	INT32 alpha;
 	fade_t *fadingdata = (fade_t *)rover->fadingdata;
@@ -7499,7 +7498,7 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 destvalue, INT16 speed, IN
 	{
 		// finish fading out
 		if (speed < 1 || (!ticbased && alpha - speed <= destvalue + speed) ||
-			(ticbased && (gametic - firsttic >= duration || alpha <= destvalue)))
+			(ticbased && (--(*timer) <= 0 || alpha <= destvalue)))
 		{
 			alpha = destvalue;
 
@@ -7521,7 +7520,7 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 destvalue, INT16 speed, IN
 		{
 			if (!ticbased)
 				alpha -= speed;
-			else if (ticbased && !((gametic - firsttic) % interval))
+			else if (ticbased && !((*timer) % interval))
 				alpha = max(alpha - speed, destvalue);
 			stillfading = true;
 		}
@@ -7530,7 +7529,7 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 destvalue, INT16 speed, IN
 	{
 		// finish fading in
 		if (speed < 1 || (!ticbased && alpha + speed >= destvalue - speed) ||
-			(ticbased && (gametic - firsttic >= duration || alpha >= destvalue)))
+			(ticbased && (--(*timer) <= 0|| alpha >= destvalue)))
 		{
 			alpha = destvalue;
 
@@ -7552,7 +7551,7 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 destvalue, INT16 speed, IN
 		{
 			if (!ticbased)
 				alpha += speed;
-			else if (ticbased && !((gametic - firsttic) % interval))
+			else if (ticbased && !((*timer) % interval))
 				alpha = min(alpha + speed, destvalue);
 			stillfading = true;
 		}
@@ -7743,16 +7742,17 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor
 
 	if (ticbased)
 	{
-		d->duration = abs(speed);
-		d->speed = max(abs(FixedFloor(FixedDiv(d->destvalue - d->alpha, d->duration))/FRACUNIT), 1);
-		d->interval = max(FixedFloor(FixedDiv(d->duration, abs(d->destvalue - d->alpha)))/FRACUNIT, 1);
-		d->firsttic = gametic;
+		d->ticbased = true;
+		d->timer = abs(speed);
+		d->speed = max(abs(FixedFloor(FixedDiv(d->destvalue - d->alpha, d->timer))/FRACUNIT), 1);
+		d->interval = max(FixedFloor(FixedDiv(d->timer, abs(d->destvalue - d->alpha)))/FRACUNIT, 1);
 	}
 	else
 	{
 		d->speed = max(1, speed); // minimum speed 1/tic // if speed < 1, alpha is set immediately in thinker
-		d->duration = -1;
-		d->interval = d->firsttic = 0;
+		d->ticbased = false;
+		d->timer = -1;
+		d->interval = 0;
 	}
 
 	d->doexists = doexists;
@@ -7779,7 +7779,7 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor
 
 		P_FadeLightBySector(&sectors[rover->secnum],
 			d->destlightlevel,
-			ticbased ? d->duration :
+			ticbased ? d->timer :
 				FixedFloor(FixedDiv(abs(d->destvalue - d->alpha), d->speed))/FRACUNIT,
 			true);
 	}
@@ -7796,7 +7796,7 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor
   */
 void T_Fade(fade_t *d)
 {
-	if (d->rover && !P_FadeFakeFloor(d->rover, d->destvalue, d->speed, d->duration, d->interval, d->firsttic,
+	if (d->rover && !P_FadeFakeFloor(d->rover, d->destvalue, d->speed, d->ticbased, &d->timer, d->interval,
 		d->doexists, d->dotranslucent, d->dolighting, d->docollision, d->doghostfade, d->exactalpha))
 	{
 		// Finalize lighting, copypasta from P_AddFakeFloorFader
diff --git a/src/p_spec.h b/src/p_spec.h
index 2499ddcba..9e602b192 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -472,9 +472,9 @@ typedef struct
 	INT16 destvalue;    ///< Transparency value to fade to
 	INT16 destlightlevel; ///< Light level to fade to
 	INT16 speed;        ///< Speed to fade by
-	INT32 duration;     ///< Duration for tic-based logic, > -1 means use tic-based
+	boolean ticbased;    ///< Tic-based logic toggle
+	INT32 timer;        ///< Timer for tic-based logic
 	UINT32 interval;    ///< Skip interval for tic-based logic
-	tic_t firsttic;     ///< First tic for tic-based logic
 	boolean doexists;   ///< Handle FF_EXISTS
 	boolean dotranslucent; ///< Handle FF_TRANSLUCENT
 	boolean dolighting; ///< Handle shadows and light blocks