diff --git a/src/command.c b/src/command.c index 62e673322..600803cdb 100644 --- a/src/command.c +++ b/src/command.c @@ -148,6 +148,20 @@ void COM_BufInsertText(const char *ptext) } } +/** Progress the wait timer and flush waiting console commands when ready. + */ +void +COM_BufTicker(void) +{ + if (com_wait) + { + com_wait--; + return; + } + + COM_BufExecute(); +} + /** Flushes (executes) console commands in the buffer. */ void COM_BufExecute(void) @@ -157,12 +171,6 @@ void COM_BufExecute(void) char line[1024] = ""; INT32 quotes; - if (com_wait) - { - com_wait--; - return; - } - while (com_text.cursize) { // find a '\n' or; line break @@ -514,7 +522,6 @@ static void COM_ExecuteString(char *ptext) { if (!stricmp(com_argv[0], cmd->name)) //case insensitive now that we have lower and uppercase! { - recursion = 0; cmd->function(); return; } @@ -526,19 +533,17 @@ static void COM_ExecuteString(char *ptext) if (!stricmp(com_argv[0], a->name)) { if (recursion > MAX_ALIAS_RECURSION) - { CONS_Alert(CONS_WARNING, M_GetText("Alias recursion cycle detected!\n")); - recursion = 0; - return; + else + { // Monster Iestyn: keep track of how many levels of recursion we're in + recursion++; + COM_BufInsertText(a->value); + recursion--; } - recursion++; - COM_BufInsertText(a->value); return; } } - recursion = 0; - // check cvars // Hurdler: added at Ebola's request ;) // (don't flood the console in software mode with bad gr_xxx command) diff --git a/src/command.h b/src/command.h index e6767825c..4682ba4a4 100644 --- a/src/command.h +++ b/src/command.h @@ -45,6 +45,9 @@ void COM_ImmedExecute(const char *ptext); // Execute commands in buffer, flush them void COM_BufExecute(void); +// As above; and progress the wait timer. +void COM_BufTicker(void); + // setup command buffer, at game tartup void COM_Init(void); diff --git a/src/console.c b/src/console.c index 81b62851c..b9a01492f 100644 --- a/src/console.c +++ b/src/console.c @@ -1115,16 +1115,6 @@ boolean CON_Responder(event_t *ev) else if (key == KEY_KPADSLASH) key = '/'; - // capslock - if (key == KEY_CAPSLOCK) // it's a toggle. - { - if (capslock) - capslock = false; - else - capslock = true; - return true; - } - if (key >= 'a' && key <= 'z') { if (capslock ^ shiftdown) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7f8c55af0..dbf70d33a 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1127,7 +1127,8 @@ static inline void CL_DrawConnectionStatus(void) INT32 ccstime = I_GetTime(); // Draw background fade - V_DrawFadeScreen(0xFF00, 16); + if (!menuactive) // menu already draws its own fade + V_DrawFadeScreen(0xFF00, 16); // force default // Draw the bottom box. M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1); @@ -2002,6 +2003,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic #ifdef CLIENT_LOADINGSCREEN if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) { + F_MenuPresTicker(true); // title sky F_TitleScreenTicker(true); F_TitleScreenDrawer(); CL_DrawConnectionStatus(); @@ -2612,7 +2614,10 @@ static void Command_Ban(void) else { if (server) // only the server is allowed to do this right now + { Ban_Add(COM_Argv(2)); + D_SaveBan(); // save the ban list + } if (COM_Argc() == 2) { @@ -2643,6 +2648,42 @@ static void Command_Ban(void) } +static void Command_BanIP(void) +{ + if (COM_Argc() < 2) + { + CONS_Printf(M_GetText("banip : ban an ip address\n")); + return; + } + + if (server) // Only the server can use this, otherwise does nothing. + { + const char *address = (COM_Argv(1)); + const char *reason; + + if (COM_Argc() == 2) + reason = NULL; + else + reason = COM_Argv(2); + + + if (I_SetBanAddress && I_SetBanAddress(address, NULL)) + { + if (reason) + CONS_Printf("Banned IP address %s for: %s\n", address, reason); + else + CONS_Printf("Banned IP address %s\n", address); + + Ban_Add(reason); + D_SaveBan(); + } + else + { + return; + } + } +} + static void Command_Kick(void) { if (COM_Argc() < 2) @@ -2922,6 +2963,7 @@ void D_ClientServerInit(void) COM_AddCommand("getplayernum", Command_GetPlayerNum); COM_AddCommand("kick", Command_Kick); COM_AddCommand("ban", Command_Ban); + COM_AddCommand("banip", Command_BanIP); COM_AddCommand("clearbans", Command_ClearBans); COM_AddCommand("showbanlist", Command_ShowBan); COM_AddCommand("reloadbans", Command_ReloadBan); @@ -4577,7 +4619,7 @@ void TryRunTics(tic_t realtics) if (realtics >= 1) { - COM_BufExecute(); + COM_BufTicker(); if (mapchangepending) D_MapChange(-1, 0, ultimatemode, false, 2, false, fromlevelselect); // finish the map change } diff --git a/src/d_main.c b/src/d_main.c index 33c89777a..c7d709aec 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -157,37 +157,11 @@ void D_PostEvent_end(void) {}; #endif // modifier keys +// Now handled in I_OsPolling UINT8 shiftdown = 0; // 0x1 left, 0x2 right UINT8 ctrldown = 0; // 0x1 left, 0x2 right UINT8 altdown = 0; // 0x1 left, 0x2 right boolean capslock = 0; // gee i wonder what this does. -// -// D_ModifierKeyResponder -// Sets global shift/ctrl/alt variables, never actually eats events -// -static inline void D_ModifierKeyResponder(event_t *ev) -{ - if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1) - { - case KEY_LSHIFT: shiftdown |= 0x1; return; - case KEY_RSHIFT: shiftdown |= 0x2; return; - case KEY_LCTRL: ctrldown |= 0x1; return; - case KEY_RCTRL: ctrldown |= 0x2; return; - case KEY_LALT: altdown |= 0x1; return; - case KEY_RALT: altdown |= 0x2; return; - default: return; - } - else if (ev->type == ev_keyup) switch (ev->data1) - { - case KEY_LSHIFT: shiftdown &= ~0x1; return; - case KEY_RSHIFT: shiftdown &= ~0x2; return; - case KEY_LCTRL: ctrldown &= ~0x1; return; - case KEY_RCTRL: ctrldown &= ~0x2; return; - case KEY_LALT: altdown &= ~0x1; return; - case KEY_RALT: altdown &= ~0x2; return; - default: return; - } -} // // D_ProcessEvents @@ -201,9 +175,6 @@ void D_ProcessEvents(void) { ev = &events[eventtail]; - // Set global shift/ctrl/alt down variables - D_ModifierKeyResponder(ev); // never eats events - // Screenshots over everything so that they can be taken anywhere. if (M_ScreenshotResponder(ev)) continue; // ate the event @@ -234,6 +205,9 @@ void D_ProcessEvents(void) // wipegamestate can be set to -1 to force a wipe on the next draw // added comment : there is a wipe eatch change of the gamestate gamestate_t wipegamestate = GS_LEVEL; +// -1: Default; 0-n: Wipe index; INT16_MAX: do not wipe +INT16 wipetypepre = -1; +INT16 wipetypepost = -1; static void D_Display(void) { @@ -267,7 +241,7 @@ static void D_Display(void) // save the current screen if about to wipe wipe = (gamestate != wipegamestate); - if (wipe) + if (wipe && wipetypepre != INT16_MAX) { // set for all later wipedefindex = gamestate; // wipe_xxx_toblack @@ -279,27 +253,37 @@ static void D_Display(void) wipedefindex = wipe_multinter_toblack; } + if (wipetypepre < 0 || !F_WipeExists(wipetypepre)) + wipetypepre = wipedefs[wipedefindex]; + if (rendermode != render_none) { // Fade to black first - if ((wipegamestate != (gamestate_t)-2) // fades to black on its own timing, always - && wipedefs[wipedefindex] != UINT8_MAX) + if ((wipegamestate == (gamestate_t)FORCEWIPE || + (wipegamestate != (gamestate_t)FORCEWIPEOFF + && !(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) + ) // fades to black on its own timing, always + && wipetypepre != UINT8_MAX) { F_WipeStartScreen(); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); F_WipeEndScreen(); - F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); + F_RunWipe(wipetypepre, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); } F_WipeStartScreen(); } + + wipetypepre = -1; } + else + wipetypepre = -1; // do buffered drawing switch (gamestate) { case GS_TITLESCREEN: - if (!titlemapinaction) { + if (!titlemapinaction || !curbghide) { F_TitleScreenDrawer(); break; } @@ -361,14 +345,14 @@ static void D_Display(void) // STUPID race condition... if (wipegamestate == GS_INTRO && gamestate == GS_TITLESCREEN) - wipegamestate = -2; + wipegamestate = FORCEWIPEOFF; else { wipegamestate = gamestate; // clean up border stuff // see if the border needs to be initially drawn - if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)) + if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide)) { // draw the view directly @@ -477,18 +461,25 @@ static void D_Display(void) // // wipe update // - if (wipe) + if (wipe && wipetypepost != INT16_MAX) { // note: moved up here because NetUpdate does input changes // and input during wipe tends to mess things up wipedefindex += WIPEFINALSHIFT; + if (wipetypepost < 0 || !F_WipeExists(wipetypepost)) + wipetypepost = wipedefs[wipedefindex]; + if (rendermode != render_none) { F_WipeEndScreen(); - F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); + F_RunWipe(wipetypepost, gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN); } + + wipetypepost = -1; } + else + wipetypepost = -1; NetUpdate(); // send out any new accumulation @@ -741,8 +732,11 @@ void D_StartTitle(void) gametype = GT_COOP; paused = false; advancedemo = false; + F_InitMenuPresValues(); F_StartTitleScreen(); + currentMenu = &MainDef; // reset the current menu ID + // Reset the palette if (rendermode != render_none) V_SetPaletteLump("PLAYPAL"); @@ -1114,6 +1108,13 @@ void D_SRB2Main(void) // adapt tables to SRB2's needs, including extra slots for dehacked file support P_PatchInfoTables(); + // initiate menu metadata before SOCcing them + M_InitMenuPresTables(); + + // init title screen display params + if (M_CheckParm("-connect")) + F_InitMenuPresValues(); + //---------------------------------------------------- READY TIME // we need to check for dedicated before initialization of some subsystems @@ -1400,6 +1401,7 @@ void D_SRB2Main(void) } else if (M_CheckParm("-skipintro")) { + F_InitMenuPresValues(); F_StartTitleScreen(); } else diff --git a/src/dehacked.c b/src/dehacked.c index 0af1520fd..ab79b21a1 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -72,6 +72,7 @@ static sfxenum_t get_sfx(const char *word); static UINT16 get_mus(const char *word, UINT8 dehacked_mode); #endif static hudnum_t get_huditem(const char *word); +static menutype_t get_menutype(const char *word); #ifndef HAVE_BLUA static powertype_t get_power(const char *word); #endif @@ -1931,6 +1932,161 @@ static void readtextprompt(MYFILE *f, INT32 num) Z_Free(s); } +static void readmenu(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + INT32 value; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = (tmp += 2); + strupr(word2); + + value = atoi(word2); // used for numerical settings + + if (fastcmp(word, "BACKGROUNDNAME")) + { + strncpy(menupres[num].bgname, word2, 8); + titlechanged = true; + } + else if (fastcmp(word, "HIDEBACKGROUND")) + { + menupres[num].bghide = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "BACKGROUNDCOLOR")) + { + menupres[num].bgcolor = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "HIDEPICS")) + { + // true by default, except MM_MAIN + menupres[num].hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "TITLESCROLLSPEED") || fastcmp(word, "TITLESCROLLXSPEED") + || fastcmp(word, "SCROLLSPEED") || fastcmp(word, "SCROLLXSPEED")) + { + menupres[num].titlescrollxspeed = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLESCROLLYSPEED") || fastcmp(word, "SCROLLYSPEED")) + { + menupres[num].titlescrollyspeed = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "MUSIC")) + { + strncpy(menupres[num].musname, word2, 7); + menupres[num].musname[6] = 0; + titlechanged = true; + } +#ifdef MUSICSLOT_COMPATIBILITY + else if (fastcmp(word, "MUSICSLOT")) + { + value = get_mus(word2, true); + if (value && value <= 1035) + snprintf(menupres[num].musname, 7, "%sM", G_BuildMapName(value)); + else if (value && value <= 1050) + strncpy(menupres[num].musname, compat_special_music_slots[value - 1036], 7); + else + menupres[num].musname[0] = 0; // becomes empty string + menupres[num].musname[6] = 0; + titlechanged = true; + } +#endif + else if (fastcmp(word, "MUSICTRACK")) + { + menupres[num].mustrack = ((UINT16)value - 1); + titlechanged = true; + } + else if (fastcmp(word, "MUSICLOOP")) + { + // true by default except MM_MAIN + menupres[num].muslooping = (value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "NOMUSIC")) + { + menupres[num].musstop = (value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "IGNOREMUSIC")) + { + menupres[num].musignore = (value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "FADESTRENGTH")) + { + // one-based, <= 0 means use default value. 1-32 + menupres[num].fadestrength = get_number(word2)-1; + titlechanged = true; + } + else if (fastcmp(word, "NOENTERBUBBLE")) + { + menupres[num].enterbubble = !(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "NOEXITBUBBLE")) + { + menupres[num].exitbubble = !(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; + } + else if (fastcmp(word, "ENTERTAG")) + { + menupres[num].entertag = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "EXITTAG")) + { + menupres[num].exittag = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "ENTERWIPE")) + { + menupres[num].enterwipe = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "EXITWIPE")) + { + menupres[num].exitwipe = get_number(word2); + titlechanged = true; + } + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + static void readhuditem(MYFILE *f, INT32 num) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -3186,9 +3342,14 @@ static void readmaincfg(MYFILE *f) hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); titlechanged = true; } - else if (fastcmp(word, "TITLESCROLLSPEED")) + else if (fastcmp(word, "TITLESCROLLSPEED") || fastcmp(word, "TITLESCROLLXSPEED")) { - titlescrollspeed = get_number(word2); + titlescrollxspeed = get_number(word2); + titlechanged = true; + } + else if (fastcmp(word, "TITLESCROLLYSPEED")) + { + titlescrollyspeed = get_number(word2); titlechanged = true; } else if (fastcmp(word, "CREDITSCUTSCENE")) @@ -3736,6 +3897,19 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) ignorelines(f); } } + else if (fastcmp(word, "MENU")) + { + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_menutype(word2); // find a huditem by name + if (i >= 1 && i < NUMMENUTYPES) + readmenu(f, i); + else + { + // zero-based, but let's start at 1 + deh_warning("Menu number %d out of range (1 - %d)", i, NUMMENUTYPES-1); + ignorelines(f); + } + } else if (fastcmp(word, "UNLOCKABLE")) { if (!mainfile && !gamedataadded) @@ -5482,6 +5656,16 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CACTI2", "S_CACTI3", "S_CACTI4", + "S_CACTI5", + "S_CACTI6", + "S_CACTI7", + "S_CACTI8", + "S_CACTI9", + + // Warning signs sprites + "S_ARIDSIGN_CAUTION", + "S_ARIDSIGN_CACTI", + "S_ARIDSIGN_SHARPTURN", // Flame jet "S_FLAMEJETSTND", @@ -7162,6 +7346,14 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_CACTI2", "MT_CACTI3", "MT_CACTI4", + "MT_CACTI5", + "MT_CACTI6", + "MT_CACTI7", + "MT_CACTI8", + "MT_CACTI9", + "MT_ARIDSIGN_CAUTION", + "MT_ARIDSIGN_CACTI", + "MT_ARIDSIGN_SHARPTURN", // Red Volcano Scenery "MT_FLAMEJET", @@ -7873,6 +8065,96 @@ static const char *const HUDITEMS_LIST[] = { "LAP" }; +static const char *const MENUTYPES_LIST[] = { + "NONE", + + "MAIN", + + // Single Player + "SP_MAIN", + + "SP_LOAD", + "SP_PLAYER", + + "SP_LEVELSELECT", + "SP_LEVELSTATS", + + "SP_TIMEATTACK", + "SP_TIMEATTACK_LEVELSELECT", + "SP_GUESTREPLAY", + "SP_REPLAY", + "SP_GHOST", + + "SP_NIGHTSATTACK", + "SP_NIGHTS_LEVELSELECT", + "SP_NIGHTS_GUESTREPLAY", + "SP_NIGHTS_REPLAY", + "SP_NIGHTS_GHOST", + + // Multiplayer + "MP_MAIN", + "MP_SPLITSCREEN", // SplitServer + "MP_SERVER", + "MP_CONNECT", + "MP_ROOM", + "MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET + + // Options + "OP_MAIN", + + "OP_P1CONTROLS", + "OP_CHANGECONTROLS", // OP_ChangeControlsDef shared with P2 + "OP_P1MOUSE", + "OP_P1JOYSTICK", + "OP_JOYSTICKSET", // OP_JoystickSetDef shared with P2 + + "OP_P2CONTROLS", + "OP_P2MOUSE", + "OP_P2JOYSTICK", + + "OP_VIDEO", + "OP_VIDEOMODE", + "OP_COLOR", + "OP_OPENGL", + "OP_OPENGL_LIGHTING", + "OP_OPENGL_FOG", + "OP_OPENGL_COLOR", + + "OP_SOUND", + + "OP_SERVER", + "OP_MONITORTOGGLE", + + "OP_DATA", + "OP_ADDONS", + "OP_SCREENSHOTS", + "OP_ERASEDATA", + + // Secrets + "SR_MAIN", + "SR_PANDORA", + "SR_LEVELSELECT", + "SR_UNLOCKCHECKLIST", + "SR_EMBLEMHINT", + + // Addons (Part of MISC, but let's make it our own) + "AD_MAIN", + + // MISC + // "MESSAGE", + // "SPAUSE", + + // "MPAUSE", + // "SCRAMBLETEAM", + // "CHANGETEAM", + // "CHANGELEVEL", + + // "MAPAUSE", + // "HELP", + + "SPECIAL" +}; + struct { const char *n; // has to be able to hold both fixed_t and angle_t, so drastic measure!! @@ -8574,6 +8856,20 @@ static hudnum_t get_huditem(const char *word) return HUD_LIVES; } +static menutype_t get_menutype(const char *word) +{ // Returns the value of MN_ enumerations + menutype_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("MN_",word,3)) + word += 3; // take off the MN_ + for (i = 0; i < NUMMENUTYPES; i++) + if (fastcmp(word, MENUTYPES_LIST[i])) + return i; + deh_warning("Couldn't find menutype named 'MN_%s'",word); + return MN_NONE; +} + #ifndef HAVE_BLUA static powertype_t get_power(const char *word) { // Returns the vlaue of pw_ enumerations @@ -8770,6 +9066,11 @@ static fixed_t find_const(const char **rword) free(word); return r; } + else if (fastncmp("MN_",word,4)) { + r = get_menutype(word); + free(word); + return r; + } else if (fastncmp("HUD_",word,4)) { r = get_huditem(word); free(word); @@ -9238,6 +9539,16 @@ static inline int lib_getenum(lua_State *L) if (mathlib) return luaL_error(L, "skincolor '%s' could not be found.\n", word); return 0; } + else if (fastncmp("MN_",word,3)) { + p = word+3; + for (i = 0; i < NUMMENUTYPES; i++) + if (fastcmp(p, MENUTYPES_LIST[i])) { + lua_pushinteger(L, i); + return 1; + } + if (mathlib) return luaL_error(L, "menutype '%s' could not be found.\n", word); + return 0; + } else if (!mathlib && fastncmp("A_",word,2)) { char *caps; // Try to get a Lua action first. diff --git a/src/doomstat.h b/src/doomstat.h index aa8ce58f1..efd347dbe 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -555,6 +555,8 @@ extern boolean precache; // wipegamestate can be set to -1 // to force a wipe on the next draw extern gamestate_t wipegamestate; +extern INT16 wipetypepre; +extern INT16 wipetypepost; // debug flag to cancel adaptiveness extern boolean singletics; diff --git a/src/f_finale.c b/src/f_finale.c index a89e0d577..df8d7b683 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -44,14 +44,15 @@ // Stage of animation: // 0 = text, 1 = art screen static INT32 finalecount; -INT32 titlescrollspeed = 80; +INT32 titlescrollxspeed = 80; +INT32 titlescrollyspeed = 0; UINT8 titlemapinaction = TITLEMAP_OFF; static INT32 timetonext; // Delay between screen changes static INT32 continuetime; // Short delay when continuing static tic_t animtimer; // Used for some animation timings -static INT16 skullAnimCounter; // Chevron animation +static INT16 skullAnimCounter; // Prompts: Chevron animation static INT32 roidtics; // Asteroid spinning static INT32 deplete; @@ -60,6 +61,20 @@ static tic_t stoptimer; static boolean keypressed = false; // (no longer) De-Demo'd Title Screen +static tic_t xscrolltimer; +static tic_t yscrolltimer; +static INT32 menuanimtimer; // Title screen: background animation timing +mobj_t *titlemapcameraref = NULL; + +// menu presentation state +char curbgname[8]; +SINT8 curfadevalue; +boolean curhidepics; +INT32 curbgcolor; +INT32 curbgxspeed; +INT32 curbgyspeed; +boolean curbghide; + static UINT8 curDemo = 0; static UINT32 demoDelayLeft; static UINT32 demoIdleLeft; @@ -80,8 +95,6 @@ static patch_t *ttspop5; static patch_t *ttspop6; static patch_t *ttspop7; -static void F_SkyScroll(INT32 scrollspeed); - // // PROMPT STATE // @@ -182,101 +195,6 @@ static void F_NewCutscene(const char *basetext) cutscene_textcount = TICRATE/2; } -// -// F_DrawPatchCol -// -static void F_DrawPatchCol(INT32 x, patch_t *patch, INT32 col) -{ - const column_t *column; - const UINT8 *source; - UINT8 *desttop, *dest = NULL; - const UINT8 *deststop, *destbottom; - size_t count; - - desttop = screens[0] + x*vid.dupx; - deststop = screens[0] + vid.rowbytes * vid.height; - destbottom = desttop + vid.height*vid.width; - - do { - INT32 topdelta, prevdelta = -1; - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[col])); - - // step through the posts in a column - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)column + 3; - dest = desttop + topdelta*vid.width; - count = column->length; - - while (count--) - { - INT32 dupycount = vid.dupy; - - while (dupycount-- && dest < destbottom) - { - INT32 dupxcount = vid.dupx; - while (dupxcount-- && dest <= deststop) - *dest++ = *source; - - dest += (vid.width - vid.dupx); - } - source++; - } - column = (const column_t *)((const UINT8 *)column + column->length + 4); - } - - desttop += SHORT(patch->height)*vid.dupy*vid.width; - } while(dest < destbottom); -} - -// -// F_SkyScroll -// -static void F_SkyScroll(INT32 scrollspeed) -{ - INT32 scrolled, x, mx, fakedwidth; - patch_t *pat; - INT16 patwidth; - - pat = W_CachePatchName("TITLESKY", PU_CACHE); - - patwidth = SHORT(pat->width); - animtimer = ((finalecount*scrollspeed)/16 + patwidth) % patwidth; - - fakedwidth = vid.width / vid.dupx; - - if (rendermode == render_soft) - { // if only hardware rendering could be this elegant and complete - scrolled = (patwidth - animtimer) - 1; - for (x = 0, mx = scrolled; x < fakedwidth; x++, mx = (mx+1)%patwidth) - F_DrawPatchCol(x, pat, mx); - } -#ifdef HWRENDER - else if (rendermode != render_none) - { // if only software rendering could be this simple and retarded - INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - INT32 y, pw = patwidth * dupz, ph = SHORT(pat->height) * dupz; - scrolled = animtimer * dupz; - for (x = 0; x < vid.width; x += pw) - { - for (y = 0; y < vid.height; y += ph) - { - if (scrolled > 0) - V_DrawScaledPatch(scrolled - pw, y, V_NOSCALESTART, pat); - - V_DrawScaledPatch(x + scrolled, y, V_NOSCALESTART, pat); - } - } - } -#endif - - W_UnlockCachedPatch(pat); -} - // ============= // INTRO SCENE // ============= @@ -474,7 +392,7 @@ void F_StartIntro(void) F_NewCutscene(introtext[0]); intro_scenenum = 0; - finalecount = animtimer = stoptimer = 0; + finalecount = animtimer = skullAnimCounter = stoptimer = 0; roidtics = BASEVIDWIDTH - 64; timetonext = introscenetime[intro_scenenum]; } @@ -706,7 +624,7 @@ static void F_IntroDrawScene(void) } else { - F_SkyScroll(80*4); + F_SkyScroll(80*4, 0, "TITLESKY"); if (timetonext == 6) { stoptimer = finalecount; @@ -1489,12 +1407,104 @@ void F_GameEndTicker(void) // ============== // TITLE SCREEN // ============== + +void F_InitMenuPresValues(void) +{ + menuanimtimer = 0; + prevMenuId = 0; + activeMenuId = MainDef.menuid; + + // Set defaults for presentation values + strncpy(curbgname, "TITLESKY", 8); + curfadevalue = 16; + curhidepics = hidetitlepics; + curbgcolor = -1; + curbgxspeed = titlescrollxspeed; + curbgyspeed = titlescrollyspeed; + curbghide = false; + + // Find current presentation values + M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "SRB2BACK" : "TITLESKY"); + M_SetMenuCurFadeValue(16); + M_SetMenuCurHideTitlePics(); +} + +// +// F_SkyScroll +// +void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) +{ + INT32 xscrolled, x, xneg = (scrollxspeed > 0) - (scrollxspeed < 0), tilex; + INT32 yscrolled, y, yneg = (scrollyspeed > 0) - (scrollyspeed < 0), tiley; + boolean xispos = (scrollxspeed >= 0), yispos = (scrollyspeed >= 0); + INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); + INT16 patwidth, patheight; + INT32 pw, ph; // scaled by dupz + patch_t *pat; + INT32 i, j; + + if (rendermode == render_none) + return; + + if (!patchname || !patchname[0]) + { + V_DrawFill(0, 0, vid.width, vid.height, 31); + return; + } + + if (!scrollxspeed && !scrollyspeed) + { + V_DrawPatchFill(W_CachePatchName(patchname, PU_CACHE)); + return; + } + + pat = W_CachePatchName(patchname, PU_CACHE); + + patwidth = SHORT(pat->width); + patheight = SHORT(pat->height); + pw = patwidth * dupz; + ph = patheight * dupz; + + tilex = max(FixedCeil(FixedDiv(vid.width, pw)) >> FRACBITS, 1)+2; // one tile on both sides of center + tiley = max(FixedCeil(FixedDiv(vid.height, ph)) >> FRACBITS, 1)+2; + + xscrolltimer = ((menuanimtimer*scrollxspeed)/16 + patwidth*xneg) % (patwidth); + yscrolltimer = ((menuanimtimer*scrollyspeed)/16 + patheight*yneg) % (patheight); + + // coordinate offsets + xscrolled = xscrolltimer * dupz; + yscrolled = yscrolltimer * dupz; + + for (x = (xispos) ? -pw*(tilex-1)+pw : 0, i = 0; + i < tilex; + x += pw, i++) + { + for (y = (yispos) ? -ph*(tiley-1)+ph : 0, j = 0; + j < tiley; + y += ph, j++) + { + V_DrawScaledPatch( + (xispos) ? xscrolled - x : x + xscrolled, + (yispos) ? yscrolled - y : y + yscrolled, + V_NOSCALESTART, pat); + } + } + + W_UnlockCachedPatch(pat); +} + void F_StartTitleScreen(void) { - S_ChangeMusicInternal("_title", looptitle); + if (menupres[MN_MAIN].musname[0]) + S_ChangeMusic(menupres[MN_MAIN].musname, menupres[MN_MAIN].mustrack, menupres[MN_MAIN].muslooping); + else + S_ChangeMusicInternal("_title", looptitle); if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) + { finalecount = 0; + wipetypepost = menupres[MN_MAIN].enterwipe; + } else wipegamestate = GS_TITLESCREEN; @@ -1504,6 +1514,7 @@ void F_StartTitleScreen(void) gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = TITLEMAP_LOADING; + titlemapcameraref = NULL; gamemap = titlemap; if (!mapheaderinfo[gamemap-1]) @@ -1544,6 +1555,10 @@ void F_StartTitleScreen(void) camera.chase = true; camera.height = 0; + // Run enter linedef exec for MN_MAIN, since this is where we start + if (menupres[MN_MAIN].entertag) + P_LinedefExecute(menupres[MN_MAIN].entertag, players[displayplayer].mo, NULL); + wipegamestate = prevwipegamestate; } else @@ -1557,7 +1572,7 @@ void F_StartTitleScreen(void) // IWAD dependent stuff. - animtimer = 0; + animtimer = skullAnimCounter = 0; demoDelayLeft = demoDelayTime; demoIdleLeft = demoIdleTime; @@ -1582,19 +1597,24 @@ void F_StartTitleScreen(void) // (no longer) De-Demo'd Title Screen void F_TitleScreenDrawer(void) { + boolean hidepics; + if (modeattacking) return; // We likely came here from retrying. Don't do a damn thing. // Draw that sky! - if (!titlemapinaction) - F_SkyScroll(titlescrollspeed); + if (curbgcolor >= 0) + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); + else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS) + F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); // Don't draw outside of the title screen, or if the patch isn't there. if (!ttwing || (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)) return; // rei|miru: use title pics? - if (hidetitlepics) + hidepics = curhidepics; + if (hidepics) #ifdef HAVE_BLUA goto luahook; #else @@ -1644,6 +1664,14 @@ luahook: #endif } +// separate animation timer for backgrounds, since we also count +// during GS_TIMEATTACK +void F_MenuPresTicker(boolean run) +{ + if (run) + menuanimtimer++; +} + // (no longer) De-Demo'd Title Screen void F_TitleScreenTicker(boolean run) { @@ -1661,22 +1689,28 @@ void F_TitleScreenTicker(boolean run) mobj_t *mo2; mobj_t *cameraref = NULL; - for (th = thinkercap.next; th != &thinkercap; th = th->next) + // If there's a Line 422 Switch Cut-Away view, don't force us. + if (!titlemapcameraref || titlemapcameraref->type != MT_ALTVIEWMAN) { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker - continue; + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker + continue; - mo2 = (mobj_t *)th; + mo2 = (mobj_t *)th; - if (!mo2) - continue; + if (!mo2) + continue; - if (mo2->type != MT_ALTVIEWMAN) - continue; + if (mo2->type != MT_ALTVIEWMAN) + continue; - cameraref = mo2; - break; + cameraref = titlemapcameraref = mo2; + break; + } } + else + cameraref = titlemapcameraref; if (cameraref) { @@ -1690,7 +1724,7 @@ void F_TitleScreenTicker(boolean run) else { // Default behavior: Do a lil' camera spin if a title map is loaded; - camera.angle += titlescrollspeed*ANG1/64; + camera.angle += titlescrollxspeed*ANG1/64; } } diff --git a/src/f_finale.h b/src/f_finale.h index ce3c65c29..c0c6360c3 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -40,6 +40,7 @@ void F_TextPromptTicker(void); void F_GameEndDrawer(void); void F_IntroDrawer(void); void F_TitleScreenDrawer(void); +void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname); void F_GameEvaluationDrawer(void); void F_StartGameEvaluation(void); @@ -69,7 +70,8 @@ void F_StartContinue(void); void F_ContinueTicker(void); void F_ContinueDrawer(void); -extern INT32 titlescrollspeed; +extern INT32 titlescrollxspeed; +extern INT32 titlescrollyspeed; typedef enum { @@ -78,17 +80,38 @@ typedef enum TITLEMAP_RUNNING } titlemap_enum; +// Current menu parameters + extern UINT8 titlemapinaction; +extern mobj_t *titlemapcameraref; +extern char curbgname[8]; +extern SINT8 curfadevalue; +extern boolean curhidepics; +extern INT32 curbgcolor; +extern INT32 curbgxspeed; +extern INT32 curbgyspeed; +extern boolean curbghide; + +#define TITLEBACKGROUNDACTIVE (curfadevalue >= 0 || curbgname[0]) + +void F_InitMenuPresValues(void); +void F_MenuPresTicker(boolean run); // // WIPE // +// HACK for menu fading while titlemapinaction; skips the level check +#define FORCEWIPE -3 +#define FORCEWIPEOFF -2 + extern boolean WipeInAction; extern INT32 lastwipetic; void F_WipeStartScreen(void); void F_WipeEndScreen(void); void F_RunWipe(UINT8 wipetype, boolean drawMenu); +tic_t F_GetWipeLength(UINT8 wipetype); +boolean F_WipeExists(UINT8 wipetype); enum { diff --git a/src/f_wipe.c b/src/f_wipe.c index 3d561075e..26c65ad91 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -378,3 +378,48 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) WipeInAction = false; #endif } + +/** Returns tic length of wipe + * One lump equals one tic + */ +tic_t F_GetWipeLength(UINT8 wipetype) +{ +#ifdef NOWIPE + return 0; +#else + static char lumpname[10] = "FADEmmss"; + lumpnum_t lumpnum; + UINT8 wipeframe; + + if (wipetype > 99) + return 0; + + for (wipeframe = 0; wipeframe < 100; wipeframe++) + { + sprintf(&lumpname[4], "%.2hu%.2hu", (UINT16)wipetype, (UINT16)wipeframe); + + lumpnum = W_CheckNumForName(lumpname); + if (lumpnum == LUMPERROR) + return --wipeframe; + } + return --wipeframe; +#endif +} + +boolean F_WipeExists(UINT8 wipetype) +{ +#ifdef NOWIPE + return false; +#else + static char lumpname[10] = "FADEmm00"; + lumpnum_t lumpnum; + + if (wipetype > 99) + return false; + + sprintf(&lumpname[4], "%.2hu00", (UINT16)wipetype); + + lumpnum = W_CheckNumForName(lumpname); + return !(lumpnum == LUMPERROR); +#endif +} diff --git a/src/g_game.c b/src/g_game.c index 4a9dedf50..af17b2b28 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2020,6 +2020,7 @@ void G_Ticker(boolean run) break; case GS_TIMEATTACK: + F_MenuPresTicker(run); break; case GS_INTRO: @@ -2059,6 +2060,7 @@ void G_Ticker(boolean run) if (titlemapinaction) P_Ticker(run); // then intentionally fall through /* FALLTHRU */ case GS_WAITINGPLAYERS: + F_MenuPresTicker(run); F_TitleScreenTicker(run); break; diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index dfb2c4351..2515c6a86 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -343,6 +343,9 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_BTBL &lspr[NOLIGHT], // SPR_STBL &lspr[NOLIGHT], // SPR_CACT + &lspr[NOLIGHT], // SPR_WWSG + &lspr[NOLIGHT], // SPR_WWS2 + &lspr[NOLIGHT], // SPR_WWS3 // Red Volcano Scenery &lspr[REDBALL_L], // SPR_FLME diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 2b32d8ff8..b1811eb45 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4265,10 +4265,45 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t } } +// This is expecting a pointer to an array containing 4 wallVerts for a sprite +static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts) +{ + if (cv_grspritebillboarding.value + && spr && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE) + && wallVerts) + { + float basey = FIXED_TO_FLOAT(spr->mobj->z); + float lowy = wallVerts[0].y; + if (P_MobjFlip(spr->mobj) == -1) + { + basey = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height); + } + // Rotate sprites to fully billboard with the camera + // X, Y, AND Z need to be manipulated for the polys to rotate around the + // origin, because of how the origin setting works I believe that should + // be mobj->z or mobj->z + mobj->height + wallVerts[2].y = wallVerts[3].y = (spr->ty - basey) * gr_viewludsin + basey; + wallVerts[0].y = wallVerts[1].y = (lowy - basey) * gr_viewludsin + basey; + // translate back to be around 0 before translating back + wallVerts[3].x += ((spr->ty - basey) * gr_viewludcos) * gr_viewcos; + wallVerts[2].x += ((spr->ty - basey) * gr_viewludcos) * gr_viewcos; + + wallVerts[0].x += ((lowy - basey) * gr_viewludcos) * gr_viewcos; + wallVerts[1].x += ((lowy - basey) * gr_viewludcos) * gr_viewcos; + + wallVerts[3].z += ((spr->ty - basey) * gr_viewludcos) * gr_viewsin; + wallVerts[2].z += ((spr->ty - basey) * gr_viewludcos) * gr_viewsin; + + wallVerts[0].z += ((lowy - basey) * gr_viewludcos) * gr_viewsin; + wallVerts[1].z += ((lowy - basey) * gr_viewludcos) * gr_viewsin; + } +} + static void HWR_SplitSprite(gr_vissprite_t *spr) { float this_scale = 1.0f; FOutVector wallVerts[4]; + FOutVector baseWallVerts[4]; // This is what the verts should end up as GLPatch_t *gpatch; FSurfaceInfo Surf; const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); @@ -4281,11 +4316,13 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) float realtop, realbot, top, bot; float towtop, towbot, towmult; float bheight; + float realheight, heightmult; const sector_t *sector = spr->mobj->subsector->sector; const lightlist_t *list = sector->lightlist; #ifdef ESLOPE float endrealtop, endrealbot, endtop, endbot; float endbheight; + float endrealheight; fixed_t temp; fixed_t v1x, v1y, v2x, v2y; #endif @@ -4318,16 +4355,16 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) HWR_DrawSpriteShadow(spr, gpatch, this_scale); } - wallVerts[0].x = wallVerts[3].x = spr->x1; - wallVerts[2].x = wallVerts[1].x = spr->x2; - wallVerts[0].z = wallVerts[3].z = spr->z1; - wallVerts[1].z = wallVerts[2].z = spr->z2; + baseWallVerts[0].x = baseWallVerts[3].x = spr->x1; + baseWallVerts[2].x = baseWallVerts[1].x = spr->x2; + baseWallVerts[0].z = baseWallVerts[3].z = spr->z1; + baseWallVerts[1].z = baseWallVerts[2].z = spr->z2; - wallVerts[2].y = wallVerts[3].y = spr->ty; + baseWallVerts[2].y = baseWallVerts[3].y = spr->ty; if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale; + baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height * this_scale; else - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; + baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height; v1x = FLOAT_TO_FIXED(spr->x1); v1y = FLOAT_TO_FIXED(spr->z1); @@ -4336,44 +4373,56 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (spr->flip) { - wallVerts[0].sow = wallVerts[3].sow = gpatch->max_s; - wallVerts[2].sow = wallVerts[1].sow = 0; - }else{ - wallVerts[0].sow = wallVerts[3].sow = 0; - wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s; + baseWallVerts[0].sow = baseWallVerts[3].sow = gpatch->max_s; + baseWallVerts[2].sow = baseWallVerts[1].sow = 0; + } + else + { + baseWallVerts[0].sow = baseWallVerts[3].sow = 0; + baseWallVerts[2].sow = baseWallVerts[1].sow = gpatch->max_s; } // flip the texture coords (look familiar?) if (spr->vflip) { - wallVerts[3].tow = wallVerts[2].tow = gpatch->max_t; - wallVerts[0].tow = wallVerts[1].tow = 0; - }else{ - wallVerts[3].tow = wallVerts[2].tow = 0; - wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t; + baseWallVerts[3].tow = baseWallVerts[2].tow = gpatch->max_t; + baseWallVerts[0].tow = baseWallVerts[1].tow = 0; + } + else + { + baseWallVerts[3].tow = baseWallVerts[2].tow = 0; + baseWallVerts[0].tow = baseWallVerts[1].tow = gpatch->max_t; } // if it has a dispoffset, push it a little towards the camera if (spr->dispoffset) { float co = -gr_viewcos*(0.05f*spr->dispoffset); float si = -gr_viewsin*(0.05f*spr->dispoffset); - wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; - wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; - wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; - wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; + baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si; + baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si; + baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co; + baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co; } - realtop = top = wallVerts[3].y; - realbot = bot = wallVerts[0].y; - towtop = wallVerts[3].tow; - towbot = wallVerts[0].tow; + // Let dispoffset work first since this adjust each vertex + HWR_RotateSpritePolyToAim(spr, baseWallVerts); + + realtop = top = baseWallVerts[3].y; + realbot = bot = baseWallVerts[0].y; + towtop = baseWallVerts[3].tow; + towbot = baseWallVerts[0].tow; towmult = (towbot - towtop) / (top - bot); #ifdef ESLOPE - endrealtop = endtop = wallVerts[2].y; - endrealbot = endbot = wallVerts[1].y; + endrealtop = endtop = baseWallVerts[2].y; + endrealbot = endbot = baseWallVerts[1].y; #endif + // copy the contents of baseWallVerts into the drawn wallVerts array + // baseWallVerts is used to know the final shape to easily get the vertex + // co-ordinates + memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts)); + if (!cv_translucency.value) // translucency disabled { Surf.FlatColor.s.alpha = 0xFF; @@ -4500,12 +4549,55 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) wallVerts[2].y = endtop; wallVerts[0].y = bot; wallVerts[1].y = endbot; + + // The x and y only need to be adjusted in the case that it's not a papersprite + if (cv_grspritebillboarding.value + && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE)) + { + // Get the x and z of the vertices so billboarding draws correctly + realheight = realbot - realtop; + endrealheight = endrealbot - endrealtop; + heightmult = (realtop - top) / realheight; + wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult; + wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult; + + heightmult = (endrealtop - endtop) / endrealheight; + wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult; + wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult; + + heightmult = (realtop - bot) / realheight; + wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult; + wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult; + + heightmult = (endrealtop - endbot) / endrealheight; + wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult; + wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult; + } #else wallVerts[3].tow = wallVerts[2].tow = towtop + ((realtop - top) * towmult); wallVerts[0].tow = wallVerts[1].tow = towtop + ((realtop - bot) * towmult); wallVerts[2].y = wallVerts[3].y = top; wallVerts[0].y = wallVerts[1].y = bot; + + // The x and y only need to be adjusted in the case that it's not a papersprite + if (cv_grspritebillboarding.value + && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE)) + { + // Get the x and z of the vertices so billboarding draws correctly + realheight = realbot - realtop; + heightmult = (realtop - top) / realheight; + wallVerts[3].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult; + wallVerts[3].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult; + wallVerts[2].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult; + wallVerts[2].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult; + + heightmult = (realtop - bot) / realheight; + wallVerts[0].x = baseWallVerts[3].x + (baseWallVerts[3].x - baseWallVerts[0].x) * heightmult; + wallVerts[0].z = baseWallVerts[3].z + (baseWallVerts[3].z - baseWallVerts[0].z) * heightmult; + wallVerts[1].x = baseWallVerts[2].x + (baseWallVerts[2].x - baseWallVerts[1].x) * heightmult; + wallVerts[1].z = baseWallVerts[2].z + (baseWallVerts[2].z - baseWallVerts[1].z) * heightmult; + } #endif if (colormap) @@ -4675,6 +4767,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; } + // Let dispoffset work first since this adjust each vertex + HWR_RotateSpritePolyToAim(spr, wallVerts); + // This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black. // sprite lighting by modulating the RGB components /// \todo coloured @@ -4756,6 +4851,9 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) wallVerts[0].z = wallVerts[3].z = spr->z1; wallVerts[1].z = wallVerts[2].z = spr->z2; + // Let dispoffset work first since this adjust each vertex + HWR_RotateSpritePolyToAim(spr, wallVerts); + wallVerts[0].sow = wallVerts[3].sow = 0; wallVerts[2].sow = wallVerts[1].sow = gpatch->max_s; diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 642e440d6..ced8f837d 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -95,6 +95,7 @@ extern consvar_t cv_grcorrecttricks; extern consvar_t cv_voodoocompatibility; extern consvar_t cv_grfovchange; extern consvar_t cv_grsolvetjoin; +extern consvar_t cv_grspritebillboarding; extern float gr_viewwidth, gr_viewheight, gr_baseviewwindowy; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 87b56adb5..cec0cfe1f 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1095,7 +1095,9 @@ static INT16 typelines = 1; // number of drawfill lines we need when drawing the // boolean HU_Responder(event_t *ev) { +#ifndef NONET INT32 c=0; +#endif if (ev->type != ev_keydown) return false; @@ -1122,19 +1124,9 @@ boolean HU_Responder(event_t *ev) return false; }*/ //We don't actually care about that unless we get splitscreen netgames. :V +#ifndef NONET c = (INT32)ev->data1; - // capslock (now handled outside of chat on so that it works everytime......) - if (c && c == KEY_CAPSLOCK) // it's a toggle. - { - if (capslock) - capslock = false; - else - capslock = true; - return true; - } - -#ifndef NONET if (!chat_on) { // enter chat mode diff --git a/src/info.c b/src/info.c index 851e565c9..04b138e8b 100644 --- a/src/info.c +++ b/src/info.c @@ -240,6 +240,9 @@ char sprnames[NUMSPRITES + 1][5] = "BTBL", // Big tumbleweed "STBL", // Small tumbleweed "CACT", // Cacti sprites + "WWSG", // Caution Sign + "WWS2", // Cacti Sign + "WWS3", // Sharp Turn Sign // Red Volcano Scenery "FLME", // Flame jet @@ -2285,6 +2288,16 @@ state_t states[NUMSTATES] = {SPR_CACT, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI2 {SPR_CACT, 2, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI3 {SPR_CACT, 3, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI4 + {SPR_CACT, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI5 + {SPR_CACT, 5, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI6 + {SPR_CACT, 6, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI7 + {SPR_CACT, 7, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI8 + {SPR_CACT, 8, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI9 + + // Warning Signs + {SPR_WWSG, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CAUTION + {SPR_WWS2, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CACTI + {SPR_WWS3, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_SHARPTURN // Flame jet {SPR_NULL, 0, 2*TICRATE, {NULL}, 0, 0, S_FLAMEJETSTART}, // S_FLAMEJETSTND @@ -11145,6 +11158,222 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_CACTI5 + 1207, // doomednum + S_CACTI5, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 40*FRACUNIT, // radius + 128*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_CACTI6 + 1208, // doomednum + S_CACTI6, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 132*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_CACTI7 + 1209, // doomednum + S_CACTI7, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 224*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_CACTI8 + 1210, // doomednum + S_CACTI8, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 208*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_CACTI9 + 1211, // doomednum + S_CACTI9, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 208*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_ARIDSIGN_CAUTION + 1212, // doomednum + S_ARIDSIGN_CAUTION, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 22*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_SOLID|MF_PAPERCOLLISION, // flags + S_NULL // raisestate + }, + + { // MT_ARIDSIGN_CACTI + 1213, // doomednum + S_ARIDSIGN_CACTI, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 22*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_SOLID|MF_PAPERCOLLISION, // flags + S_NULL // raisestate + }, + + { // MT_ARIDSIGN_SHARPTURN + 1214, // doomednum + S_ARIDSIGN_SHARPTURN, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 192*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_SOLID|MF_PAPERCOLLISION, // flags + S_NULL // raisestate + }, + { // MT_FLAMEJET 1300, // doomednum S_FLAMEJETSTND, // spawnstate diff --git a/src/info.h b/src/info.h index b3cbba78f..ad8d138e6 100644 --- a/src/info.h +++ b/src/info.h @@ -471,6 +471,9 @@ typedef enum sprite SPR_BTBL, // Big tumbleweed SPR_STBL, // Small tumbleweed SPR_CACT, // Cacti sprites + SPR_WWSG, // Caution Sign + SPR_WWS2, // Cacti Sign + SPR_WWS3, // Sharp Turn Sign // Red Volcano Scenery SPR_FLME, // Flame jet @@ -2396,6 +2399,16 @@ typedef enum state S_CACTI2, S_CACTI3, S_CACTI4, + S_CACTI5, + S_CACTI6, + S_CACTI7, + S_CACTI8, + S_CACTI9, + + // Warning signs sprites + S_ARIDSIGN_CAUTION, + S_ARIDSIGN_CACTI, + S_ARIDSIGN_SHARPTURN, // Flame jet S_FLAMEJETSTND, @@ -4096,6 +4109,14 @@ typedef enum mobj_type MT_CACTI2, MT_CACTI3, MT_CACTI4, + MT_CACTI5, // Harmful Cactus 1 + MT_CACTI6, // Harmful Cactus 2 + MT_CACTI7, // Harmful Cactus 3 + MT_CACTI8, // Harmful Cactus 4 + MT_CACTI9, // Harmful Cactus 5 + MT_ARIDSIGN_CAUTION, // Caution Sign + MT_ARIDSIGN_CACTI, // Cacti Sign + MT_ARIDSIGN_SHARPTURN, // Sharp Turn Sign // Red Volcano Scenery MT_FLAMEJET, diff --git a/src/m_menu.c b/src/m_menu.c index 1c3873613..4f78d0adc 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1454,10 +1454,11 @@ static menuitem_t OP_MonitorToggleMenu[] = // ========================================================================== // Main Menu and related -menu_t MainDef = CENTERMENUSTYLE(NULL, MainMenu, NULL, 72); +menu_t MainDef = CENTERMENUSTYLE(MN_MAIN, NULL, MainMenu, NULL, 72); menu_t MISC_AddonsDef = { + MN_AD_MAIN, NULL, sizeof (MISC_AddonsMenu)/sizeof (menuitem_t), &MainDef, @@ -1473,12 +1474,13 @@ menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); // Misc Main Menu -menu_t MISC_ScrambleTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ScrambleTeamMenu, &MPauseDef, 27, 40); -menu_t MISC_ChangeTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeTeamMenu, &MPauseDef, 27, 40); +menu_t MISC_ScrambleTeamDef = DEFAULTMENUSTYLE(MN_SPECIAL, NULL, MISC_ScrambleTeamMenu, &MPauseDef, 27, 40); +menu_t MISC_ChangeTeamDef = DEFAULTMENUSTYLE(MN_SPECIAL, NULL, MISC_ChangeTeamMenu, &MPauseDef, 27, 40); // MP Gametype and map change menu menu_t MISC_ChangeLevelDef = { + MN_SPECIAL, NULL, sizeof (MISC_ChangeLevelMenu)/sizeof (menuitem_t), &MainDef, // Doesn't matter. @@ -1497,6 +1499,7 @@ static INT32 highlightflags, recommendedflags, warningflags; // Sky Room menu_t SR_PandoraDef = { + MN_SR_MAIN + (MN_SR_PANDORA << 6), "M_PANDRA", sizeof (SR_PandorasBox)/sizeof (menuitem_t), &SPauseDef, @@ -1508,6 +1511,7 @@ menu_t SR_PandoraDef = }; menu_t SR_MainDef = { + MN_SR_MAIN, "M_SECRET", sizeof (SR_MainMenu)/sizeof (menuitem_t), &MainDef, @@ -1518,10 +1522,13 @@ menu_t SR_MainDef = NULL }; -menu_t SR_LevelSelectDef = MAPPLATTERMENUSTYLE(NULL, SR_LevelSelectMenu); +menu_t SR_LevelSelectDef = MAPPLATTERMENUSTYLE( + MN_SR_MAIN + (MN_SR_LEVELSELECT << 6), + NULL, SR_LevelSelectMenu); menu_t SR_UnlockChecklistDef = { + MN_SR_MAIN + (MN_SR_UNLOCKCHECKLIST << 6), "M_SECRET", 1, &SR_MainDef, @@ -1533,6 +1540,7 @@ menu_t SR_UnlockChecklistDef = }; menu_t SR_EmblemHintDef = { + MN_SR_MAIN + (MN_SR_EMBLEMHINT << 6), NULL, sizeof (SR_EmblemHintMenu)/sizeof (menuitem_t), &SPauseDef, @@ -1546,6 +1554,7 @@ menu_t SR_EmblemHintDef = // Single Player menu_t SP_MainDef = //CENTERMENUSTYLE(NULL, SP_MainMenu, &MainDef, 72); { + MN_SP_MAIN, NULL, sizeof(SP_MainMenu)/sizeof(menuitem_t), &MainDef, @@ -1558,6 +1567,7 @@ menu_t SP_MainDef = //CENTERMENUSTYLE(NULL, SP_MainMenu, &MainDef, 72); menu_t SP_LoadDef = { + MN_SP_MAIN + (MN_SP_LOAD << 6), "M_PICKG", 1, &SP_MainDef, @@ -1568,10 +1578,13 @@ menu_t SP_LoadDef = NULL }; -menu_t SP_LevelSelectDef = MAPPLATTERMENUSTYLE(NULL, SP_LevelSelectMenu); +menu_t SP_LevelSelectDef = MAPPLATTERMENUSTYLE( + MN_SP_MAIN + (MN_SP_LOAD << 6) + (MN_SP_PLAYER << 12) + (MN_SP_LEVELSELECT << 18), + NULL, SP_LevelSelectMenu); menu_t SP_LevelStatsDef = { + MN_SP_MAIN + (MN_SP_LEVELSTATS << 6), "M_STATS", 1, &SP_MainDef, @@ -1582,10 +1595,13 @@ menu_t SP_LevelStatsDef = NULL }; -menu_t SP_TimeAttackLevelSelectDef = MAPPLATTERMENUSTYLE("M_ATTACK", SP_TimeAttackLevelSelectMenu); +menu_t SP_TimeAttackLevelSelectDef = MAPPLATTERMENUSTYLE( + MN_SP_MAIN + (MN_SP_TIMEATTACK << 6) + (MN_SP_TIMEATTACK_LEVELSELECT << 12), + "M_ATTACK", SP_TimeAttackLevelSelectMenu); static menu_t SP_TimeAttackDef = { + MN_SP_MAIN + (MN_SP_TIMEATTACK << 6), "M_ATTACK", sizeof (SP_TimeAttackMenu)/sizeof (menuitem_t), &MainDef, // Doesn't matter. @@ -1597,6 +1613,7 @@ static menu_t SP_TimeAttackDef = }; static menu_t SP_ReplayDef = { + MN_SP_MAIN + (MN_SP_TIMEATTACK << 6) + (MN_SP_REPLAY << 12), "M_ATTACK", sizeof(SP_ReplayMenu)/sizeof(menuitem_t), &SP_TimeAttackDef, @@ -1608,6 +1625,7 @@ static menu_t SP_ReplayDef = }; static menu_t SP_GuestReplayDef = { + MN_SP_MAIN + (MN_SP_TIMEATTACK << 6) + (MN_SP_GUESTREPLAY << 12), "M_ATTACK", sizeof(SP_GuestReplayMenu)/sizeof(menuitem_t), &SP_TimeAttackDef, @@ -1619,6 +1637,7 @@ static menu_t SP_GuestReplayDef = }; static menu_t SP_GhostDef = { + MN_SP_MAIN + (MN_SP_TIMEATTACK << 6) + (MN_SP_GHOST << 12), "M_ATTACK", sizeof(SP_GhostMenu)/sizeof(menuitem_t), &SP_TimeAttackDef, @@ -1629,10 +1648,13 @@ static menu_t SP_GhostDef = NULL }; -menu_t SP_NightsAttackLevelSelectDef = MAPPLATTERMENUSTYLE("M_NIGHTS", SP_NightsAttackLevelSelectMenu); +menu_t SP_NightsAttackLevelSelectDef = MAPPLATTERMENUSTYLE( + MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6) + (MN_SP_NIGHTS_LEVELSELECT << 12), + "M_NIGHTS", SP_NightsAttackLevelSelectMenu); static menu_t SP_NightsAttackDef = { + MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6), "M_NIGHTS", sizeof (SP_NightsAttackMenu)/sizeof (menuitem_t), &MainDef, // Doesn't matter. @@ -1644,6 +1666,7 @@ static menu_t SP_NightsAttackDef = }; static menu_t SP_NightsReplayDef = { + MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6) + (MN_SP_NIGHTS_REPLAY << 12), "M_NIGHTS", sizeof(SP_NightsReplayMenu)/sizeof(menuitem_t), &SP_NightsAttackDef, @@ -1655,6 +1678,7 @@ static menu_t SP_NightsReplayDef = }; static menu_t SP_NightsGuestReplayDef = { + MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6) + (MN_SP_NIGHTS_GUESTREPLAY << 12), "M_NIGHTS", sizeof(SP_NightsGuestReplayMenu)/sizeof(menuitem_t), &SP_NightsAttackDef, @@ -1666,6 +1690,7 @@ static menu_t SP_NightsGuestReplayDef = }; static menu_t SP_NightsGhostDef = { + MN_SP_MAIN + (MN_SP_NIGHTSATTACK << 6) + (MN_SP_NIGHTS_GHOST << 12), "M_NIGHTS", sizeof(SP_NightsGhostMenu)/sizeof(menuitem_t), &SP_NightsAttackDef, @@ -1679,6 +1704,7 @@ static menu_t SP_NightsGhostDef = menu_t SP_PlayerDef = { + MN_SP_MAIN + (MN_SP_LOAD << 6) + (MN_SP_PLAYER << 12), "M_PICKP", sizeof (SP_PlayerMenu)/sizeof (menuitem_t), &SP_MainDef, @@ -1693,6 +1719,7 @@ menu_t SP_PlayerDef = menu_t MP_SplitServerDef = { + MN_MP_MAIN + (MN_MP_SPLITSCREEN << 6), "M_MULTI", sizeof (MP_SplitServerMenu)/sizeof (menuitem_t), #ifndef NONET @@ -1711,6 +1738,7 @@ menu_t MP_SplitServerDef = menu_t MP_MainDef = { + MN_MP_MAIN, "M_MULTI", sizeof (MP_MainMenu)/sizeof (menuitem_t), &MainDef, @@ -1723,6 +1751,7 @@ menu_t MP_MainDef = menu_t MP_ServerDef = { + MN_MP_MAIN + (MN_MP_SERVER << 6), "M_MULTI", sizeof (MP_ServerMenu)/sizeof (menuitem_t), &MP_MainDef, @@ -1735,6 +1764,7 @@ menu_t MP_ServerDef = menu_t MP_ConnectDef = { + MN_MP_MAIN + (MN_MP_CONNECT << 6), "M_MULTI", sizeof (MP_ConnectMenu)/sizeof (menuitem_t), &MP_MainDef, @@ -1747,6 +1777,7 @@ menu_t MP_ConnectDef = menu_t MP_RoomDef = { + MN_MP_MAIN + (MN_MP_ROOM << 6), "M_MULTI", sizeof (MP_RoomMenu)/sizeof (menuitem_t), &MP_ConnectDef, @@ -1760,6 +1791,11 @@ menu_t MP_RoomDef = menu_t MP_PlayerSetupDef = { +#ifdef NONET + MN_MP_MAIN + (MN_MP_PLAYERSETUP << 6), +#else + MN_MP_MAIN + (MN_MP_SPLITSCREEN << 6) + (MN_MP_PLAYERSETUP << 12), +#endif "M_SPLAYR", sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t), &MainDef, // doesn't matter @@ -1771,16 +1807,33 @@ menu_t MP_PlayerSetupDef = }; // Options -menu_t OP_MainDef = DEFAULTMENUSTYLE("M_OPTTTL", OP_MainMenu, &MainDef, 50, 30); -menu_t OP_ChangeControlsDef = CONTROLMENUSTYLE(OP_ChangeControlsMenu, &OP_MainDef); -menu_t OP_P1ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_P1ControlsMenu, &OP_MainDef, 50, 30); -menu_t OP_P2ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_P2ControlsMenu, &OP_MainDef, 50, 30); -menu_t OP_MouseOptionsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_MouseOptionsMenu, &OP_P1ControlsDef, 35, 30); -menu_t OP_Mouse2OptionsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_Mouse2OptionsMenu, &OP_P2ControlsDef, 35, 30); -menu_t OP_Joystick1Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick1Menu, &OP_P1ControlsDef, 50, 30); -menu_t OP_Joystick2Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick2Menu, &OP_P2ControlsDef, 50, 30); +menu_t OP_MainDef = DEFAULTMENUSTYLE( + MN_OP_MAIN, + "M_OPTTTL", OP_MainMenu, &MainDef, 50, 30); +menu_t OP_ChangeControlsDef = CONTROLMENUSTYLE( + MN_OP_MAIN + (MN_OP_CHANGECONTROLS << 12), // second level (<<6) set on runtime + OP_ChangeControlsMenu, &OP_MainDef); +menu_t OP_P1ControlsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P1CONTROLS << 6), + "M_CONTRO", OP_P1ControlsMenu, &OP_MainDef, 50, 30); +menu_t OP_P2ControlsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P2CONTROLS << 6), + "M_CONTRO", OP_P2ControlsMenu, &OP_MainDef, 50, 30); +menu_t OP_MouseOptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1MOUSE << 12), + "M_CONTRO", OP_MouseOptionsMenu, &OP_P1ControlsDef, 35, 30); +menu_t OP_Mouse2OptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P2CONTROLS << 6) + (MN_OP_P2MOUSE << 12), + "M_CONTRO", OP_Mouse2OptionsMenu, &OP_P2ControlsDef, 35, 30); +menu_t OP_Joystick1Def = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1JOYSTICK << 12), + "M_CONTRO", OP_Joystick1Menu, &OP_P1ControlsDef, 50, 30); +menu_t OP_Joystick2Def = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P2CONTROLS << 6) + (MN_OP_P2JOYSTICK << 12), + "M_CONTRO", OP_Joystick2Menu, &OP_P2ControlsDef, 50, 30); menu_t OP_JoystickSetDef = { + MN_OP_MAIN + (MN_OP_JOYSTICKSET << MENUBITS*3), // second (<<6) and third level (<<12) set on runtime "M_CONTRO", sizeof (OP_JoystickSetMenu)/sizeof (menuitem_t), &OP_Joystick1Def, @@ -1793,6 +1846,7 @@ menu_t OP_JoystickSetDef = menu_t OP_VideoOptionsDef = { + MN_OP_MAIN + (MN_OP_VIDEO << 6), "M_VIDEO", sizeof (OP_VideoOptionsMenu)/sizeof (menuitem_t), &OP_MainDef, @@ -1804,6 +1858,7 @@ menu_t OP_VideoOptionsDef = }; menu_t OP_VideoModeDef = { + MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_VIDEOMODE << 12), "M_VIDEO", 1, &OP_VideoOptionsDef, @@ -1815,6 +1870,7 @@ menu_t OP_VideoModeDef = }; menu_t OP_ColorOptionsDef = { + MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_COLOR << 12), "M_VIDEO", sizeof (OP_ColorOptionsMenu)/sizeof (menuitem_t), &OP_VideoOptionsDef, @@ -1824,12 +1880,26 @@ menu_t OP_ColorOptionsDef = 0, NULL }; +menu_t OP_SoundOptionsDef = +{ + MN_OP_MAIN + (MN_OP_SOUND << 6), + "M_SOUND", + sizeof (OP_SoundOptionsMenu)/sizeof (menuitem_t), + &OP_MainDef, + OP_SoundOptionsMenu, + M_DrawGenericMenu, + 30, 30, + 0, + NULL +}; -menu_t OP_SoundOptionsDef = DEFAULTMENUSTYLE("M_SOUND", OP_SoundOptionsMenu, &OP_MainDef, 30, 30); -menu_t OP_ServerOptionsDef = DEFAULTSCROLLMENUSTYLE("M_SERVER", OP_ServerOptionsMenu, &OP_MainDef, 30, 30); +menu_t OP_ServerOptionsDef = DEFAULTSCROLLMENUSTYLE( + MN_OP_MAIN + (MN_OP_SERVER << 6), + "M_SERVER", OP_ServerOptionsMenu, &OP_MainDef, 30, 30); menu_t OP_MonitorToggleDef = { + MN_OP_MAIN + (MN_OP_SERVER << 6) + (MN_OP_MONITORTOGGLE << 12), "M_SERVER", sizeof (OP_MonitorToggleMenu)/sizeof (menuitem_t), &OP_ServerOptionsDef, @@ -1841,12 +1911,17 @@ menu_t OP_MonitorToggleDef = }; #ifdef HWRENDER -menu_t OP_OpenGLOptionsDef = DEFAULTMENUSTYLE("M_VIDEO", OP_OpenGLOptionsMenu, &OP_VideoOptionsDef, 30, 30); +menu_t OP_OpenGLOptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12), + "M_VIDEO", OP_OpenGLOptionsMenu, &OP_VideoOptionsDef, 30, 30); #ifdef ALAM_LIGHTING -menu_t OP_OpenGLLightingDef = DEFAULTMENUSTYLE("M_VIDEO", OP_OpenGLLightingMenu, &OP_OpenGLOptionsDef, 60, 40); +menu_t OP_OpenGLLightingDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12) + (MN_OP_OPENGL_LIGHTING << 18), + "M_VIDEO", OP_OpenGLLightingMenu, &OP_OpenGLOptionsDef, 60, 40); #endif menu_t OP_OpenGLFogDef = { + MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12) + (MN_OP_OPENGL_FOG << 18), "M_VIDEO", sizeof (OP_OpenGLFogMenu)/sizeof (menuitem_t), &OP_OpenGLOptionsDef, @@ -1858,6 +1933,7 @@ menu_t OP_OpenGLFogDef = }; menu_t OP_OpenGLColorDef = { + MN_OP_MAIN + (MN_OP_VIDEO << 6) + (MN_OP_OPENGL << 12) + (MN_OP_OPENGL_COLOR << 18), "M_VIDEO", sizeof (OP_OpenGLColorMenu)/sizeof (menuitem_t), &OP_OpenGLOptionsDef, @@ -1868,10 +1944,13 @@ menu_t OP_OpenGLColorDef = NULL }; #endif -menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); +menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_DATA << 6), + "M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); menu_t OP_ScreenshotOptionsDef = { + MN_OP_MAIN + (MN_OP_DATA << 6) + (MN_OP_SCREENSHOTS << 12), "M_DATA", sizeof (OP_ScreenshotOptionsMenu)/sizeof (menuitem_t), &OP_DataOptionsDef, @@ -1882,9 +1961,13 @@ menu_t OP_ScreenshotOptionsDef = NULL }; -menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30); +menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_DATA << 6) + (MN_OP_ADDONS << 12), + "M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30); -menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 60, 30); +menu_t OP_EraseDataDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_DATA << 6) + (MN_OP_ERASEDATA << 12), + "M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 60, 30); // ========================================================================== // CVAR ONCHANGE EVENTS GO HERE @@ -2087,6 +2170,462 @@ void Addons_option_Onchange(void) // current menudef menu_t *currentMenu = &MainDef; +// ========================================================================= +// MENU PRESENTATION PARAMETER HANDLING (BACKGROUNDS) +// ========================================================================= + +// menu IDs are equal to current/prevMenu in most cases, except MN_SPECIAL when we don't want to operate on Message, Pause, etc. +UINT32 prevMenuId = 0; +UINT32 activeMenuId = 0; + +menupres_t menupres[NUMMENUTYPES]; + +void M_InitMenuPresTables(void) +{ + INT32 i; + + // Called in d_main before SOC can get to the tables + // Set menupres defaults + for (i = 0; i < NUMMENUTYPES; i++) + { + // so-called "undefined" + menupres[i].fadestrength = -1; + menupres[i].hidetitlepics = -1; // inherits global hidetitlepics + menupres[i].enterwipe = -1; + menupres[i].exitwipe = -1; + menupres[i].bgcolor = -1; + menupres[i].titlescrollxspeed = INT32_MAX; + menupres[i].titlescrollyspeed = INT32_MAX; + // default true + menupres[i].enterbubble = true; + menupres[i].exitbubble = true; + + if (i != MN_MAIN) + { + menupres[i].muslooping = true; + } + if (i == MN_SP_TIMEATTACK || i == MN_SP_NIGHTSATTACK) + strncpy(menupres[i].musname, "_inter", 7); + else if (i == MN_SP_PLAYER) + strncpy(menupres[i].musname, "_chsel", 7); + } +} + +// ==================================== +// TREE ITERATION +// ==================================== + +// UINT32 menutype - current menutype_t +// INT32 level - current level up the tree, higher means younger +// INT32 *retval - Return value +// void *input - Pointer to input of any type +// +// return true - stop iterating +// return false - continue +typedef boolean (*menutree_iterator)(UINT32, INT32, INT32 *, void **, boolean fromoldest); + +// HACK: Used in the ChangeMusic iterator because we only allow +// a single input. Maybe someday use this struct program-wide. +typedef struct +{ + char musname[7]; + UINT16 mustrack; + boolean muslooping; +} menupresmusic_t; + +static INT32 M_IterateMenuTree(menutree_iterator itfunc, void *input) +{ + INT32 i, retval = 0; + UINT32 bitmask, menutype; + + for (i = NUMMENULEVELS; i >= 0; i--) + { + bitmask = ((1 << MENUBITS) - 1) << (MENUBITS*i); + menutype = (activeMenuId & bitmask) >> (MENUBITS*i); + if (itfunc(menutype, i, &retval, &input, false)) + break; + } + + return retval; +} + +// ==================================== +// ITERATORS +// ==================================== + +static boolean MIT_GetMenuAtLevel(UINT32 menutype, INT32 level, INT32 *retval, void **input, boolean fromoldest) +{ + INT32 *inputptr = (INT32*)*input; + INT32 targetlevel = *inputptr; + if (menutype) + { + if (level == targetlevel || targetlevel < 0) + { + *retval = menutype; + return true; + } + } + else if (targetlevel >= 0) + { + // offset targetlevel by failed attempts; this should only happen in beginning of iteration + if (fromoldest) + (*inputptr)++; + else + (*inputptr)--; // iterating backwards, so count from highest + } + return false; +} + +static boolean MIT_SetCurBackground(UINT32 menutype, INT32 level, INT32 *retval, void **input, boolean fromoldest) +{ + char *defaultname = (char*)*input; + + (void)retval; + (void)fromoldest; + + if (menupres[menutype].bgcolor >= 0) + { + curbgcolor = menupres[menutype].bgcolor; + return true; + } + else if (menupres[menutype].bgname[0] && (!menupres[menutype].bghide || !titlemapinaction)) + { + 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; + } + else if (menupres[menutype].bghide && titlemapinaction) // hide the background + { + curbghide = true; + return true; + } + else if (!level) + { + if (M_GetYoungestChildMenu() == MN_SP_PLAYER || !defaultname || !defaultname[0]) + curbgcolor = 31; + else if (titlemapinaction) // hide the background by default in titlemap + curbghide = true; + else + { + strncpy(curbgname, defaultname, 8); + curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed; + curbgyspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollyspeed; + } + } + return false; +} + +static boolean MIT_ChangeMusic(UINT32 menutype, INT32 level, INT32 *retval, void **input, boolean fromoldest) +{ + menupresmusic_t *defaultmusic = (menupresmusic_t*)*input; + + (void)retval; + (void)fromoldest; + + if (menupres[menutype].musname[0]) + { + S_ChangeMusic(menupres[menutype].musname, menupres[menutype].mustrack, menupres[menutype].muslooping); + return true; + } + else if (menupres[menutype].musstop) + { + S_StopMusic(); + return true; + } + else if (menupres[menutype].musignore) + return true; + else if (!level && defaultmusic && defaultmusic->musname[0]) + S_ChangeMusic(defaultmusic->musname, defaultmusic->mustrack, defaultmusic->muslooping); + return false; +} + +static boolean MIT_SetCurFadeValue(UINT32 menutype, INT32 level, INT32 *retval, void **input, boolean fromoldest) +{ + UINT8 defaultvalue = *(UINT8*)*input; + + (void)retval; + (void)fromoldest; + + if (menupres[menutype].fadestrength >= 0) + { + curfadevalue = (menupres[menutype].fadestrength % 32); + return true; + } + else if (!level) + curfadevalue = (gamestate == GS_TIMEATTACK) ? 0 : (defaultvalue % 32); + return false; +} + +static boolean MIT_SetCurHideTitlePics(UINT32 menutype, INT32 level, INT32 *retval, void **input, boolean fromoldest) +{ + (void)input; + (void)retval; + (void)fromoldest; + + if (menupres[menutype].hidetitlepics >= 0) + { + curhidepics = menupres[menutype].hidetitlepics; + return true; + } + else if (!level) + curhidepics = hidetitlepics; + return false; +} + +// ==================================== +// TREE RETRIEVAL +// ==================================== + +UINT8 M_GetYoungestChildMenu(void) // aka the active menu +{ + INT32 targetlevel = -1; + return M_IterateMenuTree(MIT_GetMenuAtLevel, &targetlevel); +} + +// ==================================== +// EFFECTS +// ==================================== + +void M_ChangeMenuMusic(const char *defaultmusname, boolean defaultmuslooping) +{ + menupresmusic_t defaultmusic; + + if (!defaultmusname) + defaultmusname = ""; + + strncpy(defaultmusic.musname, defaultmusname, 7); + defaultmusic.musname[6] = 0; + defaultmusic.mustrack = 0; + defaultmusic.muslooping = defaultmuslooping; + + M_IterateMenuTree(MIT_ChangeMusic, &defaultmusic); +} + +void M_SetMenuCurBackground(const char *defaultname) +{ + char name[8]; + strncpy(name, defaultname, 8); + M_IterateMenuTree(MIT_SetCurBackground, &name); +} + +void M_SetMenuCurFadeValue(UINT8 defaultvalue) +{ + M_IterateMenuTree(MIT_SetCurFadeValue, &defaultvalue); +} + +void M_SetMenuCurHideTitlePics(void) +{ + M_IterateMenuTree(MIT_SetCurHideTitlePics, NULL); +} + +// ==================================== +// MENU STATE +// ==================================== + +static INT32 exitlevel, enterlevel, anceslevel; +static INT16 exittype, entertype; +static INT16 exitwipe, enterwipe; +static boolean exitbubble, enterbubble; +static INT16 exittag, entertag; + +static void M_HandleMenuPresState(menu_t *newMenu) +{ + INT32 i; + UINT32 bitmask; + SINT8 prevtype, activetype, menutype; + + if (!newMenu) + return; + + // Look for MN_SPECIAL here, because our iterators can't look at new menu IDs + for (i = 0; i <= NUMMENULEVELS; i++) + { + bitmask = ((1 << MENUBITS) - 1) << (MENUBITS*i); + menutype = (newMenu->menuid & bitmask) >> (MENUBITS*i); + prevtype = (currentMenu->menuid & bitmask) >> (MENUBITS*i); + if (menutype == MN_SPECIAL || prevtype == MN_SPECIAL) + return; + } + + if (currentMenu && newMenu && currentMenu->menuid == newMenu->menuid) // same menu? + return; + + exittype = entertype = exitlevel = enterlevel = anceslevel = exitwipe = enterwipe = -1; + exitbubble = enterbubble = true; + + prevMenuId = currentMenu ? currentMenu->menuid : 0; + activeMenuId = newMenu ? newMenu->menuid : 0; + + // Set defaults for presentation values + strncpy(curbgname, "TITLESKY", 8); + curfadevalue = 16; + curhidepics = hidetitlepics; + curbgcolor = -1; + curbgxspeed = titlescrollxspeed; + curbgyspeed = titlescrollyspeed; + curbghide = false; + + // don't do the below during the in-game menus + if (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK) + return; + + // Find current presentation values + M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "SRB2BACK" : "TITLESKY"); + M_SetMenuCurFadeValue(16); + M_SetMenuCurHideTitlePics(); + + // Loop through both menu IDs in parallel and look for type changes + // The youngest child in activeMenuId is the entered menu + // The youngest child in prevMenuId is the exited menu + + // 0. Get the type and level of each menu, and level of common ancestor + // 1. Get the wipes for both, then run the exit wipe + // 2. Change music (so that execs can change it again later) + // 3. Run each exit exec on the prevMenuId up to the common ancestor (UNLESS NoBubbleExecs) + // 4. Run each entrance exec on the activeMenuId down from the common ancestor (UNLESS NoBubbleExecs) + // 5. Run the entrance wipe + + // Get the parameters for each menu + for (i = NUMMENULEVELS; i >= 0; i--) + { + bitmask = ((1 << MENUBITS) - 1) << (MENUBITS*i); + prevtype = (prevMenuId & bitmask) >> (MENUBITS*i); + activetype = (activeMenuId & bitmask) >> (MENUBITS*i); + + if (prevtype && (exittype < 0)) + { + exittype = prevtype; + exitlevel = i; + exitwipe = menupres[exittype].exitwipe; + exitbubble = menupres[exittype].exitbubble; + exittag = menupres[exittype].exittag; + } + + if (activetype && (entertype < 0)) + { + entertype = activetype; + enterlevel = i; + enterwipe = menupres[entertype].enterwipe; + enterbubble = menupres[entertype].enterbubble; + entertag = menupres[entertype].entertag; + } + + if (prevtype && activetype && prevtype == activetype && anceslevel < 0) + { + anceslevel = i; + break; + } + } + + // if no common ancestor (top menu), force a wipe. Look for a specified wipe first. + // Don't force a wipe if you're actually going to/from the main menu + if (anceslevel < 0 && exitwipe < 0 && newMenu != &MainDef && currentMenu != &MainDef) + { + for (i = NUMMENULEVELS; i >= 0; i--) + { + bitmask = ((1 << MENUBITS) - 1) << (MENUBITS*i); + prevtype = (prevMenuId & bitmask) >> (MENUBITS*i); + + if (menupres[prevtype].exitwipe >= 0) + { + exitwipe = menupres[prevtype].exitwipe; + break; + } + } + + if (exitwipe < 0) + exitwipe = menupres[MN_MAIN].exitwipe; + } + + // do the same for enter wipe + if (anceslevel < 0 && enterwipe < 0 && newMenu != &MainDef && currentMenu != &MainDef) + { + for (i = NUMMENULEVELS; i >= 0; i--) + { + bitmask = ((1 << MENUBITS) - 1) << (MENUBITS*i); + activetype = (activeMenuId & bitmask) >> (MENUBITS*i); + + if (menupres[activetype].enterwipe >= 0) + { + exitwipe = menupres[activetype].enterwipe; + break; + } + } + + if (enterwipe < 0) + enterwipe = menupres[MN_MAIN].enterwipe; + } + + // Change the music + M_ChangeMenuMusic("_title", false); + + // Run the linedef execs + if (titlemapinaction) + { + // Run the exit tags + if (enterlevel <= exitlevel) // equals is an edge case + { + if (exitbubble) + { + for (i = exitlevel; i > anceslevel; i--) // don't run the common ancestor's exit tag + { + bitmask = ((1 << MENUBITS) - 1) << (MENUBITS*i); + menutype = (prevMenuId & bitmask) >> (MENUBITS*i); + if (menupres[menutype].exittag) + P_LinedefExecute(menupres[menutype].exittag, players[displayplayer].mo, NULL); + } + } + else if (exittag) + P_LinedefExecute(exittag, players[displayplayer].mo, NULL); + } + + // Run the enter tags + if (enterlevel >= exitlevel) // equals is an edge case + { + if (enterbubble) + { + for (i = anceslevel+1; i <= enterlevel; i++) // don't run the common ancestor's enter tag + { + bitmask = ((1 << MENUBITS) - 1) << (MENUBITS*i); + menutype = (activeMenuId & bitmask) >> (MENUBITS*i); + if (menupres[menutype].entertag) + P_LinedefExecute(menupres[menutype].entertag, players[displayplayer].mo, NULL); + } + } + else if (entertag) + P_LinedefExecute(entertag, players[displayplayer].mo, NULL); + } + } + + + // Set the wipes for next frame + if ( + (exitwipe >= 0 && enterlevel <= exitlevel) || + (enterwipe >= 0 && enterlevel >= exitlevel) || + (anceslevel < 0 && newMenu != &MainDef && currentMenu != &MainDef) + ) + { + if (gamestate == GS_TIMEATTACK) + wipetypepre = ((exitwipe && enterlevel <= exitlevel) || anceslevel < 0) ? exitwipe : -1; // force default + else + // HACK: INT16_MAX signals to not wipe + // because 0 is a valid index and -1 means default + wipetypepre = ((exitwipe && enterlevel <= exitlevel) || anceslevel < 0) ? exitwipe : INT16_MAX; + wipetypepost = ((enterwipe && enterlevel >= exitlevel) || anceslevel < 0) ? enterwipe : INT16_MAX; + wipegamestate = FORCEWIPE; + + // If just one of the above is a force not-wipe, + // mirror the other wipe. + if (wipetypepre != INT16_MAX && wipetypepost == INT16_MAX) + wipetypepost = wipetypepre; + else if (wipetypepost != INT16_MAX && wipetypepre == INT16_MAX) + wipetypepre = wipetypepost; + + // D_Display runs the next step of processing + } +} + // ========================================================================= // BASIC MENU HANDLING // ========================================================================= @@ -2116,6 +2655,7 @@ static void M_GoBack(INT32 choice) } menuactive = false; + wipetypepre = menupres[M_GetYoungestChildMenu()].exitwipe; D_StartTitle(); } else @@ -2604,8 +3144,8 @@ void M_Drawer(void) if (menuactive) { // now that's more readable with a faded background (yeah like Quake...) - if (!WipeInAction) - V_DrawFadeScreen(0xFF00, 16); + if (!WipeInAction && (curfadevalue || (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK))) + V_DrawFadeScreen(0xFF00, (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK) ? 16 : curfadevalue); if (currentMenu->drawroutine) currentMenu->drawroutine(); // call current menu Draw routine @@ -2802,6 +3342,9 @@ void M_SetupNextMenu(menu_t *menudef) if (currentMenu != menudef && !currentMenu->quitroutine()) return; // we can't quit this menu (also used to set parameter from the menu) } + + M_HandleMenuPresState(menudef); + currentMenu = menudef; itemOn = currentMenu->lastOn; @@ -4461,7 +5004,14 @@ static void M_DrawLevelPlatterMenu(void) const INT32 cursorx = (sizeselect ? 0 : (lscol*lshseperation)); if (gamestate == GS_TIMEATTACK) - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + { + 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); + } // finds row at top of the screen while (y > -8) @@ -4537,6 +5087,7 @@ static menuitem_t MessageMenu[] = menu_t MessageDef = { + MN_SPECIAL, NULL, // title 1, // # of menu items NULL, // previous menu (TO HACK) @@ -4662,7 +5213,14 @@ static void M_DrawMessageMenu(void) // hack: draw RA background in RA menus if (gamestate == GS_TIMEATTACK) - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + { + 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); + } M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines); @@ -6973,12 +7531,8 @@ static void M_SetupChoosePlayer(INT32 choice) return; } - if (Playing() == false) - { - S_StopMusic(); - S_ChangeMusicInternal("_chsel", true); - } + M_ChangeMenuMusic("_chsel", true); SP_PlayerDef.prevMenu = currentMenu; M_SetupNextMenu(&SP_PlayerDef); @@ -7072,8 +7626,12 @@ static void M_DrawSetupChoosePlayerMenu(void) UINT8 prev, next; // Black BG - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - //V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + 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); // Character select profile images!1 M_DrawTextBox(0, my, 16, 20); @@ -7461,9 +8019,14 @@ void M_DrawTimeAttackMenu(void) UINT16 dispstatus; patch_t *PictureOfUrFace; - S_ChangeMusicInternal("_inter", true); // Eww, but needed for when user hits escape during demo playback + M_ChangeMenuMusic("_inter", true); // Eww, but needed for when user hits escape during demo playback - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + 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); M_DrawMenuTitle(); @@ -7632,15 +8195,13 @@ static void M_TimeAttack(INT32 choice) M_PatchSkinNameTable(); + G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching M_SetupNextMenu(&SP_TimeAttackDef); if (!M_CanShowLevelInList(cv_nextmap.value-1, -1) && levelselect.rows[0].maplist[0]) CV_SetValue(&cv_nextmap, levelselect.rows[0].maplist[0]); else Nextmap_OnChange(); - G_SetGamestate(GS_TIMEATTACK); - S_ChangeMusicInternal("_inter", true); - itemOn = tastart; // "Start" is selected. } @@ -7650,9 +8211,14 @@ void M_DrawNightsAttackMenu(void) INT32 i, x, y, cursory = 0; UINT16 dispstatus; - S_ChangeMusicInternal("_inter", true); // Eww, but needed for when user hits escape during demo playback + M_ChangeMenuMusic("_inter", true); // Eww, but needed for when user hits escape during demo playback - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + 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); M_DrawMenuTitle(); @@ -7809,15 +8375,13 @@ static void M_NightsAttack(INT32 choice) // This is really just to make sure Sonic is the played character, just in case M_PatchSkinNameTable(); + G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching M_SetupNextMenu(&SP_NightsAttackDef); if (!M_CanShowLevelInList(cv_nextmap.value-1, -1) && levelselect.rows[0].maplist[0]) CV_SetValue(&cv_nextmap, levelselect.rows[0].maplist[0]); else Nextmap_OnChange(); - G_SetGamestate(GS_TIMEATTACK); - S_ChangeMusicInternal("_inter", true); - itemOn = nastart; // "Start" is selected. } @@ -8043,15 +8607,17 @@ static void M_ModeAttackEndGame(INT32 choice) default: case ATTACKING_RECORD: currentMenu = &SP_TimeAttackDef; + wipetypepost = menupres[MN_SP_TIMEATTACK].enterwipe; break; case ATTACKING_NIGHTS: currentMenu = &SP_NightsAttackDef; + wipetypepost = menupres[MN_SP_NIGHTSATTACK].enterwipe; break; } itemOn = currentMenu->lastOn; G_SetGamestate(GS_TIMEATTACK); modeattacking = ATTACKING_NONE; - S_ChangeMusicInternal("_inter", true); + M_ChangeMenuMusic("_title", true); Nextmap_OnChange(); } @@ -9226,6 +9792,10 @@ static void M_Setup1PJoystickMenu(INT32 choice) { setupcontrols_secondaryplayer = false; OP_JoystickSetDef.prevMenu = &OP_Joystick1Def; + OP_JoystickSetDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); + OP_JoystickSetDef.menuid &= ~(((1 << MENUBITS) - 1) << (MENUBITS*2)); + OP_JoystickSetDef.menuid |= MN_OP_P1CONTROLS << MENUBITS; + OP_JoystickSetDef.menuid |= MN_OP_P1JOYSTICK << (MENUBITS*2); M_SetupJoystickMenu(choice); } @@ -9233,6 +9803,10 @@ static void M_Setup2PJoystickMenu(INT32 choice) { setupcontrols_secondaryplayer = true; OP_JoystickSetDef.prevMenu = &OP_Joystick2Def; + OP_JoystickSetDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); + OP_JoystickSetDef.menuid &= ~(((1 << MENUBITS) - 1) << (MENUBITS*2)); + OP_JoystickSetDef.menuid |= MN_OP_P2CONTROLS << MENUBITS; + OP_JoystickSetDef.menuid |= MN_OP_P2JOYSTICK << (MENUBITS*2); M_SetupJoystickMenu(choice); } @@ -9274,6 +9848,8 @@ static void M_Setup1PControlsMenu(INT32 choice) OP_ChangeControlsMenu[27+3].status = IT_CALL|IT_STRING2; OP_ChangeControlsDef.prevMenu = &OP_P1ControlsDef; + OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove first level (<< 6) + OP_ChangeControlsDef.menuid |= MN_OP_P1CONTROLS << MENUBITS; // combine first level (<< 6) M_SetupNextMenu(&OP_ChangeControlsDef); } @@ -9303,6 +9879,8 @@ static void M_Setup2PControlsMenu(INT32 choice) OP_ChangeControlsMenu[27+3].status = IT_GRAYEDOUT2; OP_ChangeControlsDef.prevMenu = &OP_P2ControlsDef; + OP_ChangeControlsDef.menuid &= ~(((1 << MENUBITS) - 1) << MENUBITS); // remove first level (<< 6) + OP_ChangeControlsDef.menuid |= MN_OP_P2CONTROLS << MENUBITS; // combine first level (<< 6) M_SetupNextMenu(&OP_ChangeControlsDef); } diff --git a/src/m_menu.h b/src/m_menu.h index cac684792..04146ebdc 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -22,6 +22,140 @@ // // MENUS // + +// If menu hierarchies go deeper, change this up to 5. +// Zero-based, inclusive. +#define NUMMENULEVELS 3 +#define MENUBITS 6 + +// Menu IDs sectioned by numeric places to signify hierarchy +typedef enum +{ + MN_NONE, + + MN_MAIN, + + // Single Player + MN_SP_MAIN, + + MN_SP_LOAD, + MN_SP_PLAYER, + + MN_SP_LEVELSELECT, + MN_SP_LEVELSTATS, + + MN_SP_TIMEATTACK, + MN_SP_TIMEATTACK_LEVELSELECT, + MN_SP_GUESTREPLAY, + MN_SP_REPLAY, + MN_SP_GHOST, + + MN_SP_NIGHTSATTACK, + MN_SP_NIGHTS_LEVELSELECT, + MN_SP_NIGHTS_GUESTREPLAY, + MN_SP_NIGHTS_REPLAY, + MN_SP_NIGHTS_GHOST, + + // Multiplayer + MN_MP_MAIN, + MN_MP_SPLITSCREEN, // SplitServer + MN_MP_SERVER, + MN_MP_CONNECT, + MN_MP_ROOM, + MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET + + // Options + MN_OP_MAIN, + + MN_OP_P1CONTROLS, + MN_OP_CHANGECONTROLS, // OP_ChangeControlsDef shared with P2 + MN_OP_P1MOUSE, + MN_OP_P1JOYSTICK, + MN_OP_JOYSTICKSET, // OP_JoystickSetDef shared with P2 + + MN_OP_P2CONTROLS, + MN_OP_P2MOUSE, + MN_OP_P2JOYSTICK, + + MN_OP_VIDEO, + MN_OP_VIDEOMODE, + MN_OP_COLOR, + MN_OP_OPENGL, + MN_OP_OPENGL_LIGHTING, + MN_OP_OPENGL_FOG, + MN_OP_OPENGL_COLOR, + + MN_OP_SOUND, + + MN_OP_SERVER, + MN_OP_MONITORTOGGLE, + + MN_OP_DATA, + MN_OP_ADDONS, + MN_OP_SCREENSHOTS, + MN_OP_ERASEDATA, + + // Secrets + MN_SR_MAIN, + MN_SR_PANDORA, + MN_SR_LEVELSELECT, + MN_SR_UNLOCKCHECKLIST, + MN_SR_EMBLEMHINT, + + // Addons (Part of MISC, but let's make it our own) + MN_AD_MAIN, + + // MISC + // MN_MESSAGE, + // MN_SPAUSE, + + // MN_MPAUSE, + // MN_SCRAMBLETEAM, + // MN_CHANGETEAM, + // MN_CHANGELEVEL, + + // MN_MAPAUSE, + // MN_HELP, + + MN_SPECIAL, + NUMMENUTYPES, +} menutype_t; // up to 63; MN_SPECIAL = 53 + +typedef struct +{ + char bgname[8]; // name for background gfx lump; lays over titlemap if this is set + SINT8 hidetitlepics; // hide title gfx per menu; -1 means undefined, inherits global setting + INT32 titlescrollxspeed; // background gfx scroll per menu; inherits global setting + INT32 titlescrollyspeed; // y scroll + INT32 bgcolor; // fill color, overrides bg name. -1 means follow bg name rules. + boolean bghide; // for titlemaps, hide the background. + + char musname[7]; ///< Music track to play. "" for no music. + UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. + boolean muslooping; ///< Loop the music + boolean musstop; ///< Don't play any music + boolean musignore; ///< Let the current music keep playing + + SINT8 fadestrength; // darken background when displaying this menu, strength 0-31 or -1 for undefined + boolean enterbubble; // run all entrance line execs after common ancestor and up to child. If false, only run the child's exec + boolean exitbubble; // run all exit line execs from child and up to before common ancestor. If false, only run the child's exec + INT32 entertag; // line exec to run on menu enter, if titlemap + INT32 exittag; // line exec to run on menu exit, if titlemap + INT16 enterwipe; // wipe type to run on menu enter, -1 means default + INT16 exitwipe; // wipe type to run on menu exit, -1 means default +} menupres_t; + +extern menupres_t menupres[NUMMENUTYPES]; +extern UINT32 prevMenuId; +extern UINT32 activeMenuId; + +void M_InitMenuPresTables(void); +UINT8 M_GetYoungestChildMenu(void); +void M_ChangeMenuMusic(const char *defaultmusname, boolean defaultmuslooping); +void M_SetMenuCurBackground(const char *defaultname); +void M_SetMenuCurFadeValue(UINT8 defaultvalue); +void M_SetMenuCurHideTitlePics(void); + // Called by main loop, // saves config file and calls I_Quit when user exits. // Even when the menu is not displayed, @@ -156,6 +290,7 @@ typedef struct menuitem_s typedef struct menu_s { + UINT32 menuid; // ID to encode menu type and hierarchy const char *menutitlepic; INT16 numitems; // # of menu items struct menu_s *prevMenu; // previous menu @@ -262,8 +397,9 @@ void Screenshot_option_Onchange(void); void Addons_option_Onchange(void); // These defines make it a little easier to make menus -#define DEFAULTMENUSTYLE(header, source, prev, x, y)\ +#define DEFAULTMENUSTYLE(id, header, source, prev, x, y)\ {\ + id,\ header,\ sizeof(source)/sizeof(menuitem_t),\ prev,\ @@ -274,8 +410,9 @@ void Addons_option_Onchange(void); NULL\ } -#define DEFAULTSCROLLMENUSTYLE(header, source, prev, x, y)\ +#define DEFAULTSCROLLMENUSTYLE(id, header, source, prev, x, y)\ {\ + id,\ header,\ sizeof(source)/sizeof(menuitem_t),\ prev,\ @@ -288,6 +425,7 @@ void Addons_option_Onchange(void); #define PAUSEMENUSTYLE(source, x, y)\ {\ + MN_SPECIAL,\ NULL,\ sizeof(source)/sizeof(menuitem_t),\ NULL,\ @@ -298,8 +436,9 @@ void Addons_option_Onchange(void); NULL\ } -#define CENTERMENUSTYLE(header, source, prev, y)\ +#define CENTERMENUSTYLE(id, header, source, prev, y)\ {\ + id,\ header,\ sizeof(source)/sizeof(menuitem_t),\ prev,\ @@ -310,8 +449,9 @@ void Addons_option_Onchange(void); NULL\ } -#define MAPPLATTERMENUSTYLE(header, source)\ +#define MAPPLATTERMENUSTYLE(id, header, source)\ {\ + id,\ header,\ sizeof (source)/sizeof (menuitem_t),\ &MainDef,\ @@ -322,8 +462,9 @@ void Addons_option_Onchange(void); NULL\ } -#define CONTROLMENUSTYLE(source, prev)\ +#define CONTROLMENUSTYLE(id, source, prev)\ {\ + id,\ "M_CONTRO",\ sizeof (source)/sizeof (menuitem_t),\ prev,\ @@ -336,6 +477,7 @@ void Addons_option_Onchange(void); #define IMAGEDEF(source)\ {\ + MN_SPECIAL,\ NULL,\ sizeof (source)/sizeof (menuitem_t),\ NULL,\ diff --git a/src/p_setup.c b/src/p_setup.c index 3dd673906..0602865a9 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2679,7 +2679,7 @@ boolean P_SetupLevel(boolean skipprecip) players[consoleplayer].viewz = 1; // Cancel all d_main.c fadeouts (keep fade in though). - wipegamestate = -2; + wipegamestate = FORCEWIPEOFF; // Special stage fade to white // This is handled BEFORE sounds are stopped. @@ -2723,18 +2723,27 @@ boolean P_SetupLevel(boolean skipprecip) // As oddly named as this is, this handles music only. // We should be fine starting it here. S_Start(); + } - // Let's fade to black here - // But only if we didn't do the special stage wipe - if (rendermode != render_none && !ranspecialwipe) - { - F_WipeStartScreen(); - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + // Let's fade to black here + // But only if we didn't do the special stage wipe + if (rendermode != render_none && !ranspecialwipe) + { + F_WipeStartScreen(); + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - F_WipeEndScreen(); - F_RunWipe(wipedefs[wipe_level_toblack], false); - } + F_WipeEndScreen(); + // for titlemap: run a specific wipe if specified + // needed for exiting time attack + if (wipetypepre != INT16_MAX) + F_RunWipe( + (wipetypepre >= 0 && F_WipeExists(wipetypepre)) ? wipetypepre : wipedefs[wipe_level_toblack], + false); + wipetypepre = -1; + } + if (!titlemapinaction) + { if (ranspecialwipe == 2) { pausedelay = -3; // preticker plus one diff --git a/src/p_spec.c b/src/p_spec.c index 44edec870..f8aefb9c8 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2619,7 +2619,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 413: // Change music // console player only unless NOCLIMB is set - if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player))) + if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player)) || titlemapinaction) { boolean musicsame = (!sides[line->sidenum[0]].text[0] || !strnicmp(sides[line->sidenum[0]].text, S_MusicName(), 7)); UINT16 tracknum = (UINT16)max(sides[line->sidenum[0]].bottomtexture, 0); @@ -2970,7 +2970,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { mobj_t *altview; - if (!mo || !mo->player) // only players have views + if ((!mo || !mo->player) && !titlemapinaction) // only players have views, and title screens return; if ((secnum = P_FindSectorFromLineTag(line, -1)) < 0) @@ -2980,6 +2980,14 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (!altview) return; + // If titlemap, set the camera ref for title's thinker + // This is not revoked until overwritten; awayviewtics is ignored + if (titlemapinaction) + { + titlemapcameraref = altview; + return; + } + P_SetTarget(&mo->player->awayviewmobj, altview); mo->player->awayviewtics = P_AproxDistance(line->dx, line->dy)>>FRACBITS; diff --git a/src/r_main.c b/src/r_main.c index f86c89b00..23dc39d62 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1322,6 +1322,7 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_grcoronasize); #endif CV_RegisterVar(&cv_grmd2); + CV_RegisterVar(&cv_grspritebillboarding); #endif #ifdef HWRENDER diff --git a/src/r_segs.c b/src/r_segs.c index b59d6ded2..03c5fb6e5 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -877,8 +877,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (leftheight > pfloorleft && rightheight > pfloorright && i+1 < dc_numlights) { lightlist_t *nextlight = &frontsector->lightlist[i+1]; - if (nextlight->slope ? P_GetZAt(nextlight->slope, ds->leftpos.x, ds->leftpos.y) : nextlight->height > pfloorleft - && nextlight->slope ? P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y) : nextlight->height > pfloorright) + if ((nextlight->slope ? P_GetZAt(nextlight->slope, ds->leftpos.x, ds->leftpos.y) : nextlight->height) > pfloorleft + && (nextlight->slope ? P_GetZAt(nextlight->slope, ds->rightpos.x, ds->rightpos.y) : nextlight->height) > pfloorright) continue; } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 2c8deddb4..b4f1a2a9d 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -580,8 +580,6 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) if (cv_usemouse.value) I_StartupMouse(); } //else firsttimeonmouse = SDL_FALSE; - - capslock = !!( SDL_GetModState() & KMOD_CAPS );// in case CL changes } else if (!mousefocus && !kbfocus) { @@ -939,6 +937,8 @@ void I_StartupMouse(void) // void I_OsPolling(void) { + SDL_Keymod mod; + if (consolevent) I_GetConsoleEvents(); if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) @@ -951,6 +951,18 @@ void I_OsPolling(void) I_GetMouseEvents(); I_GetEvent(); + + mod = SDL_GetModState(); + /* Handle here so that our state is always synched with the system. */ + shiftdown = ctrldown = altdown = 0; + capslock = false; + if (mod & KMOD_LSHIFT) shiftdown |= 1; + if (mod & KMOD_RSHIFT) shiftdown |= 2; + if (mod & KMOD_LCTRL) ctrldown |= 1; + if (mod & KMOD_RCTRL) ctrldown |= 2; + if (mod & KMOD_LALT) altdown |= 1; + if (mod & KMOD_RALT) altdown |= 2; + if (mod & KMOD_CAPS) capslock = true; } // @@ -984,6 +996,7 @@ void I_UpdateNoBlit(void) // from PrBoom's src/SDL/i_video.c static inline boolean I_SkipFrame(void) { +#if 0 static boolean skip = false; if (rendermode != render_soft) @@ -1003,6 +1016,8 @@ static inline boolean I_SkipFrame(void) default: return false; } +#endif + return false; } // diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index dde62fc7a..045e82b15 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -902,21 +902,10 @@ boolean I_LoadSong(char *data, size_t len) const char *key1 = "LOOP"; const char *key2 = "POINT="; const char *key3 = "MS="; - const char *key4 = "LENGTHMS="; const size_t key1len = strlen(key1); const size_t key2len = strlen(key2); const size_t key3len = strlen(key3); - const size_t key4len = strlen(key4); - // for mp3 wide chars - const char *key1w = "L\0O\0O\0P\0"; - const char *key2w = "P\0O\0I\0N\0T\0\0\0\xFF\xFE"; - const char *key3w = "M\0S\0\0\0\xFF\xFE"; - const char *key4w = "L\0E\0N\0G\0T\0H\0M\0S\0\0\0\xFF\xFE"; - const char *wterm = "\0\0"; - char wval[10]; - - size_t wstart, wp; char *p = data; SDL_RWops *rw; @@ -1062,61 +1051,8 @@ boolean I_LoadSong(char *data, size_t len) // Everything that uses LOOPMS will work perfectly with SDL_Mixer. } } - else if (fpclassify(song_length) == FP_ZERO && !strncmp(p, key4, key4len)) // is it LENGTHMS=? - { - p += key4len; // skip LENGTHMS - song_length = (float)(atoi(p) / 1000.0L); - } - // below: search MP3 or other tags that use wide char encoding - else if (fpclassify(loop_point) == FP_ZERO && !memcmp(p, key1w, key1len*2)) // LOOP wide char - { - p += key1len*2; - if (!memcmp(p, key2w, (key2len+1)*2)) // POINT= wide char - { - p += (key2len+1)*2; - wstart = (size_t)p; - wp = 0; - while (wp < 9 && memcmp(p, wterm, 2)) - { - wval[wp] = *p; - p += 2; - wp = ((size_t)(p-wstart))/2; - } - wval[min(wp, 9)] = 0; - loop_point = (float)((44.1L+atoi(wval) / 44100.0L)); - } - else if (!memcmp(p, key3w, (key3len+1)*2)) // MS= wide char - { - p += (key3len+1)*2; - wstart = (size_t)p; - wp = 0; - while (wp < 9 && memcmp(p, wterm, 2)) - { - wval[wp] = *p; - p += 2; - wp = ((size_t)(p-wstart))/2; - } - wval[min(wp, 9)] = 0; - loop_point = (float)(atoi(wval) / 1000.0L); - } - } - else if (fpclassify(song_length) == FP_ZERO && !memcmp(p, key4w, (key4len+1)*2)) // LENGTHMS= wide char - { - p += (key4len+1)*2; - wstart = (size_t)p; - wp = 0; - while (wp < 9 && memcmp(p, wterm, 2)) - { - wval[wp] = *p; - p += 2; - wp = ((size_t)(p-wstart))/2; - } - wval[min(wp, 9)] = 0; - song_length = (float)(atoi(wval) / 1000.0L); - } - if (fpclassify(loop_point) != FP_ZERO && fpclassify(song_length) != FP_ZERO && song_length > loop_point) // Got what we needed - // the last case is a sanity check, in case the wide char searches were false matches. + if (fpclassify(loop_point) != FP_ZERO) // Got what we needed break; else // continue searching p++; diff --git a/src/v_video.c b/src/v_video.c index 08f65e98b..29e5ecd6b 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -111,6 +111,7 @@ consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE| CV_FLOAT, 0, NULL, 0 static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NULL}}; // console variables in development consvar_t cv_grmd2 = {"gr_md2", "Off", CV_SAVE, CV_MD2, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif // local copy of the palette for V_GetColor() diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg index def2fe682..1880abf18 100644 --- a/src/win32/Makefile.cfg +++ b/src/win32/Makefile.cfg @@ -24,8 +24,10 @@ ifndef NOASM USEASM=1 endif +ifndef NONET ifndef MINGW64 #miniupnc is broken with MINGW64 HAVE_MINIUPNPC=1 +endif endif OPTS=-DSTDC_HEADERS diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 77a21f7f3..8b7adf7c6 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -639,9 +639,6 @@ void I_Error(const char *error, ...) if (!errorcount) { M_SaveConfig(NULL); // save game config, cvars.. -#ifndef NONET - D_SaveBan(); // save the ban list -#endif G_SaveGameData(); }