diff --git a/src/d_main.cpp b/src/d_main.cpp
index 3185f9966..26df11577 100644
--- a/src/d_main.cpp
+++ b/src/d_main.cpp
@@ -971,6 +971,7 @@ void D_ErrorCleanup ()
 	{
 		menuactive = MENU_Off;
 	}
+	if (gamestate == GS_INTERMISSION) gamestate = GS_DEMOSCREEN;
 	insave = false;
 }
 
diff --git a/src/gi.cpp b/src/gi.cpp
index 34c2fefa7..3c53b5b5c 100644
--- a/src/gi.cpp
+++ b/src/gi.cpp
@@ -59,6 +59,9 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenEnteringFont)
 DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenFinishedFont)
 DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gibfactor)
 DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, intermissioncounter)
+DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_single)
+DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_coop)
+DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, statusscreen_dm)
 
 
 const char *GameNames[17] =
@@ -393,6 +396,9 @@ void FMapInfoParser::ParseGameInfo()
 		GAMEINFOKEY_BOOL(norandomplayerclass, "norandomplayerclass")
 		GAMEINFOKEY_BOOL(forcekillscripts, "forcekillscripts") // [JM] Force kill scripts on thing death. (MF7_NOKILLSCRIPTS overrides.)
 		GAMEINFOKEY_STRING(Dialogue, "dialogue")
+		GAMEINFOKEY_STRING(statusscreen_single, "statscreen_single")
+		GAMEINFOKEY_STRING(statusscreen_coop, "statscreen_coop")
+		GAMEINFOKEY_STRING(statusscreen_dm, "statscreen_dm")
 
 		else
 		{
diff --git a/src/gi.h b/src/gi.h
index 759637dea..bf9ccd450 100644
--- a/src/gi.h
+++ b/src/gi.h
@@ -181,6 +181,9 @@ struct gameinfo_t
 	FGIFont mStatscreenEnteringFont;
 	bool norandomplayerclass;
 	bool forcekillscripts;
+	FName statusscreen_single;
+	FName statusscreen_coop;
+	FName statusscreen_dm;
 
 	const char *GetFinalePage(unsigned int num) const;
 };
diff --git a/src/namedef.h b/src/namedef.h
index f4d123a58..9d1fb49b3 100644
--- a/src/namedef.h
+++ b/src/namedef.h
@@ -645,6 +645,9 @@ xx(ceilingglowheight)
 xx(fogdensity)
 xx(Static)
 xx(Staticconst)
+xx(DeathmatchStatusScreen)
+xx(CoopStatusScreen)
+xx(RavenStatusScreen)
 
 // USDF keywords
 xx(Amount)
diff --git a/src/v_font.cpp b/src/v_font.cpp
index 7f1f496d5..a1730bd04 100644
--- a/src/v_font.cpp
+++ b/src/v_font.cpp
@@ -2577,7 +2577,7 @@ EColorRange V_FindFontColor (FName name)
 
 DEFINE_ACTION_FUNCTION(FFont, FindFontColor)
 {
-	PARAM_SELF_STRUCT_PROLOGUE(FFont);
+	PARAM_PROLOGUE;
 	PARAM_NAME(code);
 	ACTION_RETURN_INT((int)V_FindFontColor(code));
 }
diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp
index c1ae84793..9e2fc7ed7 100644
--- a/src/wi_stuff.cpp
+++ b/src/wi_stuff.cpp
@@ -1,27 +1,36 @@
-// Emacs style mode select	 -*- C++ -*- 
-//-----------------------------------------------------------------------------
-//
-// $Id:$
-//
-// Copyright (C) 1993-1996 by id Software, Inc.
-//
-// This source is available for distribution and/or modification
-// only under the terms of the DOOM Source Code License as
-// published by id Software. All rights reserved.
-//
-// The source is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
-// for more details.
-//
-// $Log:$
-//
-// DESCRIPTION:
-//		Intermission screens.
-//
-//-----------------------------------------------------------------------------
-
-// Enhancements by Graf Zahl
+/*
+** wi_stuff.cpp
+** Support code for intermission status screens
+**
+**---------------------------------------------------------------------------
+** Copyright 2003-2017 Christoph Oelckers
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+**    derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**---------------------------------------------------------------------------
+**
+*/
 
 #include <ctype.h>
 #include <stdio.h>
@@ -53,6 +62,7 @@
 #include "gstrings.h"
 #include "cmdlib.h"
 #include "g_levellocals.h"
+#include "virtual.h"
 
 CVAR(Bool, wi_percents, true, CVAR_ARCHIVE)
 CVAR(Bool, wi_showtotaltime, true, CVAR_ARCHIVE)
@@ -685,1499 +695,77 @@ DEFINE_ACTION_FUNCTION(DInterBackground, drawBackground)
 
 IMPLEMENT_CLASS(DInterBackground, true, false)
 
+DObject *WI_Screen;
+
 //====================================================================
 // 
 //
 //
 //====================================================================
 
