Merge branch 'cycle-command' into 'master'

Toggle cvar between multiple values

See merge request KartKrew/Kart!688
This commit is contained in:
Sal 2022-09-24 02:31:36 +00:00
commit e9a87aaa43
2 changed files with 123 additions and 73 deletions

View file

@ -1024,15 +1024,17 @@ static void COM_Help_f(void)
/** Toggles a console variable. Useful for on/off values. /** Toggles a console variable. Useful for on/off values.
* *
* This works on on/off, yes/no values only * This works on on/off, yes/no values by default. Given
* a list of values, cycles between them.
*/ */
static void COM_Toggle_f(void) static void COM_Toggle_f(void)
{ {
consvar_t *cvar; consvar_t *cvar;
if (COM_Argc() != 2) if (COM_Argc() == 1 || COM_Argc() == 3)
{ {
CONS_Printf(M_GetText("Toggle <cvar_name>: Toggle the value of a cvar\n")); CONS_Printf(M_GetText("Toggle <cvar_name>: Toggle the value of a cvar\n"));
CONS_Printf("Toggle <cvar_name> <value1> <value2>...: Cycle along a set of values\n");
return; return;
} }
cvar = CV_FindVar(COM_Argv(1)); cvar = CV_FindVar(COM_Argv(1));
@ -1042,15 +1044,44 @@ static void COM_Toggle_f(void)
return; return;
} }
if (!(cvar->PossibleValue == CV_YesNo || cvar->PossibleValue == CV_OnOff)) if (COM_Argc() == 2)
{ {
CONS_Alert(CONS_NOTICE, M_GetText("%s is not a boolean value\n"), COM_Argv(1)); if (!(cvar->PossibleValue == CV_YesNo || cvar->PossibleValue == CV_OnOff))
return; {
CONS_Alert(CONS_NOTICE, M_GetText("%s is not a boolean value\n"), COM_Argv(1));
return;
}
} }
// netcvar don't change imediately // netcvar don't change imediately
cvar->flags |= CV_SHOWMODIFONETIME; cvar->flags |= CV_SHOWMODIFONETIME;
CV_AddValue(cvar, +1);
if (COM_Argc() == 2)
{
CV_AddValue(cvar, +1);
}
else
{
size_t i;
for (i = 2; i < COM_Argc() - 1; ++i)
{
const char *str = COM_Argv(i);
INT32 val;
if (CV_CompleteValue(cvar, &str, &val))
{
if (str ? !stricmp(cvar->string, str)
: cvar->value == val)
{
CV_Set(cvar, COM_Argv(i + 1));
return;
}
}
}
CV_Set(cvar, COM_Argv(2));
}
} }
/** Command variant of CV_AddValue /** Command variant of CV_AddValue
@ -1424,26 +1455,27 @@ const char *CV_CompleteVar(char *partial, INT32 skips)
return NULL; return NULL;
} }
/** Sets a value to a variable with less checking. Only for internal use. boolean CV_CompleteValue(consvar_t *var, const char **valstrp, INT32 *intval)
*
* \param var Variable to set.
* \param valstr String value for the variable.
*/
static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
{ {
boolean override = false; const char *valstr = *valstrp;
INT32 overrideval = 0; INT32 overrideval = 0;
// If we want messages informing us if cheats have been enabled or disabled, INT32 v;
// we need to rework the consvars a little bit. This call crashes the game
// on load because not all variables will be registered at that time. if (var == &cv_forceskin)
/* boolean prevcheats = false; {
if (var->flags & CV_CHEAT) v = R_SkinAvailable(valstr);
prevcheats = CV_CheatsEnabled(); */
if (!R_SkinUsable(-1, v))
v = -1;
goto finish;
}
if (var->PossibleValue) if (var->PossibleValue)
{ {
INT32 v; INT32 i;
if (var->flags & CV_FLOAT) if (var->flags & CV_FLOAT)
{ {
@ -1464,7 +1496,6 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
{ {
#define MINVAL 0 #define MINVAL 0
#define MAXVAL 1 #define MAXVAL 1
INT32 i;
#ifdef PARANOIA #ifdef PARANOIA
if (!var->PossibleValue[MAXVAL].strvalue) if (!var->PossibleValue[MAXVAL].strvalue)
I_Error("Bounded cvar \"%s\" without maximum!\n", var->name); I_Error("Bounded cvar \"%s\" without maximum!\n", var->name);
@ -1473,52 +1504,26 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
// search for other // search for other
for (i = MAXVAL+1; var->PossibleValue[i].strvalue; i++) for (i = MAXVAL+1; var->PossibleValue[i].strvalue; i++)
if (v == var->PossibleValue[i].value || !stricmp(var->PossibleValue[i].strvalue, valstr)) if (v == var->PossibleValue[i].value || !stricmp(var->PossibleValue[i].strvalue, valstr))
{ goto found;
if (client && execversion_enabled)
{
if (var->revert.allocated)
{
Z_Free(var->revert.v.string);
var->revert.allocated = false; // the below value is not allocated in zone memory, don't try to free it!
}
var->revert.v.const_munge = var->PossibleValue[i].strvalue;
return;
}
// free the old value string
Z_Free(var->zstring);
var->zstring = NULL;
var->value = var->PossibleValue[i].value;
var->string = var->PossibleValue[i].strvalue;
goto finish;
}
if ((v != INT32_MIN && v < var->PossibleValue[MINVAL].value) || !stricmp(valstr, "MIN")) if ((v != INT32_MIN && v < var->PossibleValue[MINVAL].value) || !stricmp(valstr, "MIN"))
{ {
v = var->PossibleValue[MINVAL].value; i = MINVAL;
valstr = var->PossibleValue[MINVAL].strvalue; goto found;
override = true;
overrideval = v;
} }
else if ((v != INT32_MIN && v > var->PossibleValue[MAXVAL].value) || !stricmp(valstr, "MAX")) else if ((v != INT32_MIN && v > var->PossibleValue[MAXVAL].value) || !stricmp(valstr, "MAX"))
{ {
v = var->PossibleValue[MAXVAL].value; i = MAXVAL;
valstr = var->PossibleValue[MAXVAL].strvalue; goto found;
override = true;
overrideval = v;
} }
if (v == INT32_MIN) if (v == INT32_MIN)
goto badinput; goto badinput;
valstr = NULL; // not a preset value
#undef MINVAL #undef MINVAL
#undef MAXVAL #undef MAXVAL
} }
else else
{ {
INT32 i;
// check first strings // check first strings
for (i = 0; var->PossibleValue[i].strvalue; i++) for (i = 0; var->PossibleValue[i].strvalue; i++)
if (!stricmp(var->PossibleValue[i].strvalue, valstr)) if (!stricmp(var->PossibleValue[i].strvalue, valstr))
@ -1550,27 +1555,69 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
// ...or not. // ...or not.
goto badinput; goto badinput;
found: found:
if (client && execversion_enabled) v = var->PossibleValue[i].value;
{ valstr = var->PossibleValue[i].strvalue;
var->revert.v.const_munge = var->PossibleValue[i].strvalue; }
return;
}
var->value = var->PossibleValue[i].value; finish:
var->string = var->PossibleValue[i].strvalue; if (intval)
goto finish; *intval = v;
*valstrp = valstr;
return true;
}
// landing point for possiblevalue failures
badinput:
return false;
}
/** Sets a value to a variable with less checking. Only for internal use.
*
* \param var Variable to set.
* \param valstr String value for the variable.
*/
static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
{
boolean override = false;
INT32 overrideval = 0;
// If we want messages informing us if cheats have been enabled or disabled,
// we need to rework the consvars a little bit. This call crashes the game
// on load because not all variables will be registered at that time.
/* boolean prevcheats = false;
if (var->flags & CV_CHEAT)
prevcheats = CV_CheatsEnabled(); */
const char *overridestr = valstr;
if (CV_CompleteValue(var, &overridestr, &overrideval))
{
if (overridestr)
{
valstr = overridestr;
override = true;
} }
} }
else if (var->PossibleValue)
goto badinput;
if (client && execversion_enabled) if (client && execversion_enabled)
{ {
if (var->revert.allocated) if (var->revert.allocated)
{ {
Z_Free(var->revert.v.string); Z_Free(var->revert.v.string);
// Z_StrDup creates a new zone memory block, so we can keep the allocated flag on // Z_StrDup creates a new zone memory block, so we can keep the allocated flag on
if (override)
var->revert.allocated = false; // the below value is not allocated in zone memory, don't try to free it!
} }
var->revert.v.string = Z_StrDup(valstr); if (override)
var->revert.v.const_munge = valstr;
else
var->revert.v.string = Z_StrDup(valstr);
return; return;
} }
@ -1578,28 +1625,25 @@ found:
// free the old value string // free the old value string
Z_Free(var->zstring); Z_Free(var->zstring);
var->string = var->zstring = Z_StrDup(valstr);
if (override) if (override)
var->value = overrideval;
else if (var->flags & CV_FLOAT)
{ {
double d = atof(var->string); var->zstring = NULL;
var->value = (INT32)(d * FRACUNIT); var->value = overrideval;
var->string = valstr;
} }
else else
{ {
if (var == &cv_forceskin) var->string = var->zstring = Z_StrDup(valstr);
if (var->flags & CV_FLOAT)
{ {
var->value = R_SkinAvailable(var->string); double d = atof(var->string);
if (!R_SkinUsable(-1, var->value)) var->value = (INT32)(d * FRACUNIT);
var->value = -1;
} }
else else
var->value = atoi(var->string); var->value = atoi(var->string);
} }
finish:
// See the note above. // See the note above.
/* if (var->flags & CV_CHEAT) /* if (var->flags & CV_CHEAT)
{ {

View file

@ -194,6 +194,12 @@ void CV_ClearChangedFlags(void);
// returns the name of the nearest console variable name found // returns the name of the nearest console variable name found
const char *CV_CompleteVar(char *partial, INT32 skips); const char *CV_CompleteVar(char *partial, INT32 skips);
// Returns true if valstrp is within the PossibleValues of
// var. If an exact string value exists, it is returned in
// valstrp. An integer value is returned in intval if it
// is not NULL.
boolean CV_CompleteValue(consvar_t *var, const char **valstrp, INT32 *intval);
// equivalent to "<varname> <value>" typed at the console // equivalent to "<varname> <value>" typed at the console
void CV_Set(consvar_t *var, const char *value); void CV_Set(consvar_t *var, const char *value);