mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-05-10 19:01:50 +00:00
Rework how Bots handle their skin availabilities
Before we can add extra unlock features, we need to make sure we're not building on a house of sand. - R_SkinUsable: Use Net Unlock system if playernum is -1 - R_BotDefaultSkin: Move to r_skins.c, cache skin search - R_GetSkinAvailabilities: Use Net Unlock when called for bots (and always permit R_BotDefaultSkin) - Got_AddBot: Call R_GetSkinAvailabilities for summoned bots to guarantee sync status of available skins - K_UpdateMatchRaceBots: Tidy up to match grand prix bot skin selection system, hiding server-locked skins and defaulting to R_BotDefaultSkin if you don't have enough unlocked for the remaining player slots
This commit is contained in:
parent
1ae5df651d
commit
0c75c40060
7 changed files with 70 additions and 87 deletions
|
|
@ -824,7 +824,7 @@ static boolean CL_SendJoin(void)
|
||||||
for (; i < MAXSPLITSCREENPLAYERS; i++)
|
for (; i < MAXSPLITSCREENPLAYERS; i++)
|
||||||
strncpy(netbuffer->u.clientcfg.names[i], va("Player %c", 'A' + i), MAXPLAYERNAME);
|
strncpy(netbuffer->u.clientcfg.names[i], va("Player %c", 'A' + i), MAXPLAYERNAME);
|
||||||
|
|
||||||
memcpy(&netbuffer->u.clientcfg.availabilities, R_GetSkinAvailabilities(false), MAXAVAILABILITY*sizeof(UINT8));
|
memcpy(&netbuffer->u.clientcfg.availabilities, R_GetSkinAvailabilities(false, false), MAXAVAILABILITY*sizeof(UINT8));
|
||||||
|
|
||||||
return HSendPacket(servernode, false, 0, sizeof (clientconfig_pak));
|
return HSendPacket(servernode, false, 0, sizeof (clientconfig_pak));
|
||||||
}
|
}
|
||||||
|
|
@ -3723,7 +3723,7 @@ static void Got_RemovePlayer(UINT8 **p, INT32 playernum)
|
||||||
static void Got_AddBot(UINT8 **p, INT32 playernum)
|
static void Got_AddBot(UINT8 **p, INT32 playernum)
|
||||||
{
|
{
|
||||||
INT16 newplayernum;
|
INT16 newplayernum;
|
||||||
UINT8 i, skinnum = 0;
|
UINT8 skinnum = 0;
|
||||||
UINT8 difficulty = DIFFICULTBOT;
|
UINT8 difficulty = DIFFICULTBOT;
|
||||||
|
|
||||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||||
|
|
@ -3753,14 +3753,8 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
|
||||||
|
|
||||||
playernode[newplayernum] = servernode;
|
playernode[newplayernum] = servernode;
|
||||||
|
|
||||||
// todo find a way to have all auto unlocked for dedicated
|
// this will permit unlocks
|
||||||
if (playeringame[0])
|
memcpy(&players[newplayernum].availabilities, R_GetSkinAvailabilities(false, true), MAXAVAILABILITY*sizeof(UINT8));
|
||||||
{
|
|
||||||
for (i = 0; i < MAXAVAILABILITY; i++)
|
|
||||||
{
|
|
||||||
players[newplayernum].availabilities[i] = players[0].availabilities[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
players[newplayernum].splitscreenindex = 0;
|
players[newplayernum].splitscreenindex = 0;
|
||||||
players[newplayernum].bot = true;
|
players[newplayernum].bot = true;
|
||||||
|
|
@ -3936,7 +3930,7 @@ boolean SV_SpawnServer(void)
|
||||||
// strictly speaking, i'm not convinced the following is necessary
|
// strictly speaking, i'm not convinced the following is necessary
|
||||||
// but I'm not confident enough to remove it entirely in case it breaks something
|
// but I'm not confident enough to remove it entirely in case it breaks something
|
||||||
{
|
{
|
||||||
UINT8 *availabilitiesbuffer = R_GetSkinAvailabilities(false);
|
UINT8 *availabilitiesbuffer = R_GetSkinAvailabilities(false, false);
|
||||||
SINT8 node = 0;
|
SINT8 node = 0;
|
||||||
for (; node < MAXNETNODES; node++)
|
for (; node < MAXNETNODES; node++)
|
||||||
result |= SV_AddWaitingPlayers(node, availabilitiesbuffer, cv_playername[0].zstring, cv_playername[1].zstring, cv_playername[2].zstring, cv_playername[3].zstring);
|
result |= SV_AddWaitingPlayers(node, availabilitiesbuffer, cv_playername[0].zstring, cv_playername[1].zstring, cv_playername[2].zstring, cv_playername[3].zstring);
|
||||||
|
|
|
||||||
|
|
@ -2239,7 +2239,7 @@ static void G_SaveDemoSkins(UINT8 **pp)
|
||||||
{
|
{
|
||||||
char skin[16];
|
char skin[16];
|
||||||
UINT8 i;
|
UINT8 i;
|
||||||
UINT8 *availabilitiesbuffer = R_GetSkinAvailabilities(true);
|
UINT8 *availabilitiesbuffer = R_GetSkinAvailabilities(true, false);
|
||||||
|
|
||||||
WRITEUINT8((*pp), numskins);
|
WRITEUINT8((*pp), numskins);
|
||||||
for (i = 0; i < numskins; i++)
|
for (i = 0; i < numskins; i++)
|
||||||
|
|
|
||||||
64
src/k_bot.c
64
src/k_bot.c
|
|
@ -108,13 +108,15 @@ boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p)
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
void K_UpdateMatchRaceBots(void)
|
void K_UpdateMatchRaceBots(void)
|
||||||
{
|
{
|
||||||
|
const UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||||
const UINT8 difficulty = cv_kartbot.value;
|
const UINT8 difficulty = cv_kartbot.value;
|
||||||
UINT8 pmax = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
|
UINT8 pmax = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
|
||||||
UINT8 numplayers = 0;
|
UINT8 numplayers = 0;
|
||||||
UINT8 numbots = 0;
|
UINT8 numbots = 0;
|
||||||
UINT8 numwaiting = 0;
|
UINT8 numwaiting = 0;
|
||||||
SINT8 wantedbots = 0;
|
SINT8 wantedbots = 0;
|
||||||
boolean skinusable[MAXSKINS];
|
UINT8 usableskins = 0;
|
||||||
|
UINT8 grabskins[MAXSKINS+1];
|
||||||
UINT8 i;
|
UINT8 i;
|
||||||
|
|
||||||
if (!server)
|
if (!server)
|
||||||
|
|
@ -122,18 +124,12 @@ void K_UpdateMatchRaceBots(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// init usable bot skins list
|
// Init usable bot skins list
|
||||||
for (i = 0; i < MAXSKINS; i++)
|
for (i = 0; i < numskins; i++)
|
||||||
{
|
{
|
||||||
if (i < numskins)
|
grabskins[usableskins++] = i;
|
||||||
{
|
|
||||||
skinusable[i] = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
skinusable[i] = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
grabskins[usableskins] = MAXSKINS;
|
||||||
|
|
||||||
if (cv_maxplayers.value > 0)
|
if (cv_maxplayers.value > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -146,7 +142,7 @@ void K_UpdateMatchRaceBots(void)
|
||||||
{
|
{
|
||||||
if (!players[i].spectator)
|
if (!players[i].spectator)
|
||||||
{
|
{
|
||||||
skinusable[players[i].skin] = false;
|
grabskins[players[i].skin] = MAXSKINS;
|
||||||
|
|
||||||
if (players[i].bot)
|
if (players[i].bot)
|
||||||
{
|
{
|
||||||
|
|
@ -185,48 +181,42 @@ void K_UpdateMatchRaceBots(void)
|
||||||
{
|
{
|
||||||
// We require MORE bots!
|
// We require MORE bots!
|
||||||
UINT8 newplayernum = 0;
|
UINT8 newplayernum = 0;
|
||||||
boolean usedallskins = false;
|
|
||||||
|
|
||||||
if (dedicated)
|
if (dedicated)
|
||||||
{
|
{
|
||||||
newplayernum = 1;
|
newplayernum = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
while (numbots < wantedbots)
|
while (numbots < wantedbots)
|
||||||
{
|
{
|
||||||
UINT8 skin = M_RandomKey(numskins);
|
UINT8 skinnum = defaultbotskin;
|
||||||
|
|
||||||
if (usedallskins == false)
|
if (usableskins > 0)
|
||||||
{
|
{
|
||||||
UINT8 loops = 0;
|
UINT8 index = M_RandomKey(usableskins);
|
||||||
|
skinnum = grabskins[index];
|
||||||
while (!skinusable[skin])
|
grabskins[index] = grabskins[--usableskins];
|
||||||
{
|
|
||||||
if (loops >= numskins)
|
|
||||||
{
|
|
||||||
// no more skins, stick to our first choice
|
|
||||||
usedallskins = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
skin++;
|
|
||||||
|
|
||||||
if (skin >= numskins)
|
|
||||||
{
|
|
||||||
skin = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
loops++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!K_AddBot(skin, difficulty, &newplayernum))
|
if (!K_AddBot(skinnum, difficulty, &newplayernum))
|
||||||
{
|
{
|
||||||
// Not enough player slots to add the bot, break the loop.
|
// Not enough player slots to add the bot, break the loop.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
skinusable[skin] = false;
|
|
||||||
numbots++;
|
numbots++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,25 +95,6 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------------------------------------
|
|
||||||
UINT8 K_BotDefaultSkin(void)
|
|
||||||
|
|
||||||
See header file for description.
|
|
||||||
--------------------------------------------------*/
|
|
||||||
UINT8 K_BotDefaultSkin(void)
|
|
||||||
{
|
|
||||||
const char *defaultbotskinname = "eggrobo";
|
|
||||||
INT32 defaultbotskin = R_SkinAvailable(defaultbotskinname);
|
|
||||||
|
|
||||||
if (defaultbotskin == -1)
|
|
||||||
{
|
|
||||||
// This shouldn't happen, but just in case
|
|
||||||
defaultbotskin = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (UINT8)defaultbotskin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_InitGrandPrixBots(void)
|
void K_InitGrandPrixBots(void)
|
||||||
|
|
||||||
|
|
@ -121,7 +102,7 @@ UINT8 K_BotDefaultSkin(void)
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
void K_InitGrandPrixBots(void)
|
void K_InitGrandPrixBots(void)
|
||||||
{
|
{
|
||||||
const UINT8 defaultbotskin = K_BotDefaultSkin();
|
const UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||||
|
|
||||||
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
||||||
UINT8 difficultylevels[MAXPLAYERS];
|
UINT8 difficultylevels[MAXPLAYERS];
|
||||||
|
|
@ -519,7 +500,7 @@ void K_IncreaseBotDifficulty(player_t *bot)
|
||||||
--------------------------------------------------*/
|
--------------------------------------------------*/
|
||||||
void K_RetireBots(void)
|
void K_RetireBots(void)
|
||||||
{
|
{
|
||||||
const UINT8 defaultbotskin = K_BotDefaultSkin();
|
const UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||||
SINT8 newDifficulty;
|
SINT8 newDifficulty;
|
||||||
|
|
||||||
UINT8 usableskins;
|
UINT8 usableskins;
|
||||||
|
|
|
||||||
|
|
@ -71,16 +71,6 @@ UINT8 K_BotStartingDifficulty(SINT8 value);
|
||||||
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
|
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
|
||||||
UINT8 K_BotDefaultSkin(void);
|
|
||||||
|
|
||||||
Returns the skin number of the skin the game
|
|
||||||
uses as a fallback option.
|
|
||||||
--------------------------------------------------*/
|
|
||||||
|
|
||||||
UINT8 K_BotDefaultSkin(void);
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
void K_InitGrandPrixBots(void);
|
void K_InitGrandPrixBots(void);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,27 @@ static void Sk_SetDefaultValue(skin_t *skin)
|
||||||
skin->soundsid[S_sfx[i].skinsound] = i;
|
skin->soundsid[S_sfx[i].skinsound] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grab the default skin
|
||||||
|
UINT8 R_BotDefaultSkin(void)
|
||||||
|
{
|
||||||
|
static INT32 defaultbotskin = -1;
|
||||||
|
|
||||||
|
if (defaultbotskin == -1)
|
||||||
|
{
|
||||||
|
const char *defaultbotskinname = "eggrobo";
|
||||||
|
|
||||||
|
defaultbotskin = R_SkinAvailable(defaultbotskinname);
|
||||||
|
|
||||||
|
if (defaultbotskin == -1)
|
||||||
|
{
|
||||||
|
// This shouldn't happen, but just in case
|
||||||
|
defaultbotskin = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (UINT8)defaultbotskin;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Initialize the basic skins
|
// Initialize the basic skins
|
||||||
//
|
//
|
||||||
|
|
@ -159,11 +180,12 @@ void R_InitSkins(void)
|
||||||
M_UpdateConditionSetsPending();
|
M_UpdateConditionSetsPending();
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 *R_GetSkinAvailabilities(boolean demolock)
|
UINT8 *R_GetSkinAvailabilities(boolean demolock, boolean forbots)
|
||||||
{
|
{
|
||||||
UINT8 i, shif, byte;
|
UINT8 i, shif, byte;
|
||||||
INT32 skinid;
|
INT32 skinid;
|
||||||
static UINT8 responsebuffer[MAXAVAILABILITY];
|
static UINT8 responsebuffer[MAXAVAILABILITY];
|
||||||
|
UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||||
|
|
||||||
memset(&responsebuffer, 0, sizeof(responsebuffer));
|
memset(&responsebuffer, 0, sizeof(responsebuffer));
|
||||||
|
|
||||||
|
|
@ -172,15 +194,17 @@ UINT8 *R_GetSkinAvailabilities(boolean demolock)
|
||||||
if (unlockables[i].type != SECRET_SKIN)
|
if (unlockables[i].type != SECRET_SKIN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// NEVER EVER EVER M_CheckNetUnlockByID
|
|
||||||
if (gamedata->unlocked[i] != true && !demolock)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
skinid = M_UnlockableSkinNum(&unlockables[i]);
|
skinid = M_UnlockableSkinNum(&unlockables[i]);
|
||||||
|
|
||||||
if (skinid < 0 || skinid >= MAXSKINS)
|
if (skinid < 0 || skinid >= MAXSKINS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if ((forbots
|
||||||
|
? (M_CheckNetUnlockByID(i) || skinid == defaultbotskin) // Assert the host's lock.
|
||||||
|
: gamedata->unlocked[i]) // Assert the local lock.
|
||||||
|
!= true && !demolock)
|
||||||
|
continue;
|
||||||
|
|
||||||
shif = (skinid % 8);
|
shif = (skinid % 8);
|
||||||
byte = (skinid / 8);
|
byte = (skinid / 8);
|
||||||
|
|
||||||
|
|
@ -251,8 +275,11 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins)
|
||||||
return !!(players[playernum].availabilities[byte] & (1 << shif));
|
return !!(players[playernum].availabilities[byte] & (1 << shif));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the host's if it's checking general state
|
||||||
|
if (playernum == -1)
|
||||||
|
return M_CheckNetUnlockByID(i);
|
||||||
|
|
||||||
// Use the unlockables table directly
|
// Use the unlockables table directly
|
||||||
// NOTE: M_CheckNetUnlockByID would be correct in many circumstances... but not all. TODO figure out how to discern.
|
|
||||||
return (boolean)(gamedata->unlocked[i]);
|
return (boolean)(gamedata->unlocked[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,9 @@ void ClearFakePlayerSkin(player_t* player);
|
||||||
boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins);
|
boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins);
|
||||||
INT32 GetSkinNumClosestToStats(UINT8 kartspeed, UINT8 kartweight, UINT32 flags, boolean unlock);
|
INT32 GetSkinNumClosestToStats(UINT8 kartspeed, UINT8 kartweight, UINT32 flags, boolean unlock);
|
||||||
|
|
||||||
UINT8 *R_GetSkinAvailabilities(boolean demolock);
|
UINT8 *R_GetSkinAvailabilities(boolean demolock, boolean forbots);
|
||||||
INT32 R_SkinAvailable(const char *name);
|
INT32 R_SkinAvailable(const char *name);
|
||||||
|
UINT8 R_BotDefaultSkin(void);
|
||||||
|
|
||||||
void R_PatchSkins(UINT16 wadnum, boolean mainfile);
|
void R_PatchSkins(UINT16 wadnum, boolean mainfile);
|
||||||
void R_AddSkins(UINT16 wadnum, boolean mainfile);
|
void R_AddSkins(UINT16 wadnum, boolean mainfile);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue