diff --git a/src/m_menu.c b/src/m_menu.c
index a866654a452107305dfd3f9669dd10e4b75fc96f..a6d4d8b63f4d2a90741d9a41316908fcb3db17a3 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -4957,22 +4957,6 @@ static void M_DrawCenteredMenu(void)
 	}
 }
 
-//
-// M_StringHeight
-//
-// Find string height from hu_font chars
-//
-static inline size_t M_StringHeight(const char *string)
-{
-	size_t h = 8, i;
-
-	for (i = 0; i < strlen(string); i++)
-		if (string[i] == '\n')
-			h += 8;
-
-	return h;
-}
-
 // ==========================================================================
 // Extraneous menu patching functions
 // ==========================================================================
@@ -6099,56 +6083,16 @@ menu_t MessageDef =
 	NULL
 };
 
-
-void M_StartMessage(const char *string, void *routine,
-	menumessagetype_t itemtype)
+void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype)
 {
-	size_t max = 0, start = 0, i, strlines;
-	static char *message = NULL;
+	static char *message;
 	Z_Free(message);
-	message = Z_StrDup(string);
+	message = V_WordWrap(0,0,V_ALLOWLOWERCASE,string);
 	DEBFILE(message);
 
-	// Rudementary word wrapping.
-	// Simple and effective. Does not handle nonuniform letter sizes, colors, etc. but who cares.
-	strlines = 0;
-	for (i = 0; message[i]; i++)
-	{
-		if (message[i] == ' ')
-		{
-			start = i;
-			max += 4;
-		}
-		else if (message[i] == '\n')
-		{
-			strlines = i;
-			start = 0;
-			max = 0;
-			continue;
-		}
-		else
-			max += 8;
-
-		// Start trying to wrap if presumed length exceeds the screen width.
-		if (max >= BASEVIDWIDTH && start > 0)
-		{
-			message[start] = '\n';
-			max -= (start-strlines)*8;
-			strlines = start;
-			start = 0;
-		}
-	}
-
-	start = 0;
-	max = 0;
-
 	M_StartControlPanel(); // can't put menuactive to true
 
-	if (currentMenu == &MessageDef) // Prevent recursion
-		MessageDef.prevMenu = &MainDef;
-	else
-		MessageDef.prevMenu = currentMenu;
-
+	MessageDef.prevMenu = (currentMenu == &MessageDef) ? &MainDef : currentMenu; // Prevent recursion
 	MessageDef.menuitems[0].text     = message;
 	MessageDef.menuitems[0].alphaKey = (UINT8)itemtype;
 	if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING;
@@ -6167,51 +6111,17 @@ void M_StartMessage(const char *string, void *routine,
 			MessageDef.menuitems[0].itemaction = routine;
 			break;
 	}
-	//added : 06-02-98: now draw a textbox around the message
-	// compute lenght max and the numbers of lines
-	for (strlines = 0; *(message+start); strlines++)
-	{
-		for (i = 0;i < strlen(message+start);i++)
-		{
-			if (*(message+start+i) == '\n')
-			{
-				if (i > max)
-					max = i;
-				start += i;
-				i = (size_t)-1; //added : 07-02-98 : damned!
-				start++;
-				break;
-			}
-		}
-
-		if (i == strlen(message+start))
-			start += i;
-	}
-
-	MessageDef.x = (INT16)((BASEVIDWIDTH  - 8*max-16)/2);
-	MessageDef.y = (INT16)((BASEVIDHEIGHT - M_StringHeight(message))/2);
+	MessageDef.x = (INT16)((BASEVIDWIDTH  - V_StringWidth(message, 0)-32)/2);
+	MessageDef.y = (INT16)((BASEVIDHEIGHT - V_StringHeight(message, V_RETURN8))/2);
 
-	MessageDef.lastOn = (INT16)((strlines<<8)+max);
-
-	//M_SetupNextMenu();
 	currentMenu = &MessageDef;
 	itemOn = 0;
 }
 
-#define MAXMSGLINELEN 256
-
 static void M_DrawMessageMenu(void)
 {
-	INT32 y = currentMenu->y;
-	size_t i, start = 0;
-	INT16 max;
-	char string[MAXMSGLINELEN];
-	INT32 mlines;
 	const char *msg = currentMenu->menuitems[0].text;
 
-	mlines = currentMenu->lastOn>>8;
-	max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8);
-
 	// hack: draw RA background in RA menus
 	if (gamestate == GS_TIMEATTACK)
 	{
@@ -6235,51 +6145,8 @@ static void M_DrawMessageMenu(void)
 			V_DrawFadeScreen(0xFF00, curfadevalue);
 	}
 
