diff --git a/src/deh_soc.c b/src/deh_soc.c
index 49c6efee9b0118280b9e8d402d730aca3ce5101c..7b4b0ad172d05b8feeca41ddf99c33c3455ffe57 100644
--- a/src/deh_soc.c
+++ b/src/deh_soc.c
@@ -2255,17 +2255,12 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
 			{
 				if (*word2 != '\0')
 				{
-					size_t j;
+					char name[256];
 
-					// HACK: Add yellow control char now
-					// so the drawing function doesn't call it repeatedly
-					char name[34];
-					name[0] = '\x82'; // color yellow
-					name[1] = 0;
-					strlcat(name, word2, sizeof(name));
+					strlcpy(name, word2, sizeof(name));
 
 					// Replace _ with ' '
-					for (j = 1; j < sizeof(name) && name[j]; j++)
+					for (size_t j = 0; j < sizeof(name) && name[j]; j++)
 					{
 						if (name[j] == '_')
 							name[j] = ' ';
diff --git a/src/doomstat.h b/src/doomstat.h
index 6f95ed453355c8356b67114e729a1003ab0ce275..e8a475b6f8208f10a4b73757af637c91dc168def 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -249,7 +249,7 @@ typedef struct
 
 	char tag[33]; // page tag
 	char name[34]; // narrator name, extra char for color
-	char iconname[9]; // narrator icon lump
+	char iconname[256]; // narrator icon lump
 	boolean rightside; // narrator side, false = left, true = right
 	boolean iconflip; // narrator flip icon horizontally
 	UINT8 hidehud; // hide hud, 0 = show all, 1 = hide depending on prompt position (top/bottom), 2 = hide all
diff --git a/src/f_finale.c b/src/f_finale.c
index ac6b796b110c7f0ba74dfec7105749815789cdea..18cf097e7f6a34be6feceeea6e0aa31b59f694a6 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -209,6 +209,11 @@ static huddrawlist_h luahuddrawlist_title;
 
 static textwriter_t textwriter;
 
+static void F_ResetTextWriter(textwriter_t *writer, const char *basetext)
+{
+	P_ResetTextWriter(writer, basetext, strlen(basetext));
+}
+
 // =============
 //  INTRO SCENE
 // =============
@@ -414,7 +419,7 @@ void F_StartIntro(void)
 	gameaction = ga_nothing;
 	paused = false;
 	CON_ToggleOff();
-	P_ResetTextWriter(&textwriter, introtext[0]);
+	F_ResetTextWriter(&textwriter, introtext[0]);
 
 	intro_scenenum = 0;
 	finalecount = animtimer = stoptimer = 0;
@@ -847,7 +852,7 @@ void F_IntroTicker(void)
 			return;
 		}
 
-		P_ResetTextWriter(&textwriter, introtext[++intro_scenenum]);
+		F_ResetTextWriter(&textwriter, introtext[++intro_scenenum]);
 		timetonext = introscenetime[intro_scenenum];
 
 		F_WipeStartScreen();
@@ -3795,7 +3800,7 @@ static void F_AdvanceToNextScene(void)
 			scene->musswitchposition, 0, 0);
 
 	// Fade to the next
-	P_ResetTextWriter(&textwriter, scene->text);
+	F_ResetTextWriter(&textwriter, scene->text);
 
 	picnum = 0;
 	pic = &scene->pics[picnum];
@@ -3851,7 +3856,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
 	paused = false;
 	CON_ToggleOff();
 
-	P_ResetTextWriter(&textwriter, cutscenes[cutscenenum]->scene[0].text);
+	F_ResetTextWriter(&textwriter, cutscenes[cutscenenum]->scene[0].text);
 
 	cutsceneover = false;
 	runningprecutscene = precutscene;
diff --git a/src/p_dialog.c b/src/p_dialog.c
index cecfba13c7ad409dd5a9609e1c0a5a2866ec64ce..6239c24e5334da90bfabe2dd1ba5a1009c9c0de3 100644
--- a/src/p_dialog.c
+++ b/src/p_dialog.c
@@ -118,9 +118,10 @@ UINT8 P_CutsceneWriteText(textwriter_t *writer)
 	return 1;
 }
 
-void P_ResetTextWriter(textwriter_t *writer, const char *basetext)
+void P_ResetTextWriter(textwriter_t *writer, const char *basetext, size_t basetextlength)
 {
 	writer->basetext = basetext;
+	writer->basetextlength = basetextlength;
 	writer->writeptr = writer->baseptr = 0;
 	writer->textspeed = 9;
 	writer->textcount = TICRATE/2;
@@ -229,14 +230,17 @@ typedef struct
 
 static void F_GetPageTextGeometry(dialog_t *dialog, dialog_geometry_t *geo)
 {
-	lumpnum_t iconlump = W_CheckNumForName(dialog->page->iconname);
+	lumpnum_t iconlump = LUMPERROR;
+
+	if (dialog->icon[0])
+		iconlump = W_CheckNumForLongName(dialog->icon);
 
 	INT32 pagelines = dialog->page->lines ? dialog->page->lines : 4;
-	boolean rightside = (iconlump != LUMPERROR && dialog->page->rightside);
+	boolean rightside = iconlump != LUMPERROR && dialog->page->rightside;
 
 	// Vertical calculations
 	INT32 boxh = pagelines*2;
-	INT32 texth = dialog->page->name[0] ? (pagelines-1)*2 : pagelines*2; // name takes up first line if it exists
+	INT32 texth = dialog->speaker[0] ? (pagelines-1)*2 : pagelines*2; // name takes up first line if it exists
 	INT32 namey = BASEVIDHEIGHT - ((boxh * 4) + (boxh/2)*4);
 
 	geo->texty = BASEVIDHEIGHT - ((texth * 4) + (texth/2)*4);
@@ -390,6 +394,18 @@ void P_SetPicsMetaPage(textpage_t *page, textpage_t *metapage)
 	memcpy(page->pics, metapage->pics, sizeof(cutscene_pic_t) * page->numpics);
 }
 
+static void P_SetDialogSpeaker(dialog_t *dialog, const char *speaker)
+{
+	char name[256];
+
+	// Add yellow control char
+	name[0] = '\x82';
+	name[1] = 0;
+
+	strlcat(name, speaker, sizeof(name));
+	strlcpy(dialog->speaker, name, sizeof(dialog->speaker));
+}
+
 #define READ_NUM(where) { \
 	int temp = 0; \
 	temp |= (*code) << 24; code++; \
@@ -399,32 +415,66 @@ void P_SetPicsMetaPage(textpage_t *page, textpage_t *metapage)
 	where = temp; \
 }
 
+static char *BytecodeReadString(const UINT8 **code)
+{
+	const UINT8 *c = *code;
+	UINT8 sz = *c++;
+	if (!sz)
+		return NULL;
+	char *str = Z_Malloc(sz + 1, PU_STATIC, NULL);
+	char *str_p = str;
+	while (sz--)
+		*str_p++ = *c++;
+	*str_p = '\0';
+	*code = c;
+	return str;
+}
+
 // Dialog control codes
 enum
 {
 	TP_OP_SPEED,
 	TP_OP_DELAY,
 
+	TP_OP_NAME,
+	TP_OP_ICON,
+
 	TP_OP_CONTROL = 0xFF
 };
 
 static const UINT8 *InterpretBytecode(const UINT8 *code, dialog_t *dialog, textwriter_t *writer)
 {
-	(void)dialog;
-
 	int num = 0;
 
 	switch (*code++)
 	{
-	case TP_OP_SPEED:
-		READ_NUM(num);
-		writer->textspeed = num;
-		break;
-	case TP_OP_DELAY:
-		READ_NUM(num);
-		writer->textcount = num;
-		writer->numtowrite = 0;
-		break;
+		case TP_OP_SPEED:
+			READ_NUM(num);
+			writer->textspeed = num;
+			break;
+		case TP_OP_DELAY:
+			READ_NUM(num);
+			writer->textcount = num;
+			writer->numtowrite = 0;
+			break;
+		case TP_OP_NAME: {
+			char *speaker = BytecodeReadString(&code);
+			if (speaker)
+			{
+				P_SetDialogSpeaker(dialog, speaker);
+				Z_Free(speaker);
+			}
+			break;
+		}
+		case TP_OP_ICON: {
+			char *icon = BytecodeReadString(&code);
+			if (icon)
+			{
+				strlcpy(dialog->icon, icon, sizeof(dialog->icon));
+				Z_Free(icon);
+			}
+			break;
+		}
 	}
 
 	return code;
@@ -436,10 +486,16 @@ static int SkipBytecode(const UINT8 *code)
 
 	switch (*code++)
 	{
-	case TP_OP_SPEED:
-	case TP_OP_DELAY:
-		code += 4;
-		break;
+		case TP_OP_SPEED:
+		case TP_OP_DELAY:
+			code += 4;
+			break;
+		case TP_OP_NAME:
+		case TP_OP_ICON: {
+			UINT8 n = *code++;
+			code += n;
+			break;
+		}
 	}
 
 	return code - baseptr;
@@ -481,10 +537,10 @@ enum
 static UINT8 P_DialogWriteText(dialog_t *dialog, textwriter_t *writer)
 {
 	const UINT8 *baseptr = (const UINT8*)writer->basetext;
-	if (!baseptr)
+	if (!baseptr || writer->baseptr >= writer->basetextlength)
 		return DIALOG_WRITETEXT_DONE;
 
-	UINT8 lastchar = 0;
+	UINT8 lastchar = '\0';
 
 	writer->numtowrite = 1;
 
@@ -500,21 +556,18 @@ static UINT8 P_DialogWriteText(dialog_t *dialog, textwriter_t *writer)
 			writer->numtowrite = 8 - writer->textspeed;
 	}
 
-	while (true)
+	while (writer->numtowrite > 0)
 	{
-		if (writer->numtowrite <= 0)
-			break;
-
 		const UINT8 *c = &baseptr[writer->baseptr];
 		if (!*c)
 			return DIALOG_WRITETEXT_DONE;
 
 		const UINT8 *code = (const UINT8*)c;
-
 		if (*code == TP_OP_CONTROL)
 		{
 			code = InterpretBytecode(code + 1, dialog, writer);
 			writer->baseptr = code - baseptr;
+			lastchar = '\0';
 			continue;
 		}
 
@@ -523,7 +576,11 @@ static UINT8 P_DialogWriteText(dialog_t *dialog, textwriter_t *writer)
 		writer->writeptr++;
 		writer->baseptr++;
 
-		// Ignore other control codes (color)
+		if (writer->numtowrite <= 0)
+			break;
+
+		// Ignore non-printable characters
+		// (that is, decrement numtowrite if this character is printable.)
 		if (lastchar < 0x80)
 			--writer->numtowrite;
 	}
@@ -537,7 +594,7 @@ static UINT8 P_DialogWriteText(dialog_t *dialog, textwriter_t *writer)
 			writer->textcount = writer->textspeed - 7;
 	}
 
-	if (!lastchar || isspace(lastchar))
+	if (lastchar == '\0' || isspace(lastchar))
 		return DIALOG_WRITETEXT_SILENT;
 	else
 		return DIALOG_WRITETEXT_TALK;
@@ -554,17 +611,21 @@ static void P_DialogSetDisplayText(dialog_t *dialog)
 	V_WordWrapInPlace(geo.textx, geo.textr, 0, dialog->disptext);
 }
 