-
-struct FPatchInfo
-{
-	FFont *mFont;
-	FTextureID mPatch;
-	EColorRange mColor;
-
-	void Init(FGIFont &gifont)
-	{
-		if (gifont.color == NAME_Null)
-		{
-			mPatch = TexMan.CheckForTexture(gifont.fontname, FTexture::TEX_MiscPatch);
-			mColor = mPatch.isValid() ? CR_UNTRANSLATED : CR_UNDEFINED;
-			mFont = NULL;
-		}
-		else
-		{
-			mFont = V_GetFont(gifont.fontname);
-			mColor = V_FindFontColor(gifont.color);
-			mPatch.SetNull();
-		}
-		if (mFont == NULL)
-		{
-			mFont = BigFont;
-		}
-	}
-};
-
-class DStatusScreen;
-static DStatusScreen *WI_Screen;
-
-
-class DStatusScreen : public DObject
-{
-	DECLARE_CLASS(DStatusScreen, DObject)
-public:
-
-	enum EValues
-	{
-		// GLOBAL LOCATIONS
-		WI_TITLEY = 2,
-
-		// SINGPLE-PLAYER STUFF
-		SP_STATSX = 50,
-		SP_STATSY = 50,
-
-		SP_TIMEX = 8,
-		SP_TIMEY = (200 - 32),
-
-		// NET GAME STUFF
-		NG_STATSY = 50,
-	};
-
-
-
-	// States for single-player
-	enum ESPState
-	{
-		SP_KILLS = 0,
-		SP_ITEMS = 2,
-		SP_SECRET = 4,
-		SP_FRAGS = 6,
-		SP_TIME = 8,
-	};
-
-	static const int SHOWNEXTLOCDELAY = 4;			// in seconds
-
-	//
-	// Animation.
-	// There is another anim_t used in p_spec.
-	// (which is why I have renamed this one!)
-	//
-
-
-	DInterBackground *bg;
-	int				acceleratestage;	// used to accelerate or skip a stage
-	bool			playerready[MAXPLAYERS];
-	int				me;					// wbs->pnum
-	int				bcnt;
-	EState			state;				// specifies current state
-	wbstartstruct_t *wbs;				// contains information passed into intermission
-	wbplayerstruct_t* Plrs[MAXPLAYERS];				// wbs->plyr[]
-	int				cnt;				// used for general timing
-	int				cnt_kills[MAXPLAYERS];
-	int				cnt_items[MAXPLAYERS];
-	int				cnt_secret[MAXPLAYERS];
-	int				cnt_frags[MAXPLAYERS];
-	int				cnt_deaths[MAXPLAYERS];
-	int				cnt_time;
-	int				cnt_total_time;
-	int				cnt_par;
-	int				cnt_pause;
-	int				total_frags;
-	int				total_deaths;
-	bool			noautostartmap;
-	int				dofrags;
-	int				ng_state;
-	float			shadowalpha;
-
-	//
-	//		GRAPHICS
-	//
-
-	FPatchInfo mapname;
-	FPatchInfo finished;
-	FPatchInfo entering;
-
-	FTextureID 		P_secret;	// "secret"
-	FTextureID 		Kills;		// "Kills", "Scrt", "Items", "Frags"
-	FTextureID 		Secret;
-	FTextureID 		Items;
-	FTextureID 		Timepic;	// Time sucks.
-	FTextureID 		Par;
-	FTextureID 		Sucks;
-
-	// [RH] Info to dynamically generate the level name graphics
-	FString			lnametexts[2];
-
-
-	bool snl_pointeron = false;
-
-	int player_deaths[MAXPLAYERS];
-	int  sp_state;
-
-	//
-	// CODE
-	//
-
-
-
-
-	//====================================================================
-	//
-	// Draws a single character with a shadow
-	//
-	//====================================================================
-
-	int WI_DrawCharPatch(FFont *font, int charcode, int x, int y, EColorRange translation = CR_UNTRANSLATED, bool nomove = false)
-	{
-		int width;
-		font->GetChar(charcode, &width);
-		screen->DrawChar(font, translation, x, y, charcode, nomove ? DTA_CleanNoMove : DTA_Clean, true, TAG_DONE);
-		return x - width;
-	}
-
-	//====================================================================
-	//
-	// Draws a level name with the big font
-	//
-	// x is no longer passed as a parameter because the text is now broken into several lines
-	// if it is too long
-	//
-	//====================================================================
-
-	int WI_DrawName(int y, FTexture *tex, const char *levelname)
-	{
-		// draw <LevelName> 
-		if (tex)
-		{
-			screen->DrawTexture(tex, (screen->GetWidth() - tex->GetScaledWidth()*CleanXfac) /2, y, DTA_CleanNoMove, true, TAG_DONE);
-			int h = tex->GetScaledHeight();
-			if (h > 50)
-			{ // Fix for Deus Vult II and similar wads that decide to make these hugely tall
-			  // patches with vast amounts of empty space at the bottom.
-				h = tex->CheckRealHeight();
-			}
-			return y + (h + BigFont->GetHeight()/4) * CleanYfac;
-		}
-		else 
-		{
-			int i;
-			size_t l;
-			const char *p;
-			int h = 0;
-			int lumph;
-
-			lumph = mapname.mFont->GetHeight() * CleanYfac;
-
-			p = levelname;
-			if (!p) return 0;
-			l = strlen(p);
-			if (!l) return 0;
-
-			FBrokenLines *lines = V_BreakLines(mapname.mFont, screen->GetWidth() / CleanXfac, p);
-
-			if (lines)
-			{
-				for (i = 0; lines[i].Width >= 0; i++)
-				{
-					screen->DrawText(mapname.mFont, mapname.mColor, (SCREENWIDTH - lines[i].Width * CleanXfac) / 2, y + h, 
-						lines[i].Text, DTA_CleanNoMove, true, TAG_DONE);
-					h += lumph;
-				}
-				V_FreeBrokenLines(lines);
-			}
-			return y + h + lumph/4;
-		}
-	}
-
-	//====================================================================
-	//
-	// Draws a text, either as patch or as string from the string table
-	//
-	//====================================================================
-
-	int WI_DrawPatchText(int y, FPatchInfo *pinfo, const char *stringname)
-	{
-		const char *string = GStrings(stringname);
-		int midx = screen->GetWidth() / 2;
-
-		if (pinfo->mPatch.isValid())
-		{
-			FTexture *tex = TexMan[pinfo->mPatch];
-			screen->DrawTexture(tex, midx - tex->GetScaledWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE);
-			return y + (tex->GetScaledHeight() * CleanYfac);
-		}
-		else 
-		{
-			screen->DrawText(pinfo->mFont, pinfo->mColor, midx - pinfo->mFont->StringWidth(string)*CleanXfac/2,
-				y, string, DTA_CleanNoMove, true, TAG_DONE);
-			return y + pinfo->mFont->GetHeight() * CleanYfac;
-		}
-	}
-
-
-	//====================================================================
-	//
-	// Draws "<Levelname> Finished!"
-	//
-	// Either uses the specified patch or the big font
-	// A level name patch can be specified for all games now, not just Doom.
-	//
-	//====================================================================
-
-	int WI_drawLF ()
-	{
-		int y = WI_TITLEY * CleanYfac;
-
-		y = WI_DrawName(y, TexMan(wbs->LName0), lnametexts[0]);
-	
-		// Adjustment for different font sizes for map name and 'finished'.
-		y -= ((mapname.mFont->GetHeight() - finished.mFont->GetHeight()) * CleanYfac) / 4;
-
-		// draw "Finished!"
-		if (y < (NG_STATSY - finished.mFont->GetHeight()*3/4) * CleanYfac)
-		{
-			// don't draw 'finished' if the level name is too tall
-			y = WI_DrawPatchText(y, &finished, "WI_FINISHED");
-		}
-		return y;
-	}
-
-
-	//====================================================================
-	//
-	// Draws "Entering <LevelName>"
-	//
-	// Either uses the specified patch or the big font
-	// A level name patch can be specified for all games now, not just Doom.
-	//
-	//====================================================================
-
-	void WI_drawEL ()
-	{
-		int y = WI_TITLEY * CleanYfac;
-
-		y = WI_DrawPatchText(y, &entering, "WI_ENTERING");
-		y += entering.mFont->GetHeight() * CleanYfac / 4;
-		WI_DrawName(y, TexMan(wbs->LName1), lnametexts[1]);
-	}
-
-
-	//====================================================================
-	//
-	// Draws a number.
-	// If digits > 0, then use that many digits minimum,
-	//	otherwise only use as many as necessary.
-	// x is the right edge of the number.
-	// Returns new x position, that is, the left edge of the number.
-	//
-	//====================================================================
-	int WI_drawNum (FFont *font, int x, int y, int n, int digits, bool leadingzeros=true, EColorRange translation=CR_UNTRANSLATED)
-	{
-		int fontwidth = font->GetCharWidth('3');
-		char text[8];
-		int len;
-		char *text_p;
-		bool nomove = font != IntermissionFont;
-
-		if (nomove)
-		{
-			fontwidth *= CleanXfac;
-		}
-		if (leadingzeros)
-		{
-			len = mysnprintf (text, countof(text), "%0*d", digits, n);
-		}
-		else
-		{
-			len = mysnprintf (text, countof(text), "%d", n);
-		}
-		text_p = text + MIN<int>(len, countof(text)-1);
-
-		while (--text_p >= text)
-		{
-			// Digits are centered in a box the width of the '3' character.
-			// Other characters (specifically, '-') are right-aligned in their cell.
-			if (*text_p >= '0' && *text_p <= '9')
-			{
-				x -= fontwidth;
-				WI_DrawCharPatch(font, *text_p, x + (fontwidth - font->GetCharWidth(*text_p)) / 2, y, translation, nomove);
-			}
-			else
-			{
-				WI_DrawCharPatch(font, *text_p, x - font->GetCharWidth(*text_p), y, translation, nomove);
-				x -= fontwidth;
-			}
-		}
-		if (len < digits)
-		{
-			x -= fontwidth * (digits - len);
-		}
-		return x;
-	}
-
-	//====================================================================
-	//
-	//
-	//
-	//====================================================================
-
-	void WI_drawPercent (FFont *font, int x, int y, int p, int b, bool show_total=true, EColorRange color=CR_UNTRANSLATED)
-	{
-		if (p < 0)
-			return;
-
-		if (wi_percents)
-		{
-			if (font != IntermissionFont)
-			{
-				x -= font->GetCharWidth('%') * CleanXfac;
-			}
-			else
-			{
-				x -= font->GetCharWidth('%');
-			}
-			screen->DrawText(font, color, x, y, "%", font != IntermissionFont ? DTA_CleanNoMove : DTA_Clean, true, TAG_DONE);
-			if (font != IntermissionFont)
-			{
-				x -= 2*CleanXfac;
-			}
-			WI_drawNum(font, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color);
-		}
-		else
-		{
-			if (show_total)
-			{
-				x = WI_drawNum(font, x, y, b, 2, false);
-				x -= font->GetCharWidth('/');
-				screen->DrawText (IntermissionFont, color, x, y, "/",
-					DTA_Clean, true, TAG_DONE);
-			}
-			WI_drawNum (font, x, y, p, -1, false, color);
-		}
-	}
-
-	//====================================================================
-	//
-	// Display level completion time and par, or "sucks" message if overflow.
-	//
-	//====================================================================
-	void WI_drawTime (int x, int y, int t, bool no_sucks=false)
-	{
-		bool sucky;
-
-		if (t<0)
-			return;
-
-		sucky = !no_sucks && t >= wbs->sucktime * 60 * 60 && wbs->sucktime > 0;
-
-		if (sucky)
-		{ // "sucks"
-			if (Sucks.isValid())
-			{
-				screen->DrawTexture (TexMan[Sucks], x - TexMan[Sucks]->GetScaledWidth(), y - IntermissionFont->GetHeight() - 2,
-					DTA_Clean, true, TAG_DONE); 
-			}
-			else
-			{
-				screen->DrawText (BigFont, CR_UNTRANSLATED, x  - BigFont->StringWidth("SUCKS"), y - IntermissionFont->GetHeight() - 2,
-					"SUCKS", DTA_Clean, true, TAG_DONE);
-			}
-		}
-
-		int hours = t / 3600;
-		t -= hours * 3600;
-		int minutes = t / 60;
-		t -= minutes * 60;
-		int seconds = t;
-
-		// Why were these offsets hard coded? Half the WADs with custom patches
-		// I tested screwed up miserably in this function!
-		int num_spacing = IntermissionFont->GetCharWidth('3');
-		int colon_spacing = IntermissionFont->GetCharWidth(':');
-
-		x = WI_drawNum (IntermissionFont, x, y, seconds, 2) - 1;
-		WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y);
-		x = WI_drawNum (IntermissionFont, x, y, minutes, 2, hours!=0);
-		if (hours)
-		{
-			WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y);
-			WI_drawNum (IntermissionFont, x, y, hours, 2);
-		}
-	}
-
-	void WI_End ()
-	{
-		state = LeavingIntermission;
-		WI_unloadData ();
-
-		//Added by mc
-		if (deathmatch)
-		{
-			bglobal.RemoveAllBots (consoleplayer != Net_Arbitrator);
-		}
-	}
-
-	bool WI_autoSkip()
-	{
-		return wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE);
-	}
-
-	void WI_initNoState ()
-	{
-		state = NoState;
-		acceleratestage = 0;
-		cnt = 10;
-	}
-
-	void WI_updateNoState ()
-	{
-		if (acceleratestage)
-		{
-			cnt = 0;
-		}
-		else
-		{
-			bool noauto = noautostartmap;
-			bool autoskip = WI_autoSkip();
-
-			for (int i = 0; !noauto && i < MAXPLAYERS; ++i)
-			{
-				if (playeringame[i])
-				{
-					noauto |= players[i].userinfo.GetNoAutostartMap();
-				}
-			}
-			if (!noauto || autoskip)
-			{
-				cnt--;
-			}
-		}
-
-		if (cnt == 0)
-		{
-			WI_End();
-			G_WorldDone();
-		}
-	}
-
-
-	void WI_initShowNextLoc ()
-	{
-		auto info = FindLevelInfo(wbs->next, false);
-		if (info == nullptr) 
-		{
-			// Last map in episode - there is no next location!
-			WI_End();
-			G_WorldDone();
-			return;
-		}
-
-		state = ShowNextLoc;
-		acceleratestage = 0;
-		cnt = SHOWNEXTLOCDELAY * TICRATE;
-		bg->LoadBackground(true);
-	}
-
-	void WI_updateShowNextLoc ()
-	{
-		if (!--cnt || acceleratestage)
-			WI_initNoState();
-		else
-			snl_pointeron = (cnt & 31) < 20;
-	}
-
-	void WI_drawShowNextLoc(void)
-	{
-		bg->drawBackground(state, true, snl_pointeron);
-
-		// draws which level you are entering..
-		WI_drawEL ();  
-
-	}
-
-	void WI_drawNoState ()
-	{
-		snl_pointeron = true;
-		WI_drawShowNextLoc();
-	}
-
-	int WI_fragSum (int playernum)
-	{
-		int i;
-		int frags = 0;
-	
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (playeringame[i]
-				&& i!=playernum)
-			{
-				frags += Plrs[playernum]->frags[i];
-			}
-		}
-		
-		// JDC hack - negative frags.
-		frags -= Plrs[playernum]->frags[playernum];
-
-		return frags;
-	}
-
-
-	void WI_initDeathmatchStats (void)
-	{
-		int i, j;
-
-		state = StatCount;
-		acceleratestage = 0;
-		memset(playerready, 0, sizeof(playerready));
-		memset(cnt_frags, 0, sizeof(cnt_frags));
-		memset(cnt_deaths, 0, sizeof(cnt_deaths));
-		memset(player_deaths, 0, sizeof(player_deaths));
-		total_frags = 0;
-		total_deaths = 0;
-
-		ng_state = 1;
-		cnt_pause = TICRATE;
-
-		for (i=0 ; i<MAXPLAYERS ; i++)
-		{
-			if (playeringame[i])
-			{
-				for (j = 0; j < MAXPLAYERS; j++)
-					if (playeringame[j])
-						player_deaths[i] += Plrs[j]->frags[i];
-				total_deaths += player_deaths[i];
-				total_frags += Plrs[i]->fragcount;
-			}
-		}
-	}
-
-	void WI_updateDeathmatchStats ()
-	{
-
-		int i;
-		bool stillticking;
-		bool autoskip = WI_autoSkip();
-
-		if ((acceleratestage || autoskip) && ng_state != 6)
-		{
-			acceleratestage = 0;
-
-			for (i = 0; i<MAXPLAYERS; i++)
-			{
-				if (!playeringame[i])
-					continue;
-
-				cnt_frags[i] = Plrs[i]->fragcount;
-				cnt_deaths[i] = player_deaths[i];
-			}
-			S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-			ng_state = 6;
-		}
-
-		if (ng_state == 2)
-		{
-			if (!(bcnt & 3))
-				S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-
-			stillticking = false;
-
-			for (i = 0; i<MAXPLAYERS; i++)
-			{
-				if (!playeringame[i])
-					continue;
-
-				cnt_frags[i] += 2;
-
-				if (cnt_frags[i] > Plrs[i]->fragcount)
-					cnt_frags[i] = Plrs[i]->fragcount;
-				else
-					stillticking = true;
-			}
-
-			if (!stillticking)
-			{
-				S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-				ng_state++;
-			}
-		}
-		else if (ng_state == 4)
-		{
-			if (!(bcnt & 3))
-				S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-
-			stillticking = false;
-
-			for (i = 0; i<MAXPLAYERS; i++)
-			{
-				if (!playeringame[i])
-					continue;
-
-				cnt_deaths[i] += 2;
-				if (cnt_deaths[i] > player_deaths[i])
-					cnt_deaths[i] = player_deaths[i];
-				else
-					stillticking = true;
-			}
-			if (!stillticking)
-			{
-				S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-				ng_state++;
-			}
-		}
-		else if (ng_state == 6)
-		{
-			int i;
-			for (i = 0; i < MAXPLAYERS; i++)
-			{
-				// If the player is in the game and not ready, stop checking
-				if (playeringame[i] && players[i].Bot == NULL && !playerready[i])
-					break;
-			}
-
-			// All players are ready; proceed.
-			if ((i == MAXPLAYERS && acceleratestage) || autoskip)
-			{
-				S_Sound(CHAN_VOICE | CHAN_UI, "intermission/pastdmstats", 1, ATTN_NONE);
-				WI_initShowNextLoc();
-			}
-		}
-		else if (ng_state & 1)
-		{
-			if (!--cnt_pause)
-			{
-				ng_state++;
-				cnt_pause = TICRATE;
-			}
-		}
-	}
-
-
-
-	void WI_drawDeathmatchStats ()
-	{
-		int i, pnum, x, y, ypadding, height, lineheight;
-		int maxnamewidth, maxscorewidth, maxiconheight;
-		int pwidth = IntermissionFont->GetCharWidth('%');
-		int icon_x, name_x, frags_x, deaths_x;
-		int deaths_len;
-		float h, s, v, r, g, b;
-		EColorRange color;
-		const char *text_deaths, *text_frags;
-		FTexture *readyico = TexMan.FindTexture("READYICO");
-		player_t *sortedplayers[MAXPLAYERS];
-
-		// draw animated background
-		bg->drawBackground(state, false, false);
-
-		y = WI_drawLF();
-
-		HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
-		// Use the readyico height if it's bigger.
-		height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset();
-		maxiconheight = MAX(height, maxiconheight);
-		height = SmallFont->GetHeight() * CleanYfac;
-		lineheight = MAX(height, maxiconheight * CleanYfac);
-		ypadding = (lineheight - height + 1) / 2;
-		y += CleanYfac;
-
-		text_deaths = GStrings("SCORE_DEATHS");
-		//text_color = GStrings("SCORE_COLOR");
-		text_frags = GStrings("SCORE_FRAGS");
-
-		icon_x = 8 * CleanXfac;
-		name_x = icon_x + maxscorewidth * CleanXfac;
-		frags_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_frags)) + 8) * CleanXfac;
-		deaths_x = frags_x + ((deaths_len = SmallFont->StringWidth(text_deaths)) + 8) * CleanXfac;
-
-		x = (SCREENWIDTH - deaths_x) >> 1;
-		icon_x += x;
-		name_x += x;
-		frags_x += x;
-		deaths_x += x;
-
-		color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
-
-		screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE);
-		screen->DrawText(SmallFont, color, frags_x - SmallFont->StringWidth(text_frags)*CleanXfac, y, text_frags, DTA_CleanNoMove, true, TAG_DONE);
-		screen->DrawText(SmallFont, color, deaths_x - deaths_len*CleanXfac, y, text_deaths, DTA_CleanNoMove, true, TAG_DONE);
-		y += height + 6 * CleanYfac;
-
-		// Sort all players
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			sortedplayers[i] = &players[i];
-		}
-
-		if (teamplay)
-			qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), compareteams);
-		else
-			qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), comparepoints);
-
-		// Draw lines for each player
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			player_t *player = sortedplayers[i];
-			pnum = int(player - players);
-
-			if (!playeringame[pnum])
-				continue;
-
-			D_GetPlayerColor(pnum, &h, &s, &v, NULL);
-			HSVtoRGB(&r, &g, &b, h, s, v);
-
-			screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), 
-				clamp(int(g*255.f), 0, 255), 
-				clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (deaths_x - x) + (8 * CleanXfac), lineheight);
-
-			if (playerready[pnum] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion
-				screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE);
-
-			color = (EColorRange)HU_GetRowColor(player, pnum == consoleplayer);
-			if (player->mo->ScoreIcon.isValid())
-			{
-				FTexture *pic = TexMan[player->mo->ScoreIcon];
-				screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE);
-			}
-			screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE);
-			WI_drawNum(SmallFont, frags_x, y + ypadding, cnt_frags[pnum], 0, false, color);
-			if (ng_state >= 2)
-			{
-				WI_drawNum(SmallFont, deaths_x, y + ypadding, cnt_deaths[pnum], 0, false, color);
-			}
-			y += lineheight + CleanYfac;
-		}
-
-		// Draw "TOTAL" line
-		y += height + 3 * CleanYfac;
-		color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
-		screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE);
-		WI_drawNum(SmallFont, frags_x, y, total_frags, 0, false, color);
-		if (ng_state >= 4)
-		{
-			WI_drawNum(SmallFont, deaths_x, y, total_deaths, 0, false, color);
-		}
-
-		// Draw game time
-		y += height + CleanYfac;
-
-		int seconds = Tics2Seconds(Plrs[me]->stime);
-		int hours = seconds / 3600;
-		int minutes = (seconds % 3600) / 60;
-		seconds = seconds % 60;
-
-		FString leveltime = GStrings("SCORE_LVLTIME");
-		leveltime += ": ";
-
-		char timer[sizeof "HH:MM:SS"];
-		mysnprintf(timer, sizeof(timer), "%02i:%02i:%02i", hours, minutes, seconds);
-		leveltime += timer;
-
-		screen->DrawText(SmallFont, color, x, y, leveltime, DTA_CleanNoMove, true, TAG_DONE);
-	}
-
-	void WI_initNetgameStats ()
-	{
-
-		int i;
-
-		state = StatCount;
-		acceleratestage = 0;
-		memset(playerready, 0, sizeof(playerready));
-		ng_state = 1;
-
-		cnt_pause = TICRATE;
-
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (!playeringame[i])
-				continue;
-
-			cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0;
-
-			dofrags += WI_fragSum (i);
-		}
-
-		dofrags = !!dofrags;
-	}
-
-	void WI_updateNetgameStats ()
-	{
-
-		int i;
-		int fsum;
-		bool stillticking;
-		bool autoskip = WI_autoSkip();
-
-		if ((acceleratestage || autoskip) && ng_state != 10)
-		{
-			acceleratestage = 0;
-
-			for (i=0 ; i<MAXPLAYERS ; i++)
-			{
-				if (!playeringame[i])
-					continue;
-
-				cnt_kills[i] = Plrs[i]->skills;
-				cnt_items[i] = Plrs[i]->sitems;
-				cnt_secret[i] = Plrs[i]->ssecret;
-
-				if (dofrags)
-					cnt_frags[i] = WI_fragSum (i);
-			}
-			S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-			ng_state = 10;
-		}
-
-		if (ng_state == 2)
-		{
-			if (!(bcnt&3))
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-
-			stillticking = false;
-
-			for (i=0 ; i<MAXPLAYERS ; i++)
-			{
-				if (!playeringame[i])
-					continue;
-
-				cnt_kills[i] += 2;
-
-				if (cnt_kills[i] > Plrs[i]->skills)
-					cnt_kills[i] = Plrs[i]->skills;
-				else
-					stillticking = true;
-			}
-		
-			if (!stillticking)
-			{
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-				ng_state++;
-			}
-		}
-		else if (ng_state == 4)
-		{
-			if (!(bcnt&3))
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-
-			stillticking = false;
-
-			for (i=0 ; i<MAXPLAYERS ; i++)
-			{
-				if (!playeringame[i])
-					continue;
-
-				cnt_items[i] += 2;
-				if (cnt_items[i] > Plrs[i]->sitems)
-					cnt_items[i] = Plrs[i]->sitems;
-				else
-					stillticking = true;
-			}
-			if (!stillticking)
-			{
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-				ng_state++;
-			}
-		}
-		else if (ng_state == 6)
-		{
-			if (!(bcnt&3))
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-
-			stillticking = false;
-
-			for (i=0 ; i<MAXPLAYERS ; i++)
-			{
-				if (!playeringame[i])
-					continue;
-
-				cnt_secret[i] += 2;
-
-				if (cnt_secret[i] > Plrs[i]->ssecret)
-					cnt_secret[i] = Plrs[i]->ssecret;
-				else
-					stillticking = true;
-			}
-		
-			if (!stillticking)
-			{
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-				ng_state += 1 + 2*!dofrags;
-			}
-		}
-		else if (ng_state == 8)
-		{
-			if (!(bcnt&3))
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-
-			stillticking = false;
-
-			for (i=0 ; i<MAXPLAYERS ; i++)
-			{
-				if (!playeringame[i])
-					continue;
-
-				cnt_frags[i] += 1;
-
-				if (cnt_frags[i] >= (fsum = WI_fragSum(i)))
-					cnt_frags[i] = fsum;
-				else
-					stillticking = true;
-			}
-		
-			if (!stillticking)
-			{
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/cooptotal", 1, ATTN_NONE);
-				ng_state++;
-			}
-		}
-		else if (ng_state == 10)
-		{
-			int i;
-			for (i = 0; i < MAXPLAYERS; i++)
-			{
-				// If the player is in the game and not ready, stop checking
-				if (playeringame[i] && players[i].Bot == NULL && !playerready[i])
-					break;
-			}
-
-			// All players are ready; proceed.
-			if ((i == MAXPLAYERS && acceleratestage) || autoskip)
-			{
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastcoopstats", 1, ATTN_NONE);
-				WI_initShowNextLoc();
-			}
-		}
-		else if (ng_state & 1)
-		{
-			if (!--cnt_pause)
-			{
-				ng_state++;
-				cnt_pause = TICRATE;
-			}
-		}
-	}
-
-	void WI_drawNetgameStats ()
-	{
-		int i, x, y, ypadding, height, lineheight;
-		int maxnamewidth, maxscorewidth, maxiconheight;
-		int pwidth = IntermissionFont->GetCharWidth('%');
-		int icon_x, name_x, kills_x, bonus_x, secret_x;
-		int bonus_len, secret_len;
-		int missed_kills, missed_items, missed_secrets;
-		float h, s, v, r, g, b;
-		EColorRange color;
-		const char *text_bonus, *text_secret, *text_kills;
-		FTexture *readyico = TexMan.FindTexture("READYICO");
-
-		// draw animated background
-		bg->drawBackground(state, false, false); 
-
-		y = WI_drawLF();
-
-		HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
-		// Use the readyico height if it's bigger.
-		height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset();
-		if (height > maxiconheight)
-		{
-			maxiconheight = height;
-		}
-		height = SmallFont->GetHeight() * CleanYfac;
-		lineheight = MAX(height, maxiconheight * CleanYfac);
-		ypadding = (lineheight - height + 1) / 2;
-		y += CleanYfac;
-
-		text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS");
-		text_secret = GStrings("SCORE_SECRET");
-		text_kills = GStrings("SCORE_KILLS");
-
-		icon_x = 8 * CleanXfac;
-		name_x = icon_x + maxscorewidth * CleanXfac;
-		kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac;
-		bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac;
-		secret_x = bonus_x + ((secret_len = SmallFont->StringWidth(text_secret)) + 8) * CleanXfac;
-
-		x = (SCREENWIDTH - secret_x) >> 1;
-		icon_x += x;
-		name_x += x;
-		kills_x += x;
-		bonus_x += x;
-		secret_x += x;
-
-		color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
-
-		screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE);
-		screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE);
-		screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE);
-		screen->DrawText(SmallFont, color, secret_x - secret_len*CleanXfac, y, text_secret, DTA_CleanNoMove, true, TAG_DONE);
-		y += height + 6 * CleanYfac;
-
-		missed_kills = wbs->maxkills;
-		missed_items = wbs->maxitems;
-		missed_secrets = wbs->maxsecret;
-
-		// Draw lines for each player
-		for (i = 0; i < MAXPLAYERS; ++i)
-		{
-			player_t *player;
-
-			if (!playeringame[i])
-				continue;
-
-			player = &players[i];
-
-			D_GetPlayerColor(i, &h, &s, &v, NULL);
-			HSVtoRGB(&r, &g, &b, h, s, v);
-
-			screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255),
-				clamp(int(g*255.f), 0, 255),
-				clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (secret_x - x) + (8 * CleanXfac), lineheight);
-
-			if (playerready[i] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion
-				screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE);
-
-			color = (EColorRange)HU_GetRowColor(player, i == consoleplayer);
-			if (player->mo->ScoreIcon.isValid())
-			{
-				FTexture *pic = TexMan[player->mo->ScoreIcon];
-				screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE);
-			}
-			screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE);
-			WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color);
-			missed_kills -= cnt_kills[i];
-			if (ng_state >= 4)
-			{
-				WI_drawPercent(SmallFont, bonus_x, y + ypadding, cnt_items[i], wbs->maxitems, false, color);
-				missed_items -= cnt_items[i];
-				if (ng_state >= 6)
-				{
-					WI_drawPercent(SmallFont, secret_x, y + ypadding, cnt_secret[i], wbs->maxsecret, false, color);
-					missed_secrets -= cnt_secret[i];
-				}
-			}
-			y += lineheight + CleanYfac;
-		}
-
-		// Draw "MISSED" line
-		y += 3 * CleanYfac;
-		screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE);
-		WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY);
-		if (ng_state >= 4)
-		{
-			WI_drawPercent(SmallFont, bonus_x, y, missed_items, wbs->maxitems, false, CR_DARKGRAY);
-			if (ng_state >= 6)
-			{
-				WI_drawPercent(SmallFont, secret_x, y, missed_secrets, wbs->maxsecret, false, CR_DARKGRAY);
-			}
-		}
-
-		// Draw "TOTAL" line
-		y += height + 3 * CleanYfac;
-		color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED;
-		screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE);
-		WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color);
-		if (ng_state >= 4)
-		{
-			WI_drawNum(SmallFont, bonus_x, y, wbs->maxitems, 0, false, color);
-			if (ng_state >= 6)
-			{
-				WI_drawNum(SmallFont, secret_x, y, wbs->maxsecret, 0, false, color);
-			}
-		}
-	}
-
-
-	void WI_initStats ()
-	{
-		state = StatCount;
-		acceleratestage = 0;
-		sp_state = 1;
-		cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1;
-		cnt_time = cnt_par = -1;
-		cnt_pause = TICRATE;
-	
-		cnt_total_time = -1;
-	}
-
-	void WI_updateStats ()
-	{
-		if (acceleratestage && sp_state != 10)
-		{
-			acceleratestage = 0;
-			sp_state = 10;
-			S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-
-			cnt_kills[0] = Plrs[me]->skills;
-			cnt_items[0] = Plrs[me]->sitems;
-			cnt_secret[0] = Plrs[me]->ssecret;
-			cnt_time = Tics2Seconds(Plrs[me]->stime);
-			cnt_par = wbs->partime / TICRATE;
-			cnt_total_time = Tics2Seconds(wbs->totaltime);
-		}
-
-		if (sp_state == 2)
-		{
-			if (gameinfo.intermissioncounter)
-			{
-				cnt_kills[0] += 2;
-
-				if (!(bcnt&3))
-					S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-			}
-			if (!gameinfo.intermissioncounter || cnt_kills[0] >= Plrs[me]->skills)
-			{
-				cnt_kills[0] = Plrs[me]->skills;
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-				sp_state++;
-			}
-		}
-		else if (sp_state == 4)
-		{
-			if (gameinfo.intermissioncounter)
-			{
-				cnt_items[0] += 2;
-
-				if (!(bcnt&3))
-					S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-			}
-			if (!gameinfo.intermissioncounter || cnt_items[0] >= Plrs[me]->sitems)
-			{
-				cnt_items[0] = Plrs[me]->sitems;
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-				sp_state++;
-			}
-		}
-		else if (sp_state == 6)
-		{
-			if (gameinfo.intermissioncounter)
-			{
-				cnt_secret[0] += 2;
-
-				if (!(bcnt&3))
-					S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-			}
-			if (!gameinfo.intermissioncounter || cnt_secret[0] >= Plrs[me]->ssecret)
-			{
-				cnt_secret[0] = Plrs[me]->ssecret;
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-				sp_state++;
-			}
-		}
-		else if (sp_state == 8)
-		{
-			if (gameinfo.intermissioncounter)
-			{
-				if (!(bcnt&3))
-					S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE);
-
-				cnt_time += 3;
-				cnt_par += 3;
-				cnt_total_time += 3;
-			}
-
-			int sec = Tics2Seconds(Plrs[me]->stime);
-			if (!gameinfo.intermissioncounter || cnt_time >= sec)
-				cnt_time = sec;
-
-			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 >= sec)
-				{
-					cnt_total_time = tsec;
-					S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE);
-					sp_state++;
-				}
-			}
-		}
-		else if (sp_state == 10)
-		{
-			if (acceleratestage)
-			{
-				S_Sound (CHAN_VOICE | CHAN_UI, "intermission/paststats", 1, ATTN_NONE);
-				WI_initShowNextLoc();
-			}
-		}
-		else if (sp_state & 1)
-		{
-			if (!--cnt_pause)
-			{
-				sp_state++;
-				cnt_pause = TICRATE;
-			}
-		}
-	}
-
-	void WI_drawStats (void)
-	{
-		// line height
-		int lh; 	
-
-		lh = IntermissionFont->GetHeight() * 3 / 2;
-
-		// draw animated background
-		bg->drawBackground(state, false, false);
-
-		WI_drawLF();
-	
-		if (gameinfo.gametype & GAME_DoomChex)
-		{
-			screen->DrawTexture (TexMan[Kills], SP_STATSX, SP_STATSY, DTA_Clean, true, TAG_DONE);
-			WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY, cnt_kills[0], wbs->maxkills);
-
-			screen->DrawTexture (TexMan[Items], SP_STATSX, SP_STATSY+lh, DTA_Clean, true, TAG_DONE);
-			WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+lh, cnt_items[0], wbs->maxitems);
-
-			screen->DrawTexture (TexMan[P_secret], SP_STATSX, SP_STATSY+2*lh, DTA_Clean, true, TAG_DONE);
-			WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0], wbs->maxsecret);
-
-			screen->DrawTexture (TexMan[Timepic], SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE);
-			WI_drawTime (160 - SP_TIMEX, SP_TIMEY, cnt_time);
-			if (wi_showtotaltime)
-			{
-				WI_drawTime (160 - SP_TIMEX, SP_TIMEY + lh, cnt_total_time, true);	// no 'sucks' for total time ever!
-			}
-
-			if (wbs->partime)
-			{
-				screen->DrawTexture (TexMan[Par], 160 + SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE);
-				WI_drawTime (320 - SP_TIMEX, SP_TIMEY, cnt_par);
-			}
-
-		}
-		else
-		{
-			screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 65, GStrings("TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
-			screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, GStrings("TXT_IMITEMS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
-			screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, GStrings("TXT_IMSECRETS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
-
-			int countpos = gameinfo.gametype==GAME_Strife? 285:270;
-			if (sp_state >= 2)
-			{
-				WI_drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs->maxkills);
-			}
-			if (sp_state >= 4)
-			{
-				WI_drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs->maxitems);
-			}
-			if (sp_state >= 6)
-			{
-				WI_drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs->maxsecret);
-			}
-			if (sp_state >= 8)
-			{
-				screen->DrawText (BigFont, CR_UNTRANSLATED, 85, 160, GStrings("TXT_IMTIME"),
-					DTA_Clean, true, DTA_Shadow, true, TAG_DONE);
-				WI_drawTime (249, 160, cnt_time);
-				if (wi_showtotaltime)
-				{
-					WI_drawTime (249, 180, cnt_total_time);
-				}
-			}
-		}
-	}
-
-	// ====================================================================
-	// WI_checkForAccelerate
-	// Purpose: See if the player has hit either the attack or use key
-	//          or mouse button.  If so we set acceleratestage to 1 and
-	//          all those display routines above jump right to the end.
-	// Args:    none
-	// Returns: void
-	//
-	// ====================================================================
-	void WI_checkForAccelerate(void)
-	{
-		int i;
-		player_t *player;
-
-		// check for button presses to skip delays
-		for (i = 0, player = players; i < MAXPLAYERS; i++, player++)
-		{
-			if (playeringame[i])
-			{
-				if ((player->cmd.ucmd.buttons ^ player->oldbuttons) &&
-					((players[i].cmd.ucmd.buttons & players[i].oldbuttons)
-						== players[i].oldbuttons) && player->Bot == NULL)
-				{
-					acceleratestage = 1;
-					playerready[i] = true;
-				}
-				player->oldbuttons = player->cmd.ucmd.buttons;
-			}
-		}
-	}
-
-	// ====================================================================
-	// WI_Ticker
-	// Purpose: Do various updates every gametic, for stats, animation,
-	//          checking that intermission music is running, etc.
-	// Args:    none
-	// Returns: void
-	//
-	// ====================================================================
-	void WI_Ticker(void)
-	{
-		// counter for general background animation
-		bcnt++;  
-	
-		if (bcnt == 1)
-		{
-			// intermission music - use the defaults if none specified
-			auto mus = level.info->MapInterMusic.CheckKey(wbs->next);
-			if (mus != nullptr)
-				S_ChangeMusic(mus->first, mus->second);
-			else if (level.info->InterMusic.IsNotEmpty()) 
-				S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder);
-			else
-				S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); 
-
-		}
-	
-		WI_checkForAccelerate();
-	
-		switch (state)
-		{
-		case StatCount:
-			if (deathmatch) WI_updateDeathmatchStats();
-			else if (multiplayer) WI_updateNetgameStats();
-			else WI_updateStats();
-			break;
-		
-		case ShowNextLoc:
-			WI_updateShowNextLoc();
-			break;
-		
-		case NoState:
-			WI_updateNoState();
-			break;
-
-		case LeavingIntermission:
-			// Hush, GCC.
-			break;
-		}
-	}
-
-
-	void WI_loadData(void)
-	{
-		entering.Init(gameinfo.mStatscreenEnteringFont);
-		finished.Init(gameinfo.mStatscreenFinishedFont);
-		mapname.Init(gameinfo.mStatscreenMapNameFont);
-
-		if (gameinfo.gametype & GAME_DoomChex)
-		{
-			Kills = TexMan.CheckForTexture("WIOSTK", FTexture::TEX_MiscPatch);		// "kills"
-			Secret = TexMan.CheckForTexture("WIOSTS", FTexture::TEX_MiscPatch);		// "scrt"
-			P_secret = TexMan.CheckForTexture("WISCRT2", FTexture::TEX_MiscPatch);	// "secret"
-			Items = TexMan.CheckForTexture("WIOSTI", FTexture::TEX_MiscPatch);		// "items"
-			Timepic = TexMan.CheckForTexture("WITIME", FTexture::TEX_MiscPatch);		// "time"
-			Sucks = TexMan.CheckForTexture("WISUCKS", FTexture::TEX_MiscPatch);		// "sucks"
-			Par = TexMan.CheckForTexture("WIPAR", FTexture::TEX_MiscPatch);			// "par"
-		}
-
-		// Use the local level structure which can be overridden by hubs
-		lnametexts[0] = level.LevelName;		
-		lnametexts[1] = wbs->nextname;
-
-		bg = new DInterBackground(wbs);
-		GC::AddSoftRoot(bg);
-		noautostartmap = bg->LoadBackground(false);
-	}
-
-	void WI_unloadData ()
-	{
-		GC::DelSoftRoot(bg);
-		bg->Destroy();
-		bg = nullptr;
-		return;
-	}
-
-	void WI_Drawer (void)
-	{
-		switch (state)
-		{
-		case StatCount:
-			if (deathmatch)
-				WI_drawDeathmatchStats();
-			else if (multiplayer)
-				WI_drawNetgameStats();
-			else
-				WI_drawStats();
-			break;
-	
-		case ShowNextLoc:
-			WI_drawShowNextLoc();
-			break;
-	
-		case LeavingIntermission:
-			break;
-
-		default:
-			WI_drawNoState();
-			break;
-		}
-	}
-
-
-	void WI_initVariables (wbstartstruct_t *wbstartstruct)
-	{
-		wbs = wbstartstruct;
-		acceleratestage = 0;
-		cnt = bcnt = 0;
-		me = wbs->pnum;
-		for (int i = 0; i < 8; i++) Plrs[i] = &wbs->plyr[i];
-	}
-
-	void WI_Start (wbstartstruct_t *wbstartstruct)
-	{
-		noautostartmap = false;
-		WI_initVariables (wbstartstruct);
-		WI_loadData ();
-		if (deathmatch)
-			WI_initDeathmatchStats();
-		else if (multiplayer)
-			WI_initNetgameStats();
-		else
-			WI_initStats();
-	}
-};
-
 void WI_Ticker()
 {
 	if (WI_Screen)
 	{
-		WI_Screen->bg->updateAnimatedBack();
-		WI_Screen->WI_Ticker();
-	}
-}
-
-// Called by main loop,
-// draws the intermission directly into the screen buffer.
-void WI_Drawer()
-{
-	if (WI_Screen)
-	{
-		WI_Screen->WI_Drawer();
-		if (WI_Screen->state == LeavingIntermission)
+		IFVIRTUALPTRNAME(WI_Screen, "StatusScreen", Ticker)
 		{
-			WI_Screen->Destroy();
-			GC::DelSoftRoot(WI_Screen);
-			WI_Screen = nullptr;
+			VMValue self = WI_Screen;
+			GlobalVMStack.Call(func, &self, 1, nullptr, 0);
 		}
 	}
 }
 
