diff --git a/src/g_game.c b/src/g_game.c index 71e8918fa..e59199a08 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4893,7 +4893,7 @@ static void G_DoCompleted(void) } else { - Y_MidIntermission(); + //Y_MidIntermission(); -- we don't want bots retired or teams wiped if (grandprixinfo.gp == true) { K_UpdateGPRank(&grandprixinfo.rank); diff --git a/src/k_grandprix.cpp b/src/k_grandprix.cpp index 58a42dde2..d990dd94a 100644 --- a/src/k_grandprix.cpp +++ b/src/k_grandprix.cpp @@ -718,99 +718,29 @@ static boolean CompareReplacements(player_t *a, player_t *b) --------------------------------------------------*/ void K_RetireBots(void) { - const UINT8 defaultbotskin = R_BotDefaultSkin(); - SINT8 newDifficulty; - - UINT8 usableskins, skincount = (demo.playback ? demo.numskins : numskins); - UINT8 grabskins[MAXSKINS+1]; - UINT8 i; if (grandprixinfo.gp == true - && (grandprixinfo.eventmode != GPEVENT_NONE - || (grandprixinfo.cup != NULL - && roundqueue.size > 0 - && roundqueue.roundnum >= grandprixinfo.cup->numlevels))) + && grandprixinfo.eventmode != GPEVENT_NONE) { - // No replacement. + // Bots can't do anything here, replacement means they never get their spotlight. return; } - // Init usable bot skins list - for (usableskins = 0; usableskins < skincount; usableskins++) + if (roundqueue.size > 0) { - grabskins[usableskins] = usableskins; - } - grabskins[usableskins] = MAXSKINS; - - // Exclude player skins - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - if (players[i].spectator) - continue; - - grabskins[players[i].skin] = MAXSKINS; - } - - // Rearrange usable bot skins list to prevent gaps for randomised selection - for (i = 0; i < usableskins; i++) - { - if (!(grabskins[i] == MAXSKINS || !R_SkinUsable(-1, grabskins[i], true))) - continue; - while (usableskins > i && (grabskins[usableskins] == MAXSKINS || !R_SkinUsable(-1, grabskins[usableskins], true))) - usableskins--; - grabskins[i] = grabskins[usableskins]; - grabskins[usableskins] = MAXSKINS; - } - - if (grandprixinfo.gp) // Sure, let's let this happen all the time :) - { - if (grandprixinfo.masterbots == true) + // Get the last non-special entry + i = roundqueue.size; + while (--i > roundqueue.position) { - newDifficulty = MAXBOTDIFFICULTY; - } - else - { - const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed); - newDifficulty = startingdifficulty - 4; - if (roundqueue.size > 0) - { - newDifficulty += roundqueue.roundnum; - } - } - } - else - { - newDifficulty = cv_kartbot.value; - } - - if (newDifficulty > MAXBOTDIFFICULTY) - { - newDifficulty = MAXBOTDIFFICULTY; - } - else if (newDifficulty < 1) - { - newDifficulty = 1; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *bot = NULL; - - if (!playeringame[i] || !players[i].bot || players[i].spectator) - { - continue; + if (!roundqueue.entries[i].rankrestricted) + break; } - bot = &players[i]; - - if (bot->pflags & PF_NOCONTEST) + if (roundqueue.position >= i) { - // HACK!!!!! two days to end of cleanup period :) - // we do this so that any bot that's been removed doesn't count for K_SetNameForBot conflicts - player_names[i][0] = '0'; + // Out of non-special entries, no replacement. + return; } } @@ -861,8 +791,6 @@ void K_RetireBots(void) std::stable_sort(humans.begin(), humans.end(), CompareReplacements); std::stable_sort(bots.begin(), bots.end(), CompareReplacements); - boolean did_replacement = false; - if (G_GametypeHasSpectators() == true && grandprixinfo.gp == false && cv_shuffleloser.value != 0) { // While joiners and players still exist, insert joiners. @@ -911,24 +839,113 @@ void K_RetireBots(void) // Add our waiting-to-play spectator to the game. P_SpectatorJoinGame(joiner); - did_replacement = true; replacements--; num_joining--; } } - if (did_replacement == true) + // No need to run any of this code if no bots afoot + if (bots.size() == 0) { - // No need to run the bot swapping code, - // we already replaced the loser. return; } - // Replace last place bot. - if (bots.size() > 0) - { - player_t *bot = bots.back(); + // Remove all still-in-contestors + bots.erase(std::remove_if(bots.begin(), bots.end(), + [](player_t *bot) { + return ( + bot->spectator + || !(bot->pflags & PF_NOCONTEST) + ); + } + ), bots.end()); + // No need to run any of this code if no *NO-CONTESTORS* afoot + if (bots.size() == 0) + { + return; + } + + // Okay, now this is essentially the original contents of K_RetireBots with cpp swag + + const UINT8 defaultbotskin = R_BotDefaultSkin(); + SINT8 newDifficulty; + + UINT8 usableskins, skincount = (demo.playback ? demo.numskins : numskins); + UINT8 grabskins[MAXSKINS+1]; + + // Handle adjusting difficulty for new bots + { + if (grandprixinfo.gp) // Sure, let's let this happen all the time :) + { + if (grandprixinfo.masterbots == true) + { + newDifficulty = MAXBOTDIFFICULTY; + } + else + { + const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed); + newDifficulty = startingdifficulty - 4; + if (roundqueue.size > 0) + { + newDifficulty += roundqueue.roundnum; + } + } + } + else + { + newDifficulty = cv_kartbot.value; + } + + if (newDifficulty > MAXBOTDIFFICULTY) + { + newDifficulty = MAXBOTDIFFICULTY; + } + else if (newDifficulty < 1) + { + newDifficulty = 1; + } + } + + // HACK!!!!! that survived allll the way since two days to end of cleanup period :) + // we do this so that any bot that's been removed doesn't count for K_SetNameForBot conflicts + for (player_t *bot : bots) + { + player_names[(bot-players)][0] = '0'; + } + + // Init usable bot skins list + for (usableskins = 0; usableskins < skincount; usableskins++) + { + grabskins[usableskins] = usableskins; + } + grabskins[usableskins] = MAXSKINS; + + // Exclude player skins + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + if (players[i].spectator) + continue; + + grabskins[players[i].skin] = MAXSKINS; + } + + // Rearrange usable bot skins list to prevent gaps for randomised selection + for (i = 0; i < usableskins; i++) + { + if (!(grabskins[i] == MAXSKINS || !R_SkinUsable(-1, grabskins[i], true))) + continue; + while (usableskins > i && (grabskins[usableskins] == MAXSKINS || !R_SkinUsable(-1, grabskins[usableskins], true))) + usableskins--; + grabskins[i] = grabskins[usableskins]; + grabskins[usableskins] = MAXSKINS; + } + + // Replace nocontested bots. + for (player_t *bot : bots) + { UINT8 skinnum = defaultbotskin; if (usableskins > 0) diff --git a/src/k_hud.cpp b/src/k_hud.cpp index 683117cab..c3e444930 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -5434,7 +5434,13 @@ playertagtype_t K_WhichPlayerTag(player_t *p) } else if (p->bot) { - if ((p->botvars.rival == true || cv_levelskull.value) && (!K_InRaceDuel())) + if (gametype == GT_TUTORIAL) + { + return (skins[p->skin].flags & SF_MACHINE) + ? PLAYERTAG_CPU + : PLAYERTAG_TUTORIALFAKELOCAL; + } + else if ((p->botvars.rival == true || cv_levelskull.value) && (!K_InRaceDuel())) { return PLAYERTAG_RIVAL; } @@ -5470,6 +5476,15 @@ void K_DrawPlayerTag(fixed_t x, fixed_t y, player_t *p, playertagtype_t type, bo K_DrawRivalTagForPlayer(x, y, p, flags); break; + case PLAYERTAG_TUTORIALFAKELOCAL: + if (p-players < 4) + { + flags |= V_SPLITSCREEN; + K_DrawLocalTagForPlayer(x, y, p, (p - players), flags); + break; + } + + // FALLTHRU case PLAYERTAG_CPU: flags |= V_SPLITSCREEN; flags |= foreground ? 0 : V_60TRANS; diff --git a/src/k_hud.h b/src/k_hud.h index e382c95ea..af5a30b68 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -153,6 +153,7 @@ typedef enum PLAYERTAG_CPU, PLAYERTAG_RIVAL, PLAYERTAG_NAME, + PLAYERTAG_TUTORIALFAKELOCAL, } playertagtype_t; diff --git a/src/y_inter.cpp b/src/y_inter.cpp index 449324357..dae9175a9 100644 --- a/src/y_inter.cpp +++ b/src/y_inter.cpp @@ -735,7 +735,10 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) V_DrawMappedPatch(x, y, 0, resbar, NULL); - V_DrawRightAlignedThinString(x+13, y-2, 0, va("%d", standings->pos[i])); + if (gametype != GT_TUTORIAL) + { + V_DrawRightAlignedThinString(x+13, y-2, 0, va("%d", standings->pos[i])); + } //if (players[pnum].skincolor != SKINCOLOR_NONE) {