-void P_DialogSetText(dialog_t *dialog, char *pagetext, size_t textlength, INT32 numchars)
+static char *P_ProcessPageText(char *pagetext, size_t textlength, size_t *outlength)
+{
+	*outlength = textlength;
+	char *buf = Z_Calloc(textlength + 1, PU_STATIC, NULL);
+	memcpy(buf, pagetext, textlength);
+	buf[textlength] = '\0';
+	return buf;
+}
+
+void P_DialogSetText(dialog_t *dialog, char *pagetext, size_t textlength)
 {
 	Z_Free(dialog->pagetext);
 
 	if (pagetext && pagetext[0])
-	{
-		dialog->pagetextlength = textlength;
-		dialog->pagetext = Z_Calloc(textlength + 1, PU_STATIC, NULL);
-		memcpy(dialog->pagetext, pagetext, textlength);
-		dialog->pagetext[textlength] = '\0';
-	}
+		dialog->pagetext = P_ProcessPageText(pagetext, textlength, &dialog->pagetextlength);
 	else
 	{
 		dialog->pagetextlength = 0;
@@ -577,37 +638,24 @@ void P_DialogSetText(dialog_t *dialog, char *pagetext, size_t textlength, INT32
 
 	textwriter_t *writer = &dialog->writer;
 
-	P_ResetTextWriter(writer, dialog->pagetext);
+	P_ResetTextWriter(writer, dialog->pagetext, dialog->pagetextlength);
 
 	writer->textspeed = dialog->page->textspeed ? dialog->page->textspeed : TICRATE/5;
 	writer->textcount = 0; // no delay in beginning
 	writer->boostspeed = false; // don't print 8 characters to start
 
 	P_DialogSetDisplayText(dialog);
-
-	if (numchars <= 0)
-		return;
-
-	while (writer->writeptr < numchars)
-	{
-		P_DialogWriteText(dialog, writer);
-
-		const char *c = &writer->basetext[writer->baseptr];
-
-		if (!*c)
-			break;
-	}
 }
 
 static void P_PreparePageText(dialog_t *dialog, char *pagetext, size_t textlength)
 {
-	P_DialogSetText(dialog, pagetext, textlength, 0);
+	P_DialogSetText(dialog, pagetext, textlength);
 
 	// \todo update control hot strings on re-config
 	// and somehow don't reset cutscene text counters
 }
 
-static void P_DialogStartPage(dialog_t *dialog)
+static void P_DialogStartPage(player_t *player, dialog_t *dialog)
 {
 	P_PreparePageText(dialog, dialog->page->text, dialog->page->textlength);
 
@@ -658,18 +706,28 @@ static void P_DialogStartPage(dialog_t *dialog)
 		dialog->picmode = 0;
 	}
 
+	// Set up narrator
+	P_SetDialogSpeaker(dialog, dialog->page->name);
+
+	strlcpy(dialog->icon, dialog->page->iconname, sizeof(dialog->icon));
+
+	dialog->iconflip = dialog->page->iconflip;
+
 	// music change
-	if (dialog->page->musswitch[0])
+	if (P_IsLocalPlayer(player) || globaltextprompt)
 	{
-		S_ChangeMusic(dialog->page->musswitch,
-			dialog->page->musswitchflags,
-			dialog->page->musicloop);
-	}
-	else if (dialog->page->restoremusic)
-	{
-		S_ChangeMusic(mapheaderinfo[gamemap-1]->musname,
-			mapheaderinfo[gamemap-1]->mustrack,
-			true);
+		if (dialog->page->musswitch[0])
+		{
+			S_ChangeMusic(dialog->page->musswitch,
+				dialog->page->musswitchflags,
+				dialog->page->musicloop);
+		}
+		else if (dialog->page->restoremusic)
+		{
+			S_ChangeMusic(mapheaderinfo[gamemap-1]->musname,
+				mapheaderinfo[gamemap-1]->mustrack,
+				true);
+		}
 	}
 }
 
@@ -735,7 +793,7 @@ static boolean P_LoadNextPageAndPrompt(player_t *player, dialog_t *dialog, INT32
 		return false;
 	}
 
-	P_DialogStartPage(dialog);
+	P_DialogStartPage(player, dialog);
 
 	return true;
 }
@@ -1009,7 +1067,7 @@ void P_StartTextPrompt(player_t *player, INT32 promptnum, INT32 pagenum, UINT16
 		dialog->prompt = textprompts[dialog->promptnum];
 		dialog->page = &dialog->prompt->page[dialog->pagenum];
 
-		P_DialogStartPage(dialog);
+		P_DialogStartPage(player, dialog);
 	}
 	else
 	{
@@ -1216,7 +1274,7 @@ void F_TextPromptDrawer(void)
 	if (!dialog)
 		return;
 
-	lumpnum_t iconlump;
+	lumpnum_t iconlump = LUMPERROR;
 	dialog_geometry_t geo;
 
 	INT32 draw_flags = V_PERPLAYER;
@@ -1225,7 +1283,6 @@ void F_TextPromptDrawer(void)
 	// Data
 	patch_t *patch;
 
-	iconlump = W_CheckNumForName(dialog->page->iconname);
 	F_GetPageTextGeometry(dialog, &geo);
 
 	boolean rightside = geo.rightside;
@@ -1250,10 +1307,13 @@ void F_TextPromptDrawer(void)
 	V_DrawPromptBack(boxh, dialog->page->backcolor, draw_flags|snap_flags);
 
 	// Draw narrator icon
+	if (dialog->icon[0])
+		iconlump = W_CheckNumForLongName(dialog->icon);
+
 	if (iconlump != LUMPERROR)
 	{
 		INT32 iconx, icony, scale, scaledsize;
-		patch = W_CachePatchLongName(dialog->page->iconname, PU_PATCH_LOWPRIORITY);
+		patch = W_CachePatchLongName(dialog->icon, PU_PATCH_LOWPRIORITY);
 
 		// scale and center
 		if (patch->width > patch->height)
@@ -1278,10 +1338,10 @@ void F_TextPromptDrawer(void)
 			icony = namey << FRACBITS;
 		}
 
-		if (dialog->page->iconflip)
+		if (dialog->iconflip)
 			iconx += FixedMul(patch->width, scale) << FRACBITS;
 
-		V_DrawFixedPatch(iconx, icony, scale, (draw_flags|snap_flags|(dialog->page->iconflip ? V_FLIP : 0)), patch, NULL);
+		V_DrawFixedPatch(iconx, icony, scale, (draw_flags|snap_flags|(dialog->iconflip ? V_FLIP : 0)), patch, NULL);
 		W_UnlockCachedPatch(patch);
 	}
 
@@ -1291,8 +1351,8 @@ void F_TextPromptDrawer(void)
 
 	// Draw name
 	// Don't use V_YELLOWMAP here so that the name color can be changed with control codes
-	if (dialog->page->name[0])
-		V_DrawString(textx, namey, (draw_flags|snap_flags|V_ALLOWLOWERCASE), dialog->page->name);
+	if (dialog->speaker[0])
+		V_DrawString(textx, namey, (draw_flags|snap_flags|V_ALLOWLOWERCASE), dialog->speaker);
 
 	// Draw choices
 	if (dialog->showchoices)
@@ -2103,6 +2163,14 @@ static void GetControlCodeEnd(char **input)
 	WRITE_CHAR((n >> 8) & 0xFF); \
 	WRITE_CHAR((n) & 0xFF); \
 }
+#define WRITE_STRING(str) { \
+	size_t maxlen = strlen(str); \
+	if (maxlen > 255) \
+		maxlen = 255; \
+	WRITE_CHAR(maxlen); \
+	for (size_t i = 0; i < maxlen; i++) \
+		WRITE_CHAR(str[i]); \
+}
 
 #define EXPECTED_NUMBER(which) CONS_Alert(CONS_WARNING, "Expected integer in '%s', got '%s' instead\n", which, param)
 #define EXPECTED_PARAM(which) CONS_Alert(CONS_WARNING, "Expected parameter for '%s'\n", which)
@@ -2143,6 +2211,32 @@ static void InterpretControlCode(char **input, UINT8 **buf, size_t *buffer_pos,
 		else
 			EXPECTED_PARAM("SPEED");
 	}
