From d2172fc54b64852448007b370111632015fd7498 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 7 May 2020 02:37:06 -0400 Subject: [PATCH] Bot amount & difficulty is now controlled by cvars --- src/d_clisrv.c | 21 +++- src/d_netcmd.c | 8 ++ src/d_netcmd.h | 1 + src/k_bot.c | 335 ++++++++++++++++++++++++++++++++++++++++--------- src/k_bot.h | 3 +- src/k_kart.c | 1 + src/p_mobj.c | 13 +- src/p_setup.c | 4 + 8 files changed, 324 insertions(+), 62 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 45627d3a2..406c07150 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2687,7 +2687,7 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) demo_extradata[playernum] |= DXD_PLAYSTATE; - if (server && !demo.playback) + if (server && !demo.playback && !players[playernum].bot) { INT32 node = playernode[playernum]; //playerpernode[node] = 0; // It'd be better to remove them all at once, but ghosting happened, so continue to let CL_RemovePlayer do it one-by-one @@ -3696,6 +3696,7 @@ static boolean SV_AddWaitingPlayers(void) { UINT8 buf[4]; UINT8 *buf_p = buf; + UINT8 nobotoverwrite; newplayer = true; @@ -3713,6 +3714,21 @@ static boolean SV_AddWaitingPlayers(void) break; } + nobotoverwrite = newplayernum; + + while (playeringame[nobotoverwrite] + && players[nobotoverwrite].bot + && nobotoverwrite < MAXPLAYERS) + { + // Only overwrite bots if there are NO other slots available. + nobotoverwrite++; + } + + if (nobotoverwrite < MAXPLAYERS) + { + newplayernum = nobotoverwrite; + } + // should never happen since we check the playernum // before accepting the join I_Assert(newplayernum < MAXPLAYERS); @@ -3801,9 +3817,6 @@ boolean SV_SpawnServer(void) if (!dedicated) CL_ConnectToServer(false); else doomcom->numslots = 1; - - // TEST - K_AddBots(7); } return SV_AddWaitingPlayers(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 82892c9c2..12d246405 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -392,6 +392,14 @@ consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedome static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; consvar_t cv_kartvoices = {"kartvoices", "Tasteful", CV_SAVE, kartvoices_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t kartbot_cons_t[] = { + {1, "MIN"}, + {9, "MAX"}, + {0, "Off"}, + {0, NULL} +}; +consvar_t cv_kartbot = {"kartbot", "5", CV_NETVAR|CV_CHEAT, kartbot_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + consvar_t cv_karteliminatelast = {"karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOSHOWHELP, CV_YesNo, KartEliminateLast_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartusepwrlv = {"kartusepwrlv", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index b5d723756..cdd54bd87 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -121,6 +121,7 @@ extern consvar_t cv_kartencore; extern consvar_t cv_kartvoterulechanges; extern consvar_t cv_kartspeedometer; extern consvar_t cv_kartvoices; +extern consvar_t cv_kartbot; extern consvar_t cv_karteliminatelast; extern consvar_t cv_kartusepwrlv; diff --git a/src/k_bot.c b/src/k_bot.c index 52731769b..13f5873ea 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -24,92 +24,315 @@ #include "i_system.h" #include "p_maputl.h" #include "d_ticcmd.h" +#include "m_random.h" +#include "r_things.h" // numskins -void K_AddBots(SINT8 numbots) +boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p) { - UINT8 newplayernum = 0; - UINT8 difficulty = MAXBOTDIFFICULTY; + UINT8 buf[3]; + UINT8 *buf_p = buf; + UINT8 newplayernum = *p; - if (dedicated) - newplayernum = 1; - - while (numbots > 0) + // search for a free playernum + // we can't use playeringame since it is not updated here + for (; newplayernum < MAXPLAYERS; newplayernum++) { - UINT8 buf[3]; - UINT8 *buf_p = buf; + UINT8 n; - numbots--; - - // search for a free playernum - // we can't use playeringame since it is not updated here - for (; newplayernum < MAXPLAYERS; newplayernum++) - { - UINT8 n; - - for (n = 0; n < MAXNETNODES; n++) - if (nodetoplayer[n] == newplayernum - || nodetoplayer2[n] == newplayernum - || nodetoplayer3[n] == newplayernum - || nodetoplayer4[n] == newplayernum) - break; - - if (n == MAXNETNODES) + for (n = 0; n < MAXNETNODES; n++) + if (nodetoplayer[n] == newplayernum + || nodetoplayer2[n] == newplayernum + || nodetoplayer3[n] == newplayernum + || nodetoplayer4[n] == newplayernum) break; + + if (n == MAXNETNODES) + break; + } + + while (playeringame[newplayernum] + && players[newplayernum].bot + && newplayernum < MAXPLAYERS) + { + newplayernum++; + } + + if (newplayernum >= MAXPLAYERS) + { + *p = newplayernum; + return false; + } + + WRITEUINT8(buf_p, newplayernum); + + if (skin > numskins) + { + skin = numskins; + } + + WRITEUINT8(buf_p, skin); + + if (difficulty < 1) + { + difficulty = 1; + } + else if (difficulty > MAXBOTDIFFICULTY) + { + difficulty = MAXBOTDIFFICULTY; + } + + WRITEUINT8(buf_p, difficulty); + + SendNetXCmd(XD_ADDBOT, buf, buf_p - buf); + + DEBFILE(va("Server added bot %d\n", newplayernum)); + // use the next free slot (we can't put playeringame[newplayernum] = true here) + newplayernum++; + + *p = newplayernum; + return true; +} + +void K_UpdateMatchRaceBots(void) +{ + const UINT8 difficulty = cv_kartbot.value; + UINT8 pmax = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value); + UINT8 numplayers = 0; + UINT8 numbots = 0; + UINT8 numwaiting = 0; + SINT8 wantedbots = 0; + UINT8 i; + + if (difficulty != 0) + { + if (cv_ingamecap.value > 0) + { + pmax = min(pmax, cv_ingamecap.value); } - WRITEUINT8(buf_p, newplayernum); + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + if (!players[i].spectator) + { + if (players[i].bot) + { + numbots++; - // test skins - if (numbots == 6) - { - difficulty = MAXBOTDIFFICULTY; - WRITEUINT8(buf_p, 1); + // While we're here, we should update bot difficulty to the proper value. + players[i].botvars.difficulty = difficulty; + } + else + { + numplayers++; + } + } + else if (players[i].pflags & PF_WANTSTOJOIN) + { + numwaiting++; + } + } } - else if (numbots == 5) + + wantedbots = pmax - numplayers - numwaiting; + + if (wantedbots < 0) { - difficulty = MAXBOTDIFFICULTY; - WRITEUINT8(buf_p, 0); + wantedbots = 0; } - else if (numbots == 4) + } + else + { + wantedbots = 0; + } + + if (numbots < wantedbots) + { + // We require MORE bots! + UINT8 newplayernum = 0; + + if (dedicated) { - difficulty = MAXBOTDIFFICULTY-1; - WRITEUINT8(buf_p, 2); + newplayernum = 1; } - else if (numbots == 3) + + while (numbots < wantedbots) { - difficulty = MAXBOTDIFFICULTY-2; - WRITEUINT8(buf_p, 3); + if (!K_AddBot(M_RandomKey(numskins), difficulty, &newplayernum)) + { + // Not enough player slots to add the bot, break the loop. + break; + } + + numbots++; } - else if (numbots == 2) + } + else if (numbots > wantedbots) + { + UINT8 buf[2]; + + i = 0; + + while (numbots > wantedbots && i < MAXPLAYERS) { - difficulty = MAXBOTDIFFICULTY-4; - WRITEUINT8(buf_p, 5); + if (playeringame[i] && players[i].bot) + { + buf[0] = i; + buf[1] = KR_LEAVE; + SendNetXCmd(XD_REMOVEPLAYER, &buf, 2); + + CONS_Printf("Removed bot %s\n", player_names[i]); + numbots--; + } + + i++; } - else if (numbots == 1) + } + + // We should have enough bots now :) +} + +#if 0 +// This is mostly just pesudo code right now... +void K_InitGrandPrixBots(void) +{ + const UINT8 defaultbotskin = 9; // eggrobo + + // startingdifficulty: Easy = 3, Normal = 6, Hard = 9 + const UINT8 startingdifficulty = min(MAXBOTDIFFICULTY, (cv_kartspeed.value + 1) * 3); + UINT8 difficultylevels[MAXPLAYERS]; + + UINT8 playercount = 8; + UINT8 wantedbots = 0; + + UINT8 numplayers = 0; + UINT8 competitors[4]; + + boolean skinusable[MAXSKINS]; + UINT8 botskinlist[MAXPLAYERS]; + UINT8 botskinlistpos = 0; + + UINT8 i; + + memset(difficultylevels, MAXBOTDIFFICULTY, sizeof (difficultylevels)); + memset(competitors, MAXPLAYERS, sizeof (competitors)); + memset(botskinlist, defaultbotskin, sizeof (botskinlist)); + + // init usable bot skins list + for (i = 0; i < MAXSKINS; i++) + { + if (i < numskins) { - difficulty = MAXBOTDIFFICULTY-4; - WRITEUINT8(buf_p, 9); + skinusable[i] = true; } else { - difficulty = MAXBOTDIFFICULTY-2; - WRITEUINT8(buf_p, 10); + skinusable[i] = false; } + } - WRITEUINT8(buf_p, difficulty); + // init difficulty levels list + //if (!mastermodebots) { + difficultylevels[MAXPLAYERS] = { + max(1, startingdifficulty), + max(1, startingdifficulty-1), + max(1, startingdifficulty-2), + max(1, startingdifficulty-3), + max(1, startingdifficulty-3), + max(1, startingdifficulty-4), + max(1, startingdifficulty-4), + max(1, startingdifficulty-4), + max(1, startingdifficulty-5), + max(1, startingdifficulty-5), + max(1, startingdifficulty-6), + max(1, startingdifficulty-6), + max(1, startingdifficulty-7), + max(1, startingdifficulty-7), + max(1, startingdifficulty-8), + max(1, startingdifficulty-8), + }; - SendNetXCmd(XD_ADDBOT, buf, buf_p - buf); - - if (difficulty > 0) + for (i = 0; i < MAXPLAYERS; i++) + { + if (numplayers < MAXSPLITSCREENPLAYERS) { - difficulty--; + if (playeringame[i] && !players[i].spectator) + { + competitors[numplayers] = i; + numplayers++; + } } + else + { + if (playeringame[i]) + { + players[i].spectator = true; // force spectate for all other players, if they happen to exist? + } + } + } - DEBFILE(va("Server added bot %d\n", newplayernum)); - // use the next free slot (we can't put playeringame[newplayernum] = true here) - newplayernum++; + if (numplayers > 2) + { + // Add 3 bots per player beyond 2P + playercount += (numplayers-2) * 3; + } + + wantedbots = playercount - numplayers; + + // Create rival list + + // TODO: Use player skin's set rivals + // Starting with P1's rival1, P2's rival1, P3's rival1, P4's rival1, + // then P1's rival2, P2's rival2, etc etc etc etc....... + // then skip over any duplicates. + + // Pad the remaining list with random skins if we need to + if (botskinlistpos < wantedbots) + { + for (i = botskinlistpos; i < wantedbots; i++) + { + UINT8 val = M_RandomKey(numskins); + UINT8 loops = 0; + + while (!skinusable[val]) + { + if (loops >= numskins) + { + // no more skins + break; + } + + val++; + + if (val >= numskins) + { + val = 0; + } + + loops++; + } + + if (loops >= numskins) + { + // leave the rest of the table as the default skin + break; + } + + botskinlist[i] = val; + skinusable[val] = false; + } + } + + for (i = 0; i < wantedbots; i++) + { + if (!K_AddBot(botskinlist[i], difficultylevels[i], &newplayernum)) + { + break; + } } } +#endif boolean K_PlayerUsesBotMovement(player_t *player) { diff --git a/src/k_bot.h b/src/k_bot.h index 4a5af7122..ef7409f97 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -22,7 +22,8 @@ typedef struct botprediction_s { angle_t dir; } botprediction_t; -void K_AddBots(SINT8 numbots); +boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *newplayernum); +void K_UpdateMatchRaceBots(void); boolean K_PlayerUsesBotMovement(player_t *player); boolean K_BotCanTakeCut(player_t *player); fixed_t K_BotRubberband(player_t *player); diff --git a/src/k_kart.c b/src/k_kart.c index 68c5c63da..83fffe056 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -623,6 +623,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartvoterulechanges); CV_RegisterVar(&cv_kartspeedometer); CV_RegisterVar(&cv_kartvoices); + CV_RegisterVar(&cv_kartbot); CV_RegisterVar(&cv_karteliminatelast); CV_RegisterVar(&cv_kartusepwrlv); CV_RegisterVar(&cv_votetime); diff --git a/src/p_mobj.c b/src/p_mobj.c index c1eed6327..3d70b3c38 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11762,9 +11762,20 @@ void P_SpawnPlayer(INT32 playernum) } // spawn as spectator determination - if (multiplayer && demo.playback); // Don't mess with spectator values since the demo setup handles them already. + if (multiplayer && demo.playback) + { + ; // Don't mess with spectator values since the demo setup handles them already. + } else if (!G_GametypeHasSpectators()) + { + // We don't have spectators p->spectator = false; + } + else if (p->bot) + { + // No point in a spectating bot! + p->spectator = false; + } else if (netgame && p->jointime <= 1 && pcount) { p->spectator = true; diff --git a/src/p_setup.c b/src/p_setup.c index bc0e00d0c..d5891e84a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -87,6 +87,7 @@ #include "k_battle.h" // K_SpawnBattleCapsules #include "k_pwrlv.h" #include "k_waypoint.h" +#include "k_bot.h" // // Map MD5, calculated on level load. @@ -2425,6 +2426,9 @@ static void P_LevelInitStuff(void) memset(&battleovertime, 0, sizeof(struct battleovertime)); speedscramble = encorescramble = -1; + + //if (!grandprix) + K_UpdateMatchRaceBots(); } //