From 02ba3e2557a28da975b02d1c7da7413b31742aeb Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Oct 2024 16:01:42 +0100 Subject: [PATCH] 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 --- src/d_clisrv.c | 38 +++++- src/d_netcmd.c | 348 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 267 insertions(+), 119 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 4081e8655..ffc956904 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -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; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 07e42f032..cea0ca727 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -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 [-gametype ] [-force]:\n"); + CONS_Printf("map [-gametype ] [-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 [-gametype ] [-force] / [-clear] / [-spoil]:\n"); + CONS_Printf("queuemap [-gametype ] [-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)