+	else if (MatchControlCode("NAME", input))
+	{
+		char *param = GetControlCodeParam(input);
+		if (param)
+		{
+			WRITE_OP(TP_OP_NAME);
+			WRITE_STRING(param);
+
+			Z_Free(param);
+		}
+		else
+			EXPECTED_PARAM("NAME");
+	}
+	else if (MatchControlCode("ICON", input))
+	{
+		char *param = GetControlCodeParam(input);
+		if (param)
+		{
+			WRITE_OP(TP_OP_ICON);
+			WRITE_STRING(param);
+
+			Z_Free(param);
+		}
+		else
+			EXPECTED_PARAM("ICON");
+	}
 }
 
 static boolean InterpretCutsceneControlCode(UINT8 chr, UINT8 **buf, size_t *buffer_pos, size_t *buffer_capacity)
@@ -2287,11 +2381,7 @@ static void ParsePage(textprompt_t *prompt, tokenizer_t *sc)
 
 			GET_TOKEN();
 
-			char name[34];
-			name[0] = '\x82'; // color yellow
-			name[1] = 0;
-			strlcat(name, tkn, sizeof(name));
-			strlcpy(page->name, name, sizeof(page->name));
+			strlcpy(page->name, tkn, sizeof(page->name));
 
 			EXPECT_TOKEN(";");
 		}
diff --git a/src/p_dialog.h b/src/p_dialog.h
index 5b20f372c12afc6efbf1ca7c1147500dd0406443..e8b68a5bb003fdd1d06400003ff21330f5f17984 100644
--- a/src/p_dialog.h
+++ b/src/p_dialog.h
@@ -25,10 +25,11 @@
 typedef struct
 {
 	const char *basetext;
+	size_t basetextlength;
 	char *disptext;
 	size_t disptextsize;
-	INT32 baseptr;
-	INT32 writeptr;
+	UINT32 baseptr;
+	UINT32 writeptr;
 	INT32 textcount;
 	INT32 textspeed;
 	INT32 numtowrite;
@@ -36,7 +37,7 @@ typedef struct
 } textwriter_t;
 
 UINT8 P_CutsceneWriteText(textwriter_t *writer);
-void P_ResetTextWriter(textwriter_t *writer, const char *basetext);
+void P_ResetTextWriter(textwriter_t *writer, const char *basetext, size_t basetextlength);
 
 //
 // PROMPT STATE
@@ -45,23 +46,32 @@ typedef struct dialog_s
 {
 	INT32 promptnum;
 	INT32 pagenum;
+
 	textprompt_t *prompt;
 	textpage_t *page;
-	INT32 timetonext;
+	player_t *callplayer;
 	textwriter_t writer;
-	INT16 postexectag;
-	boolean blockcontrols;
+
 	char *pagetext;
 	size_t pagetextlength;
 	char *disptext;
 	size_t disptextsize;
-	player_t *callplayer;
+
+	boolean blockcontrols;
+	INT32 timetonext;
+	INT16 postexectag;
+
 	INT32 picnum;
 	INT32 pictoloop;
 	INT32 pictimer;
 	INT32 picmode;
 	INT32 numpics;
 	cutscene_pic_t *pics;
+
+	char speaker[256];
+	char icon[256];
+	boolean iconflip;
+
 	boolean showchoices;
 	INT32 curchoice;
 	INT32 numchoices;
@@ -77,7 +87,7 @@ void P_EndTextPrompt(player_t *player, boolean forceexec, boolean noexec);
 void P_EndAllTextPrompts(boolean forceexec, boolean noexec);
 void P_RunDialog(player_t *player);
 void P_FreeDialog(dialog_t *dialog);
-void P_DialogSetText(dialog_t *dialog, char *pagetext, size_t textlength, INT32 numchars);
+void P_DialogSetText(dialog_t *dialog, char *pagetext, size_t textlength);
 void P_DialogUpdateLongestChoice(dialog_t *dialog);
 
 boolean P_SetCurrentDialogChoice(player_t *player, INT32 choice);
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 1274ebda6be53e3157c54c871bf040af90ff4e5e..6e6fd96dc5693fb5c3fc7bb6f90f71a21f9942aa 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -580,7 +580,7 @@ static void P_NetUnArchivePlayers(void)
 
 		if (globaltextprompt)
 			players[i].textprompt = globaltextprompt;
-		else
+		else if (players[i].promptactive)
 		{
 			players[i].textprompt = Z_Calloc(sizeof(dialog_t), PU_LEVEL, NULL);
 			P_NetUnArchiveDialog(players[i].textprompt);
@@ -4951,17 +4951,23 @@ static void P_NetArchiveDialog(dialog_t *dialog)
 	WRITEINT32(save_p, dialog->picnum);
 	WRITEINT32(save_p, dialog->pictoloop);
 	WRITEINT32(save_p, dialog->pictimer);
-	WRITEINT32(save_p, dialog->writer.writeptr);
+	WRITEUINT32(save_p, dialog->writer.baseptr);
+	WRITEUINT32(save_p, dialog->writer.writeptr);
 	WRITEINT32(save_p, dialog->writer.textcount);
 	WRITEINT32(save_p, dialog->writer.textspeed);
-	WRITEINT32(save_p, dialog->writer.boostspeed);
+	WRITEUINT8(save_p, (UINT8)dialog->writer.boostspeed);
+	WRITESTRINGN(save_p, dialog->speaker, sizeof(dialog->speaker) - 1);
+	WRITESTRINGN(save_p, dialog->icon, sizeof(dialog->icon) - 1);
+	WRITEUINT8(save_p, (UINT8)dialog->iconflip);
 }
 
 static void P_NetUnArchiveDialog(dialog_t *dialog)
 {
 	UINT8 playernum;
-
-	INT32 numchars, textcount, textspeed, boostspeed;
+	UINT32 baseptr, writeptr;
+	INT32 textcount, textspeed;
+	char speaker[256], icon[256];
+	boolean iconflip, boostspeed;
 
 	if (dialog == NULL)
 		I_Error("P_NetUnArchiveDialog: dialog == NULL");
@@ -4993,10 +4999,15 @@ static void P_NetUnArchiveDialog(dialog_t *dialog)
 	dialog->picnum = READINT32(save_p);
 	dialog->pictoloop = READINT32(save_p);
 	dialog->pictimer = READINT32(save_p);
-	numchars = READINT32(save_p);
+	baseptr = READUINT32(save_p);
+	writeptr = READUINT32(save_p);
 	textcount = READINT32(save_p);
 	textspeed = READINT32(save_p);
-	boostspeed = READINT32(save_p);
+	boostspeed = (boolean)READUINT8(save_p);
+
+	READSTRINGN(save_p, speaker, sizeof(speaker) - 1);
+	READSTRINGN(save_p, icon, sizeof(icon) - 1);
+	iconflip = (boolean)READUINT8(save_p);
 
 	if (dialog->promptnum < 0 || dialog->promptnum >= MAX_PROMPTS || !textprompts[dialog->promptnum])
 		I_Error("Invalid text prompt %d from server", dialog->promptnum);
@@ -5020,8 +5031,14 @@ static void P_NetUnArchiveDialog(dialog_t *dialog)
 			I_Error("Invalid text prompt nochoice %d from server", dialog->nochoice);
 	}
 
-	P_DialogSetText(dialog, dialog->page->text, dialog->page->textlength, numchars);
+	P_DialogSetText(dialog, dialog->page->text, dialog->page->textlength);
+
+	strlcpy(dialog->speaker, speaker, sizeof(dialog->speaker));
+	strlcpy(dialog->icon, icon, sizeof(dialog->icon));
+	dialog->iconflip = iconflip;
 
+	dialog->writer.baseptr = baseptr;
+	dialog->writer.writeptr = writeptr;
 	dialog->writer.textcount = textcount;
 	dialog->writer.textspeed = textspeed;
 	dialog->writer.boostspeed = boostspeed;