diff --git a/src/cmdlib.h b/src/cmdlib.h
index e3a9d3d08..f6f0e6ad8 100644
--- a/src/cmdlib.h
+++ b/src/cmdlib.h
@@ -5,6 +5,7 @@
 
 
 #include "doomtype.h"
+#include "doomdef.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -62,4 +63,25 @@ struct FFileList
 
 void ScanDirectory(TArray<FFileList> &list, const char *dirpath);
 
+
+//==========================================================================
+//
+// Functions to compensate for a tic being a bit short.
+// Since ZDoom uses a milliseconds timer for game timing
+// 35 tics are actually only 0.98 seconds.
+// For real time display this needs to be adjusted
+//
+//==========================================================================
+
+inline int AdjustTics(int tics)
+{
+	return (tics * 98) / 100;
+}
+
+inline int Tics2Seconds(int tics)
+{
+	return (tics * 98) / (100 * TICRATE);
+}
+
+
 #endif
diff --git a/src/g_shared/a_armor.cpp b/src/g_shared/a_armor.cpp
index 6b90a6a78..a745197c2 100644
--- a/src/g_shared/a_armor.cpp
+++ b/src/g_shared/a_armor.cpp
@@ -25,6 +25,11 @@ void ABasicArmor::Serialize (FArchive &arc)
 {
 	Super::Serialize (arc);
 	arc << SavePercent << BonusCount << MaxAbsorb << MaxFullAbsorb << AbsorbCount << ArmorType;
+
+	if (SaveVersion >= 4511)
+	{
+		 arc << ActualSaveAmount;
+	}
 }
 
 //===========================================================================
@@ -69,6 +74,7 @@ AInventory *ABasicArmor::CreateCopy (AActor *other)
 	copy->Icon = Icon;
 	copy->BonusCount = BonusCount;
 	copy->ArmorType = ArmorType;
+	copy->ActualSaveAmount = ActualSaveAmount;
 	GoAwayAndDie ();
 	return copy;
 }
@@ -268,6 +274,7 @@ bool ABasicArmorPickup::Use (bool pickup)
 	armor->MaxAbsorb = MaxAbsorb;
 	armor->MaxFullAbsorb = MaxFullAbsorb;
 	armor->ArmorType = this->GetClass()->TypeName;
+	armor->ActualSaveAmount = SaveAmount;
 	return true;
 }
 
@@ -360,6 +367,7 @@ bool ABasicArmorBonus::Use (bool pickup)
 		armor->MaxAbsorb = MaxAbsorb;
 		armor->ArmorType = this->GetClass()->TypeName;
 		armor->MaxFullAbsorb = MaxFullAbsorb;
+		armor->ActualSaveAmount = MaxSaveAmount;
 	}
 
 	armor->Amount = MIN(armor->Amount + saveAmount, MaxSaveAmount + armor->BonusCount);
diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h
index 22d1e009f..72548776a 100644
--- a/src/g_shared/a_pickups.h
+++ b/src/g_shared/a_pickups.h
@@ -423,6 +423,7 @@ public:
 	int MaxFullAbsorb;
 	int BonusCount;
 	FNameNoInit ArmorType;
+	int ActualSaveAmount;
 };
 
 // BasicArmorPickup replaces the armor you have.
diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp
index 629c31cb4..c9011e851 100644
--- a/src/g_shared/sbarinfo_commands.cpp
+++ b/src/g_shared/sbarinfo_commands.cpp
@@ -886,8 +886,11 @@ class CommandDrawString : public SBarInfoCommand
 					}
 					break;
 				case TIME:
-					str.Format("%02d:%02d:%02d", (level.time/TICRATE)/3600, ((level.time/TICRATE)%3600)/60, (level.time/TICRATE)%60);
+				{
+					int sec = Tics2Seconds(level.time); 
+					str.Format("%02d:%02d:%02d", sec / 3600, (sec % 3600) / 60, sec % 60);
 					break;
+				}
 				case LOGTEXT:
 					str = statusBar->CPlayer->LogText;
 					break;
diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp
index 3806e5f9d..2daeff7a8 100644
--- a/src/g_shared/shared_hud.cpp
+++ b/src/g_shared/shared_hud.cpp
@@ -867,7 +867,7 @@ static void DrawTime()
 				: (hud_showtime < 6
 					? level.time
 					: level.totaltime);
-		const int timeSeconds = timeTicks / TICRATE;
+		const int timeSeconds = Tics2Seconds(timeTicks);
 
 		hours   =  timeSeconds / 3600;
 		minutes = (timeSeconds % 3600) / 60;
