Dehardcode menu gametype selection, part 1

- Introduce `menugametype`
    - Controlled by IT_KEYHANDLER/M_HandleMenuGametype
    - Excludes gametypes that do not support multiplayer by default
        - GTR_CAPSULES and GTR_BOSS for now, but also user-specifiable GTR_NOMP
- Remove gametype_cons_t and G_UpdateGametypeSelections, an obstacle in the way of infinitely allocatable custom gametypes
This commit is contained in:
toaster 2022-12-30 15:23:26 +00:00
parent 52040c1248
commit 3ee8713e46
12 changed files with 89 additions and 57 deletions

View file

@ -3091,7 +3091,7 @@ static void Command_RandomMap(void)
}
else
{
newgametype = cv_dummygametype.value; // Changed from cv_newgametype to match newmenus
newgametype = menugametype;
newencoremode = false;
newresetplayers = true;
oldmapnum = -1;

View file

@ -920,9 +920,6 @@ void readgametype(MYFILE *f, char *gtname)
gametypes[numgametypes++] = newgametype;
// Update gametype_cons_t accordingly.
G_UpdateGametypeSelections();
CONS_Printf("Added gametype %s\n", gtname);
}

View file

@ -499,7 +499,7 @@ void DRPC_UpdatePresence(void)
else
{
snprintf(detailstr, 48, "%s%s%s",
gametype_cons_t[gametype].strvalue,
gametypes[gametype]->name,
(gametyperules & GTR_CIRCUIT) ? va(" | %s", kartspeed_cons_t[gamespeed].strvalue) : "",
(encoremode == true) ? " | Encore" : ""
);

View file

@ -519,11 +519,14 @@ enum GameTypeRules
GTR_CLOSERPLAYERS = 1<<21, // Buffs spindash and draft power to bring everyone together, nerfs invincibility and grow to prevent excessive combos
GTR_ENCORE = 1<<22, // Alternate Encore mirroring, scripting, and texture remapping
GTR_SPECIALSTART = 1<<23, // White fade instant start
GTR_NOMP = 1<<24, // No multiplayer
// free: to and including 1<<31
};
// Remember to update GAMETYPERULE_LIST in deh_soc.c
#define GTR_FORBIDMP (GTR_NOMP|GTR_CATCHER|GTR_BOSS)
// TODO: replace every instance
#define gametyperules (gametypes[gametype]->rules)

View file

@ -3186,23 +3186,6 @@ char *G_PrepareGametypeConstant(const char *newgtconst)
return gtconst;
}
//
// G_UpdateGametypeSelections
//
// Updates gametype_cons_t.
//
void G_UpdateGametypeSelections(void)
{
INT32 i;
for (i = 0; i < numgametypes; i++)
{
gametype_cons_t[i].value = i;
gametype_cons_t[i].strvalue = gametypes[i]->name;
}
gametype_cons_t[numgametypes].value = 0;
gametype_cons_t[numgametypes].strvalue = NULL;
}
tolinfo_t TYPEOFLEVEL[NUMTOLNAMES] = {
{"RACE",TOL_RACE},
{"BATTLE",TOL_BATTLE},

View file

@ -181,7 +181,6 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives);
void G_SetGametype(INT16 gametype);
char *G_PrepareGametypeConstant(const char *newgtconst);
void G_UpdateGametypeSelections(void);
void G_AddTOL(UINT32 newtol, const char *tolname);
INT32 G_GetGametypeByName(const char *gametypestr);
INT32 G_GuessGametypeByTOL(UINT32 tol);

View file

@ -16,7 +16,7 @@
#include "hu_stuff.h"
#include "font.h"
#include "k_menu.h" // gametype_cons_t
#include "k_menu.h" // highlightflags
#include "m_cond.h" // emblems
#include "m_misc.h" // word jumping

View file

@ -115,7 +115,8 @@ struct menucolor_t {
extern menucolor_t *menucolorhead, *menucolortail;
extern CV_PossibleValue_t gametype_cons_t[];
extern INT16 menugametype;
void M_HandleMenuGametype(INT32 choice);
//
// MENU TYPEDEFS
@ -770,7 +771,6 @@ void M_MPOptSelect(INT32 choice);
void M_MPOptSelectInit(INT32 choice);
void M_MPOptSelectTick(void);
boolean M_MPResetOpts(void);
extern consvar_t cv_dummygametype; // lazy hack to allow us to select the GT on the server host submenu
extern consvar_t cv_dummyip; // I HAVE
// HAVE YOUR IP ADDRESS (This just the hack Cvar we'll type into and then it apends itself to "connect" in the console for IP join)

View file

@ -362,8 +362,8 @@ menuitem_t PLAY_MP_Host[] =
{IT_STRING | IT_CVAR, "Max. Players", "Set how many players can play at once. Others will spectate.",
NULL, {.cvar = &cv_maxplayers}, 0, 0},
{IT_STRING | IT_CVAR, "Gamemode", "Are we racing? Or perhaps battling?",
NULL, {.cvar = &cv_dummygametype}, 0, 0},
{IT_STRING | IT_KEYHANDLER, "Gamemode", "Choose the type of play on your server.",
NULL, {.routine = M_HandleMenuGametype}, 0, 0},
{IT_STRING | IT_CALL, "GO", "Select a map with the currently selected gamemode",
NULL, {.routine = M_MPSetupNetgameMapSelect}, 0, 0},

View file

@ -2466,6 +2466,20 @@ void M_DrawMPHost(void)
}
break;
}
case IT_KEYHANDLER:
{
if (currentMenu->menuitems[i].itemaction.routine != M_HandleMenuGametype)
break;
w = V_ThinStringWidth(gametypes[menugametype]->name, V_6WIDTHSPACE);
V_DrawThinString(xp + 138 - w, yp, highlightflags|V_6WIDTHSPACE, gametypes[menugametype]->name);
if (i == itemOn)
{
V_DrawCharacter(xp + 138 - 10 - w - (skullAnimCounter/5), yp, '\x1C' | highlightflags, false); // left arrow
V_DrawCharacter(xp + 138 + 2 + (skullAnimCounter/5), yp, '\x1D' | highlightflags, false); // right arrow
}
break;
}
}
xp += 5;

View file

@ -147,10 +147,6 @@ consvar_t cv_menujam_update = CVAR_INIT ("menujam_update", "Off", CV_SAVE, CV_On
static CV_PossibleValue_t menujam_cons_t[] = {{0, "menu"}, {1, "menu2"}, {2, "menu3"}, {0, NULL}};
static consvar_t cv_menujam = CVAR_INIT ("menujam", "0", CV_SAVE, menujam_cons_t, NULL);
// This gametype list is integral for many different reasons.
// When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h!
CV_PossibleValue_t gametype_cons_t[MAXGAMETYPES+1];
static CV_PossibleValue_t serversort_cons_t[] = {
{0,"Ping"},
{1,"AVG. Power Level"},
@ -189,18 +185,18 @@ static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2
static CV_PossibleValue_t dummyspectate_cons_t[] = {{0, "Spectator"}, {1, "Playing"}, {0, NULL}};
static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}};
static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}};
static CV_PossibleValue_t dummygametype_cons_t[] = {{0, "Race"}, {1, "Battle"}, {0, NULL}};
//static consvar_t cv_dummymenuplayer = CVAR_INIT ("dummymenuplayer", "P1", CV_HIDDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange);
static consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDDEN, dummyteam_cons_t, NULL);
//static cv_dummyspectate = CVAR_INITconsvar_t ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL);
static consvar_t cv_dummyscramble = CVAR_INIT ("dummyscramble", "Random", CV_HIDDEN, dummyscramble_cons_t, NULL);
static consvar_t cv_dummystaff = CVAR_INIT ("dummystaff", "0", CV_HIDDEN|CV_CALL, dummystaff_cons_t, Dummystaff_OnChange);
consvar_t cv_dummygametype = CVAR_INIT ("dummygametype", "Race", CV_HIDDEN, dummygametype_cons_t, NULL);
consvar_t cv_dummyip = CVAR_INIT ("dummyip", "", CV_HIDDEN, NULL, NULL);
consvar_t cv_dummymenuplayer = CVAR_INIT ("dummymenuplayer", "P1", CV_HIDDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange);
consvar_t cv_dummyspectate = CVAR_INIT ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL);
INT16 menugametype = GT_RACE;
consvar_t cv_dummyprofilename = CVAR_INIT ("dummyprofilename", "", CV_HIDDEN, NULL, NULL);
consvar_t cv_dummyprofileplayername = CVAR_INIT ("dummyprofileplayername", "", CV_HIDDEN, NULL, NULL);
consvar_t cv_dummyprofilekickstart = CVAR_INIT ("dummyprofilekickstart", "Off", CV_HIDDEN, CV_OnOff, NULL);
@ -1715,7 +1711,6 @@ void M_Init(void)
CV_RegisterVar(&cv_dummyspectate);
CV_RegisterVar(&cv_dummyscramble);
CV_RegisterVar(&cv_dummystaff);
CV_RegisterVar(&cv_dummygametype);
CV_RegisterVar(&cv_dummyip);
CV_RegisterVar(&cv_dummyprofilename);
@ -4167,10 +4162,70 @@ void M_MPHostInit(INT32 choice)
itemOn = mhost_go;
}
void M_HandleMenuGametype(INT32 choice)
{
const UINT8 pid = 0;
const INT16 currentmenugametype = menugametype;
UINT32 forbidden = GTR_FORBIDMP;
(void)choice;
if (currentMenu->menuitems[itemOn].mvar1 != 0)
forbidden = currentMenu->menuitems[itemOn].mvar1;
if (menucmd[pid].dpad_lr > 0 || M_MenuConfirmPressed(pid))
{
do
{
menugametype++;
if (menugametype >= numgametypes)
menugametype = 0;
if (!(gametypes[menugametype]->rules & forbidden))
break;
} while (menugametype != currentmenugametype);
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
else if (menucmd[pid].dpad_lr < 0)
{
do
{
if (menugametype == 0)
menugametype = numgametypes;
menugametype--;
if (!(gametypes[menugametype]->rules & forbidden))
break;
} while (menugametype != currentmenugametype);
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
else if (M_MenuBackPressed(pid))
{
M_GoBack(0);
M_SetMenuDelay(pid);
return;
}
if (menucmd[pid].dpad_ud > 0)
{
M_NextOpt();
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
else if (menucmd[pid].dpad_ud < 0)
{
M_PrevOpt();
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
}
void M_MPSetupNetgameMapSelect(INT32 choice)
{
INT16 gt = GT_RACE;
(void)choice;
// Yep, we'll be starting a netgame.
@ -4181,26 +4236,10 @@ void M_MPSetupNetgameMapSelect(INT32 choice)
levellist.levelsearch.checklocked = true;
cupgrid.grandprix = false;
// In case we ever want to add new gamemodes there somehow, have at it!
switch (cv_dummygametype.value)
{
case 1: // Battle
{
gt = GT_BATTLE;
break;
}
default:
{
gt = GT_RACE;
break;
}
}
// okay this is REALLY stupid but this fixes the host menu re-folding on itself when we go back.
mpmenu.modewinextend[0][0] = 1;
M_LevelListFromGametype(gt); // Setup the level select.
M_LevelListFromGametype(menugametype); // Setup the level select.
// (This will also automatically send us to the apropriate menu)
}

View file

@ -3080,9 +3080,6 @@ static int lib_gAddGametype(lua_State *L)
gametypes[numgametypes++] = newgametype;
// Update gametype_cons_t accordingly.
G_UpdateGametypeSelections();
// done
CONS_Printf("Added gametype %s\n", gtname);
return 0;