From 0373207db5d8f475c80be7ef34532aa6feba1b06 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Tue, 4 Sep 2018 19:21:58 +0100 Subject: [PATCH 01/49] Add V_DrawTutorialBack for drawing a console-like background box, add Lorem ipsum as filler test --- src/v_video.c | 19 +++++++++++++++++++ src/v_video.h | 1 + 2 files changed, 20 insertions(+) diff --git a/src/v_video.c b/src/v_video.c index 2f84d4c7e..06f96a605 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1480,6 +1480,25 @@ void V_DrawFadeConsBack(INT32 plines) *buf = consolebgmap[*buf]; } +// Very similar to F_DrawFadeConsBack, except we draw from the middle(-ish) of the screen to the bottom. +void V_DrawTutorialBack(void) +{ + INT32 charheight = 8*vid.dupy; + UINT8 *deststop, *buf; + +#ifdef HWRENDER + if (rendermode != render_soft) // no support for OpenGL yet + return; +#endif + + // heavily simplified -- we don't need to know x or y position, + // just the start and stop positions + deststop = screens[0] + vid.rowbytes * vid.height; + buf = deststop - vid.rowbytes * ((charheight * 4) + (charheight/2)*5); // 4 lines of space plus gaps between and some leeway + for (; buf < deststop; ++buf) + *buf = consolebgmap[*buf]; +} + // Gets string colormap, used for 0x80 color codes // static const UINT8 *V_GetStringColormap(INT32 colorflags) diff --git a/src/v_video.h b/src/v_video.h index 6113d08ec..850206816 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -158,6 +158,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum); void V_DrawFadeScreen(UINT16 color, UINT8 strength); void V_DrawFadeConsBack(INT32 plines); +void V_DrawTutorialBack(void); // draw a single character void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); From f8f37959278a935a580acc00dd4139978c167134 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 01:27:32 -0400 Subject: [PATCH 02/49] TextPrompt/Page freeslots; SOC Prompt/Page parsing --- src/dehacked.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++ src/doomstat.h | 22 +++++ src/g_game.c | 1 + 3 files changed, 245 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index 6c39fc197..9f48b5f57 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1545,6 +1545,218 @@ static void readcutscene(MYFILE *f, INT32 num) Z_Free(s); } +static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) +{ + char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + INT32 i; + UINT16 usi; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + if (fastcmp(word, "PAGETEXT")) + { + char *pagetext = NULL; + char *buffer; + const int bufferlen = 4096; + + for (i = 0; i < MAXLINELEN; i++) + { + if (s[i] == '=') + { + pagetext = &s[i+2]; + break; + } + } + + if (!pagetext) + { + Z_Free(textprompts[num]->page[pagenum].text); + textprompts[num]->page[pagenum].text = NULL; + continue; + } + + for (i = 0; i < MAXLINELEN; i++) + { + if (s[i] == '\0') + { + s[i] = '\n'; + s[i+1] = '\0'; + break; + } + } + + buffer = Z_Malloc(4096, PU_STATIC, NULL); + strcpy(buffer, pagetext); + + strcat(buffer, + myhashfgets(pagetext, bufferlen + - strlen(buffer) - 1, f)); + + // A text prompt overwriting another one... + Z_Free(textprompts[num]->page[pagenum].text); + + textprompts[num]->page[pagenum].text = Z_StrDup(buffer); + + Z_Free(buffer); + + continue; + } + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + i = atoi(word2); + usi = (UINT16)i; + + + if (fastcmp(word, "NAME")) + strncpy(textprompts[num]->page[pagenum].name, word2, 32); + else if (fastcmp(word, "ICON")) + strncpy(textprompts[num]->page[pagenum].iconname, word2, 8); + else if (fastcmp(word, "ICONALIGN")) + textprompts[num]->page[pagenum].rightside = (i || word2[0] == 'R'); + else if (fastcmp(word, "LINES")) + textprompts[num]->page[pagenum].lines = usi; + else if (fastcmp(word, "BACKCOLOR")) + { + UINT8 backcolor; + if (usi == 0 || fastcmp(word2, "WHITE")) backcolor = 0; + else if (usi == 1 || fastcmp(word2, "GRAY") || fastcmp(word2, "GREY")) backcolor = 1; + else if (usi == 2 || fastcmp(word2, "BROWN")) backcolor = 2; + else if (usi == 3 || fastcmp(word2, "RED")) backcolor = 3; + else if (usi == 4 || fastcmp(word2, "ORANGE")) backcolor = 4; + else if (usi == 5 || fastcmp(word2, "YELLOW")) backcolor = 5; + else if (usi == 6 || fastcmp(word2, "GREEN")) backcolor = 6; + else if (usi == 7 || fastcmp(word2, "BLUE")) backcolor = 7; + else if (usi == 8 || fastcmp(word2, "PURPLE")) backcolor = 8; + else if (usi == 9 || fastcmp(word2, "MAGENTA")) backcolor = 9; + else if (usi == 10 || fastcmp(word2, "AQUA")) backcolor = 10; + else if (usi < 0) backcolor = UINT8_MAX; // CONS_BACKCOLOR user-configured + else backcolor = 11; // default green + textprompts[num]->page[pagenum].backcolor = backcolor; + } + else if (fastcmp(word, "ALIGN")) + { + UINT8 align = 0; // left + if (usi == 1 || word2[0] == 'R') align = 1; + else if (usi == 2 || word2[0] == 'C' || word2[0] == 'M') align = 2; + textprompts[num]->page[pagenum].align = align; + } + else if (fastcmp(word, "VERTICALALIGN")) + { + UINT8 align = 0; // top + if (usi == 1 || word2[0] == 'B') align = 1; + else if (usi == 2 || word2[0] == 'C' || word2[0] == 'M') align = 2; + textprompts[num]->page[pagenum].verticalalign = align; + } + else if (fastcmp(word, "TEXTSPEED")) + textprompts[num]->page[pagenum].textspeed = min(max(0, usi), 15); + else if (fastcmp(word, "TEXTSFX")) + textprompts[num]->page[pagenum].textsfx = get_number(word2); + else if (fastcmp(word, "METAPAGE")) + { + if (usi <= textprompts[num]->numpages) + { + strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[usi].name, 32); + strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[usi].iconname, 8); + textprompts[num]->page[pagenum].rightside = textprompts[num]->page[usi].rightside; + textprompts[num]->page[pagenum].lines = textprompts[num]->page[usi].lines; + textprompts[num]->page[pagenum].backcolor = textprompts[num]->page[usi].backcolor; + textprompts[num]->page[pagenum].align = textprompts[num]->page[usi].align; + textprompts[num]->page[pagenum].verticalalign = textprompts[num]->page[usi].verticalalign; + textprompts[num]->page[pagenum].textspeed = textprompts[num]->page[usi].textspeed; + textprompts[num]->page[pagenum].textsfx = textprompts[num]->page[usi].textsfx; + } + } + else + deh_warning("PromptPage %d: unknown word '%s'", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + +static void readtextprompt(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; + char *word2; + char *tmp; + INT32 value; + + // Allocate memory for this prompt if we don't yet have any + if (!textprompts[num]) + textprompts[num] = Z_Calloc(sizeof (textprompt_t), PU_STATIC, NULL); + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + word2 = strtok(NULL, " "); + if (word2) + value = atoi(word2); + else + { + deh_warning("No value for token %s", word); + continue; + } + + if (fastcmp(word, "NUMPAGES")) + { + textprompts[num]->numpages = value; + } + else if (fastcmp(word, "PAGE")) + { + if (1 <= value && value <= 128) + { + textprompts[num]->page[value - 1].backcolor = UINT8_MAX; // non-zero default + readtextpromptpage(f, num, value - 1); + } + else + deh_warning("Page number %d out of range (1 - 128)", value); + + } + else + deh_warning("Prompt %d: unknown word '%s', Page expected.", num, word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + static void readhuditem(MYFILE *f, INT32 num) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -3214,6 +3426,16 @@ static void DEH_LoadDehackedFile(MYFILE *f) ignorelines(f); } } + else if (fastcmp(word, "PROMPT")) + { + if (i > 0 && i < 257) + readtextprompt(f, i - 1); + else + { + deh_warning("Prompt number %d out of range (1 - 256)", i); + ignorelines(f); + } + } else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE")) { if (i == 0 && word2[0] != '0') // If word2 isn't a number diff --git a/src/doomstat.h b/src/doomstat.h index 7678c86b7..d737ef451 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -166,6 +166,28 @@ typedef struct extern cutscene_t *cutscenes[128]; +typedef struct +{ + char name[32]; // narrator name + char iconname[8]; // narrator icon lump + boolean rightside; // narrator side, false = left, true = right + UINT8 lines; // # of lines to show. If name is specified, name takes one of the lines. If 0, defaults to 4. + UINT8 backcolor; // see CON_SetupBackColormap: 0-10, 11 for default, UINT8_MAX for user-defined (CONS_BACKCOLOR) + UINT8 align; // text alignment, 0 = left, 1 = right, 2 = center + UINT8 verticalalign; // vertical text alignment, 0 = top, 1 = bottom, 2 = middle + UINT8 textspeed; // text speed 0-15, makes it slower. See f_finale.c F_WriteText + sfxenum_t textsfx; // sfx_ id for printing text + char *text; +} textpage_t; + +typedef struct +{ + textpage_t page[128]; // 128 pages per prompt. + INT32 numpages; // Number of pages in this prompt +} textprompt_t; + +extern textprompt_t *textprompts[256]; + // For the Custom Exit linedef. extern INT16 nextmapoverride; extern boolean skipstats; diff --git a/src/g_game.c b/src/g_game.c index 0a392fa85..df8e0fd79 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -138,6 +138,7 @@ tic_t countdowntimer = 0; boolean countdowntimeup = false; cutscene_t *cutscenes[128]; +textprompt_t *textprompts[256]; INT16 nextmapoverride; boolean skipstats; From c1d6fcccf07a8e532a9aff39eccd07060311a8ab Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 04:38:16 -0400 Subject: [PATCH 03/49] Broken attempt at supporting linebreaks for PageText, like cutscenes --- src/dehacked.c | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 9f48b5f57..963285cff 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -146,7 +146,7 @@ char *myfgets(char *buf, size_t bufsize, MYFILE *f) return buf; } -static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f) +static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f, boolean trim) { size_t i = 0; if (myfeof(f)) @@ -165,11 +165,34 @@ static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f) if (c == '\n') // Ensure debug line is right... dbg_line++; if (c == '#') + { + if (i > 0) + i--; // don't include the hash in our string break; + } } - i++; - buf[i] = '\0'; + // HACK: BS code to make sure i doesn't wrap past 0 + // and put the terminator char AFTER the first non-whitespace char + // OR at position 0 if the first char is whitespace OR a hash + if (trim) // trailing whitespace only + { + if (i > 0) + i--; // current char may be '#', so skip that + while (i < bufsize && i > 0 && !myfeof(f)) + { + char c = buf[i]; + if (i > 0) + i--; + if ((c != '\r' && c != '\n' && c != ' ') || i == 0) + break; + } + if (buf[i] != '\r' && buf[i] != '\n' && buf[i] != ' ' && buf[i] != '#') + i++; // put the null character after the first non-whitespace char + } + + buf[i] = '\0'; + CONS_Printf("%s", buf); return buf; } @@ -352,7 +375,7 @@ static void readPlayer(MYFILE *f, INT32 num) if (playertext) { strcpy(description[num].notes, playertext); - strcat(description[num].notes, myhashfgets(playertext, sizeof (description[num].notes), f)); + strcat(description[num].notes, myhashfgets(playertext, sizeof (description[num].notes), f, false)); } else strcpy(description[num].notes, ""); @@ -1368,7 +1391,7 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) strcat(buffer, myhashfgets(scenetext, bufferlen - - strlen(buffer) - 1, f)); + - strlen(buffer) - 1, f, false)); // A cutscene overwriting another one... Z_Free(cutscenes[num]->scene[scenenum].text); @@ -1603,7 +1626,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) strcat(buffer, myhashfgets(pagetext, bufferlen - - strlen(buffer) - 1, f)); + - strlen(buffer) - 1, f, true)); // A text prompt overwriting another one... Z_Free(textprompts[num]->page[pagenum].text); @@ -1628,7 +1651,16 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) if (fastcmp(word, "NAME")) - strncpy(textprompts[num]->page[pagenum].name, word2, 32); + { + // HACK: Add yellow control char now + // so the drawing function doesn't call it repeatedly + char name[32]; + name[0] = '\x82'; // color yellow + name[1] = 0; + strncat(name, word2, 31); + name[31] = 0; + strncpy(textprompts[num]->page[pagenum].name, name, 32); + } else if (fastcmp(word, "ICON")) strncpy(textprompts[num]->page[pagenum].iconname, word2, 8); else if (fastcmp(word, "ICONALIGN")) From 28d5add0cf62e27caa951a9b03165580e5f9e7ad Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 05:04:09 -0400 Subject: [PATCH 04/49] Kind of support line breaks with PAGETEXT. Can't trim trailing whitespace yet. --- src/dehacked.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 963285cff..b439f43de 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -146,7 +146,7 @@ char *myfgets(char *buf, size_t bufsize, MYFILE *f) return buf; } -static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f, boolean trim) +static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f) { size_t i = 0; if (myfeof(f)) @@ -166,33 +166,15 @@ static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f, boolean trim) dbg_line++; if (c == '#') { - if (i > 0) - i--; // don't include the hash in our string + if (i > 0) // don't let i wrap past 0 + i--; // don't include hash char in string break; } } - - // HACK: BS code to make sure i doesn't wrap past 0 - // and put the terminator char AFTER the first non-whitespace char - // OR at position 0 if the first char is whitespace OR a hash - if (trim) // trailing whitespace only - { - if (i > 0) - i--; // current char may be '#', so skip that - while (i < bufsize && i > 0 && !myfeof(f)) - { - char c = buf[i]; - if (i > 0) - i--; - if ((c != '\r' && c != '\n' && c != ' ') || i == 0) - break; - } - if (buf[i] != '\r' && buf[i] != '\n' && buf[i] != ' ' && buf[i] != '#') - i++; // put the null character after the first non-whitespace char - } - + if (buf[i] != '#') // don't include hash char in string + i++; buf[i] = '\0'; - CONS_Printf("%s", buf); + return buf; } @@ -375,7 +357,7 @@ static void readPlayer(MYFILE *f, INT32 num) if (playertext) { strcpy(description[num].notes, playertext); - strcat(description[num].notes, myhashfgets(playertext, sizeof (description[num].notes), f, false)); + strcat(description[num].notes, myhashfgets(playertext, sizeof (description[num].notes), f)); } else strcpy(description[num].notes, ""); @@ -1391,7 +1373,7 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) strcat(buffer, myhashfgets(scenetext, bufferlen - - strlen(buffer) - 1, f, false)); + - strlen(buffer) - 1, f)); // A cutscene overwriting another one... Z_Free(cutscenes[num]->scene[scenenum].text); @@ -1624,9 +1606,12 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) buffer = Z_Malloc(4096, PU_STATIC, NULL); strcpy(buffer, pagetext); + // \todo trim trailing whitespace before the # + // and also support # at the end of a PAGETEXT with no line break + strcat(buffer, myhashfgets(pagetext, bufferlen - - strlen(buffer) - 1, f, true)); + - strlen(buffer) - 1, f)); // A text prompt overwriting another one... Z_Free(textprompts[num]->page[pagenum].text); From e0620d70b2a9dafb55b432391f5c5e6f51826e8d Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 05:05:15 -0400 Subject: [PATCH 05/49] Text prompt features: Name, Icon, IconAlign, Lines --- src/st_stuff.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/v_video.c | 7 ++++--- src/v_video.h | 2 +- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index fa13e008a..2a9d25cc7 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2465,6 +2465,49 @@ static void ST_overlayDrawer(void) ST_drawDebugInfo(); } +static void ST_drawTutorial(INT32 promptnum, INT32 pagenum) +{ + lumpnum_t iconlump = W_CheckNumForName(textprompts[promptnum]->page[pagenum].iconname); + UINT8 pagelines = textprompts[promptnum]->page[pagenum].lines ? textprompts[promptnum]->page[pagenum].lines : 4; + + // Vertical calculations + INT32 boxh = pagelines*2; + INT32 texth = textprompts[promptnum]->page[pagenum].name[0] ? (pagelines-1)*2 : pagelines*2; // name takes up first line if it exists + INT32 texty = BASEVIDHEIGHT - ((texth * 4) + (texth/2)*4); + INT32 namey = BASEVIDHEIGHT - ((boxh * 4) + (boxh/2)*4); + + // Horizontal calculations + // Shift text to the right if we have a character icon on the left side + // Add 4 margin against icon + INT32 textx = iconlump != LUMPERROR && !textprompts[promptnum]->page[pagenum].rightside ? ((boxh * 4) + (boxh/2)*4) + 4 : 4; + INT32 textr = textprompts[promptnum]->page[pagenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4) + 4) : BASEVIDWIDTH-4; + + // Data + patch_t *patch; + char *text; + + // Draw background + V_DrawTutorialBack(boxh); + + // Draw narrator icon + if (iconlump != LUMPERROR) + { + INT32 iconx = textprompts[promptnum]->page[pagenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4; + patch = W_CachePatchName(textprompts[promptnum]->page[pagenum].iconname, PU_CACHE); + V_DrawFixedPatch(iconx<width), 0, patch, NULL); + W_UnlockCachedPatch(patch); + } + + // Draw text + // \todo Char-by-char printing, see f_finale.c F_WriteText + text = V_WordWrap(textx, textr, 0, textprompts[promptnum]->page[pagenum].text); + V_DrawString(textx, texty, V_SNAPTOBOTTOM, text); + + // Draw name + if (textprompts[promptnum]->page[pagenum].name[0]) + V_DrawString(textx, namey, V_SNAPTOBOTTOM, textprompts[promptnum]->page[pagenum].name); +} + void ST_Drawer(void) { #ifdef SEENAMES @@ -2538,4 +2581,8 @@ void ST_Drawer(void) ST_overlayDrawer(); } } + + // Draw tutorial text over everything else + //if (tutorialmode) + ST_drawTutorial(0, 0); } diff --git a/src/v_video.c b/src/v_video.c index 06f96a605..a628b1a8b 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1481,11 +1481,12 @@ void V_DrawFadeConsBack(INT32 plines) } // Very similar to F_DrawFadeConsBack, except we draw from the middle(-ish) of the screen to the bottom. -void V_DrawTutorialBack(void) +void V_DrawTutorialBack(INT32 boxheight) { - INT32 charheight = 8*vid.dupy; UINT8 *deststop, *buf; + boxheight *= vid.dupy; + #ifdef HWRENDER if (rendermode != render_soft) // no support for OpenGL yet return; @@ -1494,7 +1495,7 @@ void V_DrawTutorialBack(void) // heavily simplified -- we don't need to know x or y position, // just the start and stop positions deststop = screens[0] + vid.rowbytes * vid.height; - buf = deststop - vid.rowbytes * ((charheight * 4) + (charheight/2)*5); // 4 lines of space plus gaps between and some leeway + buf = deststop - vid.rowbytes * ((boxheight * 4) + (boxheight/2)*5); // 4 lines of space plus gaps between and some leeway for (; buf < deststop; ++buf) *buf = consolebgmap[*buf]; } diff --git a/src/v_video.h b/src/v_video.h index 850206816..ee958c2fa 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -158,7 +158,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum); void V_DrawFadeScreen(UINT16 color, UINT8 strength); void V_DrawFadeConsBack(INT32 plines); -void V_DrawTutorialBack(void); +void V_DrawTutorialBack(INT32 boxheight); // draw a single character void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); From 0865497e66a15c18b98b30d672d090a28acfd49f Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 05:06:18 -0400 Subject: [PATCH 06/49] Linedef Exec 449 Control Text Prompt - beginnings --- src/p_spec.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index 9f9e80ecc..571e6277f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3455,6 +3455,29 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; + case 449: // Control Text Prompt +#if 0 + // console player only unless NOCLIMB is set + if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player))) + { + INT32 promptnum = abs(sides[line->sidenum[0]].textureoffset>>FRACBITS); + INT32 pagenum = abs(sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT32 postexectag = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0; + INT32 closedelay = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].rowoffset>>FRACBITS) : 0; + + boolean blockcontrols = !(line->flags & ML_BLOCKMONSTERS); + boolean closetextprompt = (line->flags & ML_EFFECT2); + boolean runpostexec = (line->flags & ML_EFFECT1); + boolean freezethinkers = (line->flags & ML_TFERLINE); + + // if (closetextprompt && !promptnum) + // P_CloseTextPromptEx(closedelay, runpostexec ? postexectag : 0, mo); + // else + // P_ControlTextPromptEx(promptnum, pagenum, closetextprompt ? closedelay : 0, runpostexec ? postexectag : 0, mo, blockcontrols, freezethinkers); + } +#endif + break; + case 450: // Execute Linedef Executor - for recursion P_LinedefExecute(line->tag, mo, NULL); break; From d69cd4b9c642ce1b6291b88ccc9cbfb1f01b46e9 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 09:13:17 -0400 Subject: [PATCH 07/49] Text prompt: Fix V_DrawFixedPatch call for non-green resos --- src/st_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 2a9d25cc7..ce5042971 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2494,7 +2494,7 @@ static void ST_drawTutorial(INT32 promptnum, INT32 pagenum) { INT32 iconx = textprompts[promptnum]->page[pagenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4; patch = W_CachePatchName(textprompts[promptnum]->page[pagenum].iconname, PU_CACHE); - V_DrawFixedPatch(iconx<width), 0, patch, NULL); + V_DrawFixedPatch(iconx<width), V_SNAPTOBOTTOM, patch, NULL); W_UnlockCachedPatch(patch); } From 77c5774e515c69b653a589b97d508717789c7422 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 10:54:30 -0400 Subject: [PATCH 08/49] Moved TextPrompt logic to f_finale.c * Added basic TextPrompt ticker and drawer functions * Added chevron animation --- src/d_main.c | 1 + src/f_finale.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/f_finale.h | 5 +++ src/g_game.c | 1 + src/st_stuff.c | 47 -------------------------- 5 files changed, 99 insertions(+), 47 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 6cd6aaba6..6f9d46f36 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -424,6 +424,7 @@ static void D_Display(void) if (gamestate == GS_LEVEL) { ST_Drawer(); + F_TextPromptDrawer(); HU_Drawer(); } else diff --git a/src/f_finale.c b/src/f_finale.c index 151889c4c..c25dd9eca 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -48,6 +48,7 @@ static INT32 timetonext; // Delay between screen changes static INT32 continuetime; // Short delay when continuing static tic_t animtimer; // Used for some animation timings +static INT16 skullAnimCounter; // Chevron animation static INT32 roidtics; // Asteroid spinning static INT32 deplete; @@ -78,6 +79,8 @@ static patch_t *ttspop7; static void F_SkyScroll(INT32 scrollspeed); +static boolean promptactive = false; + // // CUTSCENE TEXT WRITING // @@ -2015,3 +2018,92 @@ boolean F_CutsceneResponder(event_t *event) return false; } + +void F_EndTextPrompt(void) +{ + promptactive = false; +} + +void F_StartTextPrompt(INT32 promptnum, INT32 pagenum) +{ + // We share vars, so no starting text prompts over cutscenes or title screens! + keypressed = false; + finalecount = 0; + timetonext = 0; + animtimer = 0; + stoptimer = 0; + skullAnimCounter = 0; + + cutnum = promptnum; + scenenum = pagenum; + promptactive = true; +} + +void F_TextPromptDrawer(void) +{ + // reuse: + // cutnum -> promptnum + // scenenum -> pagenum + + if (!promptactive) + return; + + lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); + UINT8 pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4; + + // Vertical calculations + INT32 boxh = pagelines*2; + INT32 texth = textprompts[cutnum]->page[scenenum].name[0] ? (pagelines-1)*2 : pagelines*2; // name takes up first line if it exists + INT32 texty = BASEVIDHEIGHT - ((texth * 4) + (texth/2)*4); + INT32 namey = BASEVIDHEIGHT - ((boxh * 4) + (boxh/2)*4); + INT32 chevrony = BASEVIDHEIGHT - (((1*2) * 4) + ((1*2)/2)*4); // force on last line + + // Horizontal calculations + // Shift text to the right if we have a character icon on the left side + // Add 4 margin against icon + INT32 textx = iconlump != LUMPERROR && !textprompts[cutnum]->page[scenenum].rightside ? ((boxh * 4) + (boxh/2)*4) + 4 : 4; + INT32 textr = textprompts[cutnum]->page[scenenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4) + 4) : BASEVIDWIDTH-4; + + // Data + patch_t *patch; + char *text; + + // Draw background + V_DrawTutorialBack(boxh); + + // Draw narrator icon + if (iconlump != LUMPERROR) + { + INT32 iconx = textprompts[cutnum]->page[scenenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4; + patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_CACHE); + V_DrawFixedPatch(iconx<width), V_SNAPTOBOTTOM, patch, NULL); + W_UnlockCachedPatch(patch); + } + + // Draw text + // \todo Char-by-char printing, see f_finale.c F_WriteText + text = V_WordWrap(textx, textr, 0, textprompts[cutnum]->page[scenenum].text); + V_DrawString(textx, texty, V_SNAPTOBOTTOM, text); + + // Draw name + // Don't use V_YELLOWMAP here so that the name color can be changed with control codes + if (textprompts[cutnum]->page[scenenum].name[0]) + V_DrawString(textx, namey, V_SNAPTOBOTTOM, textprompts[cutnum]->page[scenenum].name); + + // Draw chevron + V_DrawString(textr-8, chevrony + (skullAnimCounter/5), V_YELLOWMAP, "\x1B"); // down arrow +} + +void F_TextPromptTicker(void) +{ + if (!promptactive) + return; + + // advance animation + finalecount++; + cutscene_boostspeed = 0; + + // for the chevron + if (--skullAnimCounter <= 0) + skullAnimCounter = 8; +} diff --git a/src/f_finale.h b/src/f_finale.h index aadc64ad0..eb5872fca 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -33,6 +33,7 @@ void F_IntroTicker(void); void F_TitleScreenTicker(boolean run); void F_CutsceneTicker(void); void F_TitleDemoTicker(void); +void F_TextPromptTicker(void); // Called by main loop. FUNCMATH void F_GameEndDrawer(void); @@ -50,6 +51,10 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset void F_CutsceneDrawer(void); void F_EndCutScene(void); +void F_StartTextPrompt(INT32 promptnum, INT32 pagenum); +void F_TextPromptDrawer(void); +void F_EndTextPrompt(void); + void F_StartGameEnd(void); void F_StartIntro(void); void F_StartTitleScreen(void); diff --git a/src/g_game.c b/src/g_game.c index df8e0fd79..d72a1961b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1934,6 +1934,7 @@ void G_Ticker(boolean run) F_TitleDemoTicker(); P_Ticker(run); // tic the game ST_Ticker(); + F_TextPromptTicker(); AM_Ticker(); HU_Ticker(); break; diff --git a/src/st_stuff.c b/src/st_stuff.c index ce5042971..fa13e008a 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2465,49 +2465,6 @@ static void ST_overlayDrawer(void) ST_drawDebugInfo(); } -static void ST_drawTutorial(INT32 promptnum, INT32 pagenum) -{ - lumpnum_t iconlump = W_CheckNumForName(textprompts[promptnum]->page[pagenum].iconname); - UINT8 pagelines = textprompts[promptnum]->page[pagenum].lines ? textprompts[promptnum]->page[pagenum].lines : 4; - - // Vertical calculations - INT32 boxh = pagelines*2; - INT32 texth = textprompts[promptnum]->page[pagenum].name[0] ? (pagelines-1)*2 : pagelines*2; // name takes up first line if it exists - INT32 texty = BASEVIDHEIGHT - ((texth * 4) + (texth/2)*4); - INT32 namey = BASEVIDHEIGHT - ((boxh * 4) + (boxh/2)*4); - - // Horizontal calculations - // Shift text to the right if we have a character icon on the left side - // Add 4 margin against icon - INT32 textx = iconlump != LUMPERROR && !textprompts[promptnum]->page[pagenum].rightside ? ((boxh * 4) + (boxh/2)*4) + 4 : 4; - INT32 textr = textprompts[promptnum]->page[pagenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4) + 4) : BASEVIDWIDTH-4; - - // Data - patch_t *patch; - char *text; - - // Draw background - V_DrawTutorialBack(boxh); - - // Draw narrator icon - if (iconlump != LUMPERROR) - { - INT32 iconx = textprompts[promptnum]->page[pagenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4; - patch = W_CachePatchName(textprompts[promptnum]->page[pagenum].iconname, PU_CACHE); - V_DrawFixedPatch(iconx<width), V_SNAPTOBOTTOM, patch, NULL); - W_UnlockCachedPatch(patch); - } - - // Draw text - // \todo Char-by-char printing, see f_finale.c F_WriteText - text = V_WordWrap(textx, textr, 0, textprompts[promptnum]->page[pagenum].text); - V_DrawString(textx, texty, V_SNAPTOBOTTOM, text); - - // Draw name - if (textprompts[promptnum]->page[pagenum].name[0]) - V_DrawString(textx, namey, V_SNAPTOBOTTOM, textprompts[promptnum]->page[pagenum].name); -} - void ST_Drawer(void) { #ifdef SEENAMES @@ -2581,8 +2538,4 @@ void ST_Drawer(void) ST_overlayDrawer(); } } - - // Draw tutorial text over everything else - //if (tutorialmode) - ST_drawTutorial(0, 0); } From 2b36943bf06832dbf37772c2bdc28f1814a091d5 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 10:54:47 -0400 Subject: [PATCH 09/49] Basic TextPrompt line action implemented --- src/p_spec.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 571e6277f..8f93b84a1 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -35,6 +35,7 @@ #include "m_misc.h" #include "m_cond.h" //unlock triggers #include "lua_hook.h" // LUAh_LinedefExecute +#include "f_finale.h" // control text prompt #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -3456,26 +3457,33 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 449: // Control Text Prompt -#if 0 // console player only unless NOCLIMB is set if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player))) { - INT32 promptnum = abs(sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT32 pagenum = abs(sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); + INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); + + boolean closetextprompt = (line->flags & ML_EFFECT2); + + if (closetextprompt) + F_EndTextPrompt(); + else + F_StartTextPrompt(promptnum, pagenum); +#if 0 + INT32 postexectag = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0; INT32 closedelay = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].rowoffset>>FRACBITS) : 0; boolean blockcontrols = !(line->flags & ML_BLOCKMONSTERS); - boolean closetextprompt = (line->flags & ML_EFFECT2); boolean runpostexec = (line->flags & ML_EFFECT1); boolean freezethinkers = (line->flags & ML_TFERLINE); // if (closetextprompt && !promptnum) - // P_CloseTextPromptEx(closedelay, runpostexec ? postexectag : 0, mo); + // F_EndTextPrompt(closedelay, runpostexec ? postexectag : 0, mo); // else - // P_ControlTextPromptEx(promptnum, pagenum, closetextprompt ? closedelay : 0, runpostexec ? postexectag : 0, mo, blockcontrols, freezethinkers); - } + // F_StartTextPrompt(promptnum, pagenum, closetextprompt ? closedelay : 0, runpostexec ? postexectag : 0, mo, blockcontrols, freezethinkers); #endif + } break; case 450: // Execute Linedef Executor - for recursion From c914be07ab1841dc7b1bd8d4990fd6af940f094d Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 11:12:27 -0400 Subject: [PATCH 10/49] Line 449 param rearranging --- src/p_spec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 8f93b84a1..2771c85f7 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3463,7 +3463,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); - boolean closetextprompt = (line->flags & ML_EFFECT2); + boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); if (closetextprompt) F_EndTextPrompt(); @@ -3474,9 +3474,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) INT32 postexectag = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0; INT32 closedelay = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].rowoffset>>FRACBITS) : 0; - boolean blockcontrols = !(line->flags & ML_BLOCKMONSTERS); boolean runpostexec = (line->flags & ML_EFFECT1); - boolean freezethinkers = (line->flags & ML_TFERLINE); + boolean blockcontrols = !(line->flags & ML_EFFECT2); + boolean freezetimer = !(line->flags & ML_EFFECT3); + boolean freezethinkers = (line->flags & ML_EFFECT4); // if (closetextprompt && !promptnum) // F_EndTextPrompt(closedelay, runpostexec ? postexectag : 0, mo); From 8d812ab24eeb9bfea90f641f76efffff3e30e161 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 13:06:05 -0400 Subject: [PATCH 11/49] Fixes: MetaPage, AdvanceToNextPage, center/scale icons, button handling --- src/dehacked.c | 25 +++++++----- src/doomstat.h | 2 + src/f_finale.c | 107 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 116 insertions(+), 18 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index b439f43de..2b466fab7 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1690,19 +1690,24 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].textsfx = get_number(word2); else if (fastcmp(word, "METAPAGE")) { - if (usi <= textprompts[num]->numpages) + if (usi && usi <= textprompts[num]->numpages) { - strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[usi].name, 32); - strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[usi].iconname, 8); - textprompts[num]->page[pagenum].rightside = textprompts[num]->page[usi].rightside; - textprompts[num]->page[pagenum].lines = textprompts[num]->page[usi].lines; - textprompts[num]->page[pagenum].backcolor = textprompts[num]->page[usi].backcolor; - textprompts[num]->page[pagenum].align = textprompts[num]->page[usi].align; - textprompts[num]->page[pagenum].verticalalign = textprompts[num]->page[usi].verticalalign; - textprompts[num]->page[pagenum].textspeed = textprompts[num]->page[usi].textspeed; - textprompts[num]->page[pagenum].textsfx = textprompts[num]->page[usi].textsfx; + UINT8 metapagenum = usi - 1; + strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[metapagenum].name, 32); + strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[metapagenum].iconname, 8); + textprompts[num]->page[pagenum].rightside = textprompts[num]->page[metapagenum].rightside; + textprompts[num]->page[pagenum].lines = textprompts[num]->page[metapagenum].lines; + textprompts[num]->page[pagenum].backcolor = textprompts[num]->page[metapagenum].backcolor; + textprompts[num]->page[pagenum].align = textprompts[num]->page[metapagenum].align; + textprompts[num]->page[pagenum].verticalalign = textprompts[num]->page[metapagenum].verticalalign; + textprompts[num]->page[pagenum].textspeed = textprompts[num]->page[metapagenum].textspeed; + textprompts[num]->page[pagenum].textsfx = textprompts[num]->page[metapagenum].textsfx; } } + else if (fastcmp(word, "NEXTPROMPT")) + textprompts[num]->page[pagenum].nextprompt = usi; + else if (fastcmp(word, "NEXTPAGE")) + textprompts[num]->page[pagenum].nextpage = usi; else deh_warning("PromptPage %d: unknown word '%s'", num, word); } diff --git a/src/doomstat.h b/src/doomstat.h index d737ef451..eaa19e3d6 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -177,6 +177,8 @@ typedef struct UINT8 verticalalign; // vertical text alignment, 0 = top, 1 = bottom, 2 = middle UINT8 textspeed; // text speed 0-15, makes it slower. See f_finale.c F_WriteText sfxenum_t textsfx; // sfx_ id for printing text + UINT8 nextprompt; // next prompt to jump to, one-based. 0 = current prompt + UINT8 nextpage; // next page to jump to, one-based. 0 = next page within prompt->numpages char *text; } textpage_t; diff --git a/src/f_finale.c b/src/f_finale.c index c25dd9eca..baaad10b0 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2019,6 +2019,47 @@ boolean F_CutsceneResponder(event_t *event) return false; } +// ================== +// TEXT PROMPTS +// ================== + +static void F_AdvanceToNextPage(void) +{ + UINT8 nextprompt = textprompts[cutnum]->page[scenenum].nextprompt, + nextpage = textprompts[cutnum]->page[scenenum].nextpage, + oldcutnum = cutnum; + + // determine next prompt + if (nextprompt) + { + if (textprompts[nextprompt-1]) + cutnum = nextprompt-1; + else + cutnum = INT32_MAX; + } + + // determine next page + if (nextpage) + { + scenenum = nextpage-1; + if (scenenum > textprompts[cutnum]->numpages-1) + scenenum = INT32_MAX; + } + else + { + if (cutnum != oldcutnum) + scenenum = 0; + else if (scenenum < textprompts[cutnum]->numpages-1) + scenenum++; + else + scenenum = INT32_MAX; + } + + // close the prompt if either num is invalid + if (cutnum == INT32_MAX || scenenum == INT32_MAX) + F_EndTextPrompt(); +} + void F_EndTextPrompt(void) { promptactive = false; @@ -2034,9 +2075,9 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum) stoptimer = 0; skullAnimCounter = 0; - cutnum = promptnum; - scenenum = pagenum; - promptactive = true; + cutnum = (textprompts[promptnum]) ? promptnum : INT32_MAX; + scenenum = (pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; + promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX); } void F_TextPromptDrawer(void) @@ -2050,6 +2091,7 @@ void F_TextPromptDrawer(void) lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); UINT8 pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4; + boolean rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside); // Vertical calculations INT32 boxh = pagelines*2; @@ -2061,8 +2103,8 @@ void F_TextPromptDrawer(void) // Horizontal calculations // Shift text to the right if we have a character icon on the left side // Add 4 margin against icon - INT32 textx = iconlump != LUMPERROR && !textprompts[cutnum]->page[scenenum].rightside ? ((boxh * 4) + (boxh/2)*4) + 4 : 4; - INT32 textr = textprompts[cutnum]->page[scenenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4) + 4) : BASEVIDWIDTH-4; + INT32 textx = (iconlump != LUMPERROR && !rightside) ? ((boxh * 4) + (boxh/2)*4) + 4 : 4; + INT32 textr = rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4) + 4) : BASEVIDWIDTH-4; // Data patch_t *patch; @@ -2074,9 +2116,33 @@ void F_TextPromptDrawer(void) // Draw narrator icon if (iconlump != LUMPERROR) { - INT32 iconx = textprompts[cutnum]->page[scenenum].rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4; + INT32 iconx, icony, scale, scaledsize; patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_CACHE); - V_DrawFixedPatch(iconx<width), V_SNAPTOBOTTOM, patch, NULL); + + // scale and center + if (patch->width > patch->height) + { + scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->width); + scaledsize = FixedMul(patch->height, scale); + iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS; + icony = ((namey-4) << FRACBITS) + FixedDiv(BASEVIDHEIGHT - namey + 4 - scaledsize, 2); // account for 4 margin + } + else if (patch->height > patch->width) + { + scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->height); + scaledsize = FixedMul(patch->width, scale); + iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS; + icony = namey << FRACBITS; + iconx += FixedDiv(FixedMul(patch->height, scale) - scaledsize, 2); + } + else + { + scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->width); + iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS; + icony = namey << FRACBITS; + } + + V_DrawFixedPatch(iconx, icony, scale, V_SNAPTOBOTTOM, patch, NULL); W_UnlockCachedPatch(patch); } @@ -2091,11 +2157,13 @@ void F_TextPromptDrawer(void) V_DrawString(textx, namey, V_SNAPTOBOTTOM, textprompts[cutnum]->page[scenenum].name); // Draw chevron - V_DrawString(textr-8, chevrony + (skullAnimCounter/5), V_YELLOWMAP, "\x1B"); // down arrow + V_DrawString(textr-8, chevrony + (skullAnimCounter/5), (V_SNAPTOBOTTOM|V_YELLOWMAP), "\x1B"); // down arrow } void F_TextPromptTicker(void) { + INT32 i; + if (!promptactive) return; @@ -2106,4 +2174,27 @@ void F_TextPromptTicker(void) // for the chevron if (--skullAnimCounter <= 0) skullAnimCounter = 8; + + // button handling + for (i = 0; i < MAXPLAYERS; i++) + { + if (netgame && i != serverplayer && i != adminplayer) + continue; + + if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP)) + { + if (keypressed) + return; + + cutscene_boostspeed = 1; + if (timetonext) + timetonext = 2; + F_AdvanceToNextPage(); + keypressed = true; // prevent repeat events + } + else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP)) + keypressed = false; + + break; + } } From 30dbb6a64433041e296459c925fa078957526c65 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 14:43:19 -0400 Subject: [PATCH 12/49] TextPrompt: Implement player blocked controls and post-close run line --- src/f_finale.c | 69 +++++++++++++++++++++++++++++++++++++------------- src/f_finale.h | 2 +- src/p_spec.c | 22 +++++----------- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index baaad10b0..b30160b87 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -79,7 +79,13 @@ static patch_t *ttspop7; static void F_SkyScroll(INT32 scrollspeed); +// +// PROMPT STATE +// static boolean promptactive = false; +static mobj_t *promptmo; +static INT16 promptpostexectag; +static boolean promptblockcontrols; // // CUTSCENE TEXT WRITING @@ -2063,9 +2069,20 @@ static void F_AdvanceToNextPage(void) void F_EndTextPrompt(void) { promptactive = false; + + // \todo net safety, maybe loop all player thinkers? + if (promptpostexectag) + P_LinedefExecute(promptpostexectag, promptmo, NULL); + + // \todo reset blocked controls and frozen realtime? + + P_SetTarget(&promptmo, NULL); // \todo tmthing crash upon teleporting? see test map + + // \todo if !promptactive, block player jumping if BT_JUMP is set + // so player does not immediately jump upon prompt close } -void F_StartTextPrompt(INT32 promptnum, INT32 pagenum) +void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) { // We share vars, so no starting text prompts over cutscenes or title screens! keypressed = false; @@ -2075,6 +2092,13 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum) stoptimer = 0; skullAnimCounter = 0; + // Set up state + P_SetTarget(&promptmo, mo); //promptmo = mo; + promptpostexectag = postexectag; + promptblockcontrols = blockcontrols; + (void)freezerealtime; // \todo freeze player->realtime, maybe this needs to cycle through player thinkers + + // Initialize current prompt and scene cutnum = (textprompts[promptnum]) ? promptnum : INT32_MAX; scenenum = (pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX); @@ -2157,7 +2181,8 @@ void F_TextPromptDrawer(void) V_DrawString(textx, namey, V_SNAPTOBOTTOM, textprompts[cutnum]->page[scenenum].name); // Draw chevron - V_DrawString(textr-8, chevrony + (skullAnimCounter/5), (V_SNAPTOBOTTOM|V_YELLOWMAP), "\x1B"); // down arrow + if (promptblockcontrols) // \todo if !CloseTimer + V_DrawString(textr-8, chevrony + (skullAnimCounter/5), (V_SNAPTOBOTTOM|V_YELLOWMAP), "\x1B"); // down arrow } void F_TextPromptTicker(void) @@ -2176,25 +2201,35 @@ void F_TextPromptTicker(void) skullAnimCounter = 8; // button handling - for (i = 0; i < MAXPLAYERS; i++) + if (promptblockcontrols) { - if (netgame && i != serverplayer && i != adminplayer) - continue; + // \todo loop through all players that have a text prompt + if (promptmo && promptmo->player) + promptmo->player->powers[pw_nocontrol] = 1; - if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP)) + for (i = 0; i < MAXPLAYERS; i++) { - if (keypressed) - return; + if (netgame && i != serverplayer && i != adminplayer) + continue; - cutscene_boostspeed = 1; - if (timetonext) - timetonext = 2; - F_AdvanceToNextPage(); - keypressed = true; // prevent repeat events + if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP)) + { + if (keypressed) + return; + + cutscene_boostspeed = 1; + if (timetonext) + timetonext = 2; + F_AdvanceToNextPage(); + keypressed = true; // prevent repeat events + + if (promptactive) + S_StartSound(NULL, sfx_menu1); + } + else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP)) + keypressed = false; + + break; } - else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP)) - keypressed = false; - - break; } } diff --git a/src/f_finale.h b/src/f_finale.h index eb5872fca..66b608e21 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -51,7 +51,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset void F_CutsceneDrawer(void); void F_EndCutScene(void); -void F_StartTextPrompt(INT32 promptnum, INT32 pagenum); +void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime); void F_TextPromptDrawer(void); void F_EndTextPrompt(void); diff --git a/src/p_spec.c b/src/p_spec.c index 2771c85f7..cd4dd76cf 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3462,28 +3462,18 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); + INT32 postexectag = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0; boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); + boolean runpostexec = (line->flags & ML_EFFECT1); + boolean blockcontrols = !(line->flags & ML_EFFECT2); + boolean freezerealtime = !(line->flags & ML_EFFECT3); + //boolean freezethinkers = (line->flags & ML_EFFECT4); if (closetextprompt) F_EndTextPrompt(); else - F_StartTextPrompt(promptnum, pagenum); -#if 0 - - INT32 postexectag = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0; - INT32 closedelay = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].rowoffset>>FRACBITS) : 0; - - boolean runpostexec = (line->flags & ML_EFFECT1); - boolean blockcontrols = !(line->flags & ML_EFFECT2); - boolean freezetimer = !(line->flags & ML_EFFECT3); - boolean freezethinkers = (line->flags & ML_EFFECT4); - - // if (closetextprompt && !promptnum) - // F_EndTextPrompt(closedelay, runpostexec ? postexectag : 0, mo); - // else - // F_StartTextPrompt(promptnum, pagenum, closetextprompt ? closedelay : 0, runpostexec ? postexectag : 0, mo, blockcontrols, freezethinkers); -#endif + F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); } break; From 6469efc6612a8f2da80e79cf7017e98cfa3b56d0 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 15:07:02 -0400 Subject: [PATCH 13/49] EndTextPrompt: Fix tmthing crash with P_LinedefExecute --- src/f_finale.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index b30160b87..8d578c61f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2072,11 +2072,15 @@ void F_EndTextPrompt(void) // \todo net safety, maybe loop all player thinkers? if (promptpostexectag) + { + P_MapStart(); P_LinedefExecute(promptpostexectag, promptmo, NULL); + P_MapEnd(); + } - // \todo reset blocked controls and frozen realtime? + // \todo reset frozen realtime? - P_SetTarget(&promptmo, NULL); // \todo tmthing crash upon teleporting? see test map + P_SetTarget(&promptmo, NULL); // \todo if !promptactive, block player jumping if BT_JUMP is set // so player does not immediately jump upon prompt close @@ -2093,7 +2097,7 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex skullAnimCounter = 0; // Set up state - P_SetTarget(&promptmo, mo); //promptmo = mo; + P_SetTarget(&promptmo, mo); promptpostexectag = postexectag; promptblockcontrols = blockcontrols; (void)freezerealtime; // \todo freeze player->realtime, maybe this needs to cycle through player thinkers From 5a8e256ca1ab8dd218ce9682432ea6daa0b6b19d Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sat, 3 Nov 2018 21:13:44 +0000 Subject: [PATCH 14/49] Fix errors found when compiling --- src/dehacked.c | 26 +++++++++++++------------- src/f_finale.c | 45 +++++++++++++++++++++++++-------------------- src/f_finale.h | 1 + 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 2b466fab7..725a30b4e 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1655,18 +1655,18 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) else if (fastcmp(word, "BACKCOLOR")) { UINT8 backcolor; - if (usi == 0 || fastcmp(word2, "WHITE")) backcolor = 0; - else if (usi == 1 || fastcmp(word2, "GRAY") || fastcmp(word2, "GREY")) backcolor = 1; - else if (usi == 2 || fastcmp(word2, "BROWN")) backcolor = 2; - else if (usi == 3 || fastcmp(word2, "RED")) backcolor = 3; - else if (usi == 4 || fastcmp(word2, "ORANGE")) backcolor = 4; - else if (usi == 5 || fastcmp(word2, "YELLOW")) backcolor = 5; - else if (usi == 6 || fastcmp(word2, "GREEN")) backcolor = 6; - else if (usi == 7 || fastcmp(word2, "BLUE")) backcolor = 7; - else if (usi == 8 || fastcmp(word2, "PURPLE")) backcolor = 8; - else if (usi == 9 || fastcmp(word2, "MAGENTA")) backcolor = 9; - else if (usi == 10 || fastcmp(word2, "AQUA")) backcolor = 10; - else if (usi < 0) backcolor = UINT8_MAX; // CONS_BACKCOLOR user-configured + if (i == 0 || fastcmp(word2, "WHITE")) backcolor = 0; + else if (i == 1 || fastcmp(word2, "GRAY") || fastcmp(word2, "GREY")) backcolor = 1; + else if (i == 2 || fastcmp(word2, "BROWN")) backcolor = 2; + else if (i == 3 || fastcmp(word2, "RED")) backcolor = 3; + else if (i == 4 || fastcmp(word2, "ORANGE")) backcolor = 4; + else if (i == 5 || fastcmp(word2, "YELLOW")) backcolor = 5; + else if (i == 6 || fastcmp(word2, "GREEN")) backcolor = 6; + else if (i == 7 || fastcmp(word2, "BLUE")) backcolor = 7; + else if (i == 8 || fastcmp(word2, "PURPLE")) backcolor = 8; + else if (i == 9 || fastcmp(word2, "MAGENTA")) backcolor = 9; + else if (i == 10 || fastcmp(word2, "AQUA")) backcolor = 10; + else if (i < 0) backcolor = UINT8_MAX; // CONS_BACKCOLOR user-configured else backcolor = 11; // default green textprompts[num]->page[pagenum].backcolor = backcolor; } @@ -1685,7 +1685,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].verticalalign = align; } else if (fastcmp(word, "TEXTSPEED")) - textprompts[num]->page[pagenum].textspeed = min(max(0, usi), 15); + textprompts[num]->page[pagenum].textspeed = min(max(0, i), 15); else if (fastcmp(word, "TEXTSFX")) textprompts[num]->page[pagenum].textsfx = get_number(word2); else if (fastcmp(word, "METAPAGE")) diff --git a/src/f_finale.c b/src/f_finale.c index 8d578c61f..5f6d8ce42 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2113,31 +2113,36 @@ void F_TextPromptDrawer(void) // reuse: // cutnum -> promptnum // scenenum -> pagenum - - if (!promptactive) - return; - - lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); - UINT8 pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4; - boolean rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside); - - // Vertical calculations - INT32 boxh = pagelines*2; - INT32 texth = textprompts[cutnum]->page[scenenum].name[0] ? (pagelines-1)*2 : pagelines*2; // name takes up first line if it exists - INT32 texty = BASEVIDHEIGHT - ((texth * 4) + (texth/2)*4); - INT32 namey = BASEVIDHEIGHT - ((boxh * 4) + (boxh/2)*4); - INT32 chevrony = BASEVIDHEIGHT - (((1*2) * 4) + ((1*2)/2)*4); // force on last line - - // Horizontal calculations - // Shift text to the right if we have a character icon on the left side - // Add 4 margin against icon - INT32 textx = (iconlump != LUMPERROR && !rightside) ? ((boxh * 4) + (boxh/2)*4) + 4 : 4; - INT32 textr = rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4) + 4) : BASEVIDWIDTH-4; + lumpnum_t iconlump; + UINT8 pagelines; + boolean rightside; + INT32 boxh, texth, texty, namey, chevrony; + INT32 textx, textr; // Data patch_t *patch; char *text; + if (!promptactive) + return; + + iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); + pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4; + rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside); + + // Vertical calculations + boxh = pagelines*2; + texth = textprompts[cutnum]->page[scenenum].name[0] ? (pagelines-1)*2 : pagelines*2; // name takes up first line if it exists + texty = BASEVIDHEIGHT - ((texth * 4) + (texth/2)*4); + namey = BASEVIDHEIGHT - ((boxh * 4) + (boxh/2)*4); + chevrony = BASEVIDHEIGHT - (((1*2) * 4) + ((1*2)/2)*4); // force on last line + + // Horizontal calculations + // Shift text to the right if we have a character icon on the left side + // Add 4 margin against icon + textx = (iconlump != LUMPERROR && !rightside) ? ((boxh * 4) + (boxh/2)*4) + 4 : 4; + textr = rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4) + 4) : BASEVIDWIDTH-4; + // Draw background V_DrawTutorialBack(boxh); diff --git a/src/f_finale.h b/src/f_finale.h index 66b608e21..dfee247fb 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -17,6 +17,7 @@ #include "doomtype.h" #include "d_event.h" +#include "p_mobj.h" // // FINALE From 1831df3b2e015f2d9eeb52d0ce0a55179cf2e70d Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sat, 3 Nov 2018 21:14:17 +0000 Subject: [PATCH 15/49] added HWR_DrawTutorialBack for OpenGL --- src/hardware/hw_draw.c | 26 ++++++++++++++++++++++++++ src/hardware/hw_main.h | 1 + src/v_video.c | 20 +++++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 02608892e..6d4467439 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -705,6 +705,32 @@ void HWR_DrawConsoleBack(UINT32 color, INT32 height) HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } +// Very similar to HWR_DrawConsoleBack, except we draw from the middle(-ish) of the screen to the bottom. +void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight) +{ + FOutVector v[4]; + FSurfaceInfo Surf; + INT32 height = (boxheight * 4) + (boxheight/2)*5; // 4 lines of space plus gaps between and some leeway + + // setup some neat-o translucency effect + + v[0].x = v[3].x = -1.0f; + v[2].x = v[1].x = 1.0f; + v[0].y = v[1].y = -1.0f; + v[2].y = v[3].y = -1.0f+((height<<1)/(float)vid.height); + v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; + + v[0].sow = v[3].sow = 0.0f; + v[2].sow = v[1].sow = 1.0f; + v[0].tow = v[1].tow = 1.0f; + v[2].tow = v[3].tow = 0.0f; + + Surf.FlatColor.rgba = UINT2RGBA(color); + Surf.FlatColor.s.alpha = 0x80; + + HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); +} + // ========================================================================== // R_DRAW.C STUFF diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 1ae2d8fc3..f25720d1e 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -35,6 +35,7 @@ void HWR_clearAutomap(void); void HWR_drawAMline(const fline_t *fl, INT32 color); void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength); void HWR_DrawConsoleBack(UINT32 color, INT32 height); +void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight); void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player); void HWR_RenderPlayerView(INT32 viewnumber, player_t *player); void HWR_DrawViewBorder(INT32 clearlines); diff --git a/src/v_video.c b/src/v_video.c index a628b1a8b..f8d0b392c 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1488,8 +1488,26 @@ void V_DrawTutorialBack(INT32 boxheight) boxheight *= vid.dupy; #ifdef HWRENDER - if (rendermode != render_soft) // no support for OpenGL yet + if (rendermode != render_soft && rendermode != render_none) + { + UINT32 hwcolor; + switch (cons_backcolor.value) + { + case 0: hwcolor = 0xffffff00; break; // White + case 1: hwcolor = 0x80808000; break; // Gray + case 2: hwcolor = 0x40201000; break; // Brown + case 3: hwcolor = 0xff000000; break; // Red + case 4: hwcolor = 0xff800000; break; // Orange + case 5: hwcolor = 0x80800000; break; // Yellow + case 6: hwcolor = 0x00800000; break; // Green + case 7: hwcolor = 0x0000ff00; break; // Blue + case 8: hwcolor = 0x4080ff00; break; // Cyan + // Default green + default: hwcolor = 0x00800000; break; + } + HWR_DrawTutorialBack(hwcolor, boxheight); return; + } #endif // heavily simplified -- we don't need to know x or y position, From 247580a16847c81fc3b9234b9b001b291c9034fb Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 20:01:39 -0400 Subject: [PATCH 16/49] Implemented progressive text printing for TextPrompt --- src/f_finale.c | 107 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 27 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 5f6d8ce42..29789c539 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -86,6 +86,7 @@ static boolean promptactive = false; static mobj_t *promptmo; static INT16 promptpostexectag; static boolean promptblockcontrols; +static char *promptpagetext = NULL; // // CUTSCENE TEXT WRITING @@ -2029,6 +2030,52 @@ boolean F_CutsceneResponder(event_t *event) // TEXT PROMPTS // ================== +static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *boxh, INT32 *texth, INT32 *texty, INT32 *namey, INT32 *chevrony, INT32 *textx, INT32 *textr) +{ + // reuse: + // cutnum -> promptnum + // scenenum -> pagenum + lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); + + *pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4; + *rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside); + + // Vertical calculations + *boxh = *pagelines*2; + *texth = textprompts[cutnum]->page[scenenum].name[0] ? (*pagelines-1)*2 : *pagelines*2; // name takes up first line if it exists + *texty = BASEVIDHEIGHT - ((*texth * 4) + (*texth/2)*4); + *namey = BASEVIDHEIGHT - ((*boxh * 4) + (*boxh/2)*4); + *chevrony = BASEVIDHEIGHT - (((1*2) * 4) + ((1*2)/2)*4); // force on last line + + // Horizontal calculations + // Shift text to the right if we have a character icon on the left side + // Add 4 margin against icon + *textx = (iconlump != LUMPERROR && !*rightside) ? ((*boxh * 4) + (*boxh/2)*4) + 4 : 4; + *textr = *rightside ? BASEVIDWIDTH - (((*boxh * 4) + (*boxh/2)*4) + 4) : BASEVIDWIDTH-4; +} + +static void F_PreparePageText(char *pagetext) +{ + UINT8 pagelines; + boolean rightside; + INT32 boxh, texth, texty, namey, chevrony; + INT32 textx, textr; + + F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr); + + if (promptpagetext) + Z_Free(promptpagetext); + promptpagetext = V_WordWrap(textx, textr, 0, pagetext); + + F_NewCutscene(promptpagetext); + cutscene_textspeed = TICRATE/4; // \todo configurable speed by SOC + cutscene_textcount = 0; // no delay in beginning + cutscene_boostspeed = 0; // don't print 8 characters to start + + // \todo update control hot strings on re-config + // and somehow don't reset cutscene text counters +} + static void F_AdvanceToNextPage(void) { UINT8 nextprompt = textprompts[cutnum]->page[scenenum].nextprompt, @@ -2064,12 +2111,20 @@ static void F_AdvanceToNextPage(void) // close the prompt if either num is invalid if (cutnum == INT32_MAX || scenenum == INT32_MAX) F_EndTextPrompt(); + else + { + timetonext = 1; // on page-mode, delay before boosting // \todo timed mode set by SOC, enable different behavior for a legitimate timer + F_PreparePageText(textprompts[cutnum]->page[scenenum].text); + } } void F_EndTextPrompt(void) { promptactive = false; + if (promptmo && promptmo->player && promptblockcontrols) + promptmo->reactiontime = TICRATE/4; // prevent jumping right away // \todo account freeze realtime for this + // \todo net safety, maybe loop all player thinkers? if (promptpostexectag) { @@ -2106,6 +2161,12 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex cutnum = (textprompts[promptnum]) ? promptnum : INT32_MAX; scenenum = (pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX); + + if (promptactive) + { + timetonext = 1; // on page-mode, delay before boosting // \todo timed mode set by SOC, enable different behavior for a legitimate timer + F_PreparePageText(textprompts[cutnum]->page[scenenum].text); + } } void F_TextPromptDrawer(void) @@ -2121,27 +2182,12 @@ void F_TextPromptDrawer(void) // Data patch_t *patch; - char *text; if (!promptactive) return; iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); - pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4; - rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside); - - // Vertical calculations - boxh = pagelines*2; - texth = textprompts[cutnum]->page[scenenum].name[0] ? (pagelines-1)*2 : pagelines*2; // name takes up first line if it exists - texty = BASEVIDHEIGHT - ((texth * 4) + (texth/2)*4); - namey = BASEVIDHEIGHT - ((boxh * 4) + (boxh/2)*4); - chevrony = BASEVIDHEIGHT - (((1*2) * 4) + ((1*2)/2)*4); // force on last line - - // Horizontal calculations - // Shift text to the right if we have a character icon on the left side - // Add 4 margin against icon - textx = (iconlump != LUMPERROR && !rightside) ? ((boxh * 4) + (boxh/2)*4) + 4 : 4; - textr = rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4) + 4) : BASEVIDWIDTH-4; + F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr); // Draw background V_DrawTutorialBack(boxh); @@ -2181,8 +2227,7 @@ void F_TextPromptDrawer(void) // Draw text // \todo Char-by-char printing, see f_finale.c F_WriteText - text = V_WordWrap(textx, textr, 0, textprompts[cutnum]->page[scenenum].text); - V_DrawString(textx, texty, V_SNAPTOBOTTOM, text); + V_DrawString(textx, texty, V_SNAPTOBOTTOM, cutscene_disptext); // Draw name // Don't use V_YELLOWMAP here so that the name color can be changed with control codes @@ -2190,7 +2235,7 @@ void F_TextPromptDrawer(void) V_DrawString(textx, namey, V_SNAPTOBOTTOM, textprompts[cutnum]->page[scenenum].name); // Draw chevron - if (promptblockcontrols) // \todo if !CloseTimer + if (promptblockcontrols && !timetonext) // \todo if !CloseTimer V_DrawString(textr-8, chevrony + (skullAnimCounter/5), (V_SNAPTOBOTTOM|V_YELLOWMAP), "\x1B"); // down arrow } @@ -2223,17 +2268,21 @@ void F_TextPromptTicker(void) if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP)) { + if (timetonext > 1) + timetonext--; + else if (cutscene_baseptr) // don't set boost if we just reset the string + cutscene_boostspeed = 1; // only after a slight delay + if (keypressed) - return; + break; - cutscene_boostspeed = 1; - if (timetonext) - timetonext = 2; - F_AdvanceToNextPage(); + if (!timetonext) // is 0 when finished generating text + { + F_AdvanceToNextPage(); + if (promptactive) + S_StartSound(NULL, sfx_menu1); + } keypressed = true; // prevent repeat events - - if (promptactive) - S_StartSound(NULL, sfx_menu1); } else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP)) keypressed = false; @@ -2241,4 +2290,8 @@ void F_TextPromptTicker(void) break; } } + + // generate letter-by-letter text + if (!F_WriteText()) + timetonext = 0; } From 3e8238f745e48677a010d0bcd30aa974185794aa Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 21:53:17 -0400 Subject: [PATCH 17/49] Implemented auto-advancing TextPrompts * Fixed TextSpeed * New TimeToNext * Other bugs --- src/dehacked.c | 4 +- src/doomstat.h | 3 +- src/f_finale.c | 119 ++++++++++++++++++++++++++++++------------------- 3 files changed, 78 insertions(+), 48 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 725a30b4e..9f819a665 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1685,7 +1685,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].verticalalign = align; } else if (fastcmp(word, "TEXTSPEED")) - textprompts[num]->page[pagenum].textspeed = min(max(0, i), 15); + textprompts[num]->page[pagenum].textspeed = get_number(word2); else if (fastcmp(word, "TEXTSFX")) textprompts[num]->page[pagenum].textsfx = get_number(word2); else if (fastcmp(word, "METAPAGE")) @@ -1708,6 +1708,8 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].nextprompt = usi; else if (fastcmp(word, "NEXTPAGE")) textprompts[num]->page[pagenum].nextpage = usi; + else if (fastcmp(word, "TIMETONEXT")) + textprompts[num]->page[pagenum].timetonext = get_number(word2); else deh_warning("PromptPage %d: unknown word '%s'", num, word); } diff --git a/src/doomstat.h b/src/doomstat.h index eaa19e3d6..73758a6a6 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -175,10 +175,11 @@ typedef struct UINT8 backcolor; // see CON_SetupBackColormap: 0-10, 11 for default, UINT8_MAX for user-defined (CONS_BACKCOLOR) UINT8 align; // text alignment, 0 = left, 1 = right, 2 = center UINT8 verticalalign; // vertical text alignment, 0 = top, 1 = bottom, 2 = middle - UINT8 textspeed; // text speed 0-15, makes it slower. See f_finale.c F_WriteText + UINT8 textspeed; // text speed, delay in tics between characters. sfxenum_t textsfx; // sfx_ id for printing text UINT8 nextprompt; // next prompt to jump to, one-based. 0 = current prompt UINT8 nextpage; // next page to jump to, one-based. 0 = next page within prompt->numpages + INT32 timetonext; // time in tics to jump to next page automatically. 0 = don't jump automatically char *text; } textpage_t; diff --git a/src/f_finale.c b/src/f_finale.c index 29789c539..05a77cedd 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2068,7 +2068,7 @@ static void F_PreparePageText(char *pagetext) promptpagetext = V_WordWrap(textx, textr, 0, pagetext); F_NewCutscene(promptpagetext); - cutscene_textspeed = TICRATE/4; // \todo configurable speed by SOC + cutscene_textspeed = textprompts[cutnum]->page[scenenum].textspeed ? textprompts[cutnum]->page[scenenum].textspeed : TICRATE/5; cutscene_textcount = 0; // no delay in beginning cutscene_boostspeed = 0; // don't print 8 characters to start @@ -2113,17 +2113,22 @@ static void F_AdvanceToNextPage(void) F_EndTextPrompt(); else { - timetonext = 1; // on page-mode, delay before boosting // \todo timed mode set by SOC, enable different behavior for a legitimate timer + // on page mode, number of tics before allowing boost + // on timer mode, number of tics until page advances + timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10; F_PreparePageText(textprompts[cutnum]->page[scenenum].text); } } void F_EndTextPrompt(void) { - promptactive = false; + if (promptactive) { + if (promptmo && promptmo->player && promptblockcontrols) + promptmo->reactiontime = TICRATE/4; // prevent jumping right away // \todo account freeze realtime for this) + // \todo reset frozen realtime? + } - if (promptmo && promptmo->player && promptblockcontrols) - promptmo->reactiontime = TICRATE/4; // prevent jumping right away // \todo account freeze realtime for this + promptactive = false; // \todo net safety, maybe loop all player thinkers? if (promptpostexectag) @@ -2132,13 +2137,6 @@ void F_EndTextPrompt(void) P_LinedefExecute(promptpostexectag, promptmo, NULL); P_MapEnd(); } - - // \todo reset frozen realtime? - - P_SetTarget(&promptmo, NULL); - - // \todo if !promptactive, block player jumping if BT_JUMP is set - // so player does not immediately jump upon prompt close } void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) @@ -2152,21 +2150,25 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex skullAnimCounter = 0; // Set up state - P_SetTarget(&promptmo, mo); + promptmo = mo; promptpostexectag = postexectag; promptblockcontrols = blockcontrols; (void)freezerealtime; // \todo freeze player->realtime, maybe this needs to cycle through player thinkers // Initialize current prompt and scene cutnum = (textprompts[promptnum]) ? promptnum : INT32_MAX; - scenenum = (pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; + scenenum = (cutnum != INT32_MAX && pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX); if (promptactive) { - timetonext = 1; // on page-mode, delay before boosting // \todo timed mode set by SOC, enable different behavior for a legitimate timer + // on page mode, number of tics before allowing boost + // on timer mode, number of tics until page advances + timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10; F_PreparePageText(textprompts[cutnum]->page[scenenum].text); } + else + F_EndTextPrompt(); // run the post-effects immediately } void F_TextPromptDrawer(void) @@ -2255,43 +2257,68 @@ void F_TextPromptTicker(void) skullAnimCounter = 8; // button handling - if (promptblockcontrols) + if (textprompts[cutnum]->page[scenenum].timetonext) { - // \todo loop through all players that have a text prompt - if (promptmo && promptmo->player) - promptmo->player->powers[pw_nocontrol] = 1; - - for (i = 0; i < MAXPLAYERS; i++) + if (promptblockcontrols) // same procedure as below, just without the button handling { - if (netgame && i != serverplayer && i != adminplayer) - continue; - - if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP)) + for (i = 0; i < MAXPLAYERS; i++) { - if (timetonext > 1) - timetonext--; - else if (cutscene_baseptr) // don't set boost if we just reset the string - cutscene_boostspeed = 1; // only after a slight delay + if (netgame && i != serverplayer && i != adminplayer) + continue; - if (keypressed) - break; - - if (!timetonext) // is 0 when finished generating text - { - F_AdvanceToNextPage(); - if (promptactive) - S_StartSound(NULL, sfx_menu1); - } - keypressed = true; // prevent repeat events + players[i].powers[pw_nocontrol] = 1; + break; } - else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP)) - keypressed = false; - - break; } + + if (timetonext >= 1) + timetonext--; + + if (!timetonext) + F_AdvanceToNextPage(); + + F_WriteText(); + } + else + { + if (promptblockcontrols) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (netgame && i != serverplayer && i != adminplayer) + continue; + + players[i].powers[pw_nocontrol] = 1; + + if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP)) + { + if (timetonext > 1) + timetonext--; + else if (cutscene_baseptr) // don't set boost if we just reset the string + cutscene_boostspeed = 1; // only after a slight delay + + if (keypressed) + break; + + if (!timetonext) // is 0 when finished generating text + { + F_AdvanceToNextPage(); + if (promptactive) + S_StartSound(NULL, sfx_menu1); + } + keypressed = true; // prevent repeat events + } + else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP)) + keypressed = false; + + break; + } + } + + // generate letter-by-letter text + if (!F_WriteText()) + timetonext = !promptblockcontrols; // never show the chevron if we can't toggle pages } - // generate letter-by-letter text - if (!F_WriteText()) - timetonext = 0; + } From 7246b6e9a6c158f64ca4e59e3eb70d375101cb72 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 21:53:21 -0400 Subject: [PATCH 18/49] Changed Line 449 post exec tag to line tag --- src/p_spec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_spec.c b/src/p_spec.c index cd4dd76cf..e2c73a5a5 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3462,7 +3462,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); - INT32 postexectag = (line->sidenum[1] != 0xFFFF) ? abs(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0; + INT32 postexectag = line->tag; boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); boolean runpostexec = (line->flags & ML_EFFECT1); From 568d87f2545e4f8d4757a1393708f3b5decbe349 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 3 Nov 2018 22:57:39 -0400 Subject: [PATCH 19/49] Lowercase font for body text; added ICONFLIP parameter --- src/dehacked.c | 3 +++ src/doomstat.h | 1 + src/f_finale.c | 9 ++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 9f819a665..7a89cadcf 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1650,6 +1650,8 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) strncpy(textprompts[num]->page[pagenum].iconname, word2, 8); else if (fastcmp(word, "ICONALIGN")) textprompts[num]->page[pagenum].rightside = (i || word2[0] == 'R'); + else if (fastcmp(word, "ICONFLIP")) + textprompts[num]->page[pagenum].iconflip = (i || word2[0] == 'T' || word2[0] == 'Y'); else if (fastcmp(word, "LINES")) textprompts[num]->page[pagenum].lines = usi; else if (fastcmp(word, "BACKCOLOR")) @@ -1696,6 +1698,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[metapagenum].name, 32); strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[metapagenum].iconname, 8); textprompts[num]->page[pagenum].rightside = textprompts[num]->page[metapagenum].rightside; + textprompts[num]->page[pagenum].iconflip = textprompts[num]->page[metapagenum].iconflip; textprompts[num]->page[pagenum].lines = textprompts[num]->page[metapagenum].lines; textprompts[num]->page[pagenum].backcolor = textprompts[num]->page[metapagenum].backcolor; textprompts[num]->page[pagenum].align = textprompts[num]->page[metapagenum].align; diff --git a/src/doomstat.h b/src/doomstat.h index 73758a6a6..7bcf59946 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -171,6 +171,7 @@ typedef struct char name[32]; // narrator name char iconname[8]; // narrator icon lump boolean rightside; // narrator side, false = left, true = right + boolean iconflip; // narrator flip icon horizontally UINT8 lines; // # of lines to show. If name is specified, name takes one of the lines. If 0, defaults to 4. UINT8 backcolor; // see CON_SetupBackColormap: 0-10, 11 for default, UINT8_MAX for user-defined (CONS_BACKCOLOR) UINT8 align; // text alignment, 0 = left, 1 = right, 2 = center diff --git a/src/f_finale.c b/src/f_finale.c index 05a77cedd..1fae49e9d 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2223,18 +2223,21 @@ void F_TextPromptDrawer(void) icony = namey << FRACBITS; } - V_DrawFixedPatch(iconx, icony, scale, V_SNAPTOBOTTOM, patch, NULL); + if (textprompts[cutnum]->page[scenenum].iconflip) + iconx += FixedMul(patch->width, scale) << FRACBITS; + + V_DrawFixedPatch(iconx, icony, scale, (V_SNAPTOBOTTOM|(textprompts[cutnum]->page[scenenum].iconflip ? V_FLIP : 0)), patch, NULL); W_UnlockCachedPatch(patch); } // Draw text // \todo Char-by-char printing, see f_finale.c F_WriteText - V_DrawString(textx, texty, V_SNAPTOBOTTOM, cutscene_disptext); + V_DrawString(textx, texty, (V_SNAPTOBOTTOM|V_ALLOWLOWERCASE), cutscene_disptext); // Draw name // Don't use V_YELLOWMAP here so that the name color can be changed with control codes if (textprompts[cutnum]->page[scenenum].name[0]) - V_DrawString(textx, namey, V_SNAPTOBOTTOM, textprompts[cutnum]->page[scenenum].name); + V_DrawString(textx, namey, (V_SNAPTOBOTTOM|V_ALLOWLOWERCASE), textprompts[cutnum]->page[scenenum].name); // Draw chevron if (promptblockcontrols && !timetonext) // \todo if !CloseTimer From f8d64c93d719c644eaa31f12e0f4cf6529de706d Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sun, 4 Nov 2018 16:45:29 -0500 Subject: [PATCH 20/49] Move Line 449 to Line 459; allow post exec tag by either Back X offset or line tag --- src/p_spec.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index e2c73a5a5..edf9174d6 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3456,27 +3456,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; - case 449: // Control Text Prompt - // console player only unless NOCLIMB is set - if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player))) - { - INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); - INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); - INT32 postexectag = line->tag; - - boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); - boolean runpostexec = (line->flags & ML_EFFECT1); - boolean blockcontrols = !(line->flags & ML_EFFECT2); - boolean freezerealtime = !(line->flags & ML_EFFECT3); - //boolean freezethinkers = (line->flags & ML_EFFECT4); - - if (closetextprompt) - F_EndTextPrompt(); - else - F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); - } - break; - case 450: // Execute Linedef Executor - for recursion P_LinedefExecute(line->tag, mo, NULL); break; @@ -3779,6 +3758,27 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) P_ResetColormapFader(§ors[secnum]); break; + case 459: // Control Text Prompt + // console player only unless NOCLIMB is set + if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player))) + { + INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); + INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); + INT32 postexectag = abs((line->sidenum[1] != 0xFFFF) ? sides[line->sidenum[1]].textureoffset>>FRACBITS : line->tag); + + boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); + boolean runpostexec = (line->flags & ML_EFFECT1); + boolean blockcontrols = !(line->flags & ML_EFFECT2); + boolean freezerealtime = !(line->flags & ML_EFFECT3); + //boolean freezethinkers = (line->flags & ML_EFFECT4); + + if (closetextprompt) + F_EndTextPrompt(); + else + F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); + } + break; + #ifdef POLYOBJECTS case 480: // Polyobj_DoorSlide case 481: // Polyobj_DoorSwing From 039b7b17cfd351f50dd99b04ba173fe771e8cfde Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sun, 4 Nov 2018 21:14:22 -0500 Subject: [PATCH 21/49] Support underscores -> spaces in TextPrompt name --- src/dehacked.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index 7a89cadcf..dcd61bd31 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1637,6 +1637,8 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) if (fastcmp(word, "NAME")) { + INT32 i; + // HACK: Add yellow control char now // so the drawing function doesn't call it repeatedly char name[32]; @@ -1644,6 +1646,14 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) name[1] = 0; strncat(name, word2, 31); name[31] = 0; + + // Replace _ with ' ' + for (i = 0; i < 32 && name[i]; i++) + { + if (name[i] == '_') + name[i] = ' '; + } + strncpy(textprompts[num]->page[pagenum].name, name, 32); } else if (fastcmp(word, "ICON")) From 0169847e063d1a51a041fff5735c32c732284a00 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sun, 4 Nov 2018 22:09:54 -0500 Subject: [PATCH 22/49] Pause TextPrompt when game is paused --- src/f_finale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index 1fae49e9d..6ba9132cf 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2248,7 +2248,7 @@ void F_TextPromptTicker(void) { INT32 i; - if (!promptactive) + if (!promptactive || paused || P_AutoPause()) return; // advance animation From 3d86cbc729353a4c0d408381cdd65b3f03988abf Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sun, 4 Nov 2018 22:22:47 -0500 Subject: [PATCH 23/49] Close text prompt upon level load --- src/f_finale.c | 15 ++++++++------- src/f_finale.h | 2 +- src/p_setup.c | 3 +++ src/p_spec.c | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 6ba9132cf..8a6a8ce0c 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2110,7 +2110,7 @@ static void F_AdvanceToNextPage(void) // close the prompt if either num is invalid if (cutnum == INT32_MAX || scenenum == INT32_MAX) - F_EndTextPrompt(); + F_EndTextPrompt(false, false); else { // on page mode, number of tics before allowing boost @@ -2120,18 +2120,19 @@ static void F_AdvanceToNextPage(void) } } -void F_EndTextPrompt(void) +void F_EndTextPrompt(boolean forceexec, boolean noexec) { - if (promptactive) { + boolean promptwasactive = promptactive; + promptactive = false; + + if (promptwasactive) { if (promptmo && promptmo->player && promptblockcontrols) promptmo->reactiontime = TICRATE/4; // prevent jumping right away // \todo account freeze realtime for this) // \todo reset frozen realtime? } - promptactive = false; - // \todo net safety, maybe loop all player thinkers? - if (promptpostexectag) + if ((promptwasactive || forceexec) && !noexec && promptpostexectag) { P_MapStart(); P_LinedefExecute(promptpostexectag, promptmo, NULL); @@ -2168,7 +2169,7 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex F_PreparePageText(textprompts[cutnum]->page[scenenum].text); } else - F_EndTextPrompt(); // run the post-effects immediately + F_EndTextPrompt(true, false); // run the post-effects immediately } void F_TextPromptDrawer(void) diff --git a/src/f_finale.h b/src/f_finale.h index dfee247fb..8ce7ac22e 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -54,7 +54,7 @@ void F_EndCutScene(void); void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime); void F_TextPromptDrawer(void); -void F_EndTextPrompt(void); +void F_EndTextPrompt(boolean forceexec, boolean noexec); void F_StartGameEnd(void); void F_StartIntro(void); diff --git a/src/p_setup.c b/src/p_setup.c index eb25c51c8..b2dfedb4e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2753,6 +2753,9 @@ boolean P_SetupLevel(boolean skipprecip) I_UpdateNoVsync(); } + // Close text prompt before freeing the old level + F_EndTextPrompt(false, true); + #ifdef HAVE_BLUA LUA_InvalidateLevel(); #endif diff --git a/src/p_spec.c b/src/p_spec.c index edf9174d6..42153b4bf 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3773,7 +3773,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) //boolean freezethinkers = (line->flags & ML_EFFECT4); if (closetextprompt) - F_EndTextPrompt(); + F_EndTextPrompt(false, false); else F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); } From 6c785cff56d9e766e9b0f4a92d943a62b60da8c8 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 9 Nov 2018 21:55:14 -0500 Subject: [PATCH 24/49] Fix crash when page text is empty; add checks for MAX_PROMPTS and MAX_PAGES --- src/dehacked.c | 6 +++--- src/doomstat.h | 7 +++++-- src/f_finale.c | 17 ++++++++++------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index dcd61bd31..0802fc49d 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1773,17 +1773,17 @@ static void readtextprompt(MYFILE *f, INT32 num) if (fastcmp(word, "NUMPAGES")) { - textprompts[num]->numpages = value; + textprompts[num]->numpages = min(max(value, 0), MAX_PAGES); } else if (fastcmp(word, "PAGE")) { - if (1 <= value && value <= 128) + if (1 <= value && value <= MAX_PAGES) { textprompts[num]->page[value - 1].backcolor = UINT8_MAX; // non-zero default readtextpromptpage(f, num, value - 1); } else - deh_warning("Page number %d out of range (1 - 128)", value); + deh_warning("Page number %d out of range (1 - %d)", value, MAX_PAGES); } else diff --git a/src/doomstat.h b/src/doomstat.h index 7bcf59946..eb1726e54 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -166,6 +166,9 @@ typedef struct extern cutscene_t *cutscenes[128]; +#define MAX_PROMPTS 256 +#define MAX_PAGES 128 + typedef struct { char name[32]; // narrator name @@ -186,11 +189,11 @@ typedef struct typedef struct { - textpage_t page[128]; // 128 pages per prompt. + textpage_t page[MAX_PAGES]; INT32 numpages; // Number of pages in this prompt } textprompt_t; -extern textprompt_t *textprompts[256]; +extern textprompt_t *textprompts[MAX_PROMPTS]; // For the Custom Exit linedef. extern INT16 nextmapoverride; diff --git a/src/f_finale.c b/src/f_finale.c index 8a6a8ce0c..f32e44b57 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2065,7 +2065,7 @@ static void F_PreparePageText(char *pagetext) if (promptpagetext) Z_Free(promptpagetext); - promptpagetext = V_WordWrap(textx, textr, 0, pagetext); + promptpagetext = (pagetext && pagetext[0]) ? V_WordWrap(textx, textr, 0, pagetext) : ""; F_NewCutscene(promptpagetext); cutscene_textspeed = textprompts[cutnum]->page[scenenum].textspeed ? textprompts[cutnum]->page[scenenum].textspeed : TICRATE/5; @@ -2085,7 +2085,7 @@ static void F_AdvanceToNextPage(void) // determine next prompt if (nextprompt) { - if (textprompts[nextprompt-1]) + if (nextprompt <= MAX_PROMPTS && textprompts[nextprompt-1]) cutnum = nextprompt-1; else cutnum = INT32_MAX; @@ -2095,14 +2095,14 @@ static void F_AdvanceToNextPage(void) if (nextpage) { scenenum = nextpage-1; - if (scenenum > textprompts[cutnum]->numpages-1) + if (scenenum >= MAX_PAGES || scenenum > textprompts[cutnum]->numpages-1) scenenum = INT32_MAX; } else { if (cutnum != oldcutnum) scenenum = 0; - else if (scenenum < textprompts[cutnum]->numpages-1) + else if (scenenum + 1 < MAX_PAGES && scenenum < textprompts[cutnum]->numpages-1) scenenum++; else scenenum = INT32_MAX; @@ -2157,8 +2157,8 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex (void)freezerealtime; // \todo freeze player->realtime, maybe this needs to cycle through player thinkers // Initialize current prompt and scene - cutnum = (textprompts[promptnum]) ? promptnum : INT32_MAX; - scenenum = (cutnum != INT32_MAX && pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; + cutnum = (promptnum < MAX_PROMPTS && textprompts[promptnum]) ? promptnum : INT32_MAX; + scenenum = (cutnum != INT32_MAX && pagenum < MAX_PAGES && pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX); if (promptactive) @@ -2320,7 +2320,10 @@ void F_TextPromptTicker(void) } // generate letter-by-letter text - if (!F_WriteText()) + if (scenenum >= MAX_PAGES || + !textprompts[cutnum]->page[scenenum].text || + !textprompts[cutnum]->page[scenenum].text[0] || + !F_WriteText()) timetonext = !promptblockcontrols; // never show the chevron if we can't toggle pages } From 90c83962d1db9c4989496ceef69e44aadae41ae8 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 9 Nov 2018 22:06:53 -0500 Subject: [PATCH 25/49] Fix tmthing crash in EndTextPrompt when loading an invalid prompt on level start --- src/f_finale.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index f32e44b57..f120cd756 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2125,7 +2125,8 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec) boolean promptwasactive = promptactive; promptactive = false; - if (promptwasactive) { + if (promptwasactive) + { if (promptmo && promptmo->player && promptblockcontrols) promptmo->reactiontime = TICRATE/4; // prevent jumping right away // \todo account freeze realtime for this) // \todo reset frozen realtime? @@ -2134,9 +2135,14 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec) // \todo net safety, maybe loop all player thinkers? if ((promptwasactive || forceexec) && !noexec && promptpostexectag) { - P_MapStart(); - P_LinedefExecute(promptpostexectag, promptmo, NULL); - P_MapEnd(); + if (tmthing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail + P_LinedefExecute(promptpostexectag, promptmo, NULL); + else + { + P_MapStart(); + P_LinedefExecute(promptpostexectag, promptmo, NULL); + P_MapEnd(); + } } } @@ -2326,6 +2332,4 @@ void F_TextPromptTicker(void) !F_WriteText()) timetonext = !promptblockcontrols; // never show the chevron if we can't toggle pages } - - } From b7af1e385bae3847b7eae398a3ac0d0f0efc5050 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 9 Nov 2018 22:38:55 -0500 Subject: [PATCH 26/49] Set up separate background color for prompts vs. console --- src/console.c | 40 ++++++++++++++++++++++++++++++++-------- src/console.h | 2 ++ src/dehacked.c | 2 +- src/doomstat.h | 2 +- src/f_finale.c | 2 +- src/v_video.c | 11 ++++++++--- src/v_video.h | 2 +- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/console.c b/src/console.c index 9bc01cf19..f4234d949 100644 --- a/src/console.c +++ b/src/console.c @@ -232,18 +232,20 @@ UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, *orangem // Console BG color UINT8 *consolebgmap = NULL; +UINT8 *promptbgmap = NULL; +static UINT8 promptbgcolor = UINT8_MAX; -void CON_SetupBackColormap(void) +void CON_SetupBackColormapEx(INT32 color, boolean prompt) { UINT16 i, palsum; UINT8 j, palindex, shift; UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE); - if (!consolebgmap) - consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); + if (color == INT32_MAX) + color = cons_backcolor.value; shift = 6; // 12 colors -- shift of 7 means 6 colors - switch (cons_backcolor.value) + switch (color) { case 0: palindex = 15; break; // White case 1: palindex = 31; break; // Gray @@ -257,20 +259,42 @@ void CON_SetupBackColormap(void) case 9: palindex = 187; break; // Magenta case 10: palindex = 139; break; // Aqua // Default green - default: palindex = 175; break; -} + default: palindex = 175; color = 11; break; + } + + if (prompt) + { + if (!promptbgmap) + promptbgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); + + if (color == promptbgcolor) + return; + else + promptbgcolor = color; + } + else if (!consolebgmap) + consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); // setup background colormap for (i = 0, j = 0; i < 768; i += 3, j++) { palsum = (pal[i] + pal[i+1] + pal[i+2]) >> shift; - consolebgmap[j] = (UINT8)(palindex - palsum); + if (prompt) + promptbgmap[j] = (UINT8)(palindex - palsum); + else + consolebgmap[j] = (UINT8)(palindex - palsum); } } +void CON_SetupBackColormap(void) +{ + CON_SetupBackColormapEx(cons_backcolor.value, false); + CON_SetupBackColormapEx(1, true); // default to gray +} + static void CONS_backcolor_Change(void) { - CON_SetupBackColormap(); + CON_SetupBackColormapEx(cons_backcolor.value, false); } static void CON_SetupColormaps(void) diff --git a/src/console.h b/src/console.h index 970f841d0..c194f44bf 100644 --- a/src/console.h +++ b/src/console.h @@ -38,7 +38,9 @@ extern UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, * // Console bg color (auto updated to match) extern UINT8 *consolebgmap; +extern UINT8 *promptbgmap; +void CON_SetupBackColormapEx(INT32 color, boolean prompt); void CON_SetupBackColormap(void); void CON_ClearHUD(void); // clear heads up messages diff --git a/src/dehacked.c b/src/dehacked.c index 0802fc49d..61dba24c8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1779,7 +1779,7 @@ static void readtextprompt(MYFILE *f, INT32 num) { if (1 <= value && value <= MAX_PAGES) { - textprompts[num]->page[value - 1].backcolor = UINT8_MAX; // non-zero default + textprompts[num]->page[value - 1].backcolor = 1; // default to gray readtextpromptpage(f, num, value - 1); } else diff --git a/src/doomstat.h b/src/doomstat.h index eb1726e54..6ff32e95d 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -176,7 +176,7 @@ typedef struct boolean rightside; // narrator side, false = left, true = right boolean iconflip; // narrator flip icon horizontally UINT8 lines; // # of lines to show. If name is specified, name takes one of the lines. If 0, defaults to 4. - UINT8 backcolor; // see CON_SetupBackColormap: 0-10, 11 for default, UINT8_MAX for user-defined (CONS_BACKCOLOR) + INT32 backcolor; // see CON_SetupBackColormap: 0-11, INT32_MAX for user-defined (CONS_BACKCOLOR) UINT8 align; // text alignment, 0 = left, 1 = right, 2 = center UINT8 verticalalign; // vertical text alignment, 0 = top, 1 = bottom, 2 = middle UINT8 textspeed; // text speed, delay in tics between characters. diff --git a/src/f_finale.c b/src/f_finale.c index f120cd756..ad9fd26ce 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2199,7 +2199,7 @@ void F_TextPromptDrawer(void) F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr); // Draw background - V_DrawTutorialBack(boxh); + V_DrawPromptBack(boxh, textprompts[cutnum]->page[scenenum].backcolor); // Draw narrator icon if (iconlump != LUMPERROR) diff --git a/src/v_video.c b/src/v_video.c index f8d0b392c..7296dc754 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1481,17 +1481,20 @@ void V_DrawFadeConsBack(INT32 plines) } // Very similar to F_DrawFadeConsBack, except we draw from the middle(-ish) of the screen to the bottom. -void V_DrawTutorialBack(INT32 boxheight) +void V_DrawPromptBack(INT32 boxheight, INT32 color) { UINT8 *deststop, *buf; boxheight *= vid.dupy; + if (color == INT32_MAX) + color = cons_backcolor.value; + #ifdef HWRENDER if (rendermode != render_soft && rendermode != render_none) { UINT32 hwcolor; - switch (cons_backcolor.value) + switch (color) { case 0: hwcolor = 0xffffff00; break; // White case 1: hwcolor = 0x80808000; break; // Gray @@ -1510,12 +1513,14 @@ void V_DrawTutorialBack(INT32 boxheight) } #endif + CON_SetupBackColormapEx(color, true); + // heavily simplified -- we don't need to know x or y position, // just the start and stop positions deststop = screens[0] + vid.rowbytes * vid.height; buf = deststop - vid.rowbytes * ((boxheight * 4) + (boxheight/2)*5); // 4 lines of space plus gaps between and some leeway for (; buf < deststop; ++buf) - *buf = consolebgmap[*buf]; + *buf = promptbgmap[*buf]; } // Gets string colormap, used for 0x80 color codes diff --git a/src/v_video.h b/src/v_video.h index ee958c2fa..84a027963 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -158,7 +158,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum); void V_DrawFadeScreen(UINT16 color, UINT8 strength); void V_DrawFadeConsBack(INT32 plines); -void V_DrawTutorialBack(INT32 boxheight); +void V_DrawPromptBack(INT32 boxheight, INT32 color); // draw a single character void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); From 2106ff30f09c4a7d0702d47cfa4c0f2f5d1a48b5 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 9 Nov 2018 22:47:42 -0500 Subject: [PATCH 27/49] Make gray/black text prompt backcolor darker in OpenGL --- src/dehacked.c | 9 +++++---- src/hardware/hw_draw.c | 2 +- src/v_video.c | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 61dba24c8..9130c3e40 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1666,9 +1666,10 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].lines = usi; else if (fastcmp(word, "BACKCOLOR")) { - UINT8 backcolor; + INT32 backcolor; if (i == 0 || fastcmp(word2, "WHITE")) backcolor = 0; - else if (i == 1 || fastcmp(word2, "GRAY") || fastcmp(word2, "GREY")) backcolor = 1; + else if (i == 1 || fastcmp(word2, "GRAY") || fastcmp(word2, "GREY") || + fastcmp(word2, "BLACK")) backcolor = 1; else if (i == 2 || fastcmp(word2, "BROWN")) backcolor = 2; else if (i == 3 || fastcmp(word2, "RED")) backcolor = 3; else if (i == 4 || fastcmp(word2, "ORANGE")) backcolor = 4; @@ -1678,8 +1679,8 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) else if (i == 8 || fastcmp(word2, "PURPLE")) backcolor = 8; else if (i == 9 || fastcmp(word2, "MAGENTA")) backcolor = 9; else if (i == 10 || fastcmp(word2, "AQUA")) backcolor = 10; - else if (i < 0) backcolor = UINT8_MAX; // CONS_BACKCOLOR user-configured - else backcolor = 11; // default green + else if (i < 0) backcolor = INT32_MAX; // CONS_BACKCOLOR user-configured + else backcolor = 1; // default gray textprompts[num]->page[pagenum].backcolor = backcolor; } else if (fastcmp(word, "ALIGN")) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 6d4467439..4c6a29fa3 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -726,7 +726,7 @@ void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight) v[2].tow = v[3].tow = 0.0f; Surf.FlatColor.rgba = UINT2RGBA(color); - Surf.FlatColor.s.alpha = 0x80; + Surf.FlatColor.s.alpha = (color == 0 ? 0xC0 : 0x80); // make black darker, like software HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } diff --git a/src/v_video.c b/src/v_video.c index 7296dc754..3e2910df5 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1497,7 +1497,7 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color) switch (color) { case 0: hwcolor = 0xffffff00; break; // White - case 1: hwcolor = 0x80808000; break; // Gray + case 1: hwcolor = 0x00000000; break; // Gray // Note this is different from V_DrawFadeConsBack case 2: hwcolor = 0x40201000; break; // Brown case 3: hwcolor = 0xff000000; break; // Red case 4: hwcolor = 0xff800000; break; // Orange From b25cf9e0d9b67e0a1c3b34bcc6494d61cd498d3e Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 9 Nov 2018 23:26:41 -0500 Subject: [PATCH 28/49] Text prompt Hide HUD dehacked --- src/dehacked.c | 10 ++++++++++ src/doomstat.h | 1 + src/f_finale.c | 9 +++++++++ src/f_finale.h | 1 + 4 files changed, 21 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index 9130c3e40..0fc3f905a 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1701,6 +1701,14 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].textspeed = get_number(word2); else if (fastcmp(word, "TEXTSFX")) textprompts[num]->page[pagenum].textsfx = get_number(word2); + else if (fastcmp(word, "HIDEHUD")) + { + UINT8 hidehud = 0; + if (usi == 0 || (word2[0] == 'F' && (word2[1] == 'A' || !word2[1])) || word2[0] == 'N') hidehud = 1; // false + else if (usi == 1 || word2[0] == 'T' || word2[0] == 'Y') hidehud = 1; // true (hide appropriate HUD elements) + else if (usi == 2 || word2[0] == 'A' || (word2[0] == 'F' && word2[1] == 'O')) hidehud = 2; // force (hide all HUD elements) + textprompts[num]->page[pagenum].hidehud = hidehud; + } else if (fastcmp(word, "METAPAGE")) { if (usi && usi <= textprompts[num]->numpages) @@ -1716,6 +1724,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].verticalalign = textprompts[num]->page[metapagenum].verticalalign; textprompts[num]->page[pagenum].textspeed = textprompts[num]->page[metapagenum].textspeed; textprompts[num]->page[pagenum].textsfx = textprompts[num]->page[metapagenum].textsfx; + textprompts[num]->page[pagenum].hidehud = textprompts[num]->page[metapagenum].hidehud; } } else if (fastcmp(word, "NEXTPROMPT")) @@ -1781,6 +1790,7 @@ static void readtextprompt(MYFILE *f, INT32 num) if (1 <= value && value <= MAX_PAGES) { textprompts[num]->page[value - 1].backcolor = 1; // default to gray + textprompts[num]->page[value - 1].hidehud = 1; // hide appropriate HUD elements readtextpromptpage(f, num, value - 1); } else diff --git a/src/doomstat.h b/src/doomstat.h index 6ff32e95d..a46711cc4 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -175,6 +175,7 @@ typedef struct char iconname[8]; // 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 UINT8 lines; // # of lines to show. If name is specified, name takes one of the lines. If 0, defaults to 4. INT32 backcolor; // see CON_SetupBackColormap: 0-11, INT32_MAX for user-defined (CONS_BACKCOLOR) UINT8 align; // text alignment, 0 = left, 1 = right, 2 = center diff --git a/src/f_finale.c b/src/f_finale.c index ad9fd26ce..aec567123 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -33,6 +33,7 @@ #include "m_cond.h" #include "p_local.h" #include "p_setup.h" +#include "st_stuff.h" // hud hiding #ifdef HAVE_BLUA #include "lua_hud.h" @@ -2030,6 +2031,14 @@ boolean F_CutsceneResponder(event_t *event) // TEXT PROMPTS // ================== +INT32 F_GetPromptHideHud() +{ + if (cutnum == INT32_MAX || scenenum == INT32_MAX || !textprompts[cutnum] || scenenum >= textprompts[cutnum]->numpages) + return 0; + else + return textprompts[cutnum]->page[scenenum]->hidehud; +} + static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *boxh, INT32 *texth, INT32 *texty, INT32 *namey, INT32 *chevrony, INT32 *textx, INT32 *textr) { // reuse: diff --git a/src/f_finale.h b/src/f_finale.h index 8ce7ac22e..a6c962dea 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -55,6 +55,7 @@ void F_EndCutScene(void); void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime); void F_TextPromptDrawer(void); void F_EndTextPrompt(boolean forceexec, boolean noexec); +INT32 F_GetPromptHideHud(void); void F_StartGameEnd(void); void F_StartIntro(void); From 19dd2b500bcffbbe991213449c78d724186f5a51 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 00:10:16 -0500 Subject: [PATCH 29/49] Actually fix empty prompt text crash --- src/f_finale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index ad9fd26ce..0abee4b45 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2065,7 +2065,7 @@ static void F_PreparePageText(char *pagetext) if (promptpagetext) Z_Free(promptpagetext); - promptpagetext = (pagetext && pagetext[0]) ? V_WordWrap(textx, textr, 0, pagetext) : ""; + promptpagetext = (pagetext && pagetext[0]) ? V_WordWrap(textx, textr, 0, pagetext) : Z_StrDup(""); F_NewCutscene(promptpagetext); cutscene_textspeed = textprompts[cutnum]->page[scenenum].textspeed ? textprompts[cutnum]->page[scenenum].textspeed : TICRATE/5; From bf9b5c5d5bb94bbb9f54622c08d39a4da7214542 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 01:00:18 -0500 Subject: [PATCH 30/49] Prompt HUD hiding implementation --- src/f_finale.c | 62 +++++++++++++++++++++++++++++++++++++++++++------- src/f_finale.h | 3 ++- src/st_stuff.c | 35 +++++++++++++++++++++++++--- 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 64648fdda..8d3aaea67 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2031,14 +2031,6 @@ boolean F_CutsceneResponder(event_t *event) // TEXT PROMPTS // ================== -INT32 F_GetPromptHideHud() -{ - if (cutnum == INT32_MAX || scenenum == INT32_MAX || !textprompts[cutnum] || scenenum >= textprompts[cutnum]->numpages) - return 0; - else - return textprompts[cutnum]->page[scenenum]->hidehud; -} - static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *boxh, INT32 *texth, INT32 *texty, INT32 *namey, INT32 *chevrony, INT32 *textx, INT32 *textr) { // reuse: @@ -2063,6 +2055,60 @@ static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *b *textr = *rightside ? BASEVIDWIDTH - (((*boxh * 4) + (*boxh/2)*4) + 4) : BASEVIDWIDTH-4; } +static fixed_t F_GetPromptHideHudBound(void) +{ + UINT8 pagelines; + boolean rightside; + INT32 boxh, texth, texty, namey, chevrony; + INT32 textx, textr; + + if (cutnum == INT32_MAX || scenenum == INT32_MAX || !textprompts[cutnum] || scenenum >= textprompts[cutnum]->numpages || + !textprompts[cutnum]->page[scenenum].hidehud || + (splitscreen && textprompts[cutnum]->page[scenenum].hidehud != 2)) // don't hide on splitscreen, unless hide all is forced + return 0; + else if (textprompts[cutnum]->page[scenenum].hidehud == 2) // hide all + return BASEVIDHEIGHT; + + F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr); + + // calc boxheight (see V_DrawPromptBack) + boxh *= vid.dupy; + boxh = (boxh * 4) + (boxh/2)*5; // 4 lines of space plus gaps between and some leeway + + // return a coordinate to check + // if negative: don't show hud elements below this coordinate (visually) + // if positive: don't show hud elements above this coordinate (visually) + return 0 - boxh; // \todo: if prompt at top of screen (someday), make this return positive +} + +boolean F_GetPromptHideHudAll(void) +{ + if (cutnum == INT32_MAX || scenenum == INT32_MAX || !textprompts[cutnum] || scenenum >= textprompts[cutnum]->numpages || + !textprompts[cutnum]->page[scenenum].hidehud || + (splitscreen && textprompts[cutnum]->page[scenenum].hidehud != 2)) // don't hide on splitscreen, unless hide all is forced + return false; + else if (textprompts[cutnum]->page[scenenum].hidehud == 2) // hide all + return true; + else + return false; +} + +boolean F_GetPromptHideHud(fixed_t y) +{ + INT32 ybound; + boolean fromtop; + fixed_t ytest; + + if (!promptactive) + return false; + + ybound = F_GetPromptHideHudBound(); + fromtop = (ybound >= 0); + ytest = (fromtop ? ybound : BASEVIDHEIGHT + ybound); + + return (fromtop ? y < ytest : y >= ytest); // true means hide +} + static void F_PreparePageText(char *pagetext) { UINT8 pagelines; diff --git a/src/f_finale.h b/src/f_finale.h index a6c962dea..0c9032ac2 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -55,7 +55,8 @@ void F_EndCutScene(void); void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime); void F_TextPromptDrawer(void); void F_EndTextPrompt(boolean forceexec, boolean noexec); -INT32 F_GetPromptHideHud(void); +boolean F_GetPromptHideHudAll(void); +boolean F_GetPromptHideHud(fixed_t y); void F_StartGameEnd(void); void F_StartIntro(void); diff --git a/src/st_stuff.c b/src/st_stuff.c index fa13e008a..26d9678a3 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -603,6 +603,9 @@ static void ST_drawDebugInfo(void) static void ST_drawScore(void) { + if (F_GetPromptHideHud(hudinfo[HUD_SCORE].y)) + return; + // SCORE: ST_DrawPatchFromHud(HUD_SCORE, sboscore, V_HUDTRANS); if (objectplacing) @@ -712,6 +715,9 @@ static void ST_drawTime(void) tictrn = G_TicsToCentiseconds(tics); } + if (F_GetPromptHideHud(hudinfo[HUD_TIME].y)) + return; + // TIME: ST_DrawPatchFromHud(HUD_TIME, ((downwards && (tics < 30*TICRATE) && (leveltime/5 & 1)) ? sboredtime : sbotime), V_HUDTRANS); @@ -738,6 +744,9 @@ static inline void ST_drawRings(void) { INT32 ringnum; + if (F_GetPromptHideHud(hudinfo[HUD_RINGS].y)) + return; + ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0)); @@ -756,6 +765,9 @@ static void ST_drawLivesArea(void) if (!stplyr->skincolor) return; // Just joined a server, skin isn't loaded yet! + if (F_GetPromptHideHud(hudinfo[HUD_LIVES].y)) + return; + // face background V_DrawSmallScaledPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, livesback); @@ -927,6 +939,9 @@ static void ST_drawInput(void) if (stplyr->powers[pw_carry] == CR_NIGHTSMODE) y -= 16; + if (F_GetPromptHideHud(y)) + return; + // O backing V_DrawFill(x, y-1, 16, 16, hudinfo[HUD_LIVES].f|20); V_DrawFill(x, y+15, 16, 1, hudinfo[HUD_LIVES].f|29); @@ -1202,6 +1217,9 @@ static void ST_drawPowerupHUD(void) static INT32 flagoffs[2] = {0, 0}, shieldoffs[2] = {0, 0}; #define ICONSEP (16+4) // matches weapon rings HUD + if (F_GetPromptHideHud(hudinfo[HUD_POWERUPS].y)) + return; + if (stplyr->spectator || stplyr->playerstate != PST_LIVE) return; @@ -1364,7 +1382,7 @@ static void ST_drawFirstPersonHUD(void) p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); // Display the countdown drown numbers! - if (p) + if (p && !F_GetPromptHideHud(60 - SHORT(p->topoffset))) V_DrawScaledPatch((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset), 60 - SHORT(p->topoffset), V_PERPLAYER|V_PERPLAYER|V_TRANSLUCENT, p); } @@ -1908,6 +1926,9 @@ static void ST_drawMatchHUD(void) const INT32 y = 176; // HUD_LIVES INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6; + if (F_GetPromptHideHud(y)) + return; + if (!G_RingSlingerGametype()) return; @@ -1954,6 +1975,9 @@ static void ST_drawTextHUD(void) y -= 8;\ } + if (F_GetPromptHideHud(y)) + return; + if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) { if (leveltime < hidetime * TICRATE) @@ -2087,6 +2111,9 @@ static void ST_drawTeamHUD(void) patch_t *p; #define SEP 20 + if (F_GetPromptHideHud(0)) // y base is 0 + return; + if (gametype == GT_CTF) p = bflagico; else @@ -2200,7 +2227,8 @@ static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offse interval = 0; } - V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, hudinfo[HUD_HUNTPICS].y, hudinfo[HUD_HUNTPICS].f|V_PERPLAYER|V_HUDTRANS, patches[i]); + if (!F_GetPromptHideHud(hudinfo[HUD_HUNTPICS].y)) + V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, hudinfo[HUD_HUNTPICS].y, hudinfo[HUD_HUNTPICS].f|V_PERPLAYER|V_HUDTRANS, patches[i]); return interval; } @@ -2298,7 +2326,8 @@ static void ST_overlayDrawer(void) //hu_showscores = auto hide score/time/rings when tab rankings are shown if (!(hu_showscores && (netgame || multiplayer))) { - if (maptol & TOL_NIGHTS || G_IsSpecialStage(gamemap)) + if ((maptol & TOL_NIGHTS || G_IsSpecialStage(gamemap)) && + !F_GetPromptHideHudAll()) ST_drawNiGHTSHUD(); else { From 3174969755d3eaf8f787c87a7737a08cfc0ace37 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 09:32:53 -0500 Subject: [PATCH 31/49] Added page tags and find page by tag * Added tutorial mode defines to this branch --- src/dehacked.c | 2 ++ src/doomstat.h | 4 ++++ src/f_finale.c | 30 ++++++++++++++++++++++++++++++ src/f_finale.h | 1 + src/g_game.c | 3 +++ src/p_setup.c | 1 + src/p_spec.c | 3 +++ 7 files changed, 44 insertions(+) diff --git a/src/dehacked.c b/src/dehacked.c index 0fc3f905a..214d47a16 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1727,6 +1727,8 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].hidehud = textprompts[num]->page[metapagenum].hidehud; } } + else if (fastcmp(word, "TAG")) + strncpy(textprompts[num]->page[pagenum].tag, word2, 25); else if (fastcmp(word, "NEXTPROMPT")) textprompts[num]->page[pagenum].nextprompt = usi; else if (fastcmp(word, "NEXTPAGE")) diff --git a/src/doomstat.h b/src/doomstat.h index a46711cc4..eb4ed7066 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -129,6 +129,9 @@ extern INT16 titlemap; extern boolean hidetitlepics; extern INT16 bootmap; //bootmap for loading a map on startup +extern INT16 tutorialmap; // map to load for tutorial +extern boolean tutorialmode; // are we in a tutorial right now? + extern boolean looptitle; // CTF colors. @@ -171,6 +174,7 @@ extern cutscene_t *cutscenes[128]; typedef struct { + char tag[25]; // page tag (24 chars due to texture concatenating) char name[32]; // narrator name char iconname[8]; // narrator icon lump boolean rightside; // narrator side, false = left, true = right diff --git a/src/f_finale.c b/src/f_finale.c index 8d3aaea67..9217ced68 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2233,6 +2233,36 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex F_EndTextPrompt(true, false); // run the post-effects immediately } +void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) +{ + INT32 promptnum, pagenum; + char realtag[25]; + + strncpy(realtag, tag, 25); + realtag[24] = 0; + + // \todo hardcoded tutorial mode behavior: concat control mode (fps, platform, custom) to end of input tag + if (tutorialmode) + strncat(realtag, "FPS", 25); + + for (promptnum = 0; promptnum < MAX_PROMPTS; promptnum++) + { + if (!textprompts[promptnum]) + continue; + + for (pagenum = 0; pagenum < textprompts[promptnum]->numpages && pagenum < MAX_PAGES; pagenum++) + { + if (!strncmp(realtag, textprompts[promptnum]->page[pagenum].tag, 25)) + { + F_StartTextPrompt(promptnum, pagenum, mo, postexectag, blockcontrols, freezerealtime); + return; + } + } + } + + CONS_Debug(DBG_GAMELOGIC, "Text prompt: Can't find a page with named tag %s\n", realtag); +} + void F_TextPromptDrawer(void) { // reuse: diff --git a/src/f_finale.h b/src/f_finale.h index 0c9032ac2..093389c1f 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -53,6 +53,7 @@ void F_CutsceneDrawer(void); void F_EndCutScene(void); void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime); +void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime); void F_TextPromptDrawer(void); void F_EndTextPrompt(boolean forceexec, boolean noexec); boolean F_GetPromptHideHudAll(void); diff --git a/src/g_game.c b/src/g_game.c index d72a1961b..2eecbe1b3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -127,6 +127,9 @@ INT16 titlemap = 0; boolean hidetitlepics = false; INT16 bootmap; //bootmap for loading a map on startup +INT16 tutorialmap = 0; // map to load for tutorial +boolean tutorialmode = false; // are we in a tutorial right now? + boolean looptitle = false; UINT8 skincolor_redteam = SKINCOLOR_RED; diff --git a/src/p_setup.c b/src/p_setup.c index b2dfedb4e..c1e8c17e3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1541,6 +1541,7 @@ static void P_LoadRawSideDefs2(void *data) } case 443: // Calls a named Lua function + case 459: // Control text prompt (named tag) { char process[8*3+1]; memset(process,0,8*3+1); diff --git a/src/p_spec.c b/src/p_spec.c index 42153b4bf..76d7ac249 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3771,9 +3771,12 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) boolean blockcontrols = !(line->flags & ML_EFFECT2); boolean freezerealtime = !(line->flags & ML_EFFECT3); //boolean freezethinkers = (line->flags & ML_EFFECT4); + boolean callbynamedtag = (line->flags & ML_TFERLINE); if (closetextprompt) F_EndTextPrompt(false, false); + else if (callbynamedtag && sides[line->sidenum[0]].text && sides[line->sidenum[0]].text[0]) + F_StartTextPromptByNamedTag(sides[line->sidenum[0]].text, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); else F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); } From 9660c0e3c8003ab06d5038e9d554529ed7828208 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 09:38:32 -0500 Subject: [PATCH 32/49] Prompt page string field length adjustment; check empty named tag before prompt search --- src/dehacked.c | 8 ++++---- src/doomstat.h | 4 ++-- src/f_finale.c | 11 +++++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 214d47a16..c3323a6af 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1641,11 +1641,11 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) // HACK: Add yellow control char now // so the drawing function doesn't call it repeatedly - char name[32]; + char name[34]; name[0] = '\x82'; // color yellow name[1] = 0; - strncat(name, word2, 31); - name[31] = 0; + strncat(name, word2, 33); + name[33] = 0; // Replace _ with ' ' for (i = 0; i < 32 && name[i]; i++) @@ -1728,7 +1728,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) } } else if (fastcmp(word, "TAG")) - strncpy(textprompts[num]->page[pagenum].tag, word2, 25); + strncpy(textprompts[num]->page[pagenum].tag, word2, 33); else if (fastcmp(word, "NEXTPROMPT")) textprompts[num]->page[pagenum].nextprompt = usi; else if (fastcmp(word, "NEXTPAGE")) diff --git a/src/doomstat.h b/src/doomstat.h index eb4ed7066..432699d99 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -174,8 +174,8 @@ extern cutscene_t *cutscenes[128]; typedef struct { - char tag[25]; // page tag (24 chars due to texture concatenating) - char name[32]; // narrator name + char tag[33]; // page tag + char name[34]; // narrator name, extra char for color char iconname[8]; // narrator icon lump boolean rightside; // narrator side, false = left, true = right boolean iconflip; // narrator flip icon horizontally diff --git a/src/f_finale.c b/src/f_finale.c index 9217ced68..d706bf22e 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2236,14 +2236,17 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) { INT32 promptnum, pagenum; - char realtag[25]; + char realtag[33]; - strncpy(realtag, tag, 25); - realtag[24] = 0; + if (!tag || !tag[0]) + return; + + strncpy(realtag, tag, 33); + realtag[32] = 0; // \todo hardcoded tutorial mode behavior: concat control mode (fps, platform, custom) to end of input tag if (tutorialmode) - strncat(realtag, "FPS", 25); + strncat(realtag, "FPS", 33); for (promptnum = 0; promptnum < MAX_PROMPTS; promptnum++) { From b1bfc35ad7d61aa8ef5315ac059dbbbb56e4a129 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 10:06:51 -0500 Subject: [PATCH 33/49] Hardcode tutorial prompt offset index --- src/doomstat.h | 6 +++++- src/f_finale.c | 3 ++- src/g_game.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 432699d99..b57098d52 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -169,7 +169,11 @@ typedef struct extern cutscene_t *cutscenes[128]; -#define MAX_PROMPTS 256 +// Reserve prompt space for tutorials +#define TUTORIAL_PROMPT 201 // one-based +#define TUTORIAL_AREAS 6 +#define TUTORIAL_AREA_PROMPTS 5 +#define MAX_PROMPTS (TUTORIAL_PROMPT+TUTORIAL_AREAS*TUTORIAL_AREA_PROMPTS*3) // 3 control modes #define MAX_PAGES 128 typedef struct diff --git a/src/f_finale.c b/src/f_finale.c index d706bf22e..0be8dd0bc 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2236,6 +2236,7 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) { INT32 promptnum, pagenum; + INT32 tutorialpromptnum = (tutorialmode) ? TUTORIAL_PROMPT-1 : 0; char realtag[33]; if (!tag || !tag[0]) @@ -2248,7 +2249,7 @@ void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, bool if (tutorialmode) strncat(realtag, "FPS", 33); - for (promptnum = 0; promptnum < MAX_PROMPTS; promptnum++) + for (promptnum = 0 + tutorialpromptnum; promptnum < MAX_PROMPTS; promptnum++) { if (!textprompts[promptnum]) continue; diff --git a/src/g_game.c b/src/g_game.c index 2eecbe1b3..12e9cc961 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -141,7 +141,7 @@ tic_t countdowntimer = 0; boolean countdowntimeup = false; cutscene_t *cutscenes[128]; -textprompt_t *textprompts[256]; +textprompt_t *textprompts[MAX_PROMPTS]; INT16 nextmapoverride; boolean skipstats; From e48156ed66654829f6f2a8cccf8a3fbc47f6126b Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 10:30:33 -0500 Subject: [PATCH 34/49] SOC for prompt gfx and music --- src/dehacked.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++- src/doomstat.h | 11 +++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index c3323a6af..936a71777 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1557,6 +1557,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) char *word2; INT32 i; UINT16 usi; + UINT8 picid; do { @@ -1634,8 +1635,72 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) i = atoi(word2); usi = (UINT16)i; + // copypasta from readcutscenescene + if (fastcmp(word, "NUMBEROFPICS")) + { + textprompts[num]->page[pagenum].numpics = (UINT8)i; + } + else if (fastncmp(word, "PIC", 3)) + { + picid = (UINT8)atoi(word + 3); + if (picid > 8 || picid == 0) + { + deh_warning("textpromptscene %d: unknown word '%s'", num, word); + continue; + } + --picid; - if (fastcmp(word, "NAME")) + if (fastcmp(word+4, "NAME")) + { + strncpy(textprompts[num]->page[pagenum].picname[picid], word2, 8); + } + else if (fastcmp(word+4, "HIRES")) + { + textprompts[num]->page[pagenum].pichires[picid] = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + } + else if (fastcmp(word+4, "DURATION")) + { + textprompts[num]->page[pagenum].picduration[picid] = usi; + } + else if (fastcmp(word+4, "XCOORD")) + { + textprompts[num]->page[pagenum].xcoord[picid] = usi; + } + else if (fastcmp(word+4, "YCOORD")) + { + textprompts[num]->page[pagenum].ycoord[picid] = usi; + } + else + deh_warning("textpromptscene %d: unknown word '%s'", num, word); + } + else if (fastcmp(word, "MUSIC")) + { + strncpy(textprompts[num]->page[pagenum].musswitch, word2, 7); + textprompts[num]->page[pagenum].musswitch[6] = 0; + } +#ifdef MUSICSLOT_COMPATIBILITY + else if (fastcmp(word, "MUSICSLOT")) + { + i = get_mus(word2, true); + if (i && i <= 1035) + snprintf(textprompts[num]->page[pagenum].musswitch, 7, "%sM", G_BuildMapName(i)); + else if (i && i <= 1050) + strncpy(textprompts[num]->page[pagenum].musswitch, compat_special_music_slots[i - 1036], 7); + else + textprompts[num]->page[pagenum].musswitch[0] = 0; // becomes empty string + textprompts[num]->page[pagenum].musswitch[6] = 0; + } +#endif + else if (fastcmp(word, "MUSICTRACK")) + { + textprompts[num]->page[pagenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; + } + else if (fastcmp(word, "MUSICLOOP")) + { + textprompts[num]->page[pagenum].musicloop = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); + } + // end copypasta from readcutscenescene + else if (fastcmp(word, "NAME")) { INT32 i; @@ -1714,6 +1779,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) if (usi && usi <= textprompts[num]->numpages) { UINT8 metapagenum = usi - 1; + strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[metapagenum].name, 32); strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[metapagenum].iconname, 8); textprompts[num]->page[pagenum].rightside = textprompts[num]->page[metapagenum].rightside; @@ -1725,6 +1791,26 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].textspeed = textprompts[num]->page[metapagenum].textspeed; textprompts[num]->page[pagenum].textsfx = textprompts[num]->page[metapagenum].textsfx; textprompts[num]->page[pagenum].hidehud = textprompts[num]->page[metapagenum].hidehud; + + // music: don't copy, else each page change may reset the music + } + } + if (fastcmp(word, "PICSMETAPAGE")) + { + if (usi && usi <= textprompts[num]->numpages) + { + UINT8 metapagenum = usi - 1; + UINT8 picid; + + for (picid = 0; picid < 8; picid++) + { + textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; + strncpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], 8); + textprompts[num]->page[pagenum].pichires[picid] = textprompts[num]->page[metapagenum].pichires[picid]; + textprompts[num]->page[pagenum].picduration[picid] = textprompts[num]->page[metapagenum].picduration[picid]; + textprompts[num]->page[pagenum].xcoord[picid] = textprompts[num]->page[metapagenum].xcoord[picid]; + textprompts[num]->page[pagenum].ycoord[picid] = textprompts[num]->page[metapagenum].ycoord[picid]; + } } } else if (fastcmp(word, "TAG")) diff --git a/src/doomstat.h b/src/doomstat.h index b57098d52..a3428eb83 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -178,6 +178,17 @@ extern cutscene_t *cutscenes[128]; typedef struct { + UINT8 numpics; + char picname[8][8]; + UINT8 pichires[8]; + UINT16 xcoord[8]; // gfx + UINT16 ycoord[8]; // gfx + UINT16 picduration[8]; + + char musswitch[7]; + UINT16 musswitchflags; + UINT8 musicloop; + char tag[33]; // page tag char name[34]; // narrator name, extra char for color char iconname[8]; // narrator icon lump From c607991f163a9a5c125fa9b65a0c169c4fa60861 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 11:05:33 -0500 Subject: [PATCH 35/49] Implement music switching for prompts --- src/f_finale.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/f_finale.c b/src/f_finale.c index 0be8dd0bc..b78bd14d9 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2172,6 +2172,11 @@ static void F_AdvanceToNextPage(void) // on timer mode, number of tics until page advances timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10; F_PreparePageText(textprompts[cutnum]->page[scenenum].text); + + if (textprompts[cutnum]->page[scenenum].musswitch[0]) + S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch, + textprompts[cutnum]->page[scenenum].musswitchflags, + textprompts[cutnum]->page[scenenum].musicloop); } } @@ -2228,6 +2233,11 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex // on timer mode, number of tics until page advances timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10; F_PreparePageText(textprompts[cutnum]->page[scenenum].text); + + if (textprompts[cutnum]->page[scenenum].musswitch[0]) + S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch, + textprompts[cutnum]->page[scenenum].musswitchflags, + textprompts[cutnum]->page[scenenum].musicloop); } else F_EndTextPrompt(true, false); // run the post-effects immediately From 58c923221078ab815af5b8899583ea67a39517d6 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 12:42:13 -0500 Subject: [PATCH 36/49] Implemented GFX for text prompts * PicMode SOC * PicToLoop SOC --- src/dehacked.c | 18 +++++++++++--- src/doomstat.h | 16 +++++++++---- src/f_finale.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 87 insertions(+), 11 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 936a71777..4973b74ee 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1640,10 +1640,19 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) { textprompts[num]->page[pagenum].numpics = (UINT8)i; } + else if (fastcmp(word, "PICMODE")) + { + UINT8 picmode = 0; // PROMPT_PIC_PERSIST + if (usi == 1 || word2[0] == 'L') picmode = PROMPT_PIC_LOOP; + else if (usi == 2 || word2[0] == 'D' || word2[0] == 'H') picmode = PROMPT_PIC_DESTROY; + textprompts[num]->page[pagenum].picmode = picmode; + } + else if (fastcmp(word, "PICTOLOOP")) + textprompts[num]->page[pagenum].pictoloop = (UINT8)i; else if (fastncmp(word, "PIC", 3)) { picid = (UINT8)atoi(word + 3); - if (picid > 8 || picid == 0) + if (picid > MAX_PROMPT_PICS || picid == 0) { deh_warning("textpromptscene %d: unknown word '%s'", num, word); continue; @@ -1802,9 +1811,12 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) UINT8 metapagenum = usi - 1; UINT8 picid; - for (picid = 0; picid < 8; picid++) + textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; + textprompts[num]->page[pagenum].picmode = textprompts[num]->page[metapagenum].picmode; + textprompts[num]->page[pagenum].pictoloop = textprompts[num]->page[metapagenum].pictoloop; + + for (picid = 0; picid < MAX_PROMPT_PICS; picid++) { - textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; strncpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], 8); textprompts[num]->page[pagenum].pichires[picid] = textprompts[num]->page[metapagenum].pichires[picid]; textprompts[num]->page[pagenum].picduration[picid] = textprompts[num]->page[metapagenum].picduration[picid]; diff --git a/src/doomstat.h b/src/doomstat.h index a3428eb83..9b21f728a 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -176,14 +176,20 @@ extern cutscene_t *cutscenes[128]; #define MAX_PROMPTS (TUTORIAL_PROMPT+TUTORIAL_AREAS*TUTORIAL_AREA_PROMPTS*3) // 3 control modes #define MAX_PAGES 128 +#define PROMPT_PIC_PERSIST 0 +#define PROMPT_PIC_LOOP 1 +#define PROMPT_PIC_DESTROY 2 +#define MAX_PROMPT_PICS 8 typedef struct { UINT8 numpics; - char picname[8][8]; - UINT8 pichires[8]; - UINT16 xcoord[8]; // gfx - UINT16 ycoord[8]; // gfx - UINT16 picduration[8]; + UINT8 picmode; // sequence mode after displaying last pic, 0 = persist, 1 = loop, 2 = destroy + UINT8 pictoloop; // if picmode == loop, which pic to loop to? + char picname[MAX_PROMPT_PICS][8]; + UINT8 pichires[MAX_PROMPT_PICS]; + UINT16 xcoord[MAX_PROMPT_PICS]; // gfx + UINT16 ycoord[MAX_PROMPT_PICS]; // gfx + UINT16 picduration[MAX_PROMPT_PICS]; char musswitch[7]; UINT16 musswitchflags; diff --git a/src/f_finale.c b/src/f_finale.c index b78bd14d9..71812ff99 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1819,7 +1819,7 @@ boolean F_ContinueResponder(event_t *event) // CUSTOM CUTSCENES // ================== static INT32 scenenum, cutnum; -static INT32 picxpos, picypos, picnum, pictime; +static INT32 picxpos, picypos, picnum, pictime, picmode, numpics, pictoloop; static INT32 textxpos, textypos; static boolean dofadenow = false, cutsceneover = false; static boolean runningprecutscene = false, precutresetplayer = false; @@ -2173,6 +2173,16 @@ static void F_AdvanceToNextPage(void) timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10; F_PreparePageText(textprompts[cutnum]->page[scenenum].text); + // gfx + picnum = 0; + numpics = textprompts[cutnum]->page[scenenum].numpics; + picmode = textprompts[cutnum]->page[scenenum].picmode; + pictoloop = textprompts[cutnum]->page[scenenum].pictoloop - 1; + picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum]; + picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum]; + animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum]; + + // music change if (textprompts[cutnum]->page[scenenum].musswitch[0]) S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch, textprompts[cutnum]->page[scenenum].musswitchflags, @@ -2234,6 +2244,16 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10; F_PreparePageText(textprompts[cutnum]->page[scenenum].text); + // gfx + picnum = 0; + numpics = textprompts[cutnum]->page[scenenum].numpics; + picmode = textprompts[cutnum]->page[scenenum].picmode; + pictoloop = textprompts[cutnum]->page[scenenum].pictoloop - 1; + picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum]; + picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum]; + animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum]; + + // music change if (textprompts[cutnum]->page[scenenum].musswitch[0]) S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch, textprompts[cutnum]->page[scenenum].musswitchflags, @@ -2297,6 +2317,17 @@ void F_TextPromptDrawer(void) iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr); + // Draw gfx first + if (picnum >= 0 && picnum < numpics && textprompts[cutnum]->page[scenenum].picname[picnum][0] != '\0') + { + if (textprompts[cutnum]->page[scenenum].pichires[picnum]) + V_DrawSmallScaledPatch(picxpos, picypos, 0, + W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_CACHE)); + else + V_DrawScaledPatch(picxpos,picypos, 0, + W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_CACHE)); + } + // Draw background V_DrawPromptBack(boxh, textprompts[cutnum]->page[scenenum].backcolor); @@ -2337,7 +2368,6 @@ void F_TextPromptDrawer(void) } // Draw text - // \todo Char-by-char printing, see f_finale.c F_WriteText V_DrawString(textx, texty, (V_SNAPTOBOTTOM|V_ALLOWLOWERCASE), cutscene_disptext); // Draw name @@ -2346,7 +2376,7 @@ void F_TextPromptDrawer(void) V_DrawString(textx, namey, (V_SNAPTOBOTTOM|V_ALLOWLOWERCASE), textprompts[cutnum]->page[scenenum].name); // Draw chevron - if (promptblockcontrols && !timetonext) // \todo if !CloseTimer + if (promptblockcontrols && !timetonext) V_DrawString(textr-8, chevrony + (skullAnimCounter/5), (V_SNAPTOBOTTOM|V_YELLOWMAP), "\x1B"); // down arrow } @@ -2431,4 +2461,32 @@ void F_TextPromptTicker(void) !F_WriteText()) timetonext = !promptblockcontrols; // never show the chevron if we can't toggle pages } + + // gfx + if (picnum >= 0 && picnum < numpics) + { + if (animtimer <= 0) + { + boolean persistanimtimer = false; + + if (picnum < numpics-1 && textprompts[cutnum]->page[scenenum].picname[picnum+1][0] != '\0') + picnum++; + else if (picmode == PROMPT_PIC_LOOP) + picnum = pictoloop; + else if (picmode == PROMPT_PIC_DESTROY) + picnum = -1; + else // if (picmode == PROMPT_PIC_PERSIST) + persistanimtimer = true; + + if (!persistanimtimer && picnum >= 0) + { + picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum]; + picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum]; + pictime = textprompts[cutnum]->page[scenenum].picduration[picnum]; + animtimer = pictime; + } + } + else + animtimer--; + } } From b45fe054cbb08d3010178cd055938171975a5320 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 12:54:59 -0500 Subject: [PATCH 37/49] Pictoloop zero-based fix --- src/f_finale.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 71812ff99..c22c457aa 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2177,7 +2177,7 @@ static void F_AdvanceToNextPage(void) picnum = 0; numpics = textprompts[cutnum]->page[scenenum].numpics; picmode = textprompts[cutnum]->page[scenenum].picmode; - pictoloop = textprompts[cutnum]->page[scenenum].pictoloop - 1; + pictoloop = textprompts[cutnum]->page[scenenum].pictoloop > 0 ? textprompts[cutnum]->page[scenenum].pictoloop - 1 : 0; picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum]; picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum]; animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum]; @@ -2248,7 +2248,7 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex picnum = 0; numpics = textprompts[cutnum]->page[scenenum].numpics; picmode = textprompts[cutnum]->page[scenenum].picmode; - pictoloop = textprompts[cutnum]->page[scenenum].pictoloop - 1; + pictoloop = textprompts[cutnum]->page[scenenum].pictoloop > 0 ? textprompts[cutnum]->page[scenenum].pictoloop - 1 : 0; picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum]; picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum]; animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum]; From 9c8a3818eff9ae1ede531da0c8b713c0b2aebd10 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 14:23:12 -0500 Subject: [PATCH 38/49] Splitscreen "support" (one prompt only, both players freeze controls) --- src/f_finale.c | 52 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index c22c457aa..879d5aed1 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -88,6 +88,8 @@ static mobj_t *promptmo; static INT16 promptpostexectag; static boolean promptblockcontrols; static char *promptpagetext = NULL; +static INT32 callpromptnum = INT32_MAX; +static INT32 callpagenum = INT32_MAX; // // CUTSCENE TEXT WRITING @@ -2194,6 +2196,7 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec) { boolean promptwasactive = promptactive; promptactive = false; + callpromptnum = callpagenum = INT32_MAX; if (promptwasactive) { @@ -2218,6 +2221,11 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec) void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) { + // if splitscreen and we already have a prompt active, ignore. + // \todo Proper per-player splitscreen support (individual prompts) + if (promptactive && splitscreen && promptnum == callpromptnum && pagenum == callpagenum) + return; + // We share vars, so no starting text prompts over cutscenes or title screens! keypressed = false; finalecount = 0; @@ -2233,6 +2241,8 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex (void)freezerealtime; // \todo freeze player->realtime, maybe this needs to cycle through player thinkers // Initialize current prompt and scene + callpromptnum = promptnum; + callpagenum = pagenum; cutnum = (promptnum < MAX_PROMPTS && textprompts[promptnum]) ? promptnum : INT32_MAX; scenenum = (cutnum != INT32_MAX && pagenum < MAX_PAGES && pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX; promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX); @@ -2404,9 +2414,18 @@ void F_TextPromptTicker(void) { if (netgame && i != serverplayer && i != adminplayer) continue; + else if (splitscreen) { + // Both players' controls are locked, + // But only consoleplayer can advance the prompt. + // \todo Proper per-player splitscreen support (individual prompts) + if (i == consoleplayer || i == secondarydisplayplayer) + players[i].powers[pw_nocontrol] = 1; + } + else if (i == consoleplayer) + players[i].powers[pw_nocontrol] = 1; - players[i].powers[pw_nocontrol] = 1; - break; + if (!splitscreen) + break; } } @@ -2426,8 +2445,23 @@ void F_TextPromptTicker(void) { if (netgame && i != serverplayer && i != adminplayer) continue; - - players[i].powers[pw_nocontrol] = 1; + else if (splitscreen) { + // Both players' controls are locked, + // But only consoleplayer can advance the prompt. + if (i == consoleplayer) + players[i].powers[pw_nocontrol] = 1; + else if (i == secondarydisplayplayer) + { + players[i].powers[pw_nocontrol] = 1; + continue; + } + else + continue; + } + else if (i == consoleplayer) + players[i].powers[pw_nocontrol] = 1; + else + continue; if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP)) { @@ -2437,7 +2471,12 @@ void F_TextPromptTicker(void) cutscene_boostspeed = 1; // only after a slight delay if (keypressed) - break; + { + if (!splitscreen) + break; + else + continue; + } if (!timetonext) // is 0 when finished generating text { @@ -2450,7 +2489,8 @@ void F_TextPromptTicker(void) else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP)) keypressed = false; - break; + if (!splitscreen) + break; } } From 4f2f5c7e6df2ff66225724312902e54905621f5a Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 14:45:20 -0500 Subject: [PATCH 39/49] Let triggering splitscreen player control the text prompt --- src/f_finale.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 879d5aed1..b5866868c 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -90,6 +90,7 @@ static boolean promptblockcontrols; static char *promptpagetext = NULL; static INT32 callpromptnum = INT32_MAX; static INT32 callpagenum = INT32_MAX; +static INT32 callplayer = INT32_MAX; // // CUTSCENE TEXT WRITING @@ -2196,7 +2197,7 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec) { boolean promptwasactive = promptactive; promptactive = false; - callpromptnum = callpagenum = INT32_MAX; + callpromptnum = callpagenum = callplayer = INT32_MAX; if (promptwasactive) { @@ -2221,6 +2222,8 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec) void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) { + INT32 i; + // if splitscreen and we already have a prompt active, ignore. // \todo Proper per-player splitscreen support (individual prompts) if (promptactive && splitscreen && promptnum == callpromptnum && pagenum == callpagenum) @@ -2268,6 +2271,19 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch, textprompts[cutnum]->page[scenenum].musswitchflags, textprompts[cutnum]->page[scenenum].musicloop); + + // get the calling player + if (promptblockcontrols && mo && mo->player) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (players[i].mo == mo) + { + callplayer = i; + break; + } + } + } } else F_EndTextPrompt(true, false); // run the post-effects immediately @@ -2447,13 +2463,18 @@ void F_TextPromptTicker(void) continue; else if (splitscreen) { // Both players' controls are locked, - // But only consoleplayer can advance the prompt. - if (i == consoleplayer) - players[i].powers[pw_nocontrol] = 1; - else if (i == secondarydisplayplayer) + // But only the triggering player can advance the prompt. + if (i == consoleplayer || i == secondarydisplayplayer) { players[i].powers[pw_nocontrol] = 1; - continue; + + if (callplayer == consoleplayer || callplayer == secondarydisplayplayer) + { + if (i != callplayer) + continue; + } + else if (i != consoleplayer) + continue; } else continue; From 8b434072a968162b089718395f4c2ea1097ec36b Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 10 Nov 2018 15:34:56 -0500 Subject: [PATCH 40/49] Stub netgame support; ignore bots on linedef special --- src/f_finale.c | 7 +++++++ src/p_spec.c | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index b5866868c..cb3091366 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2229,6 +2229,13 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex if (promptactive && splitscreen && promptnum == callpromptnum && pagenum == callpagenum) return; + // \todo proper netgame support + if (netgame) + { + F_EndTextPrompt(true, false); // run the post-effects immediately + return; + } + // We share vars, so no starting text prompts over cutscenes or title screens! keypressed = false; finalecount = 0; diff --git a/src/p_spec.c b/src/p_spec.c index 76d7ac249..24cad33d5 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3760,13 +3760,14 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 459: // Control Text Prompt // console player only unless NOCLIMB is set - if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player))) + if (mo && mo->player && P_IsLocalPlayer(mo->player) && (!bot || bot != mo)) { INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); INT32 postexectag = abs((line->sidenum[1] != 0xFFFF) ? sides[line->sidenum[1]].textureoffset>>FRACBITS : line->tag); boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); + //boolean allplayers = (line->flags & ML_NOCLIMB); boolean runpostexec = (line->flags & ML_EFFECT1); boolean blockcontrols = !(line->flags & ML_EFFECT2); boolean freezerealtime = !(line->flags & ML_EFFECT3); From 0ed806f28128ae5c2cdce80ba504bd87a859de3e Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sun, 11 Nov 2018 14:44:57 -0500 Subject: [PATCH 41/49] Dehacked typos --- src/dehacked.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 4973b74ee..5de6606c4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1778,7 +1778,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) else if (fastcmp(word, "HIDEHUD")) { UINT8 hidehud = 0; - if (usi == 0 || (word2[0] == 'F' && (word2[1] == 'A' || !word2[1])) || word2[0] == 'N') hidehud = 1; // false + if ((word2[0] == 'F' && (word2[1] == 'A' || !word2[1])) || word2[0] == 'N') hidehud = 0; // false else if (usi == 1 || word2[0] == 'T' || word2[0] == 'Y') hidehud = 1; // true (hide appropriate HUD elements) else if (usi == 2 || word2[0] == 'A' || (word2[0] == 'F' && word2[1] == 'O')) hidehud = 2; // force (hide all HUD elements) textprompts[num]->page[pagenum].hidehud = hidehud; @@ -1804,7 +1804,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) // music: don't copy, else each page change may reset the music } } - if (fastcmp(word, "PICSMETAPAGE")) + else if (fastcmp(word, "PICSMETAPAGE")) { if (usi && usi <= textprompts[num]->numpages) { From 69d0b762590a04666091d37a96ac009abd3e0cfd Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sun, 11 Nov 2018 14:50:10 -0500 Subject: [PATCH 42/49] Fix PICSMETAPAGE --- src/dehacked.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 5de6606c4..dc967f560 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1649,6 +1649,27 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) } else if (fastcmp(word, "PICTOLOOP")) textprompts[num]->page[pagenum].pictoloop = (UINT8)i; + else if (fastcmp(word, "PICSMETAPAGE")) + { + if (usi && usi <= textprompts[num]->numpages) + { + UINT8 metapagenum = usi - 1; + UINT8 picid; + + textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; + textprompts[num]->page[pagenum].picmode = textprompts[num]->page[metapagenum].picmode; + textprompts[num]->page[pagenum].pictoloop = textprompts[num]->page[metapagenum].pictoloop; + + for (picid = 0; picid < MAX_PROMPT_PICS; picid++) + { + strncpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], 8); + textprompts[num]->page[pagenum].pichires[picid] = textprompts[num]->page[metapagenum].pichires[picid]; + textprompts[num]->page[pagenum].picduration[picid] = textprompts[num]->page[metapagenum].picduration[picid]; + textprompts[num]->page[pagenum].xcoord[picid] = textprompts[num]->page[metapagenum].xcoord[picid]; + textprompts[num]->page[pagenum].ycoord[picid] = textprompts[num]->page[metapagenum].ycoord[picid]; + } + } + } else if (fastncmp(word, "PIC", 3)) { picid = (UINT8)atoi(word + 3); @@ -1804,27 +1825,6 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) // music: don't copy, else each page change may reset the music } } - else if (fastcmp(word, "PICSMETAPAGE")) - { - if (usi && usi <= textprompts[num]->numpages) - { - UINT8 metapagenum = usi - 1; - UINT8 picid; - - textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; - textprompts[num]->page[pagenum].picmode = textprompts[num]->page[metapagenum].picmode; - textprompts[num]->page[pagenum].pictoloop = textprompts[num]->page[metapagenum].pictoloop; - - for (picid = 0; picid < MAX_PROMPT_PICS; picid++) - { - strncpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], 8); - textprompts[num]->page[pagenum].pichires[picid] = textprompts[num]->page[metapagenum].pichires[picid]; - textprompts[num]->page[pagenum].picduration[picid] = textprompts[num]->page[metapagenum].picduration[picid]; - textprompts[num]->page[pagenum].xcoord[picid] = textprompts[num]->page[metapagenum].xcoord[picid]; - textprompts[num]->page[pagenum].ycoord[picid] = textprompts[num]->page[metapagenum].ycoord[picid]; - } - } - } else if (fastcmp(word, "TAG")) strncpy(textprompts[num]->page[pagenum].tag, word2, 33); else if (fastcmp(word, "NEXTPROMPT")) From b68fb6ec4e320edf97d4dfc11edb629594a9c9ea Mon Sep 17 00:00:00 2001 From: mazmazz Date: Mon, 12 Nov 2018 22:47:20 -0500 Subject: [PATCH 43/49] F_GetTextPromptTutorialTag implementation --- src/f_finale.c | 108 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index cb3091366..426b2498c 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -34,6 +34,7 @@ #include "p_local.h" #include "p_setup.h" #include "st_stuff.h" // hud hiding +#include "fastcmp.h" #ifdef HAVE_BLUA #include "lua_hud.h" @@ -2296,21 +2297,80 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex F_EndTextPrompt(true, false); // run the post-effects immediately } +static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length) +{ + INT32 gcs = gcs_custom; + boolean suffixed = true; + + if (!tag || !tag[0] || !tutorialmode) + return false; + + if (!strncmp(tag, "TAM", 3)) // Movement + gcs = G_GetControlScheme(gamecontrol, gclist_movement, num_gclist_movement); + else if (!strncmp(tag, "TAC", 3)) // Camera + { + gcs = G_GetControlScheme(gamecontrol, gclist_camera, num_gclist_camera); + if (gcs == gcs_fps && !cv_usemouse.value) + gcs = gcs_platform; // Platform (arrow) scheme is stand-in for no mouse + } + else if (!strncmp(tag, "TAD", 3)) // Movement and Camera + gcs = G_GetControlScheme(gamecontrol, gclist_tutorial_check, num_gclist_tutorial_check); // mobement + camera + else if (!strncmp(tag, "TAJ", 3)) // Jump + gcs = G_GetControlScheme(gamecontrol, gclist_jump, num_gclist_jump); + else if (!strncmp(tag, "TAS", 3)) // Spin + gcs = G_GetControlScheme(gamecontrol, gclist_use, num_gclist_use); + else if (!strncmp(tag, "TAA", 3)) // Char ability + gcs = G_GetControlScheme(gamecontrol, gclist_jump, num_gclist_jump); + else if (!strncmp(tag, "TAW", 3)) // Shield ability + { + const INT32 gclist[2] = { + gc_jump, gc_use + }; + gcs = G_GetControlScheme(gamecontrol, gclist, 2); + } + else + { + const INT32 gclist[8] = { + gc_forward, gc_backward, gc_strafeleft, gc_straferight, + gc_turnleft, gc_turnright, gc_jump, gc_use + }; + gcs = G_GetControlScheme(gamecontrol, gclist, 8); + } + + switch (gcs) + { + case gcs_fps: + // strncat(tag, "FPS", length); + suffixed = false; + break; + + case gcs_platform: + strncat(tag, "PLATFORM", length); + break; + + default: + strncat(tag, "CUSTOM", length); + break; + } + + return suffixed; +} + void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) { - INT32 promptnum, pagenum; + INT32 promptnum, pagenum, nosuffixpromptnum = INT32_MAX, nosuffixpagenum = INT32_MAX; INT32 tutorialpromptnum = (tutorialmode) ? TUTORIAL_PROMPT-1 : 0; - char realtag[33]; + boolean suffixed = false, found = false; + char suffixedtag[33]; if (!tag || !tag[0]) return; - strncpy(realtag, tag, 33); - realtag[32] = 0; + strncpy(suffixedtag, tag, 33); + suffixedtag[32] = 0; - // \todo hardcoded tutorial mode behavior: concat control mode (fps, platform, custom) to end of input tag if (tutorialmode) - strncat(realtag, "FPS", 33); + suffixed = F_GetTextPromptTutorialTag(suffixedtag, 33); for (promptnum = 0 + tutorialpromptnum; promptnum < MAX_PROMPTS; promptnum++) { @@ -2319,15 +2379,43 @@ void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, bool for (pagenum = 0; pagenum < textprompts[promptnum]->numpages && pagenum < MAX_PAGES; pagenum++) { - if (!strncmp(realtag, textprompts[promptnum]->page[pagenum].tag, 25)) + if (suffixed && fastcmp(suffixedtag, textprompts[promptnum]->page[pagenum].tag)) { - F_StartTextPrompt(promptnum, pagenum, mo, postexectag, blockcontrols, freezerealtime); - return; + // this goes first because fastcmp ends early if first string is shorter + found = true; + break; + } + else if (nosuffixpromptnum == INT32_MAX && nosuffixpagenum == INT32_MAX && fastcmp(tag, textprompts[promptnum]->page[pagenum].tag)) + { + if (suffixed) + { + nosuffixpromptnum = promptnum; + nosuffixpagenum = pagenum; + // continue searching for the suffixed tag + } + else + { + found = true; + break; + } } } + + if (found) + break; } - CONS_Debug(DBG_GAMELOGIC, "Text prompt: Can't find a page with named tag %s\n", realtag); + if (suffixed && !found && nosuffixpromptnum != INT32_MAX && nosuffixpagenum != INT32_MAX) + { + found = true; + promptnum = nosuffixpromptnum; + pagenum = nosuffixpagenum; + } + + if (found) + F_StartTextPrompt(promptnum, pagenum, mo, postexectag, blockcontrols, freezerealtime); + else + CONS_Debug(DBG_GAMELOGIC, "Text prompt: Can't find a page with named tag %s or suffixed tag %s\n", tag, suffixedtag); } void F_TextPromptDrawer(void) From 7663c0828e4292970f5c31a862d5a312046ad950 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Mon, 12 Nov 2018 23:16:24 -0500 Subject: [PATCH 44/49] PicToStart implementation; fix NumPrompts limitation error --- src/dehacked.c | 9 ++++++--- src/doomstat.h | 1 + src/f_finale.c | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index a04c0bc5e..1ba9da30c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1653,6 +1653,8 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) } else if (fastcmp(word, "PICTOLOOP")) textprompts[num]->page[pagenum].pictoloop = (UINT8)i; + else if (fastcmp(word, "PICTOSTART")) + textprompts[num]->page[pagenum].pictostart = (UINT8)i; else if (fastcmp(word, "PICSMETAPAGE")) { if (usi && usi <= textprompts[num]->numpages) @@ -1663,6 +1665,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; textprompts[num]->page[pagenum].picmode = textprompts[num]->page[metapagenum].picmode; textprompts[num]->page[pagenum].pictoloop = textprompts[num]->page[metapagenum].pictoloop; + textprompts[num]->page[pagenum].pictostart = textprompts[num]->page[metapagenum].pictostart; for (picid = 0; picid < MAX_PROMPT_PICS; picid++) { @@ -3601,11 +3604,11 @@ static void DEH_LoadDehackedFile(MYFILE *f) } else if (fastcmp(word, "PROMPT")) { - if (i > 0 && i < 257) + if (i > 0 && i < MAX_PROMPTS) readtextprompt(f, i - 1); else { - deh_warning("Prompt number %d out of range (1 - 256)", i); + deh_warning("Prompt number %d out of range (1 - %d)", i, MAX_PROMPTS); ignorelines(f); } } @@ -8281,7 +8284,7 @@ struct { {"V_CHARCOLORSHIFT",V_CHARCOLORSHIFT}, {"V_ALPHASHIFT",V_ALPHASHIFT}, - + //Kick Reasons {"KR_KICK",KR_KICK}, {"KR_PINGLIMIT",KR_PINGLIMIT}, diff --git a/src/doomstat.h b/src/doomstat.h index d2facda3c..5066e2c3b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -186,6 +186,7 @@ typedef struct UINT8 numpics; UINT8 picmode; // sequence mode after displaying last pic, 0 = persist, 1 = loop, 2 = destroy UINT8 pictoloop; // if picmode == loop, which pic to loop to? + UINT8 pictostart; // initial pic number to show char picname[MAX_PROMPT_PICS][8]; UINT8 pichires[MAX_PROMPT_PICS]; UINT16 xcoord[MAX_PROMPT_PICS]; // gfx diff --git a/src/f_finale.c b/src/f_finale.c index 426b2498c..8aa9f1e84 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2137,7 +2137,7 @@ static void F_PreparePageText(char *pagetext) static void F_AdvanceToNextPage(void) { - UINT8 nextprompt = textprompts[cutnum]->page[scenenum].nextprompt, + INT32 nextprompt = textprompts[cutnum]->page[scenenum].nextprompt, nextpage = textprompts[cutnum]->page[scenenum].nextpage, oldcutnum = cutnum; @@ -2178,7 +2178,7 @@ static void F_AdvanceToNextPage(void) F_PreparePageText(textprompts[cutnum]->page[scenenum].text); // gfx - picnum = 0; + picnum = textprompts[cutnum]->page[scenenum].pictostart; numpics = textprompts[cutnum]->page[scenenum].numpics; picmode = textprompts[cutnum]->page[scenenum].picmode; pictoloop = textprompts[cutnum]->page[scenenum].pictoloop > 0 ? textprompts[cutnum]->page[scenenum].pictoloop - 1 : 0; @@ -2266,7 +2266,7 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex F_PreparePageText(textprompts[cutnum]->page[scenenum].text); // gfx - picnum = 0; + picnum = textprompts[cutnum]->page[scenenum].pictostart; numpics = textprompts[cutnum]->page[scenenum].numpics; picmode = textprompts[cutnum]->page[scenenum].picmode; pictoloop = textprompts[cutnum]->page[scenenum].pictoloop > 0 ? textprompts[cutnum]->page[scenenum].pictoloop - 1 : 0; From deb036058cae9bcaec574cb5abc4938f8e1f6af8 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Mon, 12 Nov 2018 23:31:10 -0500 Subject: [PATCH 45/49] text-prompts gclist -> gcl refactor --- src/f_finale.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 8aa9f1e84..25a1150b3 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2306,36 +2306,25 @@ static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length) return false; if (!strncmp(tag, "TAM", 3)) // Movement - gcs = G_GetControlScheme(gamecontrol, gclist_movement, num_gclist_movement); + gcs = G_GetControlScheme(gamecontrol, gcl_movement, num_gcl_movement); else if (!strncmp(tag, "TAC", 3)) // Camera { - gcs = G_GetControlScheme(gamecontrol, gclist_camera, num_gclist_camera); + gcs = G_GetControlScheme(gamecontrol, gcl_camera, num_gcl_camera); if (gcs == gcs_fps && !cv_usemouse.value) gcs = gcs_platform; // Platform (arrow) scheme is stand-in for no mouse } else if (!strncmp(tag, "TAD", 3)) // Movement and Camera - gcs = G_GetControlScheme(gamecontrol, gclist_tutorial_check, num_gclist_tutorial_check); // mobement + camera + gcs = G_GetControlScheme(gamecontrol, gcl_movement_camera, num_gcl_movement_camera); else if (!strncmp(tag, "TAJ", 3)) // Jump - gcs = G_GetControlScheme(gamecontrol, gclist_jump, num_gclist_jump); + gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump); else if (!strncmp(tag, "TAS", 3)) // Spin - gcs = G_GetControlScheme(gamecontrol, gclist_use, num_gclist_use); + gcs = G_GetControlScheme(gamecontrol, gcl_use, num_gcl_use); else if (!strncmp(tag, "TAA", 3)) // Char ability - gcs = G_GetControlScheme(gamecontrol, gclist_jump, num_gclist_jump); + gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump); else if (!strncmp(tag, "TAW", 3)) // Shield ability - { - const INT32 gclist[2] = { - gc_jump, gc_use - }; - gcs = G_GetControlScheme(gamecontrol, gclist, 2); - } + gcs = G_GetControlScheme(gamecontrol, gcl_jump_use, num_gcl_jump_use); else - { - const INT32 gclist[8] = { - gc_forward, gc_backward, gc_strafeleft, gc_straferight, - gc_turnleft, gc_turnright, gc_jump, gc_use - }; - gcs = G_GetControlScheme(gamecontrol, gclist, 8); - } + gcs = G_GetControlScheme(gamecontrol, gcl_tutorial_used, num_gcl_tutorial_used); switch (gcs) { From 422692ed037aa6382f12d50d5cef8690d91359c6 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Tue, 13 Nov 2018 00:13:36 -0500 Subject: [PATCH 46/49] NextTag implementation * Adjust named tag implementation to be more portable * Next page adjustments --- src/dehacked.c | 2 ++ src/doomstat.h | 1 + src/f_finale.c | 56 ++++++++++++++++++++++++++++---------------------- src/f_finale.h | 2 +- src/p_spec.c | 6 ++++-- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 1ba9da30c..a1e336064 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1838,6 +1838,8 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) textprompts[num]->page[pagenum].nextprompt = usi; else if (fastcmp(word, "NEXTPAGE")) textprompts[num]->page[pagenum].nextpage = usi; + else if (fastcmp(word, "NEXTTAG")) + strncpy(textprompts[num]->page[pagenum].nexttag, word2, 33); else if (fastcmp(word, "TIMETONEXT")) textprompts[num]->page[pagenum].timetonext = get_number(word2); else diff --git a/src/doomstat.h b/src/doomstat.h index 5066e2c3b..a0c1eda1c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -211,6 +211,7 @@ typedef struct sfxenum_t textsfx; // sfx_ id for printing text UINT8 nextprompt; // next prompt to jump to, one-based. 0 = current prompt UINT8 nextpage; // next page to jump to, one-based. 0 = next page within prompt->numpages + char nexttag[33]; // next tag to jump to. If set, this overrides nextprompt and nextpage. INT32 timetonext; // time in tics to jump to next page automatically. 0 = don't jump automatically char *text; } textpage_t; diff --git a/src/f_finale.c b/src/f_finale.c index 25a1150b3..e054ef264 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2137,25 +2137,31 @@ static void F_PreparePageText(char *pagetext) static void F_AdvanceToNextPage(void) { - INT32 nextprompt = textprompts[cutnum]->page[scenenum].nextprompt, - nextpage = textprompts[cutnum]->page[scenenum].nextpage, + INT32 nextprompt = textprompts[cutnum]->page[scenenum].nextprompt ? textprompts[cutnum]->page[scenenum].nextprompt - 1 : INT32_MAX, + nextpage = textprompts[cutnum]->page[scenenum].nextpage ? textprompts[cutnum]->page[scenenum].nextpage - 1 : INT32_MAX, oldcutnum = cutnum; + if (textprompts[cutnum]->page[scenenum].nexttag[0]) + F_GetPromptPageByNamedTag(textprompts[cutnum]->page[scenenum].nexttag, &nextprompt, &nextpage); + // determine next prompt - if (nextprompt) + if (nextprompt != INT32_MAX) { - if (nextprompt <= MAX_PROMPTS && textprompts[nextprompt-1]) - cutnum = nextprompt-1; + if (nextprompt <= MAX_PROMPTS && textprompts[nextprompt]) + cutnum = nextprompt; else cutnum = INT32_MAX; } // determine next page - if (nextpage) + if (nextpage != INT32_MAX) { - scenenum = nextpage-1; - if (scenenum >= MAX_PAGES || scenenum > textprompts[cutnum]->numpages-1) - scenenum = INT32_MAX; + if (nextprompt != INT32_MAX) + { + scenenum = nextpage; + if (scenenum >= MAX_PAGES || scenenum > textprompts[cutnum]->numpages-1) + scenenum = INT32_MAX; + } } else { @@ -2345,41 +2351,43 @@ static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length) return suffixed; } -void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime) +void F_GetPromptPageByNamedTag(const char *tag, INT32 *promptnum, INT32 *pagenum) { - INT32 promptnum, pagenum, nosuffixpromptnum = INT32_MAX, nosuffixpagenum = INT32_MAX; + INT32 nosuffixpromptnum = INT32_MAX, nosuffixpagenum = INT32_MAX; INT32 tutorialpromptnum = (tutorialmode) ? TUTORIAL_PROMPT-1 : 0; boolean suffixed = false, found = false; char suffixedtag[33]; + *promptnum = *pagenum = INT32_MAX; + if (!tag || !tag[0]) return; strncpy(suffixedtag, tag, 33); suffixedtag[32] = 0; - + tutorialmode = true; if (tutorialmode) - suffixed = F_GetTextPromptTutorialTag(suffixedtag, 33); + suffixed = F_GetTextPromptTutorialTag(suffixedtag, 33); tutorialmode = false; - for (promptnum = 0 + tutorialpromptnum; promptnum < MAX_PROMPTS; promptnum++) + for (*promptnum = 0 + tutorialpromptnum; *promptnum < MAX_PROMPTS; (*promptnum)++) { - if (!textprompts[promptnum]) + if (!textprompts[*promptnum]) continue; - for (pagenum = 0; pagenum < textprompts[promptnum]->numpages && pagenum < MAX_PAGES; pagenum++) + for (*pagenum = 0; *pagenum < textprompts[*promptnum]->numpages && *pagenum < MAX_PAGES; (*pagenum)++) { - if (suffixed && fastcmp(suffixedtag, textprompts[promptnum]->page[pagenum].tag)) + if (suffixed && fastcmp(suffixedtag, textprompts[*promptnum]->page[*pagenum].tag)) { // this goes first because fastcmp ends early if first string is shorter found = true; break; } - else if (nosuffixpromptnum == INT32_MAX && nosuffixpagenum == INT32_MAX && fastcmp(tag, textprompts[promptnum]->page[pagenum].tag)) + else if (nosuffixpromptnum == INT32_MAX && nosuffixpagenum == INT32_MAX && fastcmp(tag, textprompts[*promptnum]->page[*pagenum].tag)) { if (suffixed) { - nosuffixpromptnum = promptnum; - nosuffixpagenum = pagenum; + nosuffixpromptnum = *promptnum; + nosuffixpagenum = *pagenum; // continue searching for the suffixed tag } else @@ -2397,13 +2405,11 @@ void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, bool if (suffixed && !found && nosuffixpromptnum != INT32_MAX && nosuffixpagenum != INT32_MAX) { found = true; - promptnum = nosuffixpromptnum; - pagenum = nosuffixpagenum; + *promptnum = nosuffixpromptnum; + *pagenum = nosuffixpagenum; } - if (found) - F_StartTextPrompt(promptnum, pagenum, mo, postexectag, blockcontrols, freezerealtime); - else + if (!found) CONS_Debug(DBG_GAMELOGIC, "Text prompt: Can't find a page with named tag %s or suffixed tag %s\n", tag, suffixedtag); } diff --git a/src/f_finale.h b/src/f_finale.h index 093389c1f..ca43e17e0 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -53,7 +53,7 @@ void F_CutsceneDrawer(void); void F_EndCutScene(void); void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime); -void F_StartTextPromptByNamedTag(char *tag, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime); +void F_GetPromptPageByNamedTag(const char *tag, INT32 *promptnum, INT32 *pagenum); void F_TextPromptDrawer(void); void F_EndTextPrompt(boolean forceexec, boolean noexec); boolean F_GetPromptHideHudAll(void); diff --git a/src/p_spec.c b/src/p_spec.c index 24cad33d5..cd9c7cffd 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3776,10 +3776,12 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (closetextprompt) F_EndTextPrompt(false, false); - else if (callbynamedtag && sides[line->sidenum[0]].text && sides[line->sidenum[0]].text[0]) - F_StartTextPromptByNamedTag(sides[line->sidenum[0]].text, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); else + { + if (callbynamedtag && sides[line->sidenum[0]].text && sides[line->sidenum[0]].text[0]) + F_GetPromptPageByNamedTag(sides[line->sidenum[0]].text, &promptnum, &pagenum); F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); + } } break; From 5270743a42e9266384ce8bbfdbdff91fcfcff3de Mon Sep 17 00:00:00 2001 From: mazmazz Date: Tue, 13 Nov 2018 01:38:20 -0500 Subject: [PATCH 47/49] F_AdvanceToNextPage adjustment --- src/f_finale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index e054ef264..83ec80e7c 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2156,7 +2156,7 @@ static void F_AdvanceToNextPage(void) // determine next page if (nextpage != INT32_MAX) { - if (nextprompt != INT32_MAX) + if (cutnum != INT32_MAX) { scenenum = nextpage; if (scenenum >= MAX_PAGES || scenenum > textprompts[cutnum]->numpages-1) From 7b224cdcd51beb1802033a843e7cb6432f7f91d8 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Tue, 13 Nov 2018 02:00:58 -0500 Subject: [PATCH 48/49] Tutorial named tag detection adjustment --- src/f_finale.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index 83ec80e7c..d96baedec 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2315,7 +2315,10 @@ static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length) gcs = G_GetControlScheme(gamecontrol, gcl_movement, num_gcl_movement); else if (!strncmp(tag, "TAC", 3)) // Camera { - gcs = G_GetControlScheme(gamecontrol, gcl_camera, num_gcl_camera); + // Check for gcl_movement so we can differentiate between FPS and Platform schemes. + gcs = G_GetControlScheme(gamecontrol, gcl_movement, num_gcl_movement); + if (gcs == gcs_custom) // try again, maybe we'll get a match + gcs = G_GetControlScheme(gamecontrol, gcl_camera, num_gcl_camera); if (gcs == gcs_fps && !cv_usemouse.value) gcs = gcs_platform; // Platform (arrow) scheme is stand-in for no mouse } From c92df614f0389fb6b82bb85ac2673f8858f916ec Mon Sep 17 00:00:00 2001 From: mazmazz Date: Tue, 13 Nov 2018 10:31:06 -0500 Subject: [PATCH 49/49] Compile errors --- src/dehacked.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index a1e336064..086c658bd 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1660,7 +1660,6 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) if (usi && usi <= textprompts[num]->numpages) { UINT8 metapagenum = usi - 1; - UINT8 picid; textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics; textprompts[num]->page[pagenum].picmode = textprompts[num]->page[metapagenum].picmode; @@ -1739,7 +1738,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) // end copypasta from readcutscenescene else if (fastcmp(word, "NAME")) { - INT32 i; + INT32 j; // HACK: Add yellow control char now // so the drawing function doesn't call it repeatedly @@ -1750,10 +1749,10 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) name[33] = 0; // Replace _ with ' ' - for (i = 0; i < 32 && name[i]; i++) + for (j = 0; j < 32 && name[j]; j++) { - if (name[i] == '_') - name[i] = ' '; + if (name[j] == '_') + name[j] = ' '; } strncpy(textprompts[num]->page[pagenum].name, name, 32);