Merge branch 'menu-execs' into 'master'

New title screen features

See merge request STJr/SRB2Internal!204
This commit is contained in:
Digiku 2019-05-03 03:48:39 -04:00
commit 271e0eb5b7
12 changed files with 1360 additions and 191 deletions

View File

@ -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();

View File

@ -234,6 +234,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 +270,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 +282,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 +374,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 +490,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 +761,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 +1137,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 +1430,7 @@ void D_SRB2Main(void)
}
else if (M_CheckParm("-skipintro"))
{
F_InitMenuPresValues();
F_StartTitleScreen();
}
else

View File

@ -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);
@ -3174,9 +3330,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"))
@ -3724,6 +3885,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)
@ -7778,6 +7952,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!!
@ -8479,6 +8743,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
@ -8675,6 +8953,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);
@ -9143,6 +9426,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.

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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
{

View File

@ -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
}

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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,\

View File

@ -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

View File

@ -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;