diff --git a/src/d_main.c b/src/d_main.c index 41fa98408..e71b1cdb3 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -359,7 +359,7 @@ static void D_Display(void) // clean up border stuff // see if the border needs to be initially drawn - if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide)) + if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap))) { // draw the view directly diff --git a/src/dehacked.c b/src/dehacked.c index 7e706e39e..3bd4e9f47 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -313,7 +313,13 @@ static boolean findFreeSlot(INT32 *num) if (*num >= MAXSKINS) return false; - description[*num].picname[0] = '\0'; // Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...) + // 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); @@ -326,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)) @@ -336,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); @@ -346,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++) { @@ -395,11 +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")) + { + 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")) { /* @@ -417,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); } @@ -427,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); } @@ -9092,6 +9157,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/doomstat.h b/src/doomstat.h index 57e37f72d..7d06f03e2 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -327,7 +327,7 @@ typedef struct // Music stuff. UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds char musintername[7]; ///< Intermission screen music. - + char muspostbossname[7]; ///< Post-bossdeath music. UINT16 muspostbosstrack; ///< Post-bossdeath track. UINT32 muspostbosspos; ///< Post-bossdeath position @@ -433,6 +433,7 @@ typedef struct tic_t time; ///< Time in which the level was finished. UINT32 score; ///< Score when the level was finished. UINT16 rings; ///< Rings when the level was finished. + boolean gotperfect; ///< Got perfect bonus? } recorddata_t; /** Setup for one NiGHTS map. diff --git a/src/f_finale.c b/src/f_finale.c index e84d82279..eb1415042 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -75,6 +75,7 @@ INT32 curbgcolor; INT32 curbgxspeed; INT32 curbgyspeed; boolean curbghide; +boolean hidetitlemap; // WARNING: set to false by M_SetupNextMenu and M_ClearMenus static UINT8 curDemo = 0; static UINT32 demoDelayLeft; @@ -1585,15 +1586,15 @@ void F_StartEnding(void) UINT8 skinnum = players[consoleplayer].skin; spritedef_t *sprdef; spriteframe_t *sprframe; - if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 7) + if (skins[skinnum].sprites[SPR2_XTRA].numframes >= (XTRA_ENDING+2)+1) { sprdef = &skins[skinnum].sprites[SPR2_XTRA]; // character head, skin specific - sprframe = &sprdef->spriteframes[4]; + sprframe = &sprdef->spriteframes[XTRA_ENDING]; endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); - sprframe = &sprdef->spriteframes[5]; + sprframe = &sprdef->spriteframes[XTRA_ENDING+1]; endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); - sprframe = &sprdef->spriteframes[6]; + sprframe = &sprdef->spriteframes[XTRA_ENDING+2]; endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); } else // Show a star if your character doesn't have an ending firework display. (Basically the MISSINGs for this) @@ -2098,12 +2099,12 @@ void F_InitMenuPresValues(void) curfadevalue = 16; curhidepics = hidetitlepics; curbgcolor = -1; - curbgxspeed = titlescrollxspeed; - curbgyspeed = titlescrollyspeed; - curbghide = true; + curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed; + curbgyspeed = (gamestate == GS_TIMEATTACK) ? 22 : titlescrollyspeed; + curbghide = (gamestate == GS_TIMEATTACK) ? false : true; // Find current presentation values - M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "SRB2BACK" : "TITLESKY"); + M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "RECATTBG" : "TITLESKY"); M_SetMenuCurFadeValue(16); M_SetMenuCurHideTitlePics(); } diff --git a/src/f_finale.h b/src/f_finale.h index d640abc8a..58c492c3d 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -94,6 +94,7 @@ extern INT32 curbgcolor; extern INT32 curbgxspeed; extern INT32 curbgyspeed; extern boolean curbghide; +extern boolean hidetitlemap; #define TITLEBACKGROUNDACTIVE (curfadevalue >= 0 || curbgname[0]) diff --git a/src/g_game.c b/src/g_game.c index 246fb965a..1c6efe45e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3343,6 +3343,7 @@ void G_LoadGameData(void) UINT32 recscore; tic_t rectime; UINT16 recrings; + boolean gotperf; UINT8 recmares; INT32 curmare; @@ -3435,6 +3436,7 @@ void G_LoadGameData(void) recscore = READUINT32(save_p); rectime = (tic_t)READUINT32(save_p); recrings = READUINT16(save_p); + gotperf = (boolean)READUINT8(save_p); if (recrings > 10000 || recscore > MAXSCORE) goto datacorrupt; @@ -3446,6 +3448,9 @@ void G_LoadGameData(void) mainrecords[i]->time = rectime; mainrecords[i]->rings = recrings; } + + if (gotperf) + mainrecords[i]->gotperfect = gotperf; } // Nights records @@ -3577,12 +3582,14 @@ void G_SaveGameData(void) WRITEUINT32(save_p, mainrecords[i]->score); WRITEUINT32(save_p, mainrecords[i]->time); WRITEUINT16(save_p, mainrecords[i]->rings); + WRITEUINT8(save_p, mainrecords[i]->gotperfect); } else { WRITEUINT32(save_p, 0); WRITEUINT32(save_p, 0); WRITEUINT16(save_p, 0); + WRITEUINT8(save_p, 0); } } diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 3bc643c3c..428656bf2 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -71,6 +71,10 @@ patch_t *lt_font[LT_FONTSIZE]; patch_t *cred_font[CRED_FONTSIZE]; patch_t *ttlnum[20]; // act numbers (0-19) +// Name tag fonts +patch_t *ntb_font[NT_FONTSIZE]; +patch_t *nto_font[NT_FONTSIZE]; + static player_t *plr; boolean chat_on; // entering a chat message? static char w_chat[HU_MAXMSGLEN]; @@ -246,6 +250,32 @@ void HU_LoadGraphics(void) ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); } + // cache the base name tag font for entire game execution + j = NT_FONTSTART; + for (i = 0; i < NT_FONTSIZE; i++) + { + sprintf(buffer, "NTFNT%.3d", j); + j++; + + if (W_CheckNumForName(buffer) == LUMPERROR) + ntb_font[i] = NULL; + else + ntb_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); + } + + // cache the outline name tag font for entire game execution + j = NT_FONTSTART; + for (i = 0; i < NT_FONTSIZE; i++) + { + sprintf(buffer, "NTFNO%.3d", j); + j++; + + if (W_CheckNumForName(buffer) == LUMPERROR) + nto_font[i] = NULL; + else + nto_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); + } + // cache the crosshairs, don't bother to know which one is being used, // just cache all 3, they're so small anyway. for (i = 0; i < HU_CROSSHAIRS; i++) diff --git a/src/hu_stuff.h b/src/hu_stuff.h index ab77e67b6..55b61d4b7 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -35,6 +35,12 @@ #define CRED_FONTEND 'Z' // the last font character #define CRED_FONTSIZE (CRED_FONTEND - CRED_FONTSTART + 1) +// Name tag font +// Used by base and outline font set +#define NT_FONTSTART '!' // the first font character +#define NT_FONTEND 'Z' // the last font character +#define NT_FONTSIZE (NT_FONTEND - NT_FONTSTART + 1) + #define HU_CROSSHAIRS 3 // maximum of 9 - see HU_Init(); extern char *shiftxform; // english translation shift table @@ -77,6 +83,8 @@ extern patch_t *tallnum[10]; extern patch_t *nightsnum[10]; extern patch_t *lt_font[LT_FONTSIZE]; extern patch_t *cred_font[CRED_FONTSIZE]; +extern patch_t *ntb_font[NT_FONTSIZE]; +extern patch_t *nto_font[NT_FONTSIZE]; extern patch_t *ttlnum[20]; extern patch_t *emeraldpics[3][8]; extern patch_t *rflagico; diff --git a/src/info.h b/src/info.h index 763e91c7d..95e423dcc 100644 --- a/src/info.h +++ b/src/info.h @@ -879,6 +879,12 @@ typedef enum playersprite NUMPLAYERSPRITES } playersprite_t; +// SPR2_XTRA +#define XTRA_LIFEPIC 0 // Life icon patch +#define XTRA_CHARSEL 1 // Character select picture +#define XTRA_CONTINUE 2 // Continue icon +#define XTRA_ENDING 3 // Ending finale patches + typedef enum state { S_NULL, 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_cond.c b/src/m_cond.c index 539c6d1f6..b7520aba7 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -528,12 +528,22 @@ skincolors_t M_GetEmblemColor(emblem_t *em) return em->color; } -const char *M_GetEmblemPatch(emblem_t *em) +const char *M_GetEmblemPatch(emblem_t *em, boolean big) { - static char pnamebuf[7] = "GOTITn"; + static char pnamebuf[7]; + + if (!big) + strcpy(pnamebuf, "GOTITn"); + else + strcpy(pnamebuf, "EMBMn0"); I_Assert(em->sprite >= 'A' && em->sprite <= 'Z'); - pnamebuf[5] = em->sprite; + + if (!big) + pnamebuf[5] = em->sprite; + else + pnamebuf[4] = em->sprite; + return pnamebuf; } @@ -544,11 +554,21 @@ skincolors_t M_GetExtraEmblemColor(extraemblem_t *em) return em->color; } -const char *M_GetExtraEmblemPatch(extraemblem_t *em) +const char *M_GetExtraEmblemPatch(extraemblem_t *em, boolean big) { - static char pnamebuf[7] = "GOTITn"; + static char pnamebuf[7]; + + if (!big) + strcpy(pnamebuf, "GOTITn"); + else + strcpy(pnamebuf, "EMBMn0"); I_Assert(em->sprite >= 'A' && em->sprite <= 'Z'); - pnamebuf[5] = em->sprite; + + if (!big) + pnamebuf[5] = em->sprite; + else + pnamebuf[4] = em->sprite; + return pnamebuf; } diff --git a/src/m_cond.h b/src/m_cond.h index f82e49372..e9859cf11 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -171,9 +171,9 @@ INT32 M_CountEmblems(void); // Emblem shit emblem_t *M_GetLevelEmblems(INT32 mapnum); skincolors_t M_GetEmblemColor(emblem_t *em); -const char *M_GetEmblemPatch(emblem_t *em); +const char *M_GetEmblemPatch(emblem_t *em, boolean big); skincolors_t M_GetExtraEmblemColor(extraemblem_t *em); -const char *M_GetExtraEmblemPatch(extraemblem_t *em); +const char *M_GetExtraEmblemPatch(extraemblem_t *em, boolean big); // If you're looking to compare stats for unlocks or what not, use these // They stop checking upon reaching the target number so they diff --git a/src/m_menu.c b/src/m_menu.c index da1309de1..b232fddb3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -127,7 +127,6 @@ const char *quitmsg[NUM_QUITMESSAGES]; description_t description[MAXSKINS]; INT16 char_on = -1, startchar = 0; static char *char_notes = NULL; -static fixed_t char_scroll = 0; boolean menuactive = false; boolean fromlevelselect = false; @@ -167,6 +166,16 @@ static INT32 vidm_selected = 0; static INT32 vidm_nummodes; static INT32 vidm_column_size; +// new menus +static tic_t recatkdrawtimer = 0; +static tic_t ntsatkdrawtimer = 0; + +static tic_t charseltimer = 0; +static fixed_t char_scroll = 0; +#define charscrollamt 128*FRACUNIT + +static tic_t keydown = 0; + // // PROTOTYPES // @@ -747,8 +756,8 @@ static menuitem_t SP_TimeAttackLevelSelectMenu[] = // Single Player Time Attack static menuitem_t SP_TimeAttackMenu[] = { - {IT_STRING|IT_KEYHANDLER, NULL, "Level Select...", M_HandleTimeAttackLevelSelect, 52}, - {IT_STRING|IT_CVAR, NULL, "Character", &cv_chooseskin, 62}, + {IT_STRING|IT_KEYHANDLER, NULL, "Level Select...", M_HandleTimeAttackLevelSelect, 62}, + {IT_STRING|IT_CVAR, NULL, "Character", &cv_chooseskin, 72}, {IT_DISABLED, NULL, "Guest Option...", &SP_GuestReplayDef, 100}, {IT_DISABLED, NULL, "Replay...", &SP_ReplayDef, 110}, @@ -2293,8 +2302,10 @@ void M_InitMenuPresTables(void) { menupres[i].muslooping = true; } - if (i == MN_SP_TIMEATTACK || i == MN_SP_NIGHTSATTACK) - strncpy(menupres[i].musname, "_inter", 7); + if (i == MN_SP_TIMEATTACK) + strncpy(menupres[i].musname, "_recat", 7); + else if (i == MN_SP_NIGHTSATTACK) + strncpy(menupres[i].musname, "_nitat", 7); else if (i == MN_SP_PLAYER) strncpy(menupres[i].musname, "_chsel", 7); } @@ -2387,7 +2398,7 @@ static boolean MIT_SetCurBackground(UINT32 menutype, INT32 level, INT32 *retval, } else if (menupres[menutype].bgname[0]) { - strncpy(curbgname, menupres[menutype].bgname, 9); + strncpy(curbgname, menupres[menutype].bgname, 8); curbgxspeed = menupres[menutype].titlescrollxspeed != INT32_MAX ? menupres[menutype].titlescrollxspeed : titlescrollxspeed; curbgyspeed = menupres[menutype].titlescrollyspeed != INT32_MAX ? menupres[menutype].titlescrollyspeed : titlescrollyspeed; return true; @@ -2505,7 +2516,7 @@ void M_ChangeMenuMusic(const char *defaultmusname, boolean defaultmuslooping) void M_SetMenuCurBackground(const char *defaultname) { - char name[8]; + char name[9]; strncpy(name, defaultname, 8); M_IterateMenuTree(MIT_SetCurBackground, &name); } @@ -2571,8 +2582,6 @@ static void M_HandleMenuPresState(menu_t *newMenu) if (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK) return; - // Find current presentation values - M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "SRB2BACK" : "TITLESKY"); M_SetMenuCurFadeValue(16); M_SetMenuCurHideTitlePics(); @@ -2919,6 +2928,7 @@ boolean M_Responder(event_t *ev) { if (ev->type == ev_keydown) { + keydown++; ch = ev->data1; // added 5-2-98 remap virtual keys (mouse & joystick buttons) @@ -3025,6 +3035,8 @@ boolean M_Responder(event_t *ev) pmousex = lastx += 30; } } + else if (ev->type == ev_keyup) // Preserve event for other responders + keydown = 0; } else if (ev->type == ev_keydown) // Preserve event for other responders ch = ev->data1; @@ -3468,6 +3480,7 @@ void M_ClearMenus(boolean callexitmenufunc) if (currentMenu == &MessageDef) // Oh sod off! currentMenu = &MainDef; // Not like it matters menuactive = false; + hidetitlemap = false; } // @@ -3506,6 +3519,8 @@ void M_SetupNextMenu(menu_t *menudef) } } } + + hidetitlemap = false; } // @@ -3615,9 +3630,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].pic = NULL; + description[i].charpic = NULL; + description[i].namepic = NULL; + description[i].oppositecolor = description[i].tagtextcolor = description[i].tagoutlinecolor = 0; } } @@ -3880,7 +3899,7 @@ static void M_DrawMapEmblems(INT32 mapnum, INT32 x, INT32 y) lasttype = curtype; if (emblem->collected) - V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), + V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); else V_DrawSmallScaledPatch(x, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); @@ -4319,7 +4338,7 @@ static void M_DrawPauseMenu(void) continue; if (emblem->collected) - V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), + V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); else V_DrawSmallScaledPatch(40, 44 + (i*8), 0, W_CachePatchName("NEEDIT", PU_CACHE)); @@ -5188,18 +5207,187 @@ static void M_DrawLevelPlatterRow(UINT8 row, INT32 y) } } +// new menus +static void M_DrawRecordAttackForeground(void) +{ + patch_t *fg = W_CachePatchName("RECATKFG", PU_CACHE); + patch_t *clock = W_CachePatchName("RECCLOCK", PU_CACHE); + angle_t fa; + + INT32 i; + INT32 height = (SHORT(fg->height)/2); + INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); + + for (i = -12; i < (BASEVIDHEIGHT/height) + 12; i++) + { + INT32 y = ((i*height) - (height - ((recatkdrawtimer*2)%height))); + // don't draw above the screen + { + INT32 sy = FixedMul(y, dupz<> FRACBITS; + if (vid.height != BASEVIDHEIGHT * dupz) + sy += (vid.height - (BASEVIDHEIGHT * dupz)) / 2; + if ((sy+height) < 0) + continue; + } + V_DrawFixedPatch(0, y< vid.height) + break; + } + + // draw clock + fa = (FixedAngle(((recatkdrawtimer * 4) % 360)<>ANGLETOFINESHIFT) & FINEMASK; + V_DrawSciencePatch(160<width); + INT32 y = BASEVIDHEIGHT - SHORT(background->height)*2; + + if (vid.height != BASEVIDHEIGHT * dupz) + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 158); + V_DrawFill(0, y+50, vid.width, BASEVIDHEIGHT, V_SNAPTOLEFT|31); + + V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background); + x += SHORT(background->width); + if (x < BASEVIDWIDTH) + V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background); + + bgscrollx -= (FRACUNIT/2); +} + +// NiGHTS Attack foreground. +static void M_DrawNightsAttackBackground(void) +{ + INT32 x, y = 0; + INT32 i; + + // top + patch_t *backtopfg = W_CachePatchName("NTSATKT1", PU_CACHE); + patch_t *fronttopfg = W_CachePatchName("NTSATKT2", PU_CACHE); + INT32 backtopwidth = SHORT(backtopfg->width); + //INT32 backtopheight = SHORT(backtopfg->height); + INT32 fronttopwidth = SHORT(fronttopfg->width); + //INT32 fronttopheight = SHORT(fronttopfg->height); + + // bottom + patch_t *backbottomfg = W_CachePatchName("NTSATKB1", PU_CACHE); + patch_t *frontbottomfg = W_CachePatchName("NTSATKB2", PU_CACHE); + INT32 backbottomwidth = SHORT(backbottomfg->width); + INT32 backbottomheight = SHORT(backbottomfg->height); + INT32 frontbottomwidth = SHORT(frontbottomfg->width); + INT32 frontbottomheight = SHORT(frontbottomfg->height); + + // background + M_DrawNightsAttackMountains(); + + // back top foreground patch + x = -(ntsatkdrawtimer%backtopwidth); + V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, backtopfg); + for (i = 0; i < 3; i++) + { + x += (backtopwidth); + if (x >= vid.width) + break; + V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, backtopfg); + } + + // front top foreground patch + x = -((ntsatkdrawtimer*2)%fronttopwidth); + V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, fronttopfg); + for (i = 0; i < 3; i++) + { + x += (fronttopwidth); + if (x >= vid.width) + break; + V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, fronttopfg); + } + + // back bottom foreground patch + x = -(ntsatkdrawtimer%backbottomwidth); + y = BASEVIDHEIGHT - backbottomheight; + V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, backbottomfg); + for (i = 0; i < 3; i++) + { + x += (backbottomwidth); + if (x >= vid.width) + break; + V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, backbottomfg); + } + + // front bottom foreground patch + x = -((ntsatkdrawtimer*2)%frontbottomwidth); + y = BASEVIDHEIGHT - frontbottomheight; + V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, frontbottomfg); + for (i = 0; i < 3; i++) + { + x += (frontbottomwidth); + if (x >= vid.width) + break; + V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, frontbottomfg); + } + + // Increment timer. + ntsatkdrawtimer++; +} + +// NiGHTS Attack floating Super Sonic. +static patch_t *ntssupersonic[2]; +static void M_DrawNightsAttackSuperSonic(void) +{ + const UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_YELLOW, GTC_CACHE); + INT32 timer = (ntsatkdrawtimer/4) % 2; + angle_t fa = (FixedAngle(((ntsatkdrawtimer * 4) % 360)<>ANGLETOFINESHIFT) & FINEMASK; + V_DrawFixedPatch(235<prevMenu == &SP_TimeAttackDef) { + M_SetMenuCurBackground("RECATKBG"); + + curbgxspeed = 0; + curbgyspeed = 18; + if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction) + { F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + // Draw and animate foreground + if (!strncmp("RECATKBG", curbgname, 8)) + M_DrawRecordAttackForeground(); + } + + if (curfadevalue) + V_DrawFadeScreen(0xFF00, curfadevalue); + } + + if (currentMenu->prevMenu == &SP_NightsAttackDef) + { + M_SetMenuCurBackground("NTSATKBG"); + + if (curbgcolor >= 0) + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); + else if (!curbghide || !titlemapinaction) + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 158); + M_DrawNightsAttackMountains(); + } if (curfadevalue) V_DrawFadeScreen(0xFF00, curfadevalue); } @@ -5420,7 +5608,19 @@ static void M_DrawMessageMenu(void) if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction) - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + { + if (levellistmode == LLM_NIGHTSATTACK) + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 158); + M_DrawNightsAttackMountains(); + } + else + { + F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + if (!strncmp("RECATKBG", curbgname, 8)) + M_DrawRecordAttackForeground(); + } + } if (curfadevalue) V_DrawFadeScreen(0xFF00, curfadevalue); } @@ -6696,7 +6896,7 @@ static void M_DrawEmblemHints(void) if (emblem->collected) { collected = V_GREENMAP; - V_DrawMappedPatch(12, 12+(28*j), 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), + V_DrawMappedPatch(12, 12+(28*j), 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE)); } else @@ -7647,6 +7847,8 @@ static void M_HandleLoadSave(INT32 choice) } if (exitmenu) { + // Is this a hack? + charseltimer = 0; if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); else @@ -7723,7 +7925,7 @@ static void M_SetupChoosePlayer(INT32 choice) UINT8 firstvalid = 255; UINT8 lastvalid = 0; boolean allowed = false; - char *name; + char *and; (void)choice; SP_PlayerMenu[0].status &= ~IT_DYBIGSPACE; // Correcting a hack that may be made below. @@ -7732,8 +7934,21 @@ static void M_SetupChoosePlayer(INT32 choice) { if (description[i].used) // If the character's disabled through SOC, there's nothing we can do for it. { - name = strtok(Z_StrDup(description[i].skinname), "&"); - skinnum = R_SkinAvailable(name); + and = strchr(description[i].skinname, '&'); + if (and) + { + char firstskin[SKINNAMESIZE+1]; + strncpy(firstskin, description[i].skinname, (and - description[i].skinname)); + firstskin[(and - description[i].skinname)] = '\0'; + description[i].skinnum[0] = R_SkinAvailable(firstskin); + description[i].skinnum[1] = R_SkinAvailable(and+1); + } + else + { + description[i].skinnum[0] = R_SkinAvailable(description[i].skinname); + description[i].skinnum[1] = -1; + } + skinnum = description[i].skinnum[0]; if ((skinnum != -1) && (R_SkinUsable(-1, skinnum))) { // Handling order. @@ -7751,20 +7966,27 @@ static void M_SetupChoosePlayer(INT32 choice) if (!(description[i].picname[0])) { - if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 2) + if (skins[skinnum].sprites[SPR2_XTRA].numframes >= XTRA_CHARSEL+1) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[1]; - description[i].pic = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; + description[i].charpic = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); } else - description[i].pic = W_CachePatchName("MISSING", PU_CACHE); + description[i].charpic = W_CachePatchName("MISSING", PU_CACHE); } else - description[i].pic = W_CachePatchName(description[i].picname, PU_CACHE); + description[i].charpic = W_CachePatchName(description[i].picname, PU_CACHE); + + if (description[i].nametag[0]) + { + const char *nametag = description[i].nametag; + description[i].namepic = NULL; + if (W_LumpExists(nametag)) + description[i].namepic = W_CachePatchName(nametag, PU_CACHE); + } } // else -- Technically, character select icons without corresponding skins get bundled away behind this too. Sucks to be them. - Z_Free(name); } } @@ -7784,8 +8006,22 @@ static void M_SetupChoosePlayer(INT32 choice) return; } - if (Playing() == false) - M_ChangeMenuMusic("_chsel", true); + M_ChangeMenuMusic("_chsel", true); + + /* the menus suck -James */ + if (currentMenu == &SP_LoadDef)/* from save states */ + { + SP_PlayerDef.menuid = + MN_SP_MAIN + + ( MN_SP_LOAD << 6 ) + + ( MN_SP_PLAYER << 12 ); + } + else/* from Secret level select */ + { + SP_PlayerDef.menuid = + MN_SR_MAIN + + ( MN_SR_PLAYER << 6 ); + } SP_PlayerDef.prevMenu = currentMenu; M_SetupNextMenu(&SP_PlayerDef); @@ -7799,7 +8035,11 @@ static void M_SetupChoosePlayer(INT32 choice) char_on = description[char_on].next; } } - char_scroll = 0; // finish scrolling the menu + + // finish scrolling the menu + char_scroll = 0; + charseltimer = 0; + Z_Free(char_notes); char_notes = V_WordWrap(0, 21*8, V_ALLOWLOWERCASE, description[char_on].notes); } @@ -7814,6 +8054,9 @@ static void M_HandleChoosePlayerMenu(INT32 choice) boolean exitmenu = false; // exit to previous menu INT32 selectval; + if (keydown > 1) + return; + switch (choice) { case KEY_DOWNARROW: @@ -7821,7 +8064,7 @@ static void M_HandleChoosePlayerMenu(INT32 choice) { S_StartSound(NULL,sfx_s3kb7); char_on = selectval; - char_scroll = -128*FRACUNIT; + char_scroll = -charscrollamt; Z_Free(char_notes); char_notes = V_WordWrap(0, 21*8, V_ALLOWLOWERCASE, description[char_on].notes); } @@ -7837,7 +8080,7 @@ static void M_HandleChoosePlayerMenu(INT32 choice) { S_StartSound(NULL,sfx_s3kb7); char_on = selectval; - char_scroll = 128*FRACUNIT; + char_scroll = charscrollamt; Z_Free(char_notes); char_notes = V_WordWrap(0, 21*8, V_ALLOWLOWERCASE, description[char_on].notes); } @@ -7863,6 +8106,8 @@ static void M_HandleChoosePlayerMenu(INT32 choice) if (exitmenu) { + // Is this a hack? + charseltimer = 0; if (currentMenu->prevMenu) M_SetupNextMenu(currentMenu->prevMenu); else @@ -7871,100 +8116,218 @@ static void M_HandleChoosePlayerMenu(INT32 choice) } // Draw the choose player setup menu, had some fun with player anim +//define CHOOSEPLAYER_DRAWHEADER + static void M_DrawSetupChoosePlayerMenu(void) { - const INT32 my = 24; - patch_t *patch; - INT32 i, o; - UINT8 prev, next; + const INT32 my = 16; - // Black BG - if (curbgcolor >= 0) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); - else if (!curbghide || !titlemapinaction) - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); - if (curfadevalue) - V_DrawFadeScreen(0xFF00, curfadevalue); + skin_t *charskin = &skins[0]; + INT32 skinnum = 0; + UINT8 col; + UINT8 *colormap = NULL; + INT32 prev = -1, next = -1; - // Character select profile images!1 - M_DrawTextBox(0, my, 16, 20); + patch_t *charbg = W_CachePatchName("CHARBG", PU_CACHE); + patch_t *charfg = W_CachePatchName("CHARFG", PU_CACHE); + INT16 bgheight = SHORT(charbg->height); + INT16 fgheight = SHORT(charfg->height); + INT16 bgwidth = SHORT(charbg->width); + INT16 fgwidth = SHORT(charfg->width); + INT32 x, y; + INT32 w = (vid.width/vid.dupx); if (abs(char_scroll) > FRACUNIT) char_scroll -= (char_scroll>>2); else // close enough. char_scroll = 0; // just be exact now. - o = (char_scroll >> FRACBITS) + 16; - - if (o < 0) // A little hacky... - { - i = description[char_on].prev; - o += 128; - } - else - i = char_on; - // Get prev character... - prev = description[i].prev; - - if (prev != i) // If there's more than one character available... - { + prev = description[char_on].prev; + // If there's more than one character available... + if (prev != char_on) // Let's get the next character now. - next = description[i].next; - - // Draw prev character if it's visible and its number isn't greater than the current one or there's more than two - if (o < 32) - { - patch = description[prev].pic; - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<height) + 2*(o-32), SHORT(patch->width), 64 - 2*o); - else - V_DrawCroppedPatch(8<height) + o - 32, SHORT(patch->width), 32 - o); - W_UnlockCachedPatch(patch); - } - - // Draw next character if it's visible and its number isn't less than the current one or there's more than two - if (o < 128) // (next != i) was previously a part of this, but it's implicitly true if (prev != i) is true. - { - patch = description[next].pic; - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<width), 2*o); - else - V_DrawCroppedPatch(8<width), o); - W_UnlockCachedPatch(patch); - } - } - - patch = description[i].pic; - if (o >= 0 && o <= 32) - { - if (SHORT(patch->width) >= 256) - V_DrawSmallScaledPatch(8, my + 40 - o, 0, patch); - else - V_DrawScaledPatch(8, my + 40 - o, 0, patch); - } + next = description[char_on].next; else - { - if (SHORT(patch->width) >= 256) - V_DrawCroppedPatch(8<width), SHORT(patch->height) - 2*(o-32)); - else - V_DrawCroppedPatch(8<width), SHORT(patch->height) - (o-32)); - } - W_UnlockCachedPatch(patch); + // No there isn't. + prev = -1; - // draw title (or big pic) - M_DrawMenuTitle(); + // Find skin number from description[] + skinnum = description[char_on].skinnum[0]; + charskin = &skins[skinnum]; + + // Use the opposite of the character's skincolor + col = description[char_on].oppositecolor; + if (!col) + col = Color_Opposite[charskin->prefcolor - 1][0]; + + // Make the translation colormap + colormap = R_GetTranslationColormap(TC_DEFAULT, col, 0); + + // Don't render the title map + hidetitlemap = true; + charseltimer++; + + // Background and borders + V_DrawFill(0, 0, bgwidth, vid.height, V_SNAPTOTOP|colormap[101]); + { + INT32 sw = (BASEVIDWIDTH * vid.dupx); + INT32 bw = (vid.width - sw) / 2; + col = colormap[106]; + if (bw) + V_DrawFill(0, 0, bw, vid.height, V_NOSCALESTART|col); + } + + y = (charseltimer%32); + V_DrawMappedPatch(0, y-bgheight, V_SNAPTOTOP, charbg, colormap); + V_DrawMappedPatch(0, y, V_SNAPTOTOP, charbg, colormap); + V_DrawMappedPatch(0, y+bgheight, V_SNAPTOTOP, charbg, colormap); + V_DrawMappedPatch(0, -y, V_SNAPTOTOP, charfg, colormap); + V_DrawMappedPatch(0, -y+fgheight, V_SNAPTOTOP, charfg, colormap); + V_DrawFill(fgwidth, 0, vid.width, vid.height, V_SNAPTOTOP|colormap[106]); + + // Character pictures + { + x = 8; + y = (my+16) - FixedInt(char_scroll); + V_DrawScaledPatch(x, y, 0, description[char_on].charpic); + if (prev != -1) + V_DrawScaledPatch(x, y - 144, 0, description[prev].charpic); + if (next != -1) + V_DrawScaledPatch(x, y + 144, 0, description[next].charpic); + } // Character description - M_DrawTextBox(136, my, 21, 20); - V_DrawString(146, my + 9, V_RETURN8|V_ALLOWLOWERCASE, char_notes); + { + INT32 flags = V_ALLOWLOWERCASE|V_RETURN8; + x = 146; + y = my + 9; + V_DrawString(x, y, flags, char_notes); + } + + // Name tags + { + INT32 ox, 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 + 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 (!curtextcolor) + curtextcolor = charskin->prefcolor; + if (!curoutlinecolor) + curoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + + txsh = oxsh; + ox = 8 + SHORT((description[char_on].charpic)->width)/2; + y = my + 144; + + // cur + { + x = ox - txsh; + if (curpatch) + x -= (SHORT(curpatch->width)/2); + + if (curtext[0] != '\0') + { + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(TC_DEFAULT, curtextcolor, 0), + R_GetTranslationColormap(TC_DEFAULT, curoutlinecolor, 0), + curtext + ); + } + else if (curpatch) + V_DrawScaledPatch(x, y, 0, curpatch); + } + + if (char_scroll) + { + // prev + if ((prev != -1) && char_scroll < 0) + { + prevtext = description[prev].displayname; + prevtextcolor = description[prev].tagtextcolor; + prevoutlinecolor = description[prev].tagoutlinecolor; + if (prevtext[0] == '\0') + prevpatch = description[prev].namepic; + charskin = &skins[description[prev].skinnum[0]]; + if (!prevtextcolor) + prevtextcolor = charskin->prefcolor; + if (!prevoutlinecolor) + prevoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + + x = (ox - txsh) - w; + if (prevpatch) + x -= (SHORT(prevpatch->width)/2); + + if (prevtext[0] != '\0') + { + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(TC_DEFAULT, prevtextcolor, 0), + R_GetTranslationColormap(TC_DEFAULT, prevoutlinecolor, 0), + prevtext + ); + } + else if (prevpatch) + V_DrawScaledPatch(x, y, 0, prevpatch); + } + // next + else if ((next != -1) && char_scroll > 0) + { + nexttext = description[next].displayname; + nexttextcolor = description[next].tagtextcolor; + nextoutlinecolor = description[next].tagoutlinecolor; + if (nexttext[0] == '\0') + nextpatch = description[next].namepic; + charskin = &skins[description[next].skinnum[0]]; + if (!nexttextcolor) + nexttextcolor = charskin->prefcolor; + if (!nextoutlinecolor) + nextoutlinecolor = Color_Opposite[charskin->prefcolor - 1][0]; + + x = (ox - txsh) + w; + if (nextpatch) + x -= (SHORT(nextpatch->width)/2); + + if (nexttext[0] != '\0') + { + V_DrawNameTag( + x, y, V_CENTERNAMETAG, FRACUNIT, + R_GetTranslationColormap(TC_DEFAULT, nexttextcolor, 0), + R_GetTranslationColormap(TC_DEFAULT, nextoutlinecolor, 0), + nexttext + ); + } + else if (nextpatch) + V_DrawScaledPatch(x, y, 0, nextpatch); + } + } + } + + // Alternative menu header +#ifdef CHOOSEPLAYER_DRAWHEADER + { + patch_t *header = W_CachePatchName("M_PICKP", PU_CACHE); + INT32 xtitle = 146; + INT32 ytitle = (35 - SHORT(header->height))/2; + V_DrawFixedPatch(xtitle<collected) - V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem), PU_CACHE), + V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetExtraEmblemColor(exemblem), GTC_CACHE)); else V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); @@ -8268,16 +8626,27 @@ static void M_HandleLevelStats(INT32 choice) // Drawing function for Time Attack void M_DrawTimeAttackMenu(void) { - INT32 i, x, y, cursory = 0; + INT32 i, x, y, empatx, empaty, cursory = 0; UINT16 dispstatus; - patch_t *PictureOfUrFace; + patch_t *PictureOfUrFace; // my WHAT + patch_t *empatch; - M_ChangeMenuMusic("_inter", true); // Eww, but needed for when user hits escape during demo playback + M_SetMenuCurBackground("RECATKBG"); + + curbgxspeed = 0; + curbgyspeed = 18; + + M_ChangeMenuMusic("_recat", true); // Eww, but needed for when user hits escape during demo playback if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); else if (!curbghide || !titlemapinaction) + { F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + // Draw and animate foreground + if (!strncmp("RECATKBG", curbgname, 8)) + M_DrawRecordAttackForeground(); + } if (curfadevalue) V_DrawFadeScreen(0xFF00, curfadevalue); @@ -8328,10 +8697,10 @@ void M_DrawTimeAttackMenu(void) // Character face! { - if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes >= 2) + if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes >= XTRA_CHARSEL+1) { spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[1]; + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CHARSEL]; PictureOfUrFace = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); } else @@ -8351,6 +8720,7 @@ void M_DrawTimeAttackMenu(void) patch_t *PictureOfLevel; lumpnum_t lumpnum; char beststr[40]; + char reqscore[40], reqtime[40], reqrings[40]; M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false); @@ -8363,27 +8733,71 @@ void M_DrawTimeAttackMenu(void) PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); y = 32+lsheadingheight; - V_DrawSmallScaledPatch(208, y, 0, PictureOfLevel); + V_DrawSmallScaledPatch(216, y, 0, PictureOfLevel); - if (itemOn == talevel) + + if (currentMenu == &SP_TimeAttackDef) { - /* Draw arrows !! */ - y = y + 25 - 4; - V_DrawCharacter(208 - 10 - (skullAnimCounter/5), y, - '\x1C' | V_YELLOWMAP, false); - V_DrawCharacter(208 + 80 + 2 + (skullAnimCounter/5), y, - '\x1D' | V_YELLOWMAP, false); + if (itemOn == talevel) + { + /* Draw arrows !! */ + y = y + 25 - 4; + V_DrawCharacter(216 - 10 - (skullAnimCounter/5), y, + '\x1C' | V_YELLOWMAP, false); + V_DrawCharacter(216 + 80 + 2 + (skullAnimCounter/5), y, + '\x1D' | V_YELLOWMAP, false); + } + // Draw press ESC to exit string on main record attack menu + V_DrawString(104-72, 180, V_TRANSLUCENT, M_GetText("Press ESC to exit")); } - V_DrawString(104 - 72, 32+lsheadingheight/2, 0, "* LEVEL RECORDS *"); + em = M_GetLevelEmblems(cv_nextmap.value); + // Draw record emblems. + while (em) + { + switch (em->type) + { + case ET_SCORE: + yHeight = 33; + sprintf(reqscore, "(%u)", em->var); + break; + case ET_TIME: + yHeight = 53; + sprintf(reqtime, "(%i:%02i.%02i)", G_TicsToMinutes((tic_t)em->var, true), + G_TicsToSeconds((tic_t)em->var), + G_TicsToCentiseconds((tic_t)em->var)); + break; + case ET_RINGS: + yHeight = 73; + sprintf(reqrings, "(%u)", em->var); + break; + default: + goto skipThisOne; + } + + empatch = W_CachePatchName(M_GetEmblemPatch(em, true), PU_CACHE); + + empatx = SHORT(empatch->leftoffset)/2; + empaty = SHORT(empatch->topoffset)/2; + + if (em->collected) + V_DrawSmallMappedPatch(104+76+empatx, yHeight+lsheadingheight/2+empaty, 0, empatch, + R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); + else + V_DrawSmallScaledPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDITL", PU_CACHE)); + + skipThisOne: + em = M_GetLevelEmblems(-1); + } if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->score) sprintf(beststr, "(none)"); else sprintf(beststr, "%u", mainrecords[cv_nextmap.value-1]->score); - V_DrawString(104-72, 48+lsheadingheight/2, V_YELLOWMAP, "SCORE:"); - V_DrawRightAlignedString(104+72, 48+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawString(104-72, 33+lsheadingheight/2, V_YELLOWMAP, "SCORE:"); + V_DrawRightAlignedString(104+64, 33+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawRightAlignedString(104+72, 43+lsheadingheight/2, V_ALLOWLOWERCASE, reqscore); if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->time) sprintf(beststr, "(none)"); @@ -8392,39 +8806,23 @@ void M_DrawTimeAttackMenu(void) G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->time), G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->time)); - V_DrawString(104-72, 58+lsheadingheight/2, V_YELLOWMAP, "TIME:"); - V_DrawRightAlignedString(104+72, 58+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawString(104-72, 53+lsheadingheight/2, V_YELLOWMAP, "TIME:"); + V_DrawRightAlignedString(104+64, 53+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawRightAlignedString(104+72, 63+lsheadingheight/2, V_ALLOWLOWERCASE, reqtime); if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->rings) sprintf(beststr, "(none)"); else sprintf(beststr, "%hu", mainrecords[cv_nextmap.value-1]->rings); - V_DrawString(104-72, 68+lsheadingheight/2, V_YELLOWMAP, "RINGS:"); - V_DrawRightAlignedString(104+72, 68+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + V_DrawString(104-72, 73+lsheadingheight/2, V_YELLOWMAP, "RINGS:"); - // Draw record emblems. - em = M_GetLevelEmblems(cv_nextmap.value); - while (em) - { - switch (em->type) - { - case ET_SCORE: yHeight = 48; break; - case ET_TIME: yHeight = 58; break; - case ET_RINGS: yHeight = 68; break; - default: - goto skipThisOne; - } + if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->gotperfect) + V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE, beststr); + else + V_DrawRightAlignedString(104+64, 73+lsheadingheight/2, V_ALLOWLOWERCASE|V_YELLOWMAP, beststr); - if (em->collected) - V_DrawSmallMappedPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); - else - V_DrawSmallScaledPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - skipThisOne: - em = M_GetLevelEmblems(-1); - } + V_DrawRightAlignedString(104+72, 83+lsheadingheight/2, V_ALLOWLOWERCASE, reqrings); } // ALWAYS DRAW level and skin even when not on this menu! @@ -8516,12 +8914,11 @@ void M_DrawNightsAttackMenu(void) INT32 i, x, y, cursory = 0; UINT16 dispstatus; - M_ChangeMenuMusic("_inter", true); // Eww, but needed for when user hits escape during demo playback + M_SetMenuCurBackground("NTSATKBG"); - if (curbgcolor >= 0) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); - else if (!curbghide || !titlemapinaction) - F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); + M_ChangeMenuMusic("_nitat", true); // Eww, but needed for when user hits escape during demo playback + + M_DrawNightsAttackBackground(); if (curfadevalue) V_DrawFadeScreen(0xFF00, curfadevalue); @@ -8579,7 +8976,7 @@ void M_DrawNightsAttackMenu(void) lumpnum_t lumpnum; char beststr[40]; - UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0); + //UINT8 bestoverall = G_GetBestNightsGrade(cv_nextmap.value, 0); UINT8 bestgrade = G_GetBestNightsGrade(cv_nextmap.value, cv_dummymares.value); UINT32 bestscore = G_GetBestNightsScore(cv_nextmap.value, cv_dummymares.value); tic_t besttime = G_GetBestNightsTime(cv_nextmap.value, cv_dummymares.value); @@ -8596,10 +8993,10 @@ void M_DrawNightsAttackMenu(void) V_DrawSmallScaledPatch(208, 32+lsheadingheight, 0, PictureOfLevel); - V_DrawString(104 - 72, 32+lsheadingheight/2, 0, "* LEVEL RECORDS *"); - - if (P_HasGrades(cv_nextmap.value, 0)) - V_DrawScaledPatch(235, 135, 0, ngradeletters[bestoverall]); + // Super Sonic + M_DrawNightsAttackSuperSonic(); + //if (P_HasGrades(cv_nextmap.value, 0)) + // V_DrawScaledPatch(235 - (SHORT((ngradeletters[bestoverall])->width)*3)/2, 135, 0, ngradeletters[bestoverall]); if (P_HasGrades(cv_nextmap.value, cv_dummymares.value)) {//make bigger again @@ -8641,10 +9038,10 @@ void M_DrawNightsAttackMenu(void) } if (em->collected) - V_DrawSmallMappedPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), + V_DrawSmallMappedPatch(104+38, yHeight+lsheadingheight/2, 0, W_CachePatchName(M_GetEmblemPatch(em, false), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_CACHE)); else - V_DrawSmallScaledPatch(104+76, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawSmallScaledPatch(104+38, yHeight+lsheadingheight/2, 0, W_CachePatchName("NEEDIT", PU_CACHE)); skipThisOne: em = M_GetLevelEmblems(-1); @@ -8652,6 +9049,10 @@ void M_DrawNightsAttackMenu(void) } } + // Draw press ESC to exit string on main nights attack menu + if (currentMenu == &SP_NightsAttackDef) + V_DrawString(104-72, 180, V_TRANSLUCENT, M_GetText("Press ESC to exit")); + // ALWAYS DRAW level even when not on this menu! if (currentMenu != &SP_NightsAttackDef) V_DrawString(SP_NightsAttackDef.x, SP_NightsAttackDef.y + SP_TimeAttackMenu[nalevel].alphaKey, V_TRANSLUCENT, SP_NightsAttackMenu[nalevel].text); @@ -8680,6 +9081,9 @@ static void M_NightsAttack(INT32 choice) // This is really just to make sure Sonic is the played character, just in case M_PatchSkinNameTable(); + ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_CACHE); + ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_CACHE); + G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please M_SetupNextMenu(&SP_NightsAttackDef); @@ -9462,6 +9866,12 @@ static void M_ServerOptions(INT32 choice) } #endif + /* Disable fading because of different menu head. */ + if (currentMenu == &OP_MainDef)/* from Options menu */ + OP_ServerOptionsDef.menuid = MN_OP_MAIN + ( MN_OP_SERVER << 6 ); + else/* from Multiplayer menu */ + OP_ServerOptionsDef.menuid = MN_MP_MAIN + ( MN_MP_SERVER_OPTIONS << 6 ); + OP_ServerOptionsDef.prevMenu = currentMenu; M_SetupNextMenu(&OP_ServerOptionsDef); } @@ -9526,6 +9936,8 @@ static void M_ConnectIP(INT32 choice) return; } + M_ClearMenus(true); + COM_BufAddText(va("connect \"%s\"\n", setupm_ip)); // A little "please wait" message. @@ -9557,7 +9969,6 @@ static void M_HandleConnectIP(INT32 choice) case KEY_ENTER: S_StartSound(NULL,sfx_menu1); // Tails - M_ClearMenus(true); M_ConnectIP(1); break; @@ -9607,6 +10018,7 @@ static void M_HandleConnectIP(INT32 choice) if (exitmenu) { + currentMenu->lastOn = itemOn; if (currentMenu->prevMenu) M_SetupNextMenu (currentMenu->prevMenu); else diff --git a/src/m_menu.h b/src/m_menu.h index d568a1b53..3bfa48597 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -63,6 +63,7 @@ typedef enum MN_MP_CONNECT, MN_MP_ROOM, MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET + MN_MP_SERVER_OPTIONS, // Options MN_OP_MAIN, @@ -103,6 +104,7 @@ typedef enum MN_SR_LEVELSELECT, MN_SR_UNLOCKCHECKLIST, MN_SR_EMBLEMHINT, + MN_SR_PLAYER, // Addons (Part of MISC, but let's make it our own) MN_AD_MAIN, @@ -323,9 +325,18 @@ typedef struct char notes[441]; char picname[8]; char skinname[SKINNAMESIZE*2+2]; // skin&skin\0 - patch_t *pic; + patch_t *charpic; UINT8 prev; UINT8 next; + + // new character select + char displayname[SKINNAMESIZE+1]; + SINT8 skinnum[2]; + UINT8 oppositecolor; + char nametag[8]; + patch_t *namepic; + UINT8 tagtextcolor; + UINT8 tagoutlinecolor; } description_t; // level select platter diff --git a/src/p_mobj.c b/src/p_mobj.c index 941d8f1e6..e071f79d8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7758,7 +7758,7 @@ void P_MobjThinker(mobj_t *mobj) actualwork = work = FixedHypot(mobj->x-players[i].mo->x, mobj->y-players[i].mo->y); if (player) { - if (players[i].skin == 0 || players[i].skin == 3) + if (players[i].skin == 0 || players[i].skin == 5) work = (2*work)/3; if (work >= pdist) continue; @@ -7796,7 +7796,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target != player->mo) P_SetTarget(&mobj->target, player->mo); targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN)); - love = (player->skin == 0 || player->skin == 3); + love = (player->skin == 0 || player->skin == 5); switch (stat) { @@ -10401,13 +10401,13 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_METALSONIC_BATTLE: case MT_METALSONIC_RACE: - sc = 3; + sc = 5; break; case MT_FANG: sc = 4; break; case MT_ROSY: - sc = 5; + sc = 3; break; case MT_CORK: mobj->flags2 |= MF2_SUPERFIRE; @@ -11597,7 +11597,7 @@ You should think about modifying the deathmatch starts to take full advantage of return; // she doesn't hang out here else if (mariomode) i = MT_TOAD; // don't remove on penalty of death - else if (!(netgame || multiplayer) && players[consoleplayer].skin == 5) + else if (!(netgame || multiplayer) && players[consoleplayer].skin == 3) return; // no doubles } diff --git a/src/p_setup.c b/src/p_setup.c index a362d2ec1..cef176636 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2606,7 +2606,6 @@ boolean P_SetupLevel(boolean skipprecip) boolean loadedbm = false; sector_t *ss; boolean chase; - levelloading = true; // This is needed. Don't touch. diff --git a/src/st_stuff.c b/src/st_stuff.c index 11d05f547..392cb1c03 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -351,7 +351,7 @@ void ST_LoadFaceGraphics(INT32 skinnum) if (skins[skinnum].sprites[SPR2_XTRA].numframes) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[0]; + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_LIFEPIC]; faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX); if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes) { diff --git a/src/v_video.c b/src/v_video.c index 747300114..34d64cb04 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1074,7 +1074,7 @@ void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skin if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes >= 4) { spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; - spriteframe_t *sprframe = &sprdef->spriteframes[3]; + spriteframe_t *sprframe = &sprdef->spriteframes[XTRA_CONTINUE]; patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); const UINT8 *colormap = R_GetTranslationColormap(skinnum, skincolor, GTC_CACHE); @@ -2192,7 +2192,7 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) w = SHORT(hu_font[c]->width) * dupx; if (cx > scrwidth) - break; + continue; if (cx+left + w < 0) //left boundary check { cx += w; @@ -2306,7 +2306,7 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) w = SHORT(hu_font[c]->width) * dupx / 2; if (cx > scrwidth) - break; + continue; if (cx+left + w < 0) //left boundary check { cx += w; @@ -2411,7 +2411,7 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) w = (SHORT(tny_font[c]->width) * dupx); if (cx > scrwidth) - break; + continue; if (cx+left + w < 0) //left boundary check { cx += w; @@ -2509,7 +2509,7 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) w = SHORT(hu_font[c]->width) * dupx; if ((cx>>FRACBITS) > scrwidth) - break; + continue; if ((cx>>FRACBITS)+left + w < 0) //left boundary check { cx += w<width) * dupx; if ((cx>>FRACBITS) > scrwidth) - break; + continue; V_DrawSciencePatch(cx, cy, option, cred_font[c], FRACUNIT); cx += w<= NT_FONTSIZE || !ntb_font[c] || !nto_font[c]) + { + cx += FixedMul((4 * dupx)*FRACUNIT, scale); + continue; + } + + w = FixedMul((SHORT(ntb_font[c]->width)+2 * dupx) * FRACUNIT, scale); + + if (FixedInt(cx) > scrwidth) + continue; + if (cx+(left*FRACUNIT) + w < 0) // left boundary check + { + cx += w; + continue; + } + + V_DrawFixedPatch(cx, cy, scale, option, nto_font[c], outlinecolormap); + V_DrawFixedPatch(cx, cy, scale, option, ntb_font[c], basecolormap); + + cx += w; + } +} + +// Looks familiar. +void V_DrawNameTag(INT32 x, INT32 y, INT32 option, fixed_t scale, UINT8 *basecolormap, UINT8 *outlinecolormap, const char *string) +{ + const char *text = string; + const char *first_token = text; + char *last_token = strchr(text, '\n'); + const INT32 lbreakheight = 21; + INT32 ntlines; + + if (option & V_CENTERNAMETAG) + { + ntlines = V_CountNameTagLines(string); + y -= FixedInt(FixedMul(((lbreakheight/2) * (ntlines-1))*FRACUNIT, scale)); + } + + // No line breaks? + // Draw entire string + if (!last_token) + V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, string); + // Split string by the line break character + else + { + char *str = NULL; + INT32 len; + while (true) + { + // There are still lines left to draw + if (last_token) + { + size_t shift = 0; + // Free this line + if (str) + Z_Free(str); + // Find string length, do a malloc... + len = (last_token-first_token)+1; + str = ZZ_Alloc(len); + // Copy the line + strncpy(str, first_token, len-1); + str[len-1] = '\0'; + // Don't leave a line break character + // at the start of the string! + if ((strlen(str) >= 2) && (string[0] == '\n') && (string[1] != '\n')) + shift++; + // Then draw it + V_DrawNameTagLine(x, y, option, scale, basecolormap, outlinecolormap, str+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 >= (signed)strlen(text)) + last_token = NULL; + else + { + first_token = last_token; + last_token = strchr(first_token+1, '\n'); + } + } + // Free this line + if (str) + Z_Free(str); + } +} + +// Count the amount of lines in name tag string +INT32 V_CountNameTagLines(const char *string) +{ + INT32 ntlines = 1; + const char *text = string; + const char *first_token = text; + char *last_token = strchr(text, '\n'); + + // No line breaks? + if (!last_token) + return ntlines; + // Split string by the line break character + else + { + while (true) + { + if (last_token) + ntlines++; + // No line break character was found + else + break; + + // Next line + if ((last_token-text)+1 >= (signed)strlen(text)) + last_token = NULL; + else + { + first_token = last_token; + last_token = strchr(first_token+1, '\n'); + } + } + } + return ntlines; +} + +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) @@ -2703,7 +2900,7 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) w = SHORT(lt_font[c]->width) * dupx; if (cx > scrwidth) - break; + continue; if (cx+left + w < 0) //left boundary check { cx += w; diff --git a/src/v_video.h b/src/v_video.h index 7eb990295..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 @@ -205,6 +206,11 @@ 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, 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); // Find string width from hu_font chars, 0.5x scale diff --git a/src/y_inter.c b/src/y_inter.c index 81532dd7f..2fed35de3 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1052,6 +1052,9 @@ static void Y_UpdateRecordReplays(void) if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings) mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings); + if (data.coop.gotperfbonus) + mainrecords[gamemap-1]->gotperfect = true; + // Save demo! bestdemo[255] = '\0'; lastdemo[255] = '\0';