-	M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines);
-
-	while (*(msg+start))
-	{
-		size_t len = strlen(msg+start);
-
-		for (i = 0; i < len; i++)
-		{
-			if (*(msg+start+i) == '\n')
-			{
-				memset(string, 0, MAXMSGLINELEN);
-				if (i >= MAXMSGLINELEN)
-				{
-					CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg);
-					return;
-				}
-				else
-				{
-					strncpy(string,msg+start, i);
-					string[i] = '\0';
-					start += i;
-					i = (size_t)-1; //added : 07-02-98 : damned!
-					start++;
-				}
-				break;
-			}
-		}
-
-		if (i == strlen(msg+start))
-		{
-			if (i >= MAXMSGLINELEN)
-			{
-				CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg);
-				return;
-			}
-			else
-			{
-				strcpy(string, msg + start);
-				start += i;
-			}
-		}
-
-		V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2,y,V_ALLOWLOWERCASE,string);
-		y += 8; //hu_font.chars[0]->height;
-	}
+	M_DrawTextBox(currentMenu->x, currentMenu->y - 8, 2+V_StringWidth(msg, 0)/8, V_StringHeight(msg, V_RETURN8)/8);
+	V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, V_ALLOWLOWERCASE|V_RETURN8, msg);
 }
 
 // default message handler
diff --git a/src/v_video.c b/src/v_video.c
index a9fbceb3d49a19ca99ac354e1cd0832884544777..922b7f7d4aa42e7d16a0d7dffb2e01c74b2b33b6 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -1990,10 +1990,7 @@ void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fi
 
 	flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK);
 	c &= 0x7f;
-	if (lowercaseallowed)
-		c -= FONTSTART;
-	else
-		c = toupper(c) - FONTSTART;
+	c = (lowercaseallowed ? c : toupper(c)) - FONTSTART;
 	if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		return;
 
@@ -2009,8 +2006,7 @@ void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fi
 char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *string, fontdef_t font)
 {
 	int c;
-	size_t chw, i, lastusablespace = 0;
-	size_t slen;
+	size_t slen, chw, i, lastusablespace = 0;
 	char *newstring = Z_StrDup(string);
 	INT32 spacewidth = font.spacewidth, charwidth = 0;
 
@@ -2048,10 +2044,7 @@ char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *
 			continue;
 		}
 
-		if (!(option & V_ALLOWLOWERCASE))
-			c = toupper(c);
-		c -= FONTSTART;
-
+		c = (option & V_ALLOWLOWERCASE ? c : toupper(c)) - FONTSTART;
 		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		{
 			chw = spacewidth;
@@ -2148,20 +2141,11 @@ void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale,
 		if (*ch == '\n')
 		{
 			cx = x;
-
-			if (option & V_RETURN8)
-				cy += FixedMul((8<<FRACBITS), dupy);
-			else
-				cy += FixedMul((font.linespacing<<FRACBITS), dupy);
-
+			cy += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, dupy);
 			continue;
 		}
 
-		c = *ch;
-		if (!lowercase)
-			c = toupper(c);
-		c -= FONTSTART;
-
+		c = (lowercase ? *ch : toupper(*ch)) - FONTSTART;
 		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 		{
 			cx += FixedMul((spacewidth<<FRACBITS), dupx);
@@ -2190,16 +2174,58 @@ void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale,
 	}
 }
 
+#define MAXLINELEN 256
+void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, boolean center)
+{
+	char line[MAXLINELEN];
+	size_t i, start = 0;
+	fixed_t lx = x, ly = y;
+
+	while (*(string+start))
+	{
+		for (i = 0; i < strlen(string+start); i++)
+		{
+			if (*(string+start+i) == '\n')
+			{
+				memset(line, 0, MAXLINELEN);
+				if (i >= MAXLINELEN) 
+				{
+					CONS_Printf("V_DrawAlignedFontStringAtFixed: a line exceeds max. length %d (string: %s)\n", MAXLINELEN, string);
+					return;
+				}
+				strncpy(line,string + start, i);
+				line[i] = '\0';
+				start += i + 1;
+				i = (size_t)-1; //added : 07-02-98 : damned!
+				break;
+			}
+		}
+
+		if (i == strlen(string + start))
+		{
+			if (i >= MAXLINELEN) 
+			{
+				CONS_Printf("V_DrawAlignedFontStringAtFixed: a line exceeds max. length %d (string: %s)\n", MAXLINELEN, string);
+				return;
+			}
+			strcpy(line, string + start);
+			start += i;
+		}
+
+		lx = x - (V_FontStringWidth(line, option, font)*pscale) / (center ? 2 : 1);
+		V_DrawFontStringAtFixed(lx, ly, option, pscale, vscale, line, font);
+		ly += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, vscale);
+	}
+}
+
 void V_DrawCenteredFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font)
 {
-	x -= (V_FontStringWidth(string, option, font)*pscale)/2;
-	V_DrawFontStringAtFixed(x, y, option, pscale, vscale, string, font);
+	V_DrawAlignedFontStringAtFixed(x, y, option, pscale, vscale, string, font, true);
 }
 
 void V_DrawRightAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font)
 {
-	x -= V_FontStringWidth(string, option, font)*pscale;
-	V_DrawFontStringAtFixed(x, y, option, pscale, vscale, string, font);
+	V_DrawAlignedFontStringAtFixed(x, y, option, pscale, vscale, string, font, false);
 }
 
 // Draws a tallnum.  Replaces two functions in y_inter and st_stuff
@@ -2324,10 +2350,7 @@ static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UIN
 			continue;
 		}
 
-		c = toupper(*ch);
-		c -= FONTSTART;
-
-		// character does not exist or is a space
+		c = toupper(*ch) - FONTSTART;
 		if (c < 0 || c >= FONTSIZE || !ntb_font.chars[c] || !nto_font.chars[c])
 		{
 			cx += FixedMul((ntb_font.spacewidth * dupx)*FRACUNIT, scale);
@@ -2464,9 +2487,8 @@ INT32 V_CountNameTagLines(const char *string)
 //
 INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
 {
-	INT32 c, w = 0;
+	INT32 c, w = 0, wline = 0;
 	INT32 spacewidth = font.spacewidth, charwidth = 0;
-	size_t i;
 
 	switch (option & V_SPACINGMASK)
 	{
@@ -2482,16 +2504,24 @@ INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
 			break;
 	}
 
-	for (i = 0; i < strlen(string); i++)
+	for (size_t i = 0; i < strlen(string); i++)
 	{
+		if (string[i] == '\n')
+		{
+			if (wline < w) wline = w;
+			w = 0;
+			continue;
+		}	
 		if (string[i] & 0x80)
 			continue;
-		c = ((option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART);
+
+		c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART;
 		if (c < 0 || c >= FONTSIZE || !font.chars[c])
 			w += spacewidth;
 		else
 			w += (charwidth ? charwidth : (font.chars[c]->width)) + font.kerning;
 	}
+	w = max(wline, w);
 
 	if (option & (V_NOSCALESTART|V_NOSCALEPATCH))
 		w *= vid.dupx;
@@ -2501,22 +2531,28 @@ INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
 
 // Find max string height from supplied font characters
 //
-INT32 V_FontStringHeight(const char *string, fontdef_t font)
+INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font)
 {
-	INT32 c, h = 0;
-	size_t i;
+	INT32 c, h = 0, result = 0;
 
-	for (i = 0; i < strlen(string); i++)
+	for (size_t i = 0; i < strlen(string); i++)
 	{
-		c = string[i] - FONTSTART;
+		c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART;
 		if (c < 0 || c >= FONTSIZE || !font.chars[c])
+		{
+			if (string[i] == '\n')
+			{
+				result += (option & V_RETURN8) ? 8 : font.linespacing;
+				h = 0;
+			}	
 			continue;
+		}
 
 		if (font.chars[c]->height > h)
 			h = font.chars[c]->height;
 	}
 
-	return h;
+	return result + h;
 }
 
 boolean *heatshifter = NULL;
diff --git a/src/v_video.h b/src/v_video.h
index 0a5bbfc5190a1d53bf58a1e270325c770263fd9e..83a911db6d729967835d62c665a65d923932e8c7 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -213,6 +213,7 @@ void V_DrawCenteredFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fi
 void V_DrawRightAlignedFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
 // Draw a string, using a supplied font and scale, at fixed_t coordinates.
 void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
+void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, boolean center);
 void V_DrawCenteredFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
 void V_DrawRightAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
 
@@ -266,7 +267,7 @@ INT32 V_CountNameTagLines(const char *string);
 
 // Find string width or height from supplied font chars
 INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font);
-INT32 V_FontStringHeight(const char *string, fontdef_t font);
+INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font);
 
 // Defines for old string width functions.
 #define V_StringWidth(str,o) V_FontStringWidth(str,o,hu_font)
@@ -276,7 +277,8 @@ INT32 V_FontStringHeight(const char *string, fontdef_t font);
 #define V_CreditStringWidth(str) V_FontStringWidth(str,0,cred_font)
 #define V_NameTagWidth(str) V_FontStringWidth(str,0,ntb_font)
 #define V_LevelNameWidth(str) V_FontStringWidth(str,V_ALLOWLOWERCASE,lt_font)
-#define V_LevelNameHeight(str) V_FontStringHeight(str,lt_font)
+#define V_LevelNameHeight(str) V_FontStringHeight(str,0,lt_font)
+#define V_StringHeight(str,o) V_FontStringHeight(str,o,hu_font)
 
 void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param);