A whole lot of refactoring and updates to cvars

cvar items now use their argument to specify the amount to add for each key
press, replacing IT_CV_INTEGERSTEP
cvar items are automatically displayed as strings if they don't have
PossibleValues, replacing IT_CV_STRING
This commit is contained in:
GenericHeroGuy 2025-06-12 22:11:07 +02:00
parent f30ddcfad2
commit e276709d0c
5 changed files with 133 additions and 164 deletions

View file

@ -536,7 +536,8 @@ consvar_t cv_votetime = CVAR_INIT ("votetime", "20", CV_NETVAR, votetime_cons_t,
consvar_t cv_gravity = CVAR_INIT ("gravity", "0.8", CV_RESTRICT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange); // change DEFAULT_GRAVITY if you change this
consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange);
static CV_PossibleValue_t soundtest_cons_t[] = {{0, "MIN"}, {NUMSFX, "MAX"}};
consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, soundtest_cons_t, SoundTest_OnChange);
static CV_PossibleValue_t minitimelimit_cons_t[] = {{15, "MIN"}, {9999, "MAX"}, {0, NULL}};
consvar_t cv_countdowntime = CVAR_INIT ("countdowntime", "30", CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL);

View file

@ -1972,13 +1972,9 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem)
}
else if (fastncmp(word, "CVAR", 4))
{
UINT16 flags = IT_CVAR;
UINT16 flags = IT_INTERACT;
if (fastcmp(word+4, "SLIDER"))
flags |= IT_CV_SLIDER;
else if (fastcmp(word+4, "STRING"))
flags |= IT_CV_STRING;
//else if (fastcmp(word+4, "INTEGER"))
//flags |= IT_CV_INTEGERSTEP;
flags |= IT_SLIDER;
else if (word[4])
{
WARN("unknown word '%s'", word);
@ -2009,17 +2005,14 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem)
WARN("unknown menu '%s'", word2);
continue;
}
status |= IT_INTERACT;
menuitem->submenu = mn;
}
else if (fastcmp(word, "CALL") || fastcmp(word, "ARROWS"))
{
UINT16 flags;
if (word[0] == 'C')
flags = IT_CALL;
else if (word[0] == 'A')
flags = IT_ARROWS;
else
I_Error("bruh"); // i should probably just make "CALL" the stem for all of these
UINT16 flags = IT_INTERACT;
if (word[0] == 'A')
flags |= IT_ARROWS;
menufunc_f *routine = get_menuroutine(word2);
if (!routine)

View file

@ -282,7 +282,7 @@ static void M_ChangeItemStatus(menutype_t type, const char *name, UINT16 flag, b
static boolean M_ItemSelectable(menuitem_t *item)
{
return !(item->status & (IT_HIDDEN|IT_GRAYEDOUT|IT_SECRET)) && (item->submenu || item->routine || item->cvar);
return (item->status & IT_INTERACT) && !(item->status & (IT_HIDDEN|IT_GRAYEDOUT|IT_SECRET));
}
// bruh...
@ -806,57 +806,57 @@ void M_InitMenuPresTables(void)
static UINT8 multi_spr2;
static void M_GetFollowerState(void);
static INT32 M_ChangeCvar(INT32 choice)
static void M_ResetCvar(menuitem_t *item)
{
consvar_t *cv = currentMenu->menuitems[itemOn].cvar;
consvar_t *cv = item->cvar;
if (choice == -1)
if (cv == &cv_playercolor[0] || cv == &cv_playercolor[1] || cv == &cv_playercolor[2] || cv == &cv_playercolor[3] || cv == &cv_dummycolor)
{
if (cv == &cv_playercolor[0] || cv == &cv_playercolor[1] || cv == &cv_playercolor[2] || cv == &cv_playercolor[3] || cv == &cv_dummycolor)
{
INT32 skinno = R_SkinAvailable(skins[cv_chooseskin.value].name);
if (skinno != -1 && skincolors[skins[skinno].prefcolor].accessible)
CV_SetValue(cv,skins[skinno].prefcolor);
return true;
}
CV_Set(cv,cv->defaultvalue);
return true;
}
choice = (choice<<1) - 1;
if ((currentMenu->menuitems[itemOn].status & IT_ACTION) == IT_CV_SLIDER)
{
CV_SetValue(cv,cv->value+choice);
}
else if (cv->flags & CV_FLOAT)
{
/*if (!(currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP))
{
char s[20];
float n = FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f);
sprintf(s,"%ld%s",(long)n,M_Ftrim(n));
CV_Set(cv,s);
}
else*/
CV_SetValue(cv,FIXED_TO_FLOAT(cv->value)+(choice));
INT32 skinno = R_SkinAvailable(skins[cv_chooseskin.value].name);
if (skinno != -1 && skincolors[skins[skinno].prefcolor].accessible)
CV_SetValue(cv, skins[skinno].prefcolor);
}
else
CV_AddValue(cv,choice);
CV_Set(cv, cv->defaultvalue);
}
static void M_ChangeCvar(menuitem_t *item, SINT8 direction)
{
consvar_t *cv = item->cvar;
INT32 amount = item->argument ? item->argument : cv->flags & CV_FLOAT ? FRACUNIT/16 : 1;
amount *= direction;
if (cv->flags & CV_FLOAT)
{
char s[20];
float n = FIXED_TO_FLOAT(cv->value + amount);
sprintf(s, "%ld%s", (long)n, M_Ftrim(n));
CV_Set(cv, s);
}
else
CV_AddValue(cv, amount);
if (cv == &cv_chooseskin)
multi_spr2 = P_GetSkinSprite2(&skins[cv->value], SPR2_FSTN, NULL);
else if (cv == &cv_dummyfollower)
M_GetFollowerState(); // update follower state
}
return true;
static UINT32 M_StringCvarLength(consvar_t *cv)
{
if (cv == &cv_dummyip)
return MAXIPADDRESSLEN;
else if (cv == &cv_dummyname || cv == &cv_playername[0] || cv == &cv_playername[1] || cv == &cv_playername[2] || cv == &cv_playername[3])
return MAXPLAYERNAME + 1;
else
return MAXSTRINGLENGTH;
}
static boolean M_ChangeStringCvar(INT32 choice)
{
consvar_t *cv = currentMenu->menuitems[itemOn].cvar;
char buf[MAXSTRINGLENGTH];
size_t len;
size_t len = strlen(cv->string);
if (shiftdown && choice >= 32 && choice <= 127)
choice = shiftxform[choice];
@ -864,7 +864,6 @@ static boolean M_ChangeStringCvar(INT32 choice)
switch (choice)
{
case KEY_BACKSPACE:
len = strlen(cv->string);
if (len > 0)
{
S_StartSound(NULL,sfx_menu1); // Tails
@ -880,33 +879,35 @@ static boolean M_ChangeStringCvar(INT32 choice)
CV_Set(cv, "");
}
return true;
case KEY_LEFTARROW:
case KEY_RIGHTARROW:
// TODO: navigation
return true;
default:
if (cv == &cv_dummyip)
{
// Rudimentary number and period enforcing - also allows letters so hostnames can be used instead
if (!((choice >= '-' && choice <= ':') || (choice >= 'A' && choice <= 'Z') || (choice >= 'a' && choice <= 'z'))
&& !(choice >= KEY_KEYPAD7 && choice <= KEY_KPADDEL && choice != KEY_MINUSPAD && choice != KEY_PLUSPAD)) //numpad too!
return false;
break;
if (choice >= KEY_KEYPAD7)
// sir, have you been golfing tonight?
choice = "789-456+1230."[choice - KEY_KEYPAD7];
}
if (choice >= 32 && choice <= 127)
if (choice < 32 || choice > 127)
break;
if (len < M_StringCvarLength(cv) - 1)
{
len = strlen(cv->string);
if (len < (cv == &cv_dummyip ? MAXIPADDRESSLEN : MAXSTRINGLENGTH) - 1)
{
S_StartSound(NULL,sfx_menu1); // Tails
M_Memcpy(buf, cv->string, len);
buf[len++] = (char)choice;
buf[len] = 0;
CV_Set(cv, buf);
}
return true;
S_StartSound(NULL, sfx_menu1); // Tails
M_Memcpy(buf, cv->string, len);
buf[len++] = (char)choice;
buf[len] = 0;
CV_Set(cv, buf);
}
break;
return true;
}
return false;
}
@ -991,7 +992,6 @@ boolean M_Responder(event_t *ev)
static tic_t joywait = 0, mousewait = 0;
static INT32 pmousex = 0, pmousey = 0;
static INT32 lastx = 0, lasty = 0;
menufunc_f *routine = NULL; // for some casting problem
INT32 deviceplayer = G_GetDevicePlayer(ev->device);
if (dedicated || (demo.playback && demo.title)
@ -1246,19 +1246,10 @@ boolean M_Responder(event_t *ev)
// BP: one of the more big hack i have never made
// G: not so hacky anymore...?
// G: nevermind we have combi menuitems now
UINT16 itemtype = 0;
if (currentMenu->numitems)
{
itemtype = currentMenu->menuitems[itemOn].status;
routine = currentMenu->menuitems[itemOn].routine;
}
if ((itemtype & (IT_CVAR|IT_CV_STRING)) == (IT_CVAR|IT_CV_STRING))
{
if (shiftdown && ch >= 32 && ch <= 127)
ch = shiftxform[ch];
if (M_ChangeStringCvar(ch))
return true;
}
menuitem_t *item = currentMenu->numitems ? &currentMenu->menuitems[itemOn] : NULL;
if (item && item->cvar && !item->cvar->PossibleValue && M_ChangeStringCvar(ch))
return true;
if (menustack[0] == MN_PLAYBACK && !con_destlines)
{
@ -1283,7 +1274,7 @@ boolean M_Responder(event_t *ev)
switch (ch)
{
case KEY_DOWNARROW:
if (!currentMenu->numitems)
if (!item)
return true;
do if (++itemOn >= currentMenu->numitems)
@ -1294,7 +1285,7 @@ boolean M_Responder(event_t *ev)
return true;
case KEY_UPARROW:
if (!currentMenu->numitems)
if (!item)
return true;
do if (--itemOn < 0)
@ -1305,24 +1296,24 @@ boolean M_Responder(event_t *ev)
return true;
case KEY_LEFTARROW:
if (itemtype & (IT_ARROWS|IT_CVAR) && !(itemtype & IT_CV_STRING))
{
if (menustack[0] != MN_OP_SOUND || itemOn > 3)
S_StartSound(NULL, sfx_menu1);
(itemtype & IT_ARROWS ? routine : M_ChangeCvar)(0);
}
return true;
case KEY_RIGHTARROW:
if (itemtype & (IT_ARROWS|IT_CVAR) && !(itemtype & IT_CV_STRING))
{
if (menustack[0] != MN_OP_SOUND || itemOn > 3)
S_StartSound(NULL, sfx_menu1);
(itemtype & IT_ARROWS ? routine : M_ChangeCvar)(1);
}
if (!item || !(item->cvar || item->status & IT_ARROWS))
return true;
if (menustack[0] != MN_OP_SOUND || itemOn > 3)
S_StartSound(NULL, sfx_menu1);
if (item->cvar)
M_ChangeCvar(item, ch == KEY_RIGHTARROW ? 1 : -1);
else
item->routine(ch == KEY_RIGHTARROW ? 1 : 0);
return true;
case KEY_ENTER:
if (!item)
return true;
noFurtherInput = true;
currentMenu->lastOn = itemOn;
@ -1334,24 +1325,24 @@ boolean M_Responder(event_t *ev)
playback_enterheld = 3;
}
INT32 argument = currentMenu->menuitems[itemOn].argument;
if (currentMenu->menuitems[itemOn].cvar)
argument = currentMenu->menuitems[itemOn].cvar->value;
INT32 argument = item->argument;
if (item->cvar)
argument = item->cvar->value;
if (currentMenu->menuitems[itemOn].submenu)
if (item->submenu)
{
S_StartSound(NULL, sfx_menu1);
M_EnterMenu(currentMenu->menuitems[itemOn].submenu, true, argument);
M_EnterMenu(item->submenu, true, argument);
}
else if (currentMenu->menuitems[itemOn].routine)
else if (item->routine)
{
S_StartSound(NULL, sfx_menu1);
routine(argument);
item->routine(argument);
}
else if (currentMenu->menuitems[itemOn].cvar && !(itemtype & IT_CV_STRING))
else if (item->cvar && item->cvar->PossibleValue) // not for string cvars!
{
S_StartSound(NULL, sfx_menu1);
M_ChangeCvar(1); // right arrow
M_ChangeCvar(item, 1); // right arrow
}
return true;
@ -1371,23 +1362,17 @@ boolean M_Responder(event_t *ev)
return true;
case KEY_BACKSPACE:
if (itemtype & IT_CVAR)
{
consvar_t *cv = currentMenu->menuitems[itemOn].cvar;
if (cv == &cv_chooseskin
|| cv == &cv_dummystaff
|| cv == &cv_nextmap
|| cv == &cv_newgametype
|| cv == &cv_dummymultiplayer)
return true;
if (menustack[0] != MN_OP_SOUND || itemOn > 3)
S_StartSound(NULL, sfx_menu1);
M_ChangeCvar(-1);
if (!item || !item->cvar
|| item->cvar == &cv_chooseskin
|| item->cvar == &cv_dummystaff
|| item->cvar == &cv_nextmap
|| item->cvar == &cv_newgametype
|| item->cvar == &cv_dummymultiplayer)
return true;
}
if (menustack[0] != MN_OP_SOUND || itemOn > 3)
S_StartSound(NULL, sfx_menu1);
M_ResetCvar(item);
return true;
default:
@ -2119,22 +2104,18 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo
(BASEVIDWIDTH-currentMenu->x, y, vflags|highlightflags, name);
}
if (item->status & IT_CVAR)
if (item->cvar)
{
consvar_t *cv = item->cvar;
switch(item->status & IT_ACTION)
if (!cv->PossibleValue) // string cvar?
{
case IT_CV_SLIDER:
M_DrawSlider(x, y, cv, selected);
break;
case IT_CV_STRING:
if (currentMenu->scrollheight && y + 12 > currentMenu->y + currentMenu->scrollheight)
break;
boolean side = vflags & MDF_TIMEATTACK || cv == &cv_dummyname;
INT32 xofs = side ? 32 : 0;
INT32 yofs = side ? -8 : 4;
w = side ? MAXPLAYERNAME : cv == &cv_dummyip ? MAXIPADDRESSLEN : MAXSTRINGLENGTH;
w = M_StringCvarLength(cv);
M_DrawTextBox(x + xofs, y + yofs, w, 1);
V_DrawString(x + xofs + 8, y + yofs + 8, vflags|V_ALLOWLOWERCASE, cv->string);
@ -2144,8 +2125,12 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo
if (!side)
y += 16;
break;
default:
}
else if (item->status & IT_SLIDER)
{
M_DrawSlider(x, y, cv, selected);
}
else
{
const char *str = cv->string;
INT32 soffset = vflags & MDF_TIMEATTACK && cv != &cv_nextmap ? 40 : 0;
@ -2191,12 +2176,10 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo
V_DrawCharacter(BASEVIDWIDTH - x - soffset + 2 + (skullAnimCounter/5), y,
'\x1D' | highlightflags | strvf, false); // right arrow
}
break;
}
}
break;
}
else if (item->status & IT_CALL)
else if (item->routine)
{
char tmp[32*MAXINPUTMAPPING]; // should be enough :^)
INT32 key;

View file

@ -155,37 +155,29 @@ void M_QuitResponse(INT32 ch);
// Determines whether to show a level in the list (platter version does not need to be exposed)
boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt);
// flags for items in the menu
// menu handle (what we do when key is pressed
#define IT_CALL 1 // call the function
#define IT_ARROWS 2 // call function with 0 for left arrow and 1 for right arrow in param
//#define IT_SUBMENU 4 // go to sub menu
#define IT_CVAR 8192 // handle as a cvar
typedef enum
{
IT_INTERACT = 1<<0, // item can be interacted with
IT_HIDDEN = 1<<1, // item is invisible and cannot be interacted with (has priority over IT_INTERACT)
IT_GRAYEDOUT = 1<<2, // item is grayed out and non-interactible
IT_SECRET = 1<<3, // item text is displayed with question marks and non-interactible
// display flags
#define IT_DISPLAY (8+16+32)
#define IT_PATCH 8 // a patch or a string with big font
#define IT_STRING 16 // little string (spaced with 10)
#define IT_WHITESTRING 32 // little string in white
#define IT_HEADERTEXT (8+32) // Non-selectable header option, displays in yellow offset to the left a little
IT_ARROWS = 1<<4, // call-type items use arrow keys instead of enter
IT_SLIDER = 1<<5, // cvar-type items display a slider
// flags specific to each item action type
#define IT_ACTION (64+128+256)
IT_PATCH = 1<<6, // display a patch
IT_STRING = 1<<7, // display a string
IT_WHITESTRING = 1<<8, // displays a string with highlighted text
IT_HEADERTEXT = IT_PATCH|IT_WHITESTRING,
IT_DISPLAY = IT_PATCH|IT_STRING|IT_WHITESTRING,
//consvar specific
#define IT_CV_SLIDER 64
#define IT_CV_STRING 128
//#define IT_CV_INTEGERSTEP 256 // if cvar is CV_FLOAT, modify it by 1 instead of 0.0625
IT_OFSX = 1<<9, // X coordinate is relative to current position
IT_OFSY = 1<<10, // ditto
IT_TEMPORARY = 1<<11, // with IT_OFS*, offset applies only to this item
IT_OVERLAY = 1<<12, // item is drawn at absolute coordinates, without scrolling
// extra flags
#define IT_CENTER 512 // if IT_PATCH, center it on screen
#define IT_HIDDEN 1024 // invisible, unselectable
#define IT_GRAYEDOUT 2048 // grayed out, unselectable
#define IT_SECRET 4096 // ??????? ????????????
#define IT_OFSX 16384 // x coordinate is relative
#define IT_OFSY 32768 // ditto
#define IT_TEMPORARY 4 // offset is only applied temporarily
#define IT_OVERLAY 256 // no scrolling, draw at absolute coordinates
IT_CENTER = 1<<13, // centered text/patch
} menuitemflags_t;
// carefully chosen to not conflict with V_ flags
#define MDF_CENTERED 0x20

View file

@ -2618,17 +2618,17 @@ static CV_PossibleValue_t CV_CamSpeed[] = {{0, "MIN"}, {1*FRACUNIT, "MAX"}, {0,
static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}};
consvar_t cv_cam_dist[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("cam_dist", "190", CV_FLOAT|CV_SAVE, NULL, NULL),
CVAR_INIT ("cam2_dist", "190", CV_FLOAT|CV_SAVE, NULL, NULL),
CVAR_INIT ("cam3_dist", "190", CV_FLOAT|CV_SAVE, NULL, NULL),
CVAR_INIT ("cam4_dist", "190", CV_FLOAT|CV_SAVE, NULL, NULL)
CVAR_INIT ("cam_dist", "190", CV_FLOAT|CV_SAVE, CV_Signed, NULL),
CVAR_INIT ("cam2_dist", "190", CV_FLOAT|CV_SAVE, CV_Signed, NULL),
CVAR_INIT ("cam3_dist", "190", CV_FLOAT|CV_SAVE, CV_Signed, NULL),
CVAR_INIT ("cam4_dist", "190", CV_FLOAT|CV_SAVE, CV_Signed, NULL)
};
consvar_t cv_cam_height[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("cam_height", "75", CV_FLOAT|CV_SAVE, NULL, NULL),
CVAR_INIT ("cam2_height", "75", CV_FLOAT|CV_SAVE, NULL, NULL),
CVAR_INIT ("cam3_height", "75", CV_FLOAT|CV_SAVE, NULL, NULL),
CVAR_INIT ("cam4_height", "75", CV_FLOAT|CV_SAVE, NULL, NULL)
CVAR_INIT ("cam_height", "75", CV_FLOAT|CV_SAVE, CV_Signed, NULL),
CVAR_INIT ("cam2_height", "75", CV_FLOAT|CV_SAVE, CV_Signed, NULL),
CVAR_INIT ("cam3_height", "75", CV_FLOAT|CV_SAVE, CV_Signed, NULL),
CVAR_INIT ("cam4_height", "75", CV_FLOAT|CV_SAVE, CV_Signed, NULL)
};
consvar_t cv_cam_still[MAXSPLITSCREENPLAYERS] = {