From 92be91f416cb49fcdb85f544bf5e8eb2225758ec Mon Sep 17 00:00:00 2001
From: Shpoike <Shpoike@users.noreply.github.com>
Date: Wed, 15 Mar 2023 01:35:11 +0000
Subject: [PATCH] Prevent the user from selecting demoness when running base
 hexen2 to prevent a crash. Fixed visible menu markup too.

---
 engine/client/m_items.c | 47 ++++++++++++++++++++++++++++++++++++++---
 engine/client/m_multi.c | 20 +++++++++++++++++-
 engine/server/pr_cmds.c |  2 ++
 3 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/engine/client/m_items.c b/engine/client/m_items.c
index 5594a3b1a..5085c28e4 100644
--- a/engine/client/m_items.c
+++ b/engine/client/m_items.c
@@ -110,7 +110,8 @@ menuoption_t *M_NextSelectableItem(emenu_t *m, menuoption_t *old, qboolean wrap)
 //but we're lazy so we don't consider the next char. italic fonts are annoying like that. feel free to refudge it.
 void Draw_Hexen2BigFontString(int x, int y, const char *text)
 {
-	int c;
+	conchar_t *w, buffer[256];
+	unsigned int codeflags, oldflags=CON_WHITEMASK, c;
 	int sx, sy;
 	mpic_t *p;
 	p = R_RegisterShader ("gfx/menu/bigfont.lmp", SUF_2D,
@@ -144,9 +145,45 @@ void Draw_Hexen2BigFontString(int x, int y, const char *text)
 			p->defaulttextures->base = R_LoadHiResTexture("gfx/menu/bigfont.lmp", NULL, IF_PREMULTIPLYALPHA|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP);
 	}
 
-	while(*text)
+
+	COM_ParseFunString(oldflags, text, buffer, sizeof(buffer), false);
+
+	for (w = buffer; *w; )
 	{
-		c = *text++;
+		w = Font_Decode(w, &codeflags, &c);
+		if (codeflags & CON_HIDDEN)
+			continue;
+		if (c >= 0xe020 && c <= 0xe07f)
+			c &= 0x00ff; //convert to quake glyph to unicode/ascii...
+
+		if (codeflags != oldflags)
+		{
+			vec4_t rgba;
+			unsigned int col;
+			oldflags = codeflags;
+
+			col = (codeflags&CON_FGMASK)>>CON_FGSHIFT;
+			rgba[0] = consolecolours[col].fr;
+			rgba[1] = consolecolours[col].fg;
+			rgba[2] = consolecolours[col].fb;
+			if(codeflags & CON_HALFALPHA)
+				rgba[3] = 0.5;
+			else
+				rgba[3] = 1;
+			if (vid.flags&VID_SRGBAWARE)
+			{
+				rgba[0] = M_SRGBToLinear(rgba[0], 1);
+				rgba[1] = M_SRGBToLinear(rgba[1], 1);
+				rgba[2] = M_SRGBToLinear(rgba[2], 1);
+			}
+			if (codeflags & CON_BLINKTEXT)
+			{
+				float a = (sin(realtime*3)+1)*0.3 + 0.4;
+				VectorScale(rgba, a, rgba);
+			}
+			R2D_ImageColours(rgba[0], rgba[1], rgba[2], rgba[3]);
+		}
+
 		if (c >= 'a' && c <= 'z')
 		{
 			sx = ((c-'a')%8)*20;
@@ -197,6 +234,8 @@ void Draw_Hexen2BigFontString(int x, int y, const char *text)
 		default:	x+=20; break;
 		}
 	}
+
+	R2D_ImageColours(1, 1, 1, 1);
 }
 #endif
 
@@ -248,6 +287,8 @@ void Draw_BigFontString(int x, int y, const char *text)
 	for (w = buffer; *w; )
 	{
 		w = Font_Decode(w, &codeflags, &codepoint);
+		if (codeflags & CON_HIDDEN)
+			continue;
 		if (codepoint >= 0xe020 && codepoint <= 0xe07f)
 			codepoint &= 0x00ff; //convert to quake glyph to unicode/ascii...
 
diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c
index deb5bed6c..f9093fab0 100644
--- a/engine/client/m_multi.c
+++ b/engine/client/m_multi.c
@@ -500,6 +500,10 @@ void M_Menu_Setup_f (void)
 		};
 		cvar_t *pc = Cvar_Get("cl_playerclass", "1", CVAR_USERINFO|CVAR_ARCHIVE, "Hexen2");
 		(info->classedit = MC_AddCombo(menu, 64, 160, y, "Your class", (const char **)classnames, pc->ival-1)); y+= info->classedit->common.height;
+
+		//trim options if the artwork is missing.
+		while (info->classedit->numoptions && !COM_FCheckExists(va("gfx/menu/netp%i.lmp", info->classedit->numoptions)))
+			info->classedit->numoptions--;
 	}
 	else
 #endif
@@ -807,7 +811,21 @@ void M_Menu_GameOptions_f (void)
 	info->fraglimit		= MC_AddCombo	(menu, 64, 160, y,			"Frag Limit", (const char **)fraglimitoptions,		fraglimit.value/10);y+=8;
 	y+=8;
 
-	M_Menu_GameOptions_AddMap((mgt == MGT_QUAKE2)?"maps/base1":"maps/start", 0, 0, &mapopts, NULL);
+	//populate it with an appropriate default. its a shame it won't change with the deathmatch/coop options
+	switch(mgt)
+	{
+	case MGT_QUAKE2:
+		M_Menu_GameOptions_AddMap("maps/base1.bsp", 0, 0, &mapopts, NULL);
+		break;
+	case MGT_HEXEN2:
+		M_Menu_GameOptions_AddMap("maps/demo1.bsp", 0, 0, &mapopts, NULL);
+		break;
+	case MGT_QUAKE1:
+		M_Menu_GameOptions_AddMap("maps/start.bsp", 0, 0, &mapopts, NULL);
+		break;
+	default:
+		break;
+	}
 	COM_EnumerateFiles("maps/*.bsp",	M_Menu_GameOptions_AddMap, &mapopts);
 	COM_EnumerateFiles("maps/*.bsp.gz",	M_Menu_GameOptions_AddMap, &mapopts);
 	COM_EnumerateFiles("maps/*.bsp.xz",	M_Menu_GameOptions_AddMap, &mapopts);
diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c
index b8e3f7c16..0d6d5d094 100644
--- a/engine/server/pr_cmds.c
+++ b/engine/server/pr_cmds.c
@@ -8122,6 +8122,8 @@ void PRH2_SetPlayerClass(client_t *cl, int classnum, qboolean fromqc)
 		return; //reject it (it would crash the (standard hexen2) mod)
 	if (classnum > 5)
 		return;
+	while (classnum>1 && !COM_FCheckExists(va("gfx/menu/netp%i.lmp", classnum)))
+		classnum--;
 
 	if (!fromqc)
 	{