mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2024-11-18 10:31:42 +00:00
Merge branch 'text-prompts' into 'master'
SOC and Line Exec Text Prompts See merge request STJr/SRB2Internal!200
This commit is contained in:
commit
da0084095c
15 changed files with 1241 additions and 14 deletions
|
@ -232,18 +232,20 @@ UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, *orangem
|
||||||
|
|
||||||
// Console BG color
|
// Console BG color
|
||||||
UINT8 *consolebgmap = NULL;
|
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;
|
UINT16 i, palsum;
|
||||||
UINT8 j, palindex, shift;
|
UINT8 j, palindex, shift;
|
||||||
UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
|
UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
|
||||||
|
|
||||||
if (!consolebgmap)
|
if (color == INT32_MAX)
|
||||||
consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
color = cons_backcolor.value;
|
||||||
|
|
||||||
shift = 6; // 12 colors -- shift of 7 means 6 colors
|
shift = 6; // 12 colors -- shift of 7 means 6 colors
|
||||||
switch (cons_backcolor.value)
|
switch (color)
|
||||||
{
|
{
|
||||||
case 0: palindex = 15; break; // White
|
case 0: palindex = 15; break; // White
|
||||||
case 1: palindex = 31; break; // Gray
|
case 1: palindex = 31; break; // Gray
|
||||||
|
@ -257,20 +259,42 @@ void CON_SetupBackColormap(void)
|
||||||
case 9: palindex = 187; break; // Magenta
|
case 9: palindex = 187; break; // Magenta
|
||||||
case 10: palindex = 139; break; // Aqua
|
case 10: palindex = 139; break; // Aqua
|
||||||
// Default green
|
// 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
|
// setup background colormap
|
||||||
for (i = 0, j = 0; i < 768; i += 3, j++)
|
for (i = 0, j = 0; i < 768; i += 3, j++)
|
||||||
{
|
{
|
||||||
palsum = (pal[i] + pal[i+1] + pal[i+2]) >> shift;
|
palsum = (pal[i] + pal[i+1] + pal[i+2]) >> shift;
|
||||||
|
if (prompt)
|
||||||
|
promptbgmap[j] = (UINT8)(palindex - palsum);
|
||||||
|
else
|
||||||
consolebgmap[j] = (UINT8)(palindex - palsum);
|
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)
|
static void CONS_backcolor_Change(void)
|
||||||
{
|
{
|
||||||
CON_SetupBackColormap();
|
CON_SetupBackColormapEx(cons_backcolor.value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CON_SetupColormaps(void)
|
static void CON_SetupColormaps(void)
|
||||||
|
|
|
@ -38,7 +38,9 @@ extern UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, *
|
||||||
|
|
||||||
// Console bg color (auto updated to match)
|
// Console bg color (auto updated to match)
|
||||||
extern UINT8 *consolebgmap;
|
extern UINT8 *consolebgmap;
|
||||||
|
extern UINT8 *promptbgmap;
|
||||||
|
|
||||||
|
void CON_SetupBackColormapEx(INT32 color, boolean prompt);
|
||||||
void CON_SetupBackColormap(void);
|
void CON_SetupBackColormap(void);
|
||||||
void CON_ClearHUD(void); // clear heads up messages
|
void CON_ClearHUD(void); // clear heads up messages
|
||||||
|
|
||||||
|
|
|
@ -425,6 +425,7 @@ static void D_Display(void)
|
||||||
if (gamestate == GS_LEVEL)
|
if (gamestate == GS_LEVEL)
|
||||||
{
|
{
|
||||||
ST_Drawer();
|
ST_Drawer();
|
||||||
|
F_TextPromptDrawer();
|
||||||
HU_Drawer();
|
HU_Drawer();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
374
src/dehacked.c
374
src/dehacked.c
|
@ -166,8 +166,13 @@ static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f)
|
||||||
if (c == '\n') // Ensure debug line is right...
|
if (c == '\n') // Ensure debug line is right...
|
||||||
dbg_line++;
|
dbg_line++;
|
||||||
if (c == '#')
|
if (c == '#')
|
||||||
|
{
|
||||||
|
if (i > 0) // don't let i wrap past 0
|
||||||
|
i--; // don't include hash char in string
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (buf[i] != '#') // don't include hash char in string
|
||||||
i++;
|
i++;
|
||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
|
|
||||||
|
@ -1549,6 +1554,365 @@ static void readcutscene(MYFILE *f, INT32 num)
|
||||||
Z_Free(s);
|
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;
|
||||||
|
UINT8 picid;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// \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));
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// copypasta from readcutscenescene
|
||||||
|
if (fastcmp(word, "NUMBEROFPICS"))
|
||||||
|
{
|
||||||
|
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 (fastcmp(word, "PICTOSTART"))
|
||||||
|
textprompts[num]->page[pagenum].pictostart = (UINT8)i;
|
||||||
|
else if (fastcmp(word, "PICSMETAPAGE"))
|
||||||
|
{
|
||||||
|
if (usi && usi <= textprompts[num]->numpages)
|
||||||
|
{
|
||||||
|
UINT8 metapagenum = usi - 1;
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
if (picid > MAX_PROMPT_PICS || picid == 0)
|
||||||
|
{
|
||||||
|
deh_warning("textpromptscene %d: unknown word '%s'", num, word);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
--picid;
|
||||||
|
|
||||||
|
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 j;
|
||||||
|
|
||||||
|
// HACK: Add yellow control char now
|
||||||
|
// so the drawing function doesn't call it repeatedly
|
||||||
|
char name[34];
|
||||||
|
name[0] = '\x82'; // color yellow
|
||||||
|
name[1] = 0;
|
||||||
|
strncat(name, word2, 33);
|
||||||
|
name[33] = 0;
|
||||||
|
|
||||||
|
// Replace _ with ' '
|
||||||
|
for (j = 0; j < 32 && name[j]; j++)
|
||||||
|
{
|
||||||
|
if (name[j] == '_')
|
||||||
|
name[j] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
INT32 backcolor;
|
||||||
|
if (i == 0 || fastcmp(word2, "WHITE")) backcolor = 0;
|
||||||
|
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;
|
||||||
|
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 = INT32_MAX; // CONS_BACKCOLOR user-configured
|
||||||
|
else backcolor = 1; // default gray
|
||||||
|
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 = 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 ((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;
|
||||||
|
}
|
||||||
|
else if (fastcmp(word, "METAPAGE"))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// music: don't copy, else each page change may reset the music
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fastcmp(word, "TAG"))
|
||||||
|
strncpy(textprompts[num]->page[pagenum].tag, word2, 33);
|
||||||
|
else if (fastcmp(word, "NEXTPROMPT"))
|
||||||
|
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
|
||||||
|
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 = min(max(value, 0), MAX_PAGES);
|
||||||
|
}
|
||||||
|
else if (fastcmp(word, "PAGE"))
|
||||||
|
{
|
||||||
|
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
|
||||||
|
deh_warning("Page number %d out of range (1 - %d)", value, MAX_PAGES);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
deh_warning("Prompt %d: unknown word '%s', Page <num> expected.", num, word);
|
||||||
|
}
|
||||||
|
} while (!myfeof(f)); // finish when the line is empty
|
||||||
|
|
||||||
|
Z_Free(s);
|
||||||
|
}
|
||||||
|
|
||||||
static void readhuditem(MYFILE *f, INT32 num)
|
static void readhuditem(MYFILE *f, INT32 num)
|
||||||
{
|
{
|
||||||
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
|
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
|
||||||
|
@ -3252,6 +3616,16 @@ static void DEH_LoadDehackedFile(MYFILE *f)
|
||||||
ignorelines(f);
|
ignorelines(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (fastcmp(word, "PROMPT"))
|
||||||
|
{
|
||||||
|
if (i > 0 && i < MAX_PROMPTS)
|
||||||
|
readtextprompt(f, i - 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deh_warning("Prompt number %d out of range (1 - %d)", i, MAX_PROMPTS);
|
||||||
|
ignorelines(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE"))
|
else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE"))
|
||||||
{
|
{
|
||||||
if (i == 0 && word2[0] != '0') // If word2 isn't a number
|
if (i == 0 && word2[0] != '0') // If word2 isn't a number
|
||||||
|
|
|
@ -174,6 +174,60 @@ typedef struct
|
||||||
|
|
||||||
extern cutscene_t *cutscenes[128];
|
extern cutscene_t *cutscenes[128];
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#define PROMPT_PIC_PERSIST 0
|
||||||
|
#define PROMPT_PIC_LOOP 1
|
||||||
|
#define PROMPT_PIC_DESTROY 2
|
||||||
|
#define MAX_PROMPT_PICS 8
|
||||||
|
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
|
||||||
|
UINT16 ycoord[MAX_PROMPT_PICS]; // gfx
|
||||||
|
UINT16 picduration[MAX_PROMPT_PICS];
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
UINT8 verticalalign; // vertical text alignment, 0 = top, 1 = bottom, 2 = middle
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
textpage_t page[MAX_PAGES];
|
||||||
|
INT32 numpages; // Number of pages in this prompt
|
||||||
|
} textprompt_t;
|
||||||
|
|
||||||
|
extern textprompt_t *textprompts[MAX_PROMPTS];
|
||||||
|
|
||||||
// For the Custom Exit linedef.
|
// For the Custom Exit linedef.
|
||||||
extern INT16 nextmapoverride;
|
extern INT16 nextmapoverride;
|
||||||
extern boolean skipstats;
|
extern boolean skipstats;
|
||||||
|
|
631
src/f_finale.c
631
src/f_finale.c
|
@ -33,6 +33,8 @@
|
||||||
#include "m_cond.h"
|
#include "m_cond.h"
|
||||||
#include "p_local.h"
|
#include "p_local.h"
|
||||||
#include "p_setup.h"
|
#include "p_setup.h"
|
||||||
|
#include "st_stuff.h" // hud hiding
|
||||||
|
#include "fastcmp.h"
|
||||||
|
|
||||||
#ifdef HAVE_BLUA
|
#ifdef HAVE_BLUA
|
||||||
#include "lua_hud.h"
|
#include "lua_hud.h"
|
||||||
|
@ -48,6 +50,7 @@ static INT32 timetonext; // Delay between screen changes
|
||||||
static INT32 continuetime; // Short delay when continuing
|
static INT32 continuetime; // Short delay when continuing
|
||||||
|
|
||||||
static tic_t animtimer; // Used for some animation timings
|
static tic_t animtimer; // Used for some animation timings
|
||||||
|
static INT16 skullAnimCounter; // Chevron animation
|
||||||
static INT32 roidtics; // Asteroid spinning
|
static INT32 roidtics; // Asteroid spinning
|
||||||
|
|
||||||
static INT32 deplete;
|
static INT32 deplete;
|
||||||
|
@ -78,6 +81,18 @@ static patch_t *ttspop7;
|
||||||
|
|
||||||
static void F_SkyScroll(INT32 scrollspeed);
|
static void F_SkyScroll(INT32 scrollspeed);
|
||||||
|
|
||||||
|
//
|
||||||
|
// PROMPT STATE
|
||||||
|
//
|
||||||
|
static boolean promptactive = false;
|
||||||
|
static mobj_t *promptmo;
|
||||||
|
static INT16 promptpostexectag;
|
||||||
|
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
|
// CUTSCENE TEXT WRITING
|
||||||
//
|
//
|
||||||
|
@ -1809,7 +1824,7 @@ boolean F_ContinueResponder(event_t *event)
|
||||||
// CUSTOM CUTSCENES
|
// CUSTOM CUTSCENES
|
||||||
// ==================
|
// ==================
|
||||||
static INT32 scenenum, cutnum;
|
static INT32 scenenum, cutnum;
|
||||||
static INT32 picxpos, picypos, picnum, pictime;
|
static INT32 picxpos, picypos, picnum, pictime, picmode, numpics, pictoloop;
|
||||||
static INT32 textxpos, textypos;
|
static INT32 textxpos, textypos;
|
||||||
static boolean dofadenow = false, cutsceneover = false;
|
static boolean dofadenow = false, cutsceneover = false;
|
||||||
static boolean runningprecutscene = false, precutresetplayer = false;
|
static boolean runningprecutscene = false, precutresetplayer = false;
|
||||||
|
@ -2016,3 +2031,617 @@ boolean F_CutsceneResponder(event_t *event)
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// 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 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;
|
||||||
|
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 = (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;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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 != INT32_MAX)
|
||||||
|
{
|
||||||
|
if (nextprompt <= MAX_PROMPTS && textprompts[nextprompt])
|
||||||
|
cutnum = nextprompt;
|
||||||
|
else
|
||||||
|
cutnum = INT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine next page
|
||||||
|
if (nextpage != INT32_MAX)
|
||||||
|
{
|
||||||
|
if (cutnum != INT32_MAX)
|
||||||
|
{
|
||||||
|
scenenum = nextpage;
|
||||||
|
if (scenenum >= MAX_PAGES || scenenum > textprompts[cutnum]->numpages-1)
|
||||||
|
scenenum = INT32_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cutnum != oldcutnum)
|
||||||
|
scenenum = 0;
|
||||||
|
else if (scenenum + 1 < MAX_PAGES && 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(false, false);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// gfx
|
||||||
|
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;
|
||||||
|
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,
|
||||||
|
textprompts[cutnum]->page[scenenum].musicloop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void F_EndTextPrompt(boolean forceexec, boolean noexec)
|
||||||
|
{
|
||||||
|
boolean promptwasactive = promptactive;
|
||||||
|
promptactive = false;
|
||||||
|
callpromptnum = callpagenum = callplayer = INT32_MAX;
|
||||||
|
|
||||||
|
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?
|
||||||
|
}
|
||||||
|
|
||||||
|
// \todo net safety, maybe loop all player thinkers?
|
||||||
|
if ((promptwasactive || forceexec) && !noexec && promptpostexectag)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
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;
|
||||||
|
timetonext = 0;
|
||||||
|
animtimer = 0;
|
||||||
|
stoptimer = 0;
|
||||||
|
skullAnimCounter = 0;
|
||||||
|
|
||||||
|
// Set up state
|
||||||
|
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
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (promptactive)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// gfx
|
||||||
|
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;
|
||||||
|
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,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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, gcl_movement, num_gcl_movement);
|
||||||
|
else if (!strncmp(tag, "TAC", 3)) // 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
|
||||||
|
}
|
||||||
|
else if (!strncmp(tag, "TAD", 3)) // Movement and Camera
|
||||||
|
gcs = G_GetControlScheme(gamecontrol, gcl_movement_camera, num_gcl_movement_camera);
|
||||||
|
else if (!strncmp(tag, "TAJ", 3)) // Jump
|
||||||
|
gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump);
|
||||||
|
else if (!strncmp(tag, "TAS", 3)) // Spin
|
||||||
|
gcs = G_GetControlScheme(gamecontrol, gcl_use, num_gcl_use);
|
||||||
|
else if (!strncmp(tag, "TAA", 3)) // Char ability
|
||||||
|
gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump);
|
||||||
|
else if (!strncmp(tag, "TAW", 3)) // Shield ability
|
||||||
|
gcs = G_GetControlScheme(gamecontrol, gcl_jump_use, num_gcl_jump_use);
|
||||||
|
else
|
||||||
|
gcs = G_GetControlScheme(gamecontrol, gcl_tutorial_used, num_gcl_tutorial_used);
|
||||||
|
|
||||||
|
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_GetPromptPageByNamedTag(const char *tag, INT32 *promptnum, INT32 *pagenum)
|
||||||
|
{
|
||||||
|
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); tutorialmode = false;
|
||||||
|
|
||||||
|
for (*promptnum = 0 + tutorialpromptnum; *promptnum < MAX_PROMPTS; (*promptnum)++)
|
||||||
|
{
|
||||||
|
if (!textprompts[*promptnum])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (*pagenum = 0; *pagenum < textprompts[*promptnum]->numpages && *pagenum < MAX_PAGES; (*pagenum)++)
|
||||||
|
{
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
if (suffixed)
|
||||||
|
{
|
||||||
|
nosuffixpromptnum = *promptnum;
|
||||||
|
nosuffixpagenum = *pagenum;
|
||||||
|
// continue searching for the suffixed tag
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suffixed && !found && nosuffixpromptnum != INT32_MAX && nosuffixpagenum != INT32_MAX)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
*promptnum = nosuffixpromptnum;
|
||||||
|
*pagenum = nosuffixpagenum;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// reuse:
|
||||||
|
// cutnum -> promptnum
|
||||||
|
// scenenum -> pagenum
|
||||||
|
lumpnum_t iconlump;
|
||||||
|
UINT8 pagelines;
|
||||||
|
boolean rightside;
|
||||||
|
INT32 boxh, texth, texty, namey, chevrony;
|
||||||
|
INT32 textx, textr;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
patch_t *patch;
|
||||||
|
|
||||||
|
if (!promptactive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Draw narrator icon
|
||||||
|
if (iconlump != LUMPERROR)
|
||||||
|
{
|
||||||
|
INT32 iconx, icony, scale, scaledsize;
|
||||||
|
patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_CACHE);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
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|V_ALLOWLOWERCASE), textprompts[cutnum]->page[scenenum].name);
|
||||||
|
|
||||||
|
// Draw chevron
|
||||||
|
if (promptblockcontrols && !timetonext)
|
||||||
|
V_DrawString(textr-8, chevrony + (skullAnimCounter/5), (V_SNAPTOBOTTOM|V_YELLOWMAP), "\x1B"); // down arrow
|
||||||
|
}
|
||||||
|
|
||||||
|
void F_TextPromptTicker(void)
|
||||||
|
{
|
||||||
|
INT32 i;
|
||||||
|
|
||||||
|
if (!promptactive || paused || P_AutoPause())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// advance animation
|
||||||
|
finalecount++;
|
||||||
|
cutscene_boostspeed = 0;
|
||||||
|
|
||||||
|
// for the chevron
|
||||||
|
if (--skullAnimCounter <= 0)
|
||||||
|
skullAnimCounter = 8;
|
||||||
|
|
||||||
|
// button handling
|
||||||
|
if (textprompts[cutnum]->page[scenenum].timetonext)
|
||||||
|
{
|
||||||
|
if (promptblockcontrols) // same procedure as below, just without the button handling
|
||||||
|
{
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!splitscreen)
|
||||||
|
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;
|
||||||
|
else if (splitscreen) {
|
||||||
|
// Both players' controls are locked,
|
||||||
|
// But only the triggering player can advance the prompt.
|
||||||
|
if (i == consoleplayer || i == secondarydisplayplayer)
|
||||||
|
{
|
||||||
|
players[i].powers[pw_nocontrol] = 1;
|
||||||
|
|
||||||
|
if (callplayer == consoleplayer || callplayer == secondarydisplayplayer)
|
||||||
|
{
|
||||||
|
if (i != callplayer)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (i != consoleplayer)
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (!splitscreen)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!splitscreen)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate letter-by-letter text
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
#include "d_event.h"
|
#include "d_event.h"
|
||||||
|
#include "p_mobj.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// FINALE
|
// FINALE
|
||||||
|
@ -33,6 +34,7 @@ void F_IntroTicker(void);
|
||||||
void F_TitleScreenTicker(boolean run);
|
void F_TitleScreenTicker(boolean run);
|
||||||
void F_CutsceneTicker(void);
|
void F_CutsceneTicker(void);
|
||||||
void F_TitleDemoTicker(void);
|
void F_TitleDemoTicker(void);
|
||||||
|
void F_TextPromptTicker(void);
|
||||||
|
|
||||||
// Called by main loop.
|
// Called by main loop.
|
||||||
void F_GameEndDrawer(void);
|
void F_GameEndDrawer(void);
|
||||||
|
@ -50,6 +52,13 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
|
||||||
void F_CutsceneDrawer(void);
|
void F_CutsceneDrawer(void);
|
||||||
void F_EndCutScene(void);
|
void F_EndCutScene(void);
|
||||||
|
|
||||||
|
void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, 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);
|
||||||
|
boolean F_GetPromptHideHud(fixed_t y);
|
||||||
|
|
||||||
void F_StartGameEnd(void);
|
void F_StartGameEnd(void);
|
||||||
void F_StartIntro(void);
|
void F_StartIntro(void);
|
||||||
void F_StartTitleScreen(void);
|
void F_StartTitleScreen(void);
|
||||||
|
|
|
@ -146,6 +146,7 @@ tic_t countdowntimer = 0;
|
||||||
boolean countdowntimeup = false;
|
boolean countdowntimeup = false;
|
||||||
|
|
||||||
cutscene_t *cutscenes[128];
|
cutscene_t *cutscenes[128];
|
||||||
|
textprompt_t *textprompts[MAX_PROMPTS];
|
||||||
|
|
||||||
INT16 nextmapoverride;
|
INT16 nextmapoverride;
|
||||||
boolean skipstats;
|
boolean skipstats;
|
||||||
|
@ -1941,6 +1942,7 @@ void G_Ticker(boolean run)
|
||||||
F_TitleDemoTicker();
|
F_TitleDemoTicker();
|
||||||
P_Ticker(run); // tic the game
|
P_Ticker(run); // tic the game
|
||||||
ST_Ticker();
|
ST_Ticker();
|
||||||
|
F_TextPromptTicker();
|
||||||
AM_Ticker();
|
AM_Ticker();
|
||||||
HU_Ticker();
|
HU_Ticker();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -716,6 +716,32 @@ void HWR_DrawConsoleBack(UINT32 color, INT32 height)
|
||||||
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
|
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 = (color == 0 ? 0xC0 : 0x80); // make black darker, like software
|
||||||
|
|
||||||
|
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// R_DRAW.C STUFF
|
// R_DRAW.C STUFF
|
||||||
|
|
|
@ -35,6 +35,7 @@ void HWR_clearAutomap(void);
|
||||||
void HWR_drawAMline(const fline_t *fl, INT32 color);
|
void HWR_drawAMline(const fline_t *fl, INT32 color);
|
||||||
void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength);
|
void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength);
|
||||||
void HWR_DrawConsoleBack(UINT32 color, INT32 height);
|
void HWR_DrawConsoleBack(UINT32 color, INT32 height);
|
||||||
|
void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight);
|
||||||
void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player);
|
void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player);
|
||||||
void HWR_RenderPlayerView(INT32 viewnumber, player_t *player);
|
void HWR_RenderPlayerView(INT32 viewnumber, player_t *player);
|
||||||
void HWR_DrawViewBorder(INT32 clearlines);
|
void HWR_DrawViewBorder(INT32 clearlines);
|
||||||
|
|
|
@ -1541,6 +1541,7 @@ static void P_LoadRawSideDefs2(void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 443: // Calls a named Lua function
|
case 443: // Calls a named Lua function
|
||||||
|
case 459: // Control text prompt (named tag)
|
||||||
{
|
{
|
||||||
char process[8*3+1];
|
char process[8*3+1];
|
||||||
memset(process,0,8*3+1);
|
memset(process,0,8*3+1);
|
||||||
|
@ -2753,6 +2754,9 @@ boolean P_SetupLevel(boolean skipprecip)
|
||||||
I_UpdateNoVsync();
|
I_UpdateNoVsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close text prompt before freeing the old level
|
||||||
|
F_EndTextPrompt(false, true);
|
||||||
|
|
||||||
#ifdef HAVE_BLUA
|
#ifdef HAVE_BLUA
|
||||||
LUA_InvalidateLevel();
|
LUA_InvalidateLevel();
|
||||||
#endif
|
#endif
|
||||||
|
|
28
src/p_spec.c
28
src/p_spec.c
|
@ -35,6 +35,7 @@
|
||||||
#include "m_misc.h"
|
#include "m_misc.h"
|
||||||
#include "m_cond.h" //unlock triggers
|
#include "m_cond.h" //unlock triggers
|
||||||
#include "lua_hook.h" // LUAh_LinedefExecute
|
#include "lua_hook.h" // LUAh_LinedefExecute
|
||||||
|
#include "f_finale.h" // control text prompt
|
||||||
|
|
||||||
#ifdef HW3SOUND
|
#ifdef HW3SOUND
|
||||||
#include "hardware/hw3sound.h"
|
#include "hardware/hw3sound.h"
|
||||||
|
@ -3792,6 +3793,33 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 459: // Control Text Prompt
|
||||||
|
// console player only unless NOCLIMB is set
|
||||||
|
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);
|
||||||
|
//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_GetPromptPageByNamedTag(sides[line->sidenum[0]].text, &promptnum, &pagenum);
|
||||||
|
F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
#ifdef POLYOBJECTS
|
#ifdef POLYOBJECTS
|
||||||
case 480: // Polyobj_DoorSlide
|
case 480: // Polyobj_DoorSlide
|
||||||
case 481: // Polyobj_DoorSwing
|
case 481: // Polyobj_DoorSwing
|
||||||
|
|
|
@ -603,6 +603,9 @@ static void ST_drawDebugInfo(void)
|
||||||
|
|
||||||
static void ST_drawScore(void)
|
static void ST_drawScore(void)
|
||||||
{
|
{
|
||||||
|
if (F_GetPromptHideHud(hudinfo[HUD_SCORE].y))
|
||||||
|
return;
|
||||||
|
|
||||||
// SCORE:
|
// SCORE:
|
||||||
ST_DrawPatchFromHud(HUD_SCORE, sboscore, V_HUDTRANS);
|
ST_DrawPatchFromHud(HUD_SCORE, sboscore, V_HUDTRANS);
|
||||||
if (objectplacing)
|
if (objectplacing)
|
||||||
|
@ -712,6 +715,9 @@ static void ST_drawTime(void)
|
||||||
tictrn = G_TicsToCentiseconds(tics);
|
tictrn = G_TicsToCentiseconds(tics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (F_GetPromptHideHud(hudinfo[HUD_TIME].y))
|
||||||
|
return;
|
||||||
|
|
||||||
// TIME:
|
// TIME:
|
||||||
ST_DrawPatchFromHud(HUD_TIME, ((downwards && (tics < 30*TICRATE) && (leveltime/5 & 1)) ? sboredtime : sbotime), V_HUDTRANS);
|
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;
|
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));
|
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));
|
ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0));
|
||||||
|
@ -756,6 +765,9 @@ static void ST_drawLivesArea(void)
|
||||||
if (!stplyr->skincolor)
|
if (!stplyr->skincolor)
|
||||||
return; // Just joined a server, skin isn't loaded yet!
|
return; // Just joined a server, skin isn't loaded yet!
|
||||||
|
|
||||||
|
if (F_GetPromptHideHud(hudinfo[HUD_LIVES].y))
|
||||||
|
return;
|
||||||
|
|
||||||
// face background
|
// face background
|
||||||
V_DrawSmallScaledPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y,
|
V_DrawSmallScaledPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y,
|
||||||
hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, livesback);
|
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)
|
if (stplyr->powers[pw_carry] == CR_NIGHTSMODE)
|
||||||
y -= 16;
|
y -= 16;
|
||||||
|
|
||||||
|
if (F_GetPromptHideHud(y))
|
||||||
|
return;
|
||||||
|
|
||||||
// O backing
|
// O backing
|
||||||
V_DrawFill(x, y-1, 16, 16, hudinfo[HUD_LIVES].f|20);
|
V_DrawFill(x, y-1, 16, 16, hudinfo[HUD_LIVES].f|20);
|
||||||
V_DrawFill(x, y+15, 16, 1, hudinfo[HUD_LIVES].f|29);
|
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};
|
static INT32 flagoffs[2] = {0, 0}, shieldoffs[2] = {0, 0};
|
||||||
#define ICONSEP (16+4) // matches weapon rings HUD
|
#define ICONSEP (16+4) // matches weapon rings HUD
|
||||||
|
|
||||||
|
if (F_GetPromptHideHud(hudinfo[HUD_POWERUPS].y))
|
||||||
|
return;
|
||||||
|
|
||||||
if (stplyr->spectator || stplyr->playerstate != PST_LIVE)
|
if (stplyr->spectator || stplyr->playerstate != PST_LIVE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1364,7 +1382,7 @@ static void ST_drawFirstPersonHUD(void)
|
||||||
p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
|
p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
|
||||||
|
|
||||||
// Display the countdown drown numbers!
|
// 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_DrawScaledPatch((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset), 60 - SHORT(p->topoffset),
|
||||||
V_PERPLAYER|V_PERPLAYER|V_TRANSLUCENT, p);
|
V_PERPLAYER|V_PERPLAYER|V_TRANSLUCENT, p);
|
||||||
}
|
}
|
||||||
|
@ -1908,6 +1926,9 @@ static void ST_drawMatchHUD(void)
|
||||||
const INT32 y = 176; // HUD_LIVES
|
const INT32 y = 176; // HUD_LIVES
|
||||||
INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6;
|
INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6;
|
||||||
|
|
||||||
|
if (F_GetPromptHideHud(y))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!G_RingSlingerGametype())
|
if (!G_RingSlingerGametype())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1954,6 +1975,9 @@ static void ST_drawTextHUD(void)
|
||||||
y -= 8;\
|
y -= 8;\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (F_GetPromptHideHud(y))
|
||||||
|
return;
|
||||||
|
|
||||||
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator))
|
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator))
|
||||||
{
|
{
|
||||||
if (leveltime < hidetime * TICRATE)
|
if (leveltime < hidetime * TICRATE)
|
||||||
|
@ -2087,6 +2111,9 @@ static void ST_drawTeamHUD(void)
|
||||||
patch_t *p;
|
patch_t *p;
|
||||||
#define SEP 20
|
#define SEP 20
|
||||||
|
|
||||||
|
if (F_GetPromptHideHud(0)) // y base is 0
|
||||||
|
return;
|
||||||
|
|
||||||
if (gametype == GT_CTF)
|
if (gametype == GT_CTF)
|
||||||
p = bflagico;
|
p = bflagico;
|
||||||
else
|
else
|
||||||
|
@ -2200,6 +2227,7 @@ static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offse
|
||||||
interval = 0;
|
interval = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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]);
|
V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, hudinfo[HUD_HUNTPICS].y, hudinfo[HUD_HUNTPICS].f|V_PERPLAYER|V_HUDTRANS, patches[i]);
|
||||||
return interval;
|
return interval;
|
||||||
}
|
}
|
||||||
|
@ -2298,7 +2326,8 @@ static void ST_overlayDrawer(void)
|
||||||
//hu_showscores = auto hide score/time/rings when tab rankings are shown
|
//hu_showscores = auto hide score/time/rings when tab rankings are shown
|
||||||
if (!(hu_showscores && (netgame || multiplayer)))
|
if (!(hu_showscores && (netgame || multiplayer)))
|
||||||
{
|
{
|
||||||
if (maptol & TOL_NIGHTS || G_IsSpecialStage(gamemap))
|
if ((maptol & TOL_NIGHTS || G_IsSpecialStage(gamemap)) &&
|
||||||
|
!F_GetPromptHideHudAll())
|
||||||
ST_drawNiGHTSHUD();
|
ST_drawNiGHTSHUD();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1489,6 +1489,49 @@ void V_DrawFadeConsBack(INT32 plines)
|
||||||
*buf = consolebgmap[*buf];
|
*buf = consolebgmap[*buf];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Very similar to F_DrawFadeConsBack, except we draw from the middle(-ish) of the screen to the bottom.
|
||||||
|
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 (color)
|
||||||
|
{
|
||||||
|
case 0: hwcolor = 0xffffff00; break; // White
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
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 = promptbgmap[*buf];
|
||||||
|
}
|
||||||
|
|
||||||
// Gets string colormap, used for 0x80 color codes
|
// Gets string colormap, used for 0x80 color codes
|
||||||
//
|
//
|
||||||
static const UINT8 *V_GetStringColormap(INT32 colorflags)
|
static const UINT8 *V_GetStringColormap(INT32 colorflags)
|
||||||
|
|
|
@ -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_DrawFadeScreen(UINT16 color, UINT8 strength);
|
||||||
|
|
||||||
void V_DrawFadeConsBack(INT32 plines);
|
void V_DrawFadeConsBack(INT32 plines);
|
||||||
|
void V_DrawPromptBack(INT32 boxheight, INT32 color);
|
||||||
|
|
||||||
// draw a single character
|
// draw a single character
|
||||||
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
|
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
|
||||||
|
|
Loading…
Reference in a new issue