Rework bot skin randomisation

- Instead of picking over numskins and adjust the number if it picks an already used skin, build and shuffle a list of allowed skins and pick over that instead.
- Fixes some issues with increased weighting towards the skins immediately after your rivals' skins.
- Use PR_RULESCRAMBLE instead of PR_UNDEFINED.
- Why am I doing it in this branch? I'm getting re-acquainted with how bots are handled between matches in advance of disabling them for bonus events without losing or corrupting data.
This commit is contained in:
toaster 2022-10-11 18:42:04 +01:00
parent dbc067f87a
commit 13c8d45764
3 changed files with 61 additions and 91 deletions

View file

@ -96,14 +96,14 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
}
/*--------------------------------------------------
SINT8 K_BotDefaultSkin(void)
UINT8 K_BotDefaultSkin(void)
See header file for description.
--------------------------------------------------*/
SINT8 K_BotDefaultSkin(void)
UINT8 K_BotDefaultSkin(void)
{
const char *defaultbotskinname = "eggrobo";
SINT8 defaultbotskin = R_SkinAvailable(defaultbotskinname);
INT32 defaultbotskin = R_SkinAvailable(defaultbotskinname);
if (defaultbotskin == -1)
{
@ -111,7 +111,7 @@ SINT8 K_BotDefaultSkin(void)
defaultbotskin = 0;
}
return defaultbotskin;
return (UINT8)defaultbotskin;
}
/*--------------------------------------------------
@ -121,7 +121,7 @@ SINT8 K_BotDefaultSkin(void)
--------------------------------------------------*/
void K_InitGrandPrixBots(void)
{
const SINT8 defaultbotskin = K_BotDefaultSkin();
const UINT8 defaultbotskin = K_BotDefaultSkin();
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
UINT8 difficultylevels[MAXPLAYERS];
@ -132,7 +132,9 @@ void K_InitGrandPrixBots(void)
UINT8 numplayers = 0;
UINT8 competitors[MAXSPLITSCREENPLAYERS];
boolean skinusable[MAXSKINS];
UINT8 usableskins;
UINT8 grabskins[MAXSKINS];
UINT8 botskinlist[MAXPLAYERS];
UINT8 botskinlistpos = 0;
@ -142,17 +144,10 @@ void K_InitGrandPrixBots(void)
memset(competitors, MAXPLAYERS, sizeof (competitors));
memset(botskinlist, defaultbotskin, sizeof (botskinlist));
// init usable bot skins list
for (i = 0; i < MAXSKINS; i++)
// Init usable bot skins list
for (usableskins = 0; usableskins < numskins; usableskins++)
{
if (i < numskins)
{
skinusable[i] = true;
}
else
{
skinusable[i] = false;
}
grabskins[usableskins] = usableskins;
}
#if MAXPLAYERS != 16
@ -192,7 +187,7 @@ void K_InitGrandPrixBots(void)
if (numplayers < MAXSPLITSCREENPLAYERS && !players[i].spectator)
{
competitors[numplayers] = i;
skinusable[players[i].skin] = false;
grabskins[players[i].skin] = MAXSKINS;
numplayers++;
}
else
@ -219,52 +214,42 @@ void K_InitGrandPrixBots(void)
{
player_t *p = &players[competitors[j]];
char *rivalname = skins[p->skin].rivals[i];
SINT8 rivalnum = R_SkinAvailable(rivalname);
INT32 rivalnum = R_SkinAvailable(rivalname);
if (rivalnum != -1 && skinusable[rivalnum])
// Intentionally referenced before (currently dummied out) unlock check. Such a tease!
if (rivalnum != -1 && grabskins[(UINT8)rivalnum] != MAXSKINS)
{
botskinlist[botskinlistpos] = rivalnum;
skinusable[rivalnum] = false;
botskinlist[botskinlistpos++] = (UINT8)rivalnum;
grabskins[(UINT8)rivalnum] = MAXSKINS;
botskinlistpos++;
}
}
}
}
// Rearrange usable bot skins list to prevent gaps for randomised selection
for (i = 0; i < usableskins; i++)
{
if (grabskins[i] != MAXSKINS /*&& !K_SkinLocked(usableskins)*/)
continue;
grabskins[i] = grabskins[--usableskins];
}
// Pad the remaining list with random skins if we need to
if (botskinlistpos < wantedbots)
{
for (i = botskinlistpos; i < wantedbots; i++)
while (botskinlistpos < wantedbots)
{
UINT8 val = M_RandomKey(numskins);
UINT8 loops = 0;
UINT8 skinnum = defaultbotskin;
while (!skinusable[val])
if (usableskins > 0)
{
if (loops >= numskins)
{
// no more skins
break;
}
val++;
if (val >= numskins)
{
val = 0;
}
loops++;
UINT8 index = M_RandomKey(usableskins);
skinnum = grabskins[index];
grabskins[index] = grabskins[--usableskins];
}
if (loops >= numskins)
{
// leave the rest of the table as the default skin
break;
}
botskinlist[i] = val;
skinusable[val] = false;
botskinlist[botskinlistpos++] = skinnum;
}
}
@ -519,10 +504,11 @@ void K_IncreaseBotDifficulty(player_t *bot)
--------------------------------------------------*/
void K_RetireBots(void)
{
const SINT8 defaultbotskin = K_BotDefaultSkin();
const UINT8 defaultbotskin = K_BotDefaultSkin();
SINT8 newDifficulty;
boolean skinusable[MAXSKINS];
UINT8 usableskins;
UINT8 grabskins[MAXSKINS];
UINT8 i;
@ -532,25 +518,29 @@ void K_RetireBots(void)
return;
}
// init usable bot skins list
for (i = 0; i < MAXSKINS; i++)
// Init usable bot skins list
for (usableskins = 0; usableskins < numskins; usableskins++)
{
if (i < numskins)
{
skinusable[i] = true;
}
else
{
skinusable[i] = false;
}
grabskins[usableskins] = usableskins;
}
// Exclude player skins
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
{
skinusable[players[i].skin] = false;
}
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 /*&& !K_SkinLocked(usableskins)*/)
continue;
grabskins[i] = grabskins[--usableskins];
}
if (!grandprixinfo.gp) // Sure, let's let this happen all the time :)
@ -590,35 +580,15 @@ void K_RetireBots(void)
if (bot->pflags & PF_NOCONTEST)
{
UINT8 skinnum = P_RandomKey(PR_UNDEFINED, numskins);
UINT8 loops = 0;
UINT8 skinnum = defaultbotskin;
while (!skinusable[skinnum])
if (usableskins > 0)
{
if (loops >= numskins)
{
// no more skins
break;
}
skinnum++;
if (skinnum >= numskins)
{
skinnum = 0;
}
loops++;
UINT8 index = P_RandomKey(PR_RULESCRAMBLE, usableskins);
skinnum = grabskins[index];
grabskins[index] = grabskins[--usableskins];
}
if (loops >= numskins)
{
// Use default skin
skinnum = defaultbotskin;
}
skinusable[skinnum] = false;
bot->botvars.difficulty = newDifficulty;
bot->botvars.diffincrease = 0;

View file

@ -63,13 +63,13 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
/*--------------------------------------------------
SINT8 K_BotDefaultSkin(void);
UINT8 K_BotDefaultSkin(void);
Returns the skin number of the skin the game
uses as a fallback option.
--------------------------------------------------*/
SINT8 K_BotDefaultSkin(void);
UINT8 K_BotDefaultSkin(void);
/*--------------------------------------------------

View file

@ -47,7 +47,7 @@ typedef enum
PR_PLAYERSTARTS, // Player starts
PR_VOICES, // Player voice sounds
PR_RULESCRAMBLE, // Netgame rule scrambing events
PR_RULESCRAMBLE, // Rule scrambing events
PR_ITEM_ROULETTE, // Item results
PR_ITEM_RINGS, // Flung ring/bumper/player (on death)