diff --git a/wadsrc/static/fonts/indexfont/0030.png b/wadsrc/static/fonts/hudindexfont/0030.png
similarity index 100%
rename from wadsrc/static/fonts/indexfont/0030.png
rename to wadsrc/static/fonts/hudindexfont/0030.png
diff --git a/wadsrc/static/fonts/indexfont/font.inf b/wadsrc/static/fonts/hudindexfont/font.inf
similarity index 100%
rename from wadsrc/static/fonts/indexfont/font.inf
rename to wadsrc/static/fonts/hudindexfont/font.inf
diff --git a/wadsrc/static/zscript/alt_hud.zs b/wadsrc/static/zscript/alt_hud.zs
index ad8597f65..b480e24a4 100644
--- a/wadsrc/static/zscript/alt_hud.zs
+++ b/wadsrc/static/zscript/alt_hud.zs
@@ -96,6 +96,7 @@ class AltHud ui
 	Font HudFont;					// The font for the health and armor display
 	Font IndexFont;					// The font for the inventory indices
 	Font StatFont;
+	int HudFontOffset;
 	const POWERUPICONSIZE = 32;
 	HudStats currentStats;			// must be filled in by the status bar.
 
@@ -104,7 +105,8 @@ class AltHud ui
 	{
 		HudFont = BigFont;	// Strife doesn't have anything nice so use the standard font
 		if (Raze.isBlood()) HudFont = Font.GetFont("HUDFONT_BLOOD");
-		IndexFont = Font.GetFont("INDEXFONT");
+		else if (Raze.isDuke()) HudFontOffset = 6;
+		IndexFont = Font.GetFont("HUDINDEXFONT");
 		if (IndexFont == NULL) IndexFont = ConFont;	// Emergency fallback
 		if (!Raze.isNamWW2GI())
 			StatFont = SmallFont;
@@ -123,7 +125,7 @@ class AltHud ui
 	//
 	//---------------------------------------------------------------------------
 
-	void DrawImageToBox(TextureID tex, int x, int y, int w, int h, double trans = 0.75, bool animate = false)
+	void DrawImageToBox(TextureID tex, int x, int y, int w, int h, double trans = 0.75, bool animate = false, int translation = 0)
 	{
 		double scale1, scale2;
 
@@ -146,7 +148,7 @@ class AltHud ui
 
 			screen.DrawTexture(tex, animate, x, y,
 				DTA_KeepRatio, true,
-				DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, 
+				DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans,  DTA_TranslationIndex, translation,
 				DTA_DestWidth, w, DTA_DestHeight, h, DTA_CenterBottomOffset, 1);
 
 		}
@@ -161,6 +163,7 @@ class AltHud ui
 
 	void DrawHudText(Font fnt, int color, String text, int x, int y, double trans = 0.75)
 	{
+		if (fnt == HudFont) y += HudFontOffset;
 		int zerowidth = fnt.GetCharWidth("0");
 		screen.DrawText(fnt, color, x, y-fnt.GetHeight(), text, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight,
 			 DTA_KeepRatio, true, DTA_Alpha, trans, DTA_Monospace, MONO_CellCenter, DTA_Spacing, zerowidth);
@@ -323,7 +326,9 @@ class AltHud ui
 
 		if (icon.isValid())
 		{
-			DrawImageToBox(icon, x, y, 8, 10);
+			int trans = 0;
+			if (currentStats.keytranslations.Size()) trans = currentStats.keytranslations[keyindex];
+			DrawImageToBox(icon, x, y, 8, 10, 0.75, false, trans);
 			return true;
 		}
 		return false;
diff --git a/wadsrc/static/zscript/games/blood/ui/sbar.zs b/wadsrc/static/zscript/games/blood/ui/sbar.zs
index 654ca702f..0cf16b46e 100644
--- a/wadsrc/static/zscript/games/blood/ui/sbar.zs
+++ b/wadsrc/static/zscript/games/blood/ui/sbar.zs
@@ -763,7 +763,7 @@ class BloodStatusBar : RazeStatusBar
 	override void GetAllStats(HudStats stats)
 	{
 		stats.Clear();
-		stats.info.fontscale = 1.;
+		stats.info.fontscale = 1.0;
 		stats.info.screenbottomspace = 200;
 		stats.info.letterColor = TEXTCOLOR_DARKRED;
 		stats.info.standardColor = TEXTCOLOR_DARKGRAY;
diff --git a/wadsrc/static/zscript/games/duke/ui/sbar_d.zs b/wadsrc/static/zscript/games/duke/ui/sbar_d.zs
index b28a0ba64..0f1624bd4 100644
--- a/wadsrc/static/zscript/games/duke/ui/sbar_d.zs
+++ b/wadsrc/static/zscript/games/duke/ui/sbar_d.zs
@@ -88,9 +88,9 @@ class DukeStatusBar : DukeCommonStatusBar
 	//
 	//==========================================================================
 
-	int getinvamount(DukePlayer p)
+	int getinvamountforitem(DukePlayer p, int which)
 	{
-		switch (p.inven_icon)
+		switch (which)
 		{
 		case Duke.ICON_FIRSTAID:
 			return p.firstaid_amount;
@@ -111,6 +111,11 @@ class DukeStatusBar : DukeCommonStatusBar
 		return -1;
 	}
 
+	int getinvamount(DukePlayer p)
+	{
+		return getinvamountforitem(p, p.inven_icon);
+	}
+
 	int GetMoraleOrShield(DukePlayer p)
 	{
 		// special handling for WW2GI
@@ -476,4 +481,113 @@ class DukeStatusBar : DukeCommonStatusBar
 			DoLevelStats(-1, info);
 		}
 	}
+	
+	//---------------------------------------------------------------------------
+	//
+	//
+	//
+	//---------------------------------------------------------------------------
+
+
+
+	override void GetAllStats(HudStats stats)
+	{
+		stats.Clear();
+		stats.info.fontscale = 1.;
+
+		stats.info.statfont = SmallFont;
+		stats.info.letterColor = Font.TEXTCOLOR_ORANGE;
+		if (Raze.isNamWW2GI())
+		{
+			stats.info.statfont = ConFont;
+			stats.info.spacing = 8;
+			stats.info.standardColor = Font.TEXTCOLOR_YELLOW;
+			stats.info.completeColor = Font.TEXTCOLOR_FIRE;
+		}
+		else
+		{
+			stats.info.spacing = 7;
+			stats.info.standardColor = Font.TEXTCOLOR_CREAM;
+			stats.info.completeColor = Font.TEXTCOLOR_FIRE;
+		}
+		
+		let p = Duke.GetViewPlayer();
+		stats.healthicon = Raze.isNamWW2GI()? "FIRSTAID_ICON" : "COLA";
+		stats.healthvalue = p.last_extra;
+		
+		let armorval = GetMoraleOrShield(p);
+		if (armorval > 0)
+		{
+			stats.armoricons.Push("SHIELD");
+			stats.armorvalues.Push(armorval);
+		}
+		
+		for (int i = 0; i < 3; i++)
+		{
+			if (p.got_access & (1 << i))
+			{
+				static const int translations[] = { 8, 23, 21 };
+				stats.keyicons.Push("ACCESSCARD");
+				stats.keytranslations.Push(Translation.MakeID(Translation_Remap, translations[i]));
+			}
+		}
+
+		// omits all weapons where ammo == weapon or secondary fire mode.
+		static const String weaponIcons[] = { "", "FIRSTGUNSPRITE",  "SHOTGUNSPRITE", "CHAINGUNSPRITE", "RPGSPRITE", "" /*pipe bomb*/, "SHRINKERSPRITE", 
+			"DEVISTATORSPRITE", "" /*trip bomb*/, "FREEZESPRITE", "" /*handremote*/, "" /*grower*/, "FLAMETHROWERSPRITE" };
+			
+		int maxweap = Raze.IsWorldTour()? 12 : 10;
+		
+		for(int i = 0; i <= maxweap; i++)
+		{
+			if (p.gotweapon[i] && weaponIcons[i] != "") 
+			{
+				if (p.curr_weapon == i || 
+					(p.curr_weapon == DukeWpn.HANDREMOTE_WEAPON && i == DukeWpn.HANDREMOTE_WEAPON) ||
+					(p.curr_weapon == DukeWpn.GROW_WEAPON && i == DukeWpn.SHRINKER_WEAPON))
+				{
+					stats.weaponselect = stats.weaponicons.Size();
+				}
+				stats.weaponicons.Push(weaponIcons[i]);
+			}
+		}
+		
+		static const int ammoOrder[] = { DukeWpn.PISTOL_WEAPON, DukeWpn.SHOTGUN_WEAPON, DukeWpn.CHAINGUN_WEAPON, DukeWpn.RPG_WEAPON, DukeWpn.HANDBOMB_WEAPON, DukeWpn.SHRINKER_WEAPON, 
+										DukeWpn.GROW_WEAPON, DukeWpn.DEVISTATOR_WEAPON, DukeWpn.TRIPBOMB_WEAPON, DukeWpn.FREEZE_WEAPON, DukeWpn.FLAMETHROWER_WEAPON };
+		int maxammo = Raze.IsWorldTour()? 11 : 10;
+		
+		for(int i = 0; i < maxammo; i++)
+		{
+			int ammonum = ammoorder[i];
+			if (ammonum == DukeWpn.GROW_WEAPON && !Raze.isPlutoPak()) continue;
+			if (p.curr_weapon == ammonum) 
+			{
+				stats.ammoselect = stats.ammoicons.Size();
+			}
+			stats.ammoicons.Push(ammo_sprites[ammonum]);
+			int num = p.ammo_amount[ammonum];
+			stats.ammovalues.Push(num);
+			stats.ammomaxvalues.Push(Duke.MaxAmmoAmount(ammonum));
+		}
+		
+		int n = 0, j = 0;
+		if (p.firstaid_amount > 0) { n |= 1; j++; }
+		if (p.steroids_amount > 0) { n |= 2; j++; }
+		if (p.holoduke_amount > 0) { n |= 4; j++; }
+		if (p.jetpack_amount > 0) { n |= 8; j++; }
+		if (p.heat_amount > 0) { n |= 16; j++; }
+		if (p.scuba_amount > 0) { n |= 32; j++; }
+		if (p.boot_amount > 0) { n |= 64; j++; }
+
+		for(int bit = 0; bit < 7; bit++)
+		{
+			int i = 1 << bit;
+			if (n & i)
+			{
+				if (p.inven_icon == bit + 1) stats.inventoryselect = stats.inventoryicons.Size();
+				stats.inventoryicons.Push(item_icons[bit+1]);
+				stats.inventoryamounts.Push(getinvamountforitem(p, bit + 1));
+			}
+		}
+	}
 }
diff --git a/wadsrc/static/zscript/razebase.zs b/wadsrc/static/zscript/razebase.zs
index 69a1be505..a7ebe8f4f 100644
--- a/wadsrc/static/zscript/razebase.zs
+++ b/wadsrc/static/zscript/razebase.zs
@@ -149,6 +149,12 @@ struct Raze
 	native static Font PickSmallFont(String cmptext = "");
 
 	// game check shortcuts
+
+	static bool isDuke()
+	{
+		return gameinfo.gametype & GAMEFLAG_DUKE;
+	}
+
 	static bool isNam()
 	{
 		return gameinfo.gametype & (GAMEFLAG_NAM | GAMEFLAG_NAPALM);