+//====================================================================
+// 
+// Called by main loop,
+// draws the intermission directly into the screen buffer.
+//
+//====================================================================
+
+void WI_Drawer()
+{
+	if (WI_Screen)
+	{
+		IFVIRTUALPTRNAME(WI_Screen, "StatusScreen", Drawer)
+		{
+			VMValue self = WI_Screen;
+			GlobalVMStack.Call(func, &self, 1, nullptr, 0);
+
+			// The internal handling here is somewhat poor. After being set to 'LeavingIntermission'
+			// the screen is needed for one more draw operation so we cannot delete it right away but only here.
+			if (WI_Screen->IntVar("CurState") == LeavingIntermission)
+			{
+				WI_Screen->Destroy();
+				GC::DelSoftRoot(WI_Screen);
+				WI_Screen = nullptr;
+			}
+		}
+	}
+}
+
+//====================================================================
+// 
 // Setup for an intermission screen.
+//
+//====================================================================
+
 void WI_Start(wbstartstruct_t *wbstartstruct)
 {
-	WI_Screen = new DStatusScreen;
+	FName screenclass = deathmatch ? gameinfo.statusscreen_dm : multiplayer ? gameinfo.statusscreen_coop : gameinfo.statusscreen_single;
+	auto cls = PClass::FindClass(screenclass);
+
+	if (cls == nullptr || !cls->IsDescendantOf("StatusScreen"))
+	{
+		// Name was invalid - pick some working default.
+		Printf("Status screen class %s not found - reverting to default", screenclass.GetChars());
+		screenclass = deathmatch ? NAME_DeathmatchStatusScreen : multiplayer ? NAME_CoopStatusScreen : NAME_RavenStatusScreen;
+		cls = PClass::FindClass(screenclass);
+		if (cls == nullptr)
+		{
+			I_FatalError("Cannot create statis screen");
+		}
+	}
+	// Set up some global stuff that is always needed.
 	auto info = FindLevelInfo(wbstartstruct->next, false);
 	if (info == nullptr)
 	{
@@ -2187,11 +775,20 @@ void WI_Start(wbstartstruct_t *wbstartstruct)
 	V_SetBlend(0, 0, 0, 0);
 	S_StopAllChannels();
 	SN_StopAllSequences();
-
-	WI_Screen->WI_Start(wbstartstruct);
+	WI_Screen = cls->CreateNew();
+	IFVIRTUALPTRNAME(WI_Screen, "StatusScreen", Start)
+	{
+		VMValue val[2] = { WI_Screen, wbstartstruct };
+		GlobalVMStack.Call(func, val, 2, nullptr, 0);
+	}
 	GC::AddSoftRoot(WI_Screen);
 }
 
+//====================================================================
+// 
+//
+//
+//====================================================================
 
 DEFINE_ACTION_FUNCTION(DStatusScreen, GetPlayerWidths)
 {
@@ -2204,6 +801,12 @@ DEFINE_ACTION_FUNCTION(DStatusScreen, GetPlayerWidths)
 	return MIN(numret, 3);
 }
 
+//====================================================================
+// 
+//
+//
+//====================================================================
+
 DEFINE_ACTION_FUNCTION(DStatusScreen, GetRowColor)
 {
 	PARAM_PROLOGUE;
@@ -2212,6 +815,12 @@ DEFINE_ACTION_FUNCTION(DStatusScreen, GetRowColor)
 	ACTION_RETURN_INT(HU_GetRowColor(p, highlight));
 }
 
+//====================================================================
+// 
+//
+//
+//====================================================================
+
 DEFINE_ACTION_FUNCTION(DStatusScreen, GetSortedPlayers)
 {
 	PARAM_PROLOGUE;
@@ -2238,6 +847,11 @@ DEFINE_ACTION_FUNCTION(DStatusScreen, GetSortedPlayers)
 	return 0;
 }
 
+//====================================================================
+// 
+//
+//
+//====================================================================
 
 DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, skills);
 DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, sitems);
@@ -2263,42 +877,3 @@ DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, totaltime);
 DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, pnum);
 DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, plyr);
 
-IMPLEMENT_CLASS(DStatusScreen, false, false)
-DEFINE_FIELD(DStatusScreen, bg);
-DEFINE_FIELD(DStatusScreen, acceleratestage);
-DEFINE_FIELD(DStatusScreen, playerready);
-DEFINE_FIELD(DStatusScreen, me);
-DEFINE_FIELD(DStatusScreen, bcnt);
-DEFINE_FIELD_NAMED(DStatusScreen, state, CurState);
-DEFINE_FIELD(DStatusScreen, wbs);
-DEFINE_FIELD(DStatusScreen, Plrs);
-DEFINE_FIELD(DStatusScreen, cnt);			
-DEFINE_FIELD(DStatusScreen, cnt_kills);
-DEFINE_FIELD(DStatusScreen, cnt_items);
-DEFINE_FIELD(DStatusScreen, cnt_secret);
-DEFINE_FIELD(DStatusScreen, cnt_frags);
-DEFINE_FIELD(DStatusScreen, cnt_deaths);
-DEFINE_FIELD(DStatusScreen, cnt_time);
-DEFINE_FIELD(DStatusScreen, cnt_total_time);
-DEFINE_FIELD(DStatusScreen, cnt_par);
-DEFINE_FIELD(DStatusScreen, cnt_pause);
-DEFINE_FIELD(DStatusScreen, total_frags);
-DEFINE_FIELD(DStatusScreen, total_deaths);
-DEFINE_FIELD(DStatusScreen, noautostartmap);
-DEFINE_FIELD(DStatusScreen, dofrags);
-DEFINE_FIELD(DStatusScreen, ng_state);
-DEFINE_FIELD(DStatusScreen, shadowalpha);
-DEFINE_FIELD(DStatusScreen, mapname);
-DEFINE_FIELD(DStatusScreen, finished);
-DEFINE_FIELD(DStatusScreen, entering);
-DEFINE_FIELD(DStatusScreen, P_secret);
-DEFINE_FIELD(DStatusScreen, Kills);
-DEFINE_FIELD(DStatusScreen, Secret);
-DEFINE_FIELD(DStatusScreen, Items);
-DEFINE_FIELD(DStatusScreen, Timepic);
-DEFINE_FIELD(DStatusScreen, Par);
-DEFINE_FIELD(DStatusScreen, Sucks);
-DEFINE_FIELD(DStatusScreen, lnametexts);
-DEFINE_FIELD(DStatusScreen, snl_pointeron);
-DEFINE_FIELD(DStatusScreen, player_deaths);
-DEFINE_FIELD(DStatusScreen, sp_state);
diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt
index bf42fcbcd..4bff1283e 100644
--- a/wadsrc/static/mapinfo/chex.txt
+++ b/wadsrc/static/mapinfo/chex.txt
@@ -65,6 +65,9 @@ gameinfo
 	statscreen_mapnamefont = "BigFont"
 	statscreen_finishedpatch = "WIF"
 	statscreen_enteringpatch = "WIENTER"
+	statscreen_coop = "CoopStatusScreen"
+	statscreen_dm = "DeathmatchStatusScreen"
+	statscreen_single = "DoomStatusScreen"
 }
 
 DoomEdNums
diff --git a/wadsrc/static/mapinfo/doomcommon.txt b/wadsrc/static/mapinfo/doomcommon.txt
index ece243d14..f24095941 100644
--- a/wadsrc/static/mapinfo/doomcommon.txt
+++ b/wadsrc/static/mapinfo/doomcommon.txt
@@ -65,6 +65,9 @@ gameinfo
 	statscreen_mapnamefont = "BigFont"
 	statscreen_finishedpatch = "WIF"
 	statscreen_enteringpatch = "WIENTER"
+	statscreen_coop = "CoopStatusScreen"
+	statscreen_dm = "DeathmatchStatusScreen"
+	statscreen_single = "DoomStatusScreen"
 }
 
 spawnnums
diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt
index 5f822d870..361bf5cde 100644
--- a/wadsrc/static/mapinfo/heretic.txt
+++ b/wadsrc/static/mapinfo/heretic.txt
@@ -63,6 +63,9 @@ gameinfo
 	statscreen_mapnamefont = "BigFont"
 	statscreen_finishedfont = "SmallFont"
 	statscreen_enteringfont = "SmallFont"
+	statscreen_coop = "CoopStatusScreen"
+	statscreen_dm = "DeathmatchStatusScreen"
+	statscreen_single = "RavenStatusScreen"
 }
 
 DoomEdNums
diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt
index be9a6ef65..6b17df101 100644
--- a/wadsrc/static/mapinfo/hexen.txt
+++ b/wadsrc/static/mapinfo/hexen.txt
@@ -61,6 +61,9 @@ gameinfo
 	statscreen_mapnamefont = "BigFont"
 	statscreen_finishedfont = "SmallFont"
 	statscreen_enteringfont = "SmallFont"
+	statscreen_coop = "CoopStatusScreen"
+	statscreen_dm = "DeathmatchStatusScreen"
+	statscreen_single = "RavenStatusScreen"
 }
 
 DoomEdNums
diff --git a/wadsrc/static/mapinfo/strife.txt b/wadsrc/static/mapinfo/strife.txt
index 2536be848..17b8a1924 100644
--- a/wadsrc/static/mapinfo/strife.txt
+++ b/wadsrc/static/mapinfo/strife.txt
@@ -63,6 +63,9 @@ gameinfo
 	statscreen_mapnamefont = "BigFont"
 	statscreen_finishedfont = "BigFont", "white"
 	statscreen_enteringfont = "BigFont", "white"
+	statscreen_coop = "CoopStatusScreen"
+	statscreen_dm = "DeathmatchStatusScreen"
+	statscreen_single = "RavenStatusScreen"
 }
 
 DoomEdNums
diff --git a/wadsrc/static/zscript/statscreen/statscreen.txt b/wadsrc/static/zscript/statscreen/statscreen.txt
index 2fba79f33..ca2b479e2 100644
--- a/wadsrc/static/zscript/statscreen/statscreen.txt
+++ b/wadsrc/static/zscript/statscreen/statscreen.txt
@@ -37,7 +37,7 @@ struct PatchInfo play version("2.4")
 
 
 // Will be made a class later, but for now needs to mirror the internal version.
-class StatusScreen native play version("2.4")
+class StatusScreen abstract play version("2.4")
 {
 	enum EValues
 	{
@@ -75,55 +75,50 @@ class StatusScreen native play version("2.4")
 
 	const SHOWNEXTLOCDELAY = 4;			// in seconds
 
-	InterBackground 		bg;
-	native int				acceleratestage;	// used to accelerate or skip a stage
-	native bool				playerready[MAXPLAYERS];
-	native int				me;					// wbs.pnum
-	native int				bcnt;
-	native int				CurState;				// specifies current CurState
-	native wbstartstruct	wbs;				// contains information passed into intermission
-	native wbplayerstruct	Plrs[MAXPLAYERS];				// wbs.plyr[]
-	native int				cnt;				// used for general timing
-	native int				cnt_kills[MAXPLAYERS];
-	native int				cnt_items[MAXPLAYERS];
-	native int				cnt_secret[MAXPLAYERS];
-	native int				cnt_frags[MAXPLAYERS];
-	native int				cnt_deaths[MAXPLAYERS];
-	native int				cnt_time;
-	native int				cnt_total_time;
-	native int				cnt_par;
-	native int				cnt_pause;
-	native int				total_frags;
-	native int				total_deaths;
-	native bool				noautostartmap;
-	native int				dofrags;
-	native int				ng_state;
-	native float			shadowalpha;
+	InterBackground bg;
+	int				acceleratestage;	// used to accelerate or skip a stage
+	bool				playerready[MAXPLAYERS];
+	int				me;					// wbs.pnum
+	int				bcnt;
+	int				CurState;				// specifies current CurState
+	wbstartstruct	wbs;				// contains information passed into intermission
+	wbplayerstruct	Plrs[MAXPLAYERS];				// wbs.plyr[]
+	int				cnt;				// used for general timing
+	int				cnt_kills[MAXPLAYERS];
+	int				cnt_items[MAXPLAYERS];
+	int				cnt_secret[MAXPLAYERS];
+	int				cnt_frags[MAXPLAYERS];
+	int				cnt_deaths[MAXPLAYERS];
+	int				cnt_time;
+	int				cnt_total_time;
+	int				cnt_par;
+	int				cnt_pause;
+	int				total_frags;
+	int				total_deaths;
+	bool			noautostartmap;
+	int				dofrags;
+	int				ng_state;
+	float			shadowalpha;
 
-	//
-	//		GRAPHICS
-	//
+	PatchInfo 		mapname;
+	PatchInfo 		finished;
+	PatchInfo 		entering;
 
-	native PatchInfo mapname;
-	native PatchInfo finished;
-	native PatchInfo entering;
-
-	native TextureID 		p_secret;
-	native TextureID 		kills;
-	native TextureID 		secret;
-	native TextureID 		items;
-	native TextureID 		timepic;
-	native TextureID 		par;
-	native TextureID 		sucks;
+	TextureID 		p_secret;
+	TextureID 		kills;
+	TextureID 		secret;
+	TextureID 		items;
+	TextureID 		timepic;
+	TextureID 		par;
+	TextureID 		sucks;
 
 	// [RH] Info to dynamically generate the level name graphics
-	native String			lnametexts[2];
+	String			lnametexts[2];
 
+	bool 			snl_pointeron;
 
-	native bool snl_pointeron;
-
-	native int player_deaths[MAXPLAYERS];
-	native int  sp_state;
+	int 			player_deaths[MAXPLAYERS];
+	int  			sp_state;
 
 
 	//====================================================================
@@ -660,7 +655,7 @@ class StatusScreen native play version("2.4")
 			break;
 		}
 	}