@@ -994,7 +994,7 @@ void DrawHUD()
 
 		if (am_showtotaltime)
 		{
-			seconds = level.totaltime / TICRATE;
+			seconds = Tics2Seconds(level.totaltime);
 			mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
 			DrawHudText(SmallFont, hudcolor_ttim, printstr, hudwidth-length, bottom, FRACUNIT);
 			bottom -= fonth;
@@ -1004,14 +1004,14 @@ void DrawHUD()
 		{
 			if (level.clusterflags&CLUSTER_HUB)
 			{
-				seconds = level.time /TICRATE;
+				seconds = Tics2Seconds(level.time);
 				mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
 				DrawHudText(SmallFont, hudcolor_time, printstr, hudwidth-length, bottom, FRACUNIT);
 				bottom -= fonth;
 			}
 
 			// Single level time for hubs
-			seconds= level.maptime /TICRATE;
+			seconds= Tics2Seconds(level.maptime);
 			mysnprintf(printstr, countof(printstr), "%02i:%02i:%02i", seconds/3600, (seconds%3600)/60, seconds%60);
 			DrawHudText(SmallFont, hudcolor_ltim, printstr, hudwidth-length, bottom, FRACUNIT);
 		}
diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp
index 6b2f609b7..89921e3a2 100644
--- a/src/g_shared/shared_sbar.cpp
+++ b/src/g_shared/shared_sbar.cpp
@@ -1306,8 +1306,8 @@ void DBaseStatusBar::Draw (EHudState state)
 	}
 	else if (automapactive)
 	{
-		int y, time = level.time / TICRATE, height;
-		int totaltime = level.totaltime / TICRATE;
+		int y, time = Tics2Seconds(level.time), height;
+		int totaltime = Tics2Seconds(level.totaltime);
 		EColorRange highlight = (gameinfo.gametype & GAME_DoomChex) ?
 			CR_UNTRANSLATED : CR_YELLOW;
 
diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp
index 1a355b90a..89659e61d 100644
--- a/src/g_strife/strife_sbar.cpp
+++ b/src/g_strife/strife_sbar.cpp
@@ -586,29 +586,33 @@ private:
 		screen->DrawTexture (Images[back], left, top, DTA_CleanNoMove, true, DTA_Alpha, FRACUNIT*3/4, TAG_DONE);
 		screen->DrawTexture (Images[bars], left, top, DTA_CleanNoMove, true, TAG_DONE);
 
+
 		switch (CurrentPop)
 		{
 		case POP_Log:
+		{
+			int seconds = Tics2Seconds(level.time);
 			// Draw the latest log message.
-			mysnprintf (buff, countof(buff), "%02d:%02d:%02d",
-				(level.time/TICRATE)/3600,
-				((level.time/TICRATE)%3600)/60,
-				(level.time/TICRATE)%60);
+			mysnprintf(buff, countof(buff), "%02d:%02d:%02d",
+				seconds / 3600,
+				(seconds % 3600) / 60,
+				(seconds) % 60);
 
-			screen->DrawText (SmallFont2, CR_UNTRANSLATED, left+210*xscale, top+8*yscale, buff,
+			screen->DrawText(SmallFont2, CR_UNTRANSLATED, left + 210 * xscale, top + 8 * yscale, buff,
 				DTA_CleanNoMove, true, TAG_DONE);
 
 			if (CPlayer->LogText != NULL)
 			{
-				FBrokenLines *lines = V_BreakLines (SmallFont2, 272, CPlayer->LogText);
+				FBrokenLines *lines = V_BreakLines(SmallFont2, 272, CPlayer->LogText);
 				for (i = 0; lines[i].Width >= 0; ++i)
 				{
-					screen->DrawText (SmallFont2, CR_UNTRANSLATED, left+24*xscale, top+(18+i*12)*yscale,
+					screen->DrawText(SmallFont2, CR_UNTRANSLATED, left + 24 * xscale, top + (18 + i * 12)*yscale,
 						lines[i].Text, DTA_CleanNoMove, true, TAG_DONE);
 				}
-				V_FreeBrokenLines (lines);
+				V_FreeBrokenLines(lines);
 			}
 			break;
+		}
 
 		case POP_Keys:
 			// List the keys the player has.
diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index 1646ab7b7..e0967d400 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -128,6 +128,7 @@ enum
 	ARMORINFO_SAVEPERCENT,
 	ARMORINFO_MAXABSORB,
 	ARMORINFO_MAXFULLABSORB,
+	ARMORINFO_ACTUALSAVEAMOUNT,
 };
 
 struct CallReturn
@@ -4858,6 +4859,9 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const
 					case ARMORINFO_MAXFULLABSORB:
 						return equippedarmor->MaxFullAbsorb;
 
+					case ARMORINFO_ACTUALSAVEAMOUNT:
+						return equippedarmor->ActualSaveAmount;
+
 					default:
 						return 0;
 				}
diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp
index 17fc97d2f..3a4a4c6a0 100644
--- a/src/p_maputl.cpp
+++ b/src/p_maputl.cpp
@@ -434,8 +434,8 @@ static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node)
 	// add on a 386/486, but it certainly isn't on anything newer than that.
 	fixed_t	dx;
 	fixed_t	dy;
-	fixed_t	left;
-	fixed_t	right;
+	double	left;
+	double	right;
 
 	if (!node->dx)
 	{
@@ -466,8 +466,9 @@ static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node)
 		return 0;
 	}
 
-	left = FixedMul ( node->dy>>FRACBITS , dx );
-	right = FixedMul ( dy , node->dx>>FRACBITS );
+	// we must use doubles here because the fixed point code will produce errors due to loss of precision for extremely short linedefs.
+	left = (double)node->dy * (double)dx;
+	right = (double)dy * (double)node->dx;
 
 	if (right < left)
 	{
diff --git a/src/statistics.cpp b/src/statistics.cpp
index acd8440e8..7ed6e7f8e 100644
--- a/src/statistics.cpp
+++ b/src/statistics.cpp
@@ -420,7 +420,7 @@ static void StoreLevelStats()
 		LevelData[i].killcount = level.killed_monsters;
 		LevelData[i].totalsecrets = level.total_secrets;
 		LevelData[i].secretcount = level.found_secrets;
-		LevelData[i].leveltime = level.maptime;
+		LevelData[i].leveltime = AdjustTics(level.maptime);
 
 		// Check for living monsters. On some maps it can happen
 		// that the counter misses some. 
@@ -490,7 +490,7 @@ void STAT_ChangeLevel(const char *newl)
 			}
 
 			infostring.Format("%4d/%4d, %3d/%3d, %2d", statvals[0], statvals[1], statvals[2], statvals[3], validlevels);
-			FSessionStatistics *es = StatisticsEntry(sl, infostring, level.totaltime);
+			FSessionStatistics *es = StatisticsEntry(sl, infostring, AdjustTics(level.totaltime));
 
 			for(unsigned i = 0; i < LevelData.Size(); i++)
 			{
diff --git a/src/version.h b/src/version.h
index 6d24c3fe8..af376938c 100644
--- a/src/version.h
+++ b/src/version.h
@@ -76,7 +76,7 @@ const char *GetVersionString();
 
 // Use 4500 as the base git save version, since it's higher than the
 // SVN revision ever got.
-#define SAVEVER 4510
+#define SAVEVER 4511
 
 #define SAVEVERSTRINGIFY2(x) #x
 #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp
index e60fee303..2ab93f090 100644
--- a/src/wi_stuff.cpp
+++ b/src/wi_stuff.cpp
@@ -1460,7 +1460,7 @@ void WI_drawDeathmatchStats ()
 	// Draw game time
 	y += height + CleanYfac;
 
-	int seconds = plrs[me].stime / TICRATE;
+	int seconds = Tics2Seconds(plrs[me].stime);
 	int hours = seconds / 3600;
 	int minutes = (seconds % 3600) / 60;
 	seconds = seconds % 60;
@@ -1817,9 +1817,9 @@ void WI_updateStats ()
 		cnt_kills[0] = plrs[me].skills;
 		cnt_items[0] = plrs[me].sitems;
 		cnt_secret[0] = plrs[me].ssecret;
-		cnt_time = plrs[me].stime / TICRATE;
+		cnt_time = Tics2Seconds(plrs[me].stime);
 		cnt_par = wbs->partime / TICRATE;
-	    cnt_total_time = wbs->totaltime / TICRATE;
+	    cnt_total_time = Tics2Seconds(wbs->totaltime);
 	}
 
 	if (sp_state == 2)
@@ -1882,19 +1882,21 @@ void WI_updateStats ()
 			cnt_total_time += 3;
 		}
 
-		if (!gameinfo.intermissioncounter || cnt_time >= plrs[me].stime / TICRATE)
-			cnt_time = plrs[me].stime / TICRATE;
+		int sec = Tics2Seconds(plrs[me].stime);
+		if (!gameinfo.intermissioncounter || cnt_time >= sec)
+			cnt_time = sec;
 
-		if (!gameinfo.intermissioncounter || cnt_total_time >= wbs->totaltime / TICRATE)
-			cnt_total_time = wbs->totaltime / TICRATE;
+		int tsec = Tics2Seconds(wbs->totaltime);
+		if (!gameinfo.intermissioncounter || cnt_total_time >= tsec)
+			cnt_total_time = tsec;
 
 		if (!gameinfo.intermissioncounter || cnt_par >= wbs->partime / TICRATE)
 		{
 			cnt_par = wbs->partime / TICRATE;
 
-			if (cnt_time >= plrs[me].stime / TICRATE)
+			if (cnt_time >= sec)
 			{
-				cnt_total_time = wbs->totaltime / TICRATE;
+				cnt_total_time = tsec;
 				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
 				sp_state++;
 			}