From edd016690dc7fde6409545995d5e690e6a11a119 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 14 Oct 2019 02:24:44 -0300 Subject: [PATCH] A bunch of stuff --- src/dehacked.c | 81 +++++++++++++++++---- src/lua_hudlib.c | 72 +++++++++++++++++++ src/m_menu.c | 146 +++++++++++++++++++++++++++++-------- src/m_menu.h | 10 ++- src/v_video.c | 183 +++++++++++++++++++++++++++++++++++++++++------ src/v_video.h | 8 ++- 6 files changed, 434 insertions(+), 66 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index d4f27b61c..463a71253 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -316,6 +316,10 @@ static boolean findFreeSlot(INT32 *num) // Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...) description[*num].picname[0] = '\0'; description[*num].nametag[0] = '\0'; + description[*num].displayname[0] = '\0'; + description[*num].oppositecolor = SKINCOLOR_NONE; + description[*num].tagtextcolor = SKINCOLOR_NONE; + description[*num].tagoutlinecolor = SKINCOLOR_NONE; // Found one! ^_^ return (description[*num].used = true); @@ -328,9 +332,16 @@ static void readPlayer(MYFILE *f, INT32 num) char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *word; char *word2; + char *displayname = ZZ_Alloc(MAXLINELEN+1); INT32 i; boolean slotfound = false; + #define SLOTFOUND \ + if (!slotfound && (slotfound = findFreeSlot(&num)) == false) \ + goto done; + + displayname[MAXLINELEN] = '\0'; + do { if (myfgets(s, MAXLINELEN, f)) @@ -338,6 +349,17 @@ static void readPlayer(MYFILE *f, INT32 num) if (s[0] == '\n') break; + for (i = 0; i < MAXLINELEN-3; i++) + { + char *tmp; + if (s[i] == '=') + { + tmp = &s[i+2]; + strncpy(displayname, tmp, SKINNAMESIZE); + break; + } + } + word = strtok(s, " "); if (word) strupr(word); @@ -348,8 +370,7 @@ static void readPlayer(MYFILE *f, INT32 num) { char *playertext = NULL; - if (!slotfound && (slotfound = findFreeSlot(&num)) == false) - goto done; + SLOTFOUND for (i = 0; i < MAXLINELEN-3; i++) { @@ -397,18 +418,54 @@ static void readPlayer(MYFILE *f, INT32 num) if (fastcmp(word, "PICNAME")) { - if (!slotfound && (slotfound = findFreeSlot(&num)) == false) - goto done; - + SLOTFOUND strncpy(description[num].picname, word2, 8); } + // new character select + else if (fastcmp(word, "DISPLAYNAME")) + { + SLOTFOUND + // replace '#' with line breaks + // (also remove any '\n') + { + char *cur = NULL; + + // remove '\n' + cur = strchr(displayname, '\n'); + if (cur) + *cur = '\0'; + + // turn '#' into '\n' + cur = strchr(displayname, '#'); + while (cur) + { + *cur = '\n'; + cur = strchr(cur, '#'); + } + } + // copy final string + strncpy(description[num].displayname, displayname, SKINNAMESIZE); + } + else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR")) + { + SLOTFOUND + description[num].oppositecolor = (UINT8)get_number(word2); + } else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME")) { - if (!slotfound && (slotfound = findFreeSlot(&num)) == false) - goto done; - + SLOTFOUND strncpy(description[num].nametag, word2, 8); } + else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR")) + { + SLOTFOUND + description[num].tagtextcolor = (UINT8)get_number(word2); + } + else if (fastcmp(word, "TAGOUTLINECOLOR") || fastcmp(word, "TAGOUTLINECOLOUR")) + { + SLOTFOUND + description[num].tagoutlinecolor = (UINT8)get_number(word2); + } else if (fastcmp(word, "STATUS")) { /* @@ -426,9 +483,7 @@ static void readPlayer(MYFILE *f, INT32 num) else if (fastcmp(word, "SKINNAME")) { // Send to free slot. - if (!slotfound && (slotfound = findFreeSlot(&num)) == false) - goto done; - + SLOTFOUND strlcpy(description[num].skinname, word2, sizeof description[num].skinname); strlwr(description[num].skinname); } @@ -436,8 +491,9 @@ static void readPlayer(MYFILE *f, INT32 num) deh_warning("readPlayer %d: unknown word '%s'", num, word); } } while (!myfeof(f)); // finish when the line is empty - + #undef SLOTFOUND done: + Z_Free(displayname); Z_Free(s); } @@ -9057,6 +9113,7 @@ struct { {"V_OFFSET",V_OFFSET}, {"V_ALLOWLOWERCASE",V_ALLOWLOWERCASE}, {"V_FLIP",V_FLIP}, + {"V_CENTERNAMETAG",V_CENTERNAMETAG}, {"V_SNAPTOTOP",V_SNAPTOTOP}, {"V_SNAPTOBOTTOM",V_SNAPTOBOTTOM}, {"V_SNAPTOLEFT",V_SNAPTOLEFT}, diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 8c1134bca..865b61e8f 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -637,6 +637,68 @@ static int libd_drawString(lua_State *L) return 0; } +static int libd_drawNameTag(lua_State *L) +{ + INT32 x; + INT32 y; + const char *str; + INT32 flags; + UINT8 basecolor; + UINT8 outlinecolor; + UINT8 *basecolormap = NULL; + UINT8 *outlinecolormap = NULL; + + HUDONLY + + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + str = luaL_checkstring(L, 3); + flags = luaL_optinteger(L, 4, 0); + basecolor = luaL_optinteger(L, 5, SKINCOLOR_BLUE); + outlinecolor = luaL_optinteger(L, 6, SKINCOLOR_ORANGE); + if (basecolor != SKINCOLOR_NONE) + basecolormap = R_GetTranslationColormap(TC_DEFAULT, basecolor, GTC_CACHE); + if (outlinecolor != SKINCOLOR_NONE) + outlinecolormap = R_GetTranslationColormap(TC_DEFAULT, outlinecolor, GTC_CACHE); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + V_DrawNameTag(x, y, flags, FRACUNIT, basecolormap, outlinecolormap, str); + return 0; +} + +static int libd_drawScaledNameTag(lua_State *L) +{ + fixed_t x; + fixed_t y; + const char *str; + INT32 flags; + fixed_t scale; + UINT8 basecolor; + UINT8 outlinecolor; + UINT8 *basecolormap = NULL; + UINT8 *outlinecolormap = NULL; + + HUDONLY + + x = luaL_checkfixed(L, 1); + y = luaL_checkfixed(L, 2); + str = luaL_checkstring(L, 3); + flags = luaL_optinteger(L, 4, 0); + scale = luaL_optinteger(L, 5, FRACUNIT); + if (scale < 0) + return luaL_error(L, "negative scale"); + basecolor = luaL_optinteger(L, 6, SKINCOLOR_BLUE); + outlinecolor = luaL_optinteger(L, 7, SKINCOLOR_ORANGE); + if (basecolor != SKINCOLOR_NONE) + basecolormap = R_GetTranslationColormap(TC_DEFAULT, basecolor, GTC_CACHE); + if (outlinecolor != SKINCOLOR_NONE) + outlinecolormap = R_GetTranslationColormap(TC_DEFAULT, outlinecolor, GTC_CACHE); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + V_DrawNameTag(FixedInt(x), FixedInt(y), flags, scale, basecolormap, outlinecolormap, str); + return 0; +} + static int libd_stringWidth(lua_State *L) { const char *str = luaL_checkstring(L, 1); @@ -659,6 +721,13 @@ static int libd_stringWidth(lua_State *L) return 1; } +static int libd_nameTagWidth(lua_State *L) +{ + HUDONLY + lua_pushinteger(L, V_NameTagWidth(luaL_checkstring(L, 1))); + return 1; +} + static int libd_getColormap(lua_State *L) { INT32 skinnum = TC_DEFAULT; @@ -837,9 +906,12 @@ static luaL_Reg lib_draw[] = { {"drawPaddedNum", libd_drawPaddedNum}, {"drawFill", libd_drawFill}, {"drawString", libd_drawString}, + {"drawNameTag", libd_drawNameTag}, + {"drawScaledNameTag", libd_drawScaledNameTag}, {"fadeScreen", libd_fadeScreen}, // misc {"stringWidth", libd_stringWidth}, + {"nameTagWidth", libd_nameTagWidth}, // m_random {"RandomFixed",libd_RandomFixed}, {"RandomByte",libd_RandomByte}, diff --git a/src/m_menu.c b/src/m_menu.c index 894b2956c..958efaaa2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3637,10 +3637,13 @@ void M_InitCharacterTables(void) description[i].used = false; strcpy(description[i].notes, "???"); strcpy(description[i].picname, ""); + strcpy(description[i].nametag, ""); strcpy(description[i].skinname, ""); + strcpy(description[i].displayname, ""); description[i].prev = description[i].next = 0; description[i].charpic = NULL; description[i].namepic = NULL; + description[i].oppositecolor = description[i].tagtextcolor = description[i].tagoutlinecolor = 0; } } @@ -7942,19 +7945,11 @@ static void M_SetupChoosePlayer(INT32 choice) description[i].namepic = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); } else - { - // If no name tag patch was provided, - // the character select screen - // will simply not draw anything. description[i].namepic = NULL; - } } - else + else if (description[i].nametag[0]) { const char *nametag = description[i].nametag; - // If no name tag patch was provided, - // the character select screen - // will simply not draw anything. description[i].namepic = NULL; if (W_LumpExists(nametag)) description[i].namepic = W_CachePatchName(nametag, PU_CACHE); @@ -8129,7 +8124,9 @@ static void M_DrawSetupChoosePlayerMenu(void) charskin = &skins[skinnum]; // Use the opposite of the character's skincolor - col = Color_Opposite[charskin->prefcolor - 1][0]; + col = description[char_on].oppositecolor; + if (!col) + col = Color_Opposite[charskin->prefcolor - 1][0]; // Make the translation colormap colormap = R_GetTranslationColormap(skinnum, col, 0); @@ -8180,43 +8177,136 @@ static void M_DrawSetupChoosePlayerMenu(void) INT32 ox, x, y; INT32 oxsh = FixedInt(FixedMul(BASEVIDWIDTH*FRACUNIT, FixedDiv(char_scroll, 128*FRACUNIT))), txsh; patch_t *curpatch = NULL, *prevpatch = NULL, *nextpatch = NULL; + const char *curtext = NULL, *prevtext = NULL, *nexttext = NULL; + UINT8 curtextcolor = 0, prevtextcolor = 0, nexttextcolor = 0; + UINT8 curoutlinecolor = 0, prevoutlinecolor = 0, nextoutlinecolor = 0; - // Name tag patches - curpatch = description[char_on].namepic; - if (prev != -1) prevpatch = description[prev].namepic; - if (next != -1) nextpatch = description[next].namepic; + // Name tag + curtext = description[char_on].displayname; + curtextcolor = description[char_on].tagtextcolor; + curoutlinecolor = description[char_on].tagoutlinecolor; + if (curtext[0] == '\0') + curpatch = description[char_on].namepic; + if (skinnum != -1) + { + if (!curtextcolor) + curtextcolor = charskin->prefcolor; + if (!curoutlinecolor) + curoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + } + + // previous character + if (prev != -1) + { + prevtext = description[prev].displayname; + prevtextcolor = description[prev].tagtextcolor; + prevoutlinecolor = description[prev].tagoutlinecolor; + if (prevtext[0] == '\0') + prevpatch = description[prev].namepic; + // Find skin number from description[] + skinnum = getskinfromdescription(prev); + if (skinnum != -1) + { + charskin = &skins[skinnum]; + if (!prevtextcolor) + prevtextcolor = charskin->prefcolor; + if (!prevoutlinecolor) + prevoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + } + } + + // next character + if (next != -1) + { + nexttext = description[next].displayname; + nexttextcolor = description[next].tagtextcolor; + nextoutlinecolor = description[next].tagoutlinecolor; + if (nexttext[0] == '\0') + nextpatch = description[next].namepic; + // Find skin number from description[] + skinnum = getskinfromdescription(next); + if (skinnum != -1) + { + charskin = &skins[skinnum]; + if (!nexttextcolor) + nexttextcolor = charskin->prefcolor; + if (!nextoutlinecolor) + nextoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + } + } txsh = oxsh; ox = 8 + SHORT((description[char_on].charpic)->width)/2; - if (curpatch) - ox -= (SHORT(curpatch->width)/2); y = my + 144; if (char_scroll) { // prev - if (prevpatch && char_scroll < 0) + if ((prev != -1) && char_scroll < 0) { + INT32 ox2 = ox; + if (prevpatch) + ox2 -= (SHORT(prevpatch->width)/2); // Why does this work? - x = (ox - txsh) - BASEVIDWIDTH; - V_DrawScaledPatch(x, y, 0, prevpatch); + x = (ox2 - txsh) - BASEVIDWIDTH; + if (prevtext[0] != '\0') + { + skinnum = getskinfromdescription(prev); + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(skinnum, prevtextcolor, 0), + R_GetTranslationColormap(skinnum, prevoutlinecolor, 0), + prevtext + ); + } + else if (prevpatch) + V_DrawScaledPatch(x, y, 0, prevpatch); } // next - else if (nextpatch && char_scroll > 0) + else if ((next != -1) && char_scroll > 0) { - x = (ox - txsh) + BASEVIDWIDTH; + INT32 ox2 = ox; + if (nextpatch) + ox2 -= (SHORT(nextpatch->width)/2); + x = (ox2 - txsh) + BASEVIDWIDTH; if (x < BASEVIDWIDTH) - V_DrawScaledPatch(x, y, 0, nextpatch); + { + if (nexttext[0] != '\0') + { + skinnum = getskinfromdescription(next); + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(skinnum, nexttextcolor, 0), + R_GetTranslationColormap(skinnum, nextoutlinecolor, 0), + nexttext + ); + } + else if (nextpatch) + V_DrawScaledPatch(x, y, 0, nextpatch); + } } } // cur - x = ox - txsh; - //if (curpatch) - // V_DrawScaledPatch(x, y, 0, curpatch); - - // Dummy string to be removed when finalized - V_DrawNameTag(x, y, 0, R_GetTranslationColormap(skinnum, SKINCOLOR_BLUE, 0), R_GetTranslationColormap(skinnum, SKINCOLOR_YELLOW, 0), "Sonic\n&Tails."); + skinnum = getskinfromdescription(next); + if (skinnum != -1) + { + INT32 ox2 = ox; + if (curpatch) + ox2 -= (SHORT(curpatch->width)/2); + x = ox2 - txsh; + if (curtext[0] != '\0') + { + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(skinnum, curtextcolor, 0), + R_GetTranslationColormap(skinnum, curoutlinecolor, 0), + curtext + ); + } + else if (curpatch) + V_DrawScaledPatch(x, y, 0, curpatch); + } } // Alternative menu header diff --git a/src/m_menu.h b/src/m_menu.h index 409ef4e08..ad29cf2e7 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -322,12 +322,18 @@ typedef struct boolean used; char notes[441]; char picname[8]; - char nametag[8]; char skinname[SKINNAMESIZE*2+2]; // skin&skin\0 patch_t *charpic; - patch_t *namepic; UINT8 prev; UINT8 next; + + // new character select + char displayname[SKINNAMESIZE+1]; + UINT8 oppositecolor; + char nametag[8]; + patch_t *namepic; + UINT8 tagtextcolor; + UINT8 tagoutlinecolor; } description_t; // level select platter diff --git a/src/v_video.c b/src/v_video.c index c39f708ee..8f44ca8cd 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2630,18 +2630,32 @@ void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string) // Draw a string using the nt_font // Note that the outline is a seperate font set -void V_DrawNameTag(INT32 x, INT32 y, INT32 option, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string) +static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string) { - INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0; + fixed_t cx, cy, w; + INT32 c, dupx, dupy, scrwidth, left = 0; const char *ch = string; - INT32 spacewidth = 4; - INT32 lowercase = (option & V_ALLOWLOWERCASE); - option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE... - dupx = dupy = 1; - scrwidth = vid.width/vid.dupx; - left = (scrwidth - BASEVIDWIDTH)/2; - scrwidth -= left; + if (option & V_CENTERNAMETAG) + x -= FixedInt(FixedMul((V_NameTagWidth(string)/2)*FRACUNIT, scale)); + option &= ~V_CENTERNAMETAG; // which is also shared with V_ALLOWLOWERCASE... + + cx = x<= NT_FONTSIZE || !ntb_font[c] || !nto_font[c]) { - cx += spacewidth * dupx; + cx += FixedMul((4 * dupx)*FRACUNIT, scale); continue; } - w = SHORT(ntb_font[c]->width)+4 * dupx; + w = FixedMul((SHORT(ntb_font[c]->width)+2 * dupx) * FRACUNIT, scale); - if (cx > scrwidth) + if (FixedInt(cx) > scrwidth) continue; - if (cx+left + w < 0) //left boundary check + if (cx+(left*FRACUNIT) + w < 0) // left boundary check { cx += w; continue; } - V_DrawFixedPatch((cx)<= 2) && (string[0] == '\n') && (string[1] != '\n')) + shift++; + // Then draw it + V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, string+shift); + } + // No line break character was found + else + { + // Don't leave a line break character + // at the start of the string! + if ((strlen(first_token) >= 2) && (first_token[0] == '\n') && (first_token[1] != '\n')) + first_token++; + // Then draw it + V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, first_token); + break; + } + + // Next line + y += FixedInt(FixedMul(lbreakheight*FRACUNIT, scale)); + if ((last_token-text)+1 >= strlen(text)) + last_token = NULL; + else + { + first_token = last_token; + last_token = strchr(first_token+1, '\n'); + } + } + // Free this line + if (string) + Z_Free(string); + } +} + +// Count the amount of lines in name tag string +INT32 V_CountNameTagLines(const char *string) +{ + INT32 lines = 1; + char *text = (char *)string; + char *first_token = text; + char *last_token = strchr(text, '\n'); + + // No line breaks? + if (!last_token) + return lines; + // Split string by the line break character + else + { + while (true) + { + if (last_token) + lines++; + // No line break character was found + else + break; + + // Next line + if ((last_token-text)+1 >= strlen(text)) + last_token = NULL; + else + { + first_token = last_token; + last_token = strchr(first_token+1, '\n'); + } + } + } + return lines; +} + +INT32 V_NameTagWidth(const char *string) +{ + INT32 c, w = 0; + size_t i; + + // It's possible for string to be a null pointer + if (!string) + return 0; + + for (i = 0; i < strlen(string); i++) + { + c = toupper(string[i]) - NT_FONTSTART; + if (c < 0 || c >= NT_FONTSIZE || !ntb_font[c] || !nto_font[c]) + w += 4; + else + w += SHORT(ntb_font[c]->width)+2; + } + + return w; +} + // Find string width from cred_font chars // INT32 V_CreditStringWidth(const char *string) diff --git a/src/v_video.h b/src/v_video.h index ad1454cb7..01d50cd57 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -112,6 +112,7 @@ extern RGBA_t *pMasterPalette; #define V_OFFSET 0x00400000 // account for offsets in patches #define V_ALLOWLOWERCASE 0x00800000 // (strings only) allow fonts that have lowercase letters to use them #define V_FLIP 0x00800000 // (patches only) Horizontal flip +#define V_CENTERNAMETAG 0x00800000 // (nametag only) center nametag lines #define V_SNAPTOTOP 0x01000000 // for centering #define V_SNAPTOBOTTOM 0x02000000 // for centering @@ -203,11 +204,12 @@ INT32 V_LevelNameHeight(const char *string); INT32 V_LevelActNumWidth(INT32 num); // act number width void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string); +INT32 V_CreditStringWidth(const char *string); // Draw a string using the nt_font -void V_DrawNameTag(INT32 x, INT32 y, INT32 option, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string); - -INT32 V_CreditStringWidth(const char *string); +void V_DrawNameTag(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string); +INT32 V_CountNameTagLines(const char *string); +INT32 V_NameTagWidth(const char *string); // Find string width from hu_font chars INT32 V_StringWidth(const char *string, INT32 option);