-
+	
 	//====================================================================
 	//
 	//
@@ -672,6 +667,8 @@ class StatusScreen native play version("2.4")
 		switch (CurState)
 		{
 		case StatCount:
+			// draw animated background
+			bg.drawBackground(CurState, false, false);
 			drawStats();
 			break;
 	
@@ -717,10 +714,10 @@ class StatusScreen native play version("2.4")
 
 		// Use the local level structure which can be overridden by hubs
 		lnametexts[0] = level.LevelName;		
-		lnametexts[1] = wbs.nextname;
+		lnametexts[1] = wbstartstruct.nextname;
 
 		bg = InterBackground.Create(wbs);
-
+		bg.LoadBackground(false);
 		initStats();
 	}
 	
@@ -729,7 +726,7 @@ class StatusScreen native play version("2.4")
 	protected virtual void updateStats() {}
 	protected virtual void drawStats() {}
 
-	native int, int, int GetPlayerWidths();
-	native Color GetRowColor(PlayerInfo player, bool highlight);
-	native void GetSortedPlayers(in out Array<int> sorted, bool teamplay);
+	native static int, int, int GetPlayerWidths();
+	native static Color GetRowColor(PlayerInfo player, bool highlight);
+	native static void GetSortedPlayers(in out Array<int> sorted, bool teamplay);
 }
diff --git a/wadsrc/static/zscript/statscreen/statscreen_coop.txt b/wadsrc/static/zscript/statscreen/statscreen_coop.txt
index 1d8cae370..a38d924a2 100644
--- a/wadsrc/static/zscript/statscreen/statscreen_coop.txt
+++ b/wadsrc/static/zscript/statscreen/statscreen_coop.txt
@@ -215,19 +215,14 @@ class CoopStatusScreen : StatusScreen
 		String text_bonus, text_secret, text_kills;
 		TextureID readyico = TexMan.CheckForTexture("READYICO", TexMan.Type_MiscPatch);
 
-		// draw animated background
-		bg.drawBackground(CurState, false, false); 
-
 		y = drawLF();
 
 		[maxnamewidth, maxscorewidth, maxiconheight] = GetPlayerWidths();
 		// Use the readyico height if it's bigger.
 		Vector2 readysize = TexMan.GetScaledSize(readyico);
 		Vector2 readyoffset = TexMan.GetScaledOffset(readyico);
-		if (readysize.Y > maxiconheight)
-		{
-			maxiconheight = height;
-		}
+		height = readysize.Y - readyoffset.Y;
+		maxiconheight = MAX(height, maxiconheight);
 		height = SmallFont.GetHeight() * CleanYfac;
 		lineheight = MAX(height, maxiconheight * CleanYfac);
 		ypadding = (lineheight - height + 1) / 2;
diff --git a/wadsrc/static/zscript/statscreen/statscreen_dm.txt b/wadsrc/static/zscript/statscreen/statscreen_dm.txt
index 1697e959b..430c5f4ce 100644
--- a/wadsrc/static/zscript/statscreen/statscreen_dm.txt
+++ b/wadsrc/static/zscript/statscreen/statscreen_dm.txt
@@ -152,9 +152,6 @@ class DeathmatchStatusScreen : StatusScreen
 		String text_deaths, text_frags;
 		TextureID readyico = TexMan.CheckForTexture("READYICO", TexMan.Type_MiscPatch);
 
-		// draw animated background
-		bg.drawBackground(CurState, false, false);
-
 		y = drawLF();
 
 		[maxnamewidth, maxscorewidth, maxiconheight] = GetPlayerWidths();
diff --git a/wadsrc/static/zscript/statscreen/statscreen_sp.txt b/wadsrc/static/zscript/statscreen/statscreen_sp.txt
index 284560307..2f6c23bcb 100644
--- a/wadsrc/static/zscript/statscreen/statscreen_sp.txt
+++ b/wadsrc/static/zscript/statscreen/statscreen_sp.txt
@@ -135,9 +135,6 @@ class DoomStatusScreen : StatusScreen
 		// line height
 		int lh = IntermissionFont.GetHeight() * 3 / 2;
 
-		// draw animated background
-		bg.drawBackground(CurState, false, false);
-
 		drawLF();
 	
 		screen.DrawTexture (Kills, true, SP_STATSX, SP_STATSY, DTA_Clean, true);
@@ -171,9 +168,6 @@ class RavenStatusScreen : DoomStatusScreen
 		// line height
 		int lh = IntermissionFont.GetHeight() * 3 / 2;
 
-		// draw animated background
-		bg.drawBackground(CurState, false, false);
-
 		drawLF();
 	
 		screen.DrawText (BigFont, Font.CR_UNTRANSLATED, 50, 65, Stringtable.Localize("$TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true);