mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-03-03 01:41:15 +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++)
|
||||
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));
|
||||
}
|
||||
|
|
@ -3723,7 +3723,7 @@ static void Got_RemovePlayer(UINT8 **p, INT32 playernum)
|
|||
static void Got_AddBot(UINT8 **p, INT32 playernum)
|
||||
{
|
||||
INT16 newplayernum;
|
||||
UINT8 i, skinnum = 0;
|
||||
UINT8 skinnum = 0;
|
||||
UINT8 difficulty = DIFFICULTBOT;
|
||||
|
||||
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
|
||||
|
|
@ -3753,14 +3753,8 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
|
|||
|
||||
playernode[newplayernum] = servernode;
|
||||
|
||||
// todo find a way to have all auto unlocked for dedicated
|
||||
if (playeringame[0])
|
||||
{
|
||||
for (i = 0; i < MAXAVAILABILITY; i++)
|
||||
{
|
||||
players[newplayernum].availabilities[i] = players[0].availabilities[i];
|
||||
}
|
||||
}
|
||||
// this will permit unlocks
|
||||
memcpy(&players[newplayernum].availabilities, R_GetSkinAvailabilities(false, true), MAXAVAILABILITY*sizeof(UINT8));
|
||||
|
||||
players[newplayernum].splitscreenindex = 0;
|
||||
players[newplayernum].bot = true;
|
||||
|
|
@ -3936,7 +3930,7 @@ boolean SV_SpawnServer(void)
|
|||
// 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
|
||||
{
|
||||
UINT8 *availabilitiesbuffer = R_GetSkinAvailabilities(false);
|
||||
UINT8 *availabilitiesbuffer = R_GetSkinAvailabilities(false, false);
|
||||
SINT8 node = 0;
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -2239,7 +2239,7 @@ static void G_SaveDemoSkins(UINT8 **pp)
|
|||
{
|
||||
char skin[16];
|
||||
UINT8 i;
|
||||
UINT8 *availabilitiesbuffer = R_GetSkinAvailabilities(true);
|
||||
UINT8 *availabilitiesbuffer = R_GetSkinAvailabilities(true, false);
|
||||
|
||||
WRITEUINT8((*pp), numskins);
|
||||
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)
|
||||
{
|
||||
const UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||
const UINT8 difficulty = cv_kartbot.value;
|
||||
UINT8 pmax = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
|
||||
UINT8 numplayers = 0;
|
||||
UINT8 numbots = 0;
|
||||
UINT8 numwaiting = 0;
|
||||
SINT8 wantedbots = 0;
|
||||
boolean skinusable[MAXSKINS];
|
||||
UINT8 usableskins = 0;
|
||||
UINT8 grabskins[MAXSKINS+1];
|
||||
UINT8 i;
|
||||
|
||||
if (!server)
|
||||
|
|
@ -122,18 +124,12 @@ void K_UpdateMatchRaceBots(void)
|
|||
return;
|
||||
}
|
||||
|
||||
// init usable bot skins list
|
||||
for (i = 0; i < MAXSKINS; i++)
|
||||
// Init usable bot skins list
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
if (i < numskins)
|
||||
{
|
||||
skinusable[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
skinusable[i] = false;
|
||||
}
|
||||
grabskins[usableskins++] = i;
|
||||
}
|
||||
grabskins[usableskins] = MAXSKINS;
|
||||
|
||||
if (cv_maxplayers.value > 0)
|
||||
{
|
||||
|
|
@ -146,7 +142,7 @@ void K_UpdateMatchRaceBots(void)
|
|||
{
|
||||
if (!players[i].spectator)
|
||||
{
|
||||
skinusable[players[i].skin] = false;
|
||||
grabskins[players[i].skin] = MAXSKINS;
|
||||
|
||||
if (players[i].bot)
|
||||
{
|
||||
|
|
@ -185,48 +181,42 @@ void K_UpdateMatchRaceBots(void)
|
|||
{
|
||||
// We require MORE bots!
|
||||
UINT8 newplayernum = 0;
|
||||
boolean usedallskins = false;
|
||||
|
||||
if (dedicated)
|
||||
{
|
||||
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)
|
||||
{
|
||||
UINT8 skin = M_RandomKey(numskins);
|
||||
UINT8 skinnum = defaultbotskin;
|
||||
|
||||
if (usedallskins == false)
|
||||
if (usableskins > 0)
|
||||
{
|
||||
UINT8 loops = 0;
|
||||
|
||||
while (!skinusable[skin])
|
||||
{
|
||||
if (loops >= numskins)
|
||||
{
|
||||
// no more skins, stick to our first choice
|
||||
usedallskins = true;
|
||||
break;
|
||||
}
|
||||
|
||||
skin++;
|
||||
|
||||
if (skin >= numskins)
|
||||
{
|
||||
skin = 0;
|
||||
}
|
||||
|
||||
loops++;
|
||||
}
|
||||
UINT8 index = M_RandomKey(usableskins);
|
||||
skinnum = grabskins[index];
|
||||
grabskins[index] = grabskins[--usableskins];
|
||||
}
|
||||
|
||||
if (!K_AddBot(skin, difficulty, &newplayernum))
|
||||
if (!K_AddBot(skinnum, difficulty, &newplayernum))
|
||||
{
|
||||
// Not enough player slots to add the bot, break the loop.
|
||||
break;
|
||||
}
|
||||
|
||||
skinusable[skin] = false;
|
||||
numbots++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,25 +95,6 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
|
|||
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)
|
||||
|
||||
|
|
@ -121,7 +102,7 @@ UINT8 K_BotDefaultSkin(void)
|
|||
--------------------------------------------------*/
|
||||
void K_InitGrandPrixBots(void)
|
||||
{
|
||||
const UINT8 defaultbotskin = K_BotDefaultSkin();
|
||||
const UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||
|
||||
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
||||
UINT8 difficultylevels[MAXPLAYERS];
|
||||
|
|
@ -519,7 +500,7 @@ void K_IncreaseBotDifficulty(player_t *bot)
|
|||
--------------------------------------------------*/
|
||||
void K_RetireBots(void)
|
||||
{
|
||||
const UINT8 defaultbotskin = K_BotDefaultSkin();
|
||||
const UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||
SINT8 newDifficulty;
|
||||
|
||||
UINT8 usableskins;
|
||||
|
|
|
|||
|
|
@ -71,16 +71,6 @@ UINT8 K_BotStartingDifficulty(SINT8 value);
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,27 @@ static void Sk_SetDefaultValue(skin_t *skin)
|
|||
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
|
||||
//
|
||||
|
|
@ -159,11 +180,12 @@ void R_InitSkins(void)
|
|||
M_UpdateConditionSetsPending();
|
||||
}
|
||||
|
||||
UINT8 *R_GetSkinAvailabilities(boolean demolock)
|
||||
UINT8 *R_GetSkinAvailabilities(boolean demolock, boolean forbots)
|
||||
{
|
||||
UINT8 i, shif, byte;
|
||||
INT32 skinid;
|
||||
static UINT8 responsebuffer[MAXAVAILABILITY];
|
||||
UINT8 defaultbotskin = R_BotDefaultSkin();
|
||||
|
||||
memset(&responsebuffer, 0, sizeof(responsebuffer));
|
||||
|
||||
|
|
@ -172,15 +194,17 @@ UINT8 *R_GetSkinAvailabilities(boolean demolock)
|
|||
if (unlockables[i].type != SECRET_SKIN)
|
||||
continue;
|
||||
|
||||
// NEVER EVER EVER M_CheckNetUnlockByID
|
||||
if (gamedata->unlocked[i] != true && !demolock)
|
||||
continue;
|
||||
|
||||
skinid = M_UnlockableSkinNum(&unlockables[i]);
|
||||
|
||||
if (skinid < 0 || skinid >= MAXSKINS)
|
||||
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);
|
||||
byte = (skinid / 8);
|
||||
|
||||
|
|
@ -251,8 +275,11 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins)
|
|||
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
|
||||
// NOTE: M_CheckNetUnlockByID would be correct in many circumstances... but not all. TODO figure out how to discern.
|
||||
return (boolean)(gamedata->unlocked[i]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,9 @@ void ClearFakePlayerSkin(player_t* player);
|
|||
boolean R_SkinUsable(INT32 playernum, INT32 skinnum, boolean demoskins);
|
||||
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);
|
||||
UINT8 R_BotDefaultSkin(void);
|
||||
|
||||
void R_PatchSkins(UINT16 wadnum, boolean mainfile);
|
||||
void R_AddSkins(UINT16 wadnum, boolean mainfile);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue