Rework the map command suite a little

The following funcs are now a suite with almost-identical argument lists.

- `map` is for immediately going to a map
    - Add `-random`/`-r`
- `queuemap` is for interacting with the live Round Queue
    - Add `-random`/`-r`
        - Performed server-side
    - `-clear` and `-show` now accept partial params `-c` and `-s`
    - Fix minor error with 0-argument print's text
- `showmap` is for printing information
    - Add arbitrary map name/ID input
        - `showmap robo` prints the course `map robo` would resolve to
    - Add `-gametype`/`-gt`/`-g`
        - For compatibility testing
    - Add `-random`/`-r`
        - Combine with `-gametype` for extra guarantees
- `randommap` was deprecated
    - Will only print replacement instructions of `map -random`, and nothing else
This commit is contained in:
toaster 2024-10-06 16:01:42 +01:00 committed by NepDisk
parent dd98ee93e2
commit 02ba3e2557
2 changed files with 267 additions and 119 deletions

View file

@ -5808,7 +5808,6 @@ static void PT_ReqMapQueue(int node)
CONS_Alert(CONS_ERROR, "Recieved REQMAPQUEUE, but unable to add map beyond %u\n", roundqueue.size);
// But this one does, because otherwise it's silent failure!
// Todo print the map's name, maybe?
char rejectmsg[256];
strlcpy(rejectmsg, "The server couldn't queue your chosen map.", 256);
SendServerNotice(reqmapqueue.source, rejectmsg);
@ -5816,6 +5815,43 @@ static void PT_ReqMapQueue(int node)
return;
}
if (reqmapqueue.newmapnum == NEXTMAP_VOTING)
{
/*UINT8 numPlayers = 0, i;
for (i = 0; i < MAXPLAYERS; ++i)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
extern consvar_t cv_forcebots; // debug
if (!(gametypes[reqmapqueue.newgametype]->rules & GTR_BOTS) && players[i].bot && !cv_forcebots.value)
{
// Gametype doesn't support bots
continue;
}
numPlayers++;
}*/
reqmapqueue.newmapnum = G_RandMap(G_TOLFlag(reqmapqueue.newgametype), UINT16_MAX, false, 0, false, NULL);
}
if (reqmapqueue.newmapnum >= nummapheaders)
{
CONS_Alert(CONS_ERROR, "Recieved REQMAPQUEUE, but unable to add map of invalid ID (%u)\n", reqmapqueue.newmapnum);
char rejectmsg[256];
strlcpy(rejectmsg, "The server couldn't queue your chosen map.", 256);
SendServerNotice(reqmapqueue.source, rejectmsg);
return;
}
G_AddMapToBuffer(reqmapqueue.newmapnum);
UINT8 buf[1+2+1];
UINT8 *buf_p = buf;

View file

@ -3653,6 +3653,7 @@ static void Command_Map_f(void)
size_t option_force;
size_t option_gametype;
size_t option_encore;
size_t option_random;
size_t option_skill;
boolean newresetplayers;
boolean newforcespecialstage;
@ -3661,7 +3662,7 @@ static void Command_Map_f(void)
INT32 newmapnum;
char * mapname;
char * mapname = NULL;
char *realmapname = NULL;
INT32 newgametype = gametype;
@ -3676,6 +3677,7 @@ static void Command_Map_f(void)
option_force = COM_CheckPartialParm("-f");
option_gametype = COM_CheckPartialParm("-g");
option_encore = COM_CheckPartialParm("-e");
option_random = COM_CheckPartialParm("-r");
option_skill = COM_CheckPartialParm("-s");
newresetplayers = ! COM_CheckParm("-noresetplayers");
newforcespecialstage = COM_CheckParm("-forcespecialstage");
@ -3715,31 +3717,17 @@ static void Command_Map_f(void)
if (!( first_option = COM_FirstOption() ))
first_option = COM_Argc();
if (first_option < 2)
if (!option_random && first_option < 2)
{
/* I'm going over the fucking lines and I DON'T CAREEEEE */
CONS_Printf("map <name / [MAP]code / number> [-gametype <type>] [-force]:\n");
CONS_Printf("map <name / number> [-gametype <type>] [-force] / [-random]:\n");
CONS_Printf(M_GetText(
"Warp to a map, by its name, two character code, with optional \"MAP\" prefix, or by its number (though why would you).\n"
"All parameters are case-insensitive and may be abbreviated.\n"));
return;
}
mapname = ConcatCommandArgv(1, first_option);
newmapnum = G_FindMapByNameOrCode(mapname, &realmapname);
if (newmapnum == 0)
{
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
Z_Free(mapname);
return;
}
if (mustmodifygame && option_force)
{
G_SetGameModified(multiplayer, true);
}
boolean getgametypefrommap = false;
// new gametype value
// use current one by default
@ -3751,15 +3739,23 @@ static void Command_Map_f(void)
return;
}
}
else if (!Playing())
else if (option_random)
{
newresetplayers = true;
if (mapheaderinfo[newmapnum-1])
if (!Playing())
{
// Let's just guess so we don't have to specify the gametype EVERY time...
newgametype = (mapheaderinfo[newmapnum-1]->typeoflevel & TOL_RACE) ? GT_RACE : GT_BATTLE;
CONS_Printf("Can't use -random from the menu without -gametype.\n");
return;
}
}
else if (!Playing() || (netgame == false && grandprixinfo.gp == true))
{
getgametypefrommap = true;
}
if (mustmodifygame && option_force)
{
G_SetGameModified(multiplayer, true);
}
// new encoremode value
if (option_encore)
@ -3773,11 +3769,69 @@ static void Command_Map_f(void)
}
}
if (!option_force && newgametype == gametype && Playing()) // SRB2Kart
if (option_random)
{
//UINT8 numPlayers = 0;
UINT16 oldmapnum = UINT16_MAX;
if (Playing())
{
//UINT8 i;
/*for (i = 0; i < MAXPLAYERS; ++i)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
extern consvar_t cv_forcebots; // debug
if (!(gametypes[newgametype]->rules & GTR_BOTS) && players[i].bot && !cv_forcebots.value)
{
// Gametype doesn't support bots
continue;
}
numPlayers++;
} */
oldmapnum = (gamestate == GS_LEVEL)
? (gamemap-1)
: prevmap;
}
newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, false, 0, false, NULL) + 1;
}
else
{
mapname = ConcatCommandArgv(1, first_option);
newmapnum = G_FindMapByNameOrCode(mapname, &realmapname);
if (newmapnum == 0)
{
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
Z_Free(mapname);
return;
}
}
if (getgametypefrommap)
{
if (mapheaderinfo[newmapnum-1])
{
// Let's just guess so we don't have to specify the gametype EVERY time...
newgametype = (mapheaderinfo[newmapnum-1]->typeoflevel & TOL_RACE) ? GT_RACE : GT_BATTLE;
}
}
if (!Playing())
newresetplayers = true;
else if (!option_force && newgametype == gametype) // SRB2Kart
newresetplayers = false; // if not forcing and gametypes is the same
// don't use a gametype the map doesn't support
if (cht_debug || option_force || cv_skipmapcheck.value)
if (option_random || cht_debug || option_force || cv_skipmapcheck.value)
{
// The player wants us to trek on anyway. Do so.
}
@ -4081,46 +4135,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
static void Command_RandomMap(void)
{
INT32 oldmapnum;
INT32 newmapnum;
INT32 newgametype;
boolean newencoremode;
boolean newresetplayers;
if (client && !IsPlayerAdmin(consoleplayer))
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
}
// TODO: Handle singleplayer conditions.
// The existing ones are way too annoyingly complicated and "anti-cheat" for my tastes.
if (Playing())
{
newgametype = gametype;
newencoremode = encoremode;
newresetplayers = false;
if (gamestate == GS_LEVEL)
{
oldmapnum = gamemap-1;
}
else
{
oldmapnum = prevmap;
}
}
else
{
newgametype = cv_newgametype.value;
newencoremode = false;
newresetplayers = true;
oldmapnum = NEXTMAP_INVALID;
}
newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, true, 0, false, NULL) + 1;
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false);
CONS_Printf("randommap is deprecated, please use \"map -random\" instead.\n");
}
static void Command_RestartLevel(void)
@ -4172,13 +4187,11 @@ static void Command_QueueMap_f(void)
size_t option_encore;
size_t option_clear;
size_t option_show;
boolean usingcheats;
boolean ischeating;
size_t option_random;
INT32 newmapnum;
char * mapname;
char * mapname = NULL;
char *realmapname = NULL;
INT32 newgametype = gametype;
@ -4196,19 +4209,10 @@ static void Command_QueueMap_f(void)
return;
}
usingcheats = CV_CheatsEnabled();
ischeating = (!(netgame || multiplayer) || !K_CanChangeRules(false));
option_clear = COM_CheckParm("-clear");
option_clear = COM_CheckPartialParm("-c");
if (option_clear)
{
if (ischeating && !usingcheats)
{
CONS_Printf(M_GetText("Cheats must be enabled.\n"));
return;
}
if (roundqueue.size == 0)
{
CONS_Printf(M_GetText("Round queue is already empty!\n"));
@ -4219,16 +4223,10 @@ static void Command_QueueMap_f(void)
return;
}
option_show = COM_CheckParm("-show");
option_show = COM_CheckPartialParm("-s");
if (option_show)
{
if (ischeating && !usingcheats)
{
CONS_Printf(M_GetText("Cheats must be enabled.\n"));
return;
}
Handle_MapQueueSend(0, ROUNDQUEUE_CMD_SHOW, false);
return;
}
@ -4242,44 +4240,21 @@ static void Command_QueueMap_f(void)
option_force = COM_CheckPartialParm("-f");
option_gametype = COM_CheckPartialParm("-g");
option_encore = COM_CheckPartialParm("-e");
option_random = COM_CheckPartialParm("-r");
if (!( first_option = COM_FirstOption() ))
first_option = COM_Argc();
if (first_option < 2)
if (!option_random && first_option < 2)
{
/* I'm going over the fucking lines and I DON'T CAREEEEE */
CONS_Printf("queuemap <name / number> [-gametype <type>] [-force] / [-clear] / [-spoil]:\n");
CONS_Printf("queuemap <name / number> [-gametype <type>] [-force] / [-random] / [-clear] / [-show]:\n");
CONS_Printf(M_GetText(
"Queue up a map by its name, or by its number (though why would you).\n"
"All parameters are case-insensitive and may be abbreviated.\n"));
return;
}
mapname = ConcatCommandArgv(1, first_option);
newmapnum = G_FindMapByNameOrCode(mapname, &realmapname);
if (newmapnum == 0)
{
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
Z_Free(mapname);
return;
}
if ((/*newmapnum != 1 &&*/ M_MapLocked(newmapnum)))
{
ischeating = true;
}
if (ischeating && !usingcheats)
{
CONS_Printf(M_GetText("Cheats must be enabled.\n"));
Z_Free(realmapname);
Z_Free(mapname);
return;
}
// new gametype value
// use current one by default
if (option_gametype)
@ -4298,17 +4273,34 @@ static void Command_QueueMap_f(void)
{
newencoremode = !newencoremode;
if (!M_SecretUnlocked(SECRET_ENCORE) && newencoremode == true && !usingcheats)
if (!M_SecretUnlocked(SECRET_ENCORE) && newencoremode == true && !option_force)
{
CONS_Alert(CONS_NOTICE, M_GetText("You haven't unlocked Encore Mode yet!\n"));
Z_Free(realmapname);
return;
}
}
if (option_random)
{
// Unlike map -random, this is a server side RNG roll
newmapnum = NEXTMAP_VOTING + 1;
}
else
{
mapname = ConcatCommandArgv(1, first_option);
newmapnum = G_FindMapByNameOrCode(mapname, &realmapname);
if (newmapnum == 0)
{
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
Z_Free(mapname);
return;
}
}
// don't use a gametype the map doesn't support
if (cht_debug || option_force || cv_skipmapcheck.value)
if (option_random || cht_debug || option_force || cv_skipmapcheck.value)
{
// The player wants us to trek on anyway. Do so.
}
@ -6702,12 +6694,105 @@ retryscramble:
static void Command_Showmap_f(void)
{
if (gamestate == GS_LEVEL)
UINT16 printmap = NEXTMAP_INVALID;
size_t first_option;
size_t option_random;
size_t option_gametype;
INT32 newgametype = gametype;
char * mapname = NULL;
char *realmapname = NULL;
option_gametype = COM_CheckPartialParm("-g");
option_random = COM_CheckPartialParm("-r");
if (!( first_option = COM_FirstOption() ))
first_option = COM_Argc();
if (option_gametype)
{
newgametype = GetGametypeParm(option_gametype);
if (newgametype == -1)
{
return;
}
}
if (option_random)
{
UINT8 numPlayers = 0;
UINT16 oldmapnum = UINT16_MAX;
if (Playing())
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; ++i)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
extern consvar_t cv_forcebots; // debug
if (!(gametypes[newgametype]->rules & GTR_BOTS) && players[i].bot && !cv_forcebots.value)
{
// Gametype doesn't support bots
continue;
}
numPlayers++;
}
oldmapnum = (gamestate == GS_LEVEL)
? (gamemap-1)
: prevmap;
}
else if (!option_gametype)
{
CONS_Printf("Can't use -random from the menu without -gametype.\n");
return;
}
printmap = G_RandMap(G_TOLFlag(newgametype), oldmapnum, false, 0, false, NULL);
}
else if (first_option < 2)
{
if (!Playing())
{
CONS_Printf(M_GetText("You must be in a game to use this.\n"));
return;
}
printmap = (gamestate == GS_LEVEL)
? gamemap-1
: prevmap;
}
else
{
mapname = ConcatCommandArgv(1, first_option);
printmap = G_FindMapByNameOrCode(mapname, &realmapname);
if (printmap == 0)
{
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
Z_Free(mapname);
return;
}
printmap--; // i hate the gamemap off-by-one system
}
if (printmap < nummapheaders && mapheaderinfo[printmap])
{
char *title = G_BuildMapTitle(printmap + 1);
if (mapheaderinfo[gamemap-1]->zonttl[0] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
{
if (mapheaderinfo[gamemap-1]->actnum[0])
CONS_Printf("%s (%d): %s %s %s\n", G_BuildMapName(gamemap), gamemap, mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl, mapheaderinfo[gamemap-1]->actnum);
CONS_Printf("%s (%d): %s %s %s", G_BuildMapName(gamemap), gamemap, mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl, mapheaderinfo[gamemap-1]->actnum);
else
CONS_Printf("%s (%d): %s %s\n", G_BuildMapName(gamemap), gamemap, mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl);
}
@ -6718,9 +6803,36 @@ static void Command_Showmap_f(void)
else
CONS_Printf("%s (%d): %s\n", G_BuildMapName(gamemap), gamemap, mapheaderinfo[gamemap-1]->lvlttl);
}
Z_Free(title);
if ((option_random || first_option < 2) && !option_gametype)
;
else if (mapheaderinfo[printmap]->typeoflevel & G_TOLFlag(newgametype))
{
CONS_Printf(" compatible with this gametype\n");
}
else
{
newgametype = G_GuessGametypeByTOL(mapheaderinfo[printmap]->typeoflevel);
if (newgametype == -1)
{
CONS_Printf(" NOT compatible with any known gametype\n");
}
else
{
CONS_Printf(" NOT compatible with this gametype (try \"%s\" instead)\n", gametypes[newgametype]->name);
}
}
}
else
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
{
CONS_Printf("Invalid map ID %u\n", printmap);
}
Z_Free(realmapname);
Z_Free(mapname);
}
static void Command_Maphash_f(void)