mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-11 09:12:22 +00:00
SECRET_FOLLOWER
Completely clientside, unlike SECRET_SKIN. Followers have no gameplay function, and it saves us having to write even more to our demos/netsaves. Replaces SECRET_WARP. Also: - Now don't apply skins or followers from profiles if the skin is locked - instead, get the closest skin in stats. (Same function as from demos!) - If you're looking at a profile and the skin or follower are locked, make them solid colour (TC_BLINK). - Don't show the ring cursor before you've selected a profile.
This commit is contained in:
parent
a33d6d9235
commit
fefaee1982
12 changed files with 271 additions and 112 deletions
|
|
@ -1535,7 +1535,8 @@ static void SendNameAndColor(UINT8 n)
|
|||
|
||||
K_KartResetPlayerColor(player);
|
||||
|
||||
if ((foundskin = R_SkinAvailable(cv_skin[n].string)) != -1 && R_SkinUsable(playernum, foundskin, false))
|
||||
foundskin = R_SkinAvailable(cv_skin[n].string);
|
||||
if (foundskin != -1 && R_SkinUsable(playernum, foundskin, false))
|
||||
{
|
||||
SetPlayerSkin(playernum, cv_skin[n].string);
|
||||
CV_StealthSet(&cv_skin[n], skins[foundskin].name);
|
||||
|
|
@ -1553,6 +1554,8 @@ static void SendNameAndColor(UINT8 n)
|
|||
|
||||
// Update follower for local games:
|
||||
foundskin = K_FollowerAvailable(cv_follower[n].string);
|
||||
if (!K_FollowerUsable(foundskin))
|
||||
foundskin = -1;
|
||||
CV_StealthSet(&cv_follower[n], (foundskin == -1) ? "None" : followers[foundskin].name);
|
||||
cv_follower[n].value = foundskin;
|
||||
K_SetFollowerByNum(playernum, foundskin);
|
||||
|
|
@ -1587,7 +1590,7 @@ static void SendNameAndColor(UINT8 n)
|
|||
}
|
||||
|
||||
cv_follower[n].value = K_FollowerAvailable(cv_follower[n].string);
|
||||
if (cv_follower[n].value < 0)
|
||||
if (cv_follower[n].value < 0 || !K_FollowerUsable(cv_follower[n].value))
|
||||
{
|
||||
CV_StealthSet(&cv_follower[n], "None");
|
||||
cv_follower[n].value = -1;
|
||||
|
|
|
|||
|
|
@ -2265,8 +2265,8 @@ void readunlockable(MYFILE *f, INT32 num)
|
|||
unlockables[num].type = SECRET_HEADER;
|
||||
else if (fastcmp(word2, "SKIN"))
|
||||
unlockables[num].type = SECRET_SKIN;
|
||||
else if (fastcmp(word2, "WARP"))
|
||||
unlockables[num].type = SECRET_WARP;
|
||||
else if (fastcmp(word2, "FOLLOWER"))
|
||||
unlockables[num].type = SECRET_FOLLOWER;
|
||||
else if (fastcmp(word2, "TIMEATTACK"))
|
||||
unlockables[num].type = SECRET_TIMEATTACK;
|
||||
else if (fastcmp(word2, "BREAKTHECAPSULES"))
|
||||
|
|
|
|||
43
src/g_demo.c
43
src/g_demo.c
|
|
@ -212,47 +212,6 @@ void G_LoadMetal(UINT8 **buffer)
|
|||
metal_p = metalbuffer + READUINT32(*buffer);
|
||||
}
|
||||
|
||||
// Finds a skin with the closest stats if the expected skin doesn't exist.
|
||||
static INT32 GetSkinNumClosestToStats(UINT8 kartspeed, UINT8 kartweight, UINT32 flags)
|
||||
{
|
||||
INT32 i, closest_skin = 0;
|
||||
UINT8 closest_stats, stat_diff;
|
||||
boolean doflagcheck = true;
|
||||
UINT32 flagcheck = flags;
|
||||
|
||||
flaglessretry:
|
||||
closest_stats = UINT8_MAX;
|
||||
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
stat_diff = abs(skins[i].kartspeed - kartspeed) + abs(skins[i].kartweight - kartweight);
|
||||
if (doflagcheck && (skins[i].flags & flagcheck) != flagcheck)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (stat_diff < closest_stats)
|
||||
{
|
||||
closest_stats = stat_diff;
|
||||
closest_skin = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat_diff && (doflagcheck || closest_stats == UINT8_MAX))
|
||||
{
|
||||
// Just grab *any* SF_IRONMAN if we don't get it on the first pass.
|
||||
if ((flagcheck & SF_IRONMAN) && (flagcheck != SF_IRONMAN))
|
||||
{
|
||||
flagcheck = SF_IRONMAN;
|
||||
}
|
||||
|
||||
doflagcheck = false;
|
||||
|
||||
goto flaglessretry;
|
||||
}
|
||||
|
||||
return closest_skin;
|
||||
}
|
||||
|
||||
void G_ReadDemoExtraData(void)
|
||||
{
|
||||
INT32 p, extradata, i;
|
||||
|
|
@ -2321,7 +2280,7 @@ static democharlist_t *G_LoadDemoSkins(UINT8 **pp, UINT8 *worknumskins, boolean
|
|||
}
|
||||
else
|
||||
{
|
||||
result = GetSkinNumClosestToStats(skinlist[i].kartspeed, skinlist[i].kartweight, skinlist[i].flags);
|
||||
result = GetSkinNumClosestToStats(skinlist[i].kartspeed, skinlist[i].kartweight, skinlist[i].flags, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "r_skins.h"
|
||||
#include "p_local.h"
|
||||
#include "p_mobj.h"
|
||||
#include "m_cond.h"
|
||||
|
||||
INT32 numfollowers = 0;
|
||||
follower_t followers[MAXSKINS];
|
||||
|
|
@ -38,6 +39,49 @@ INT32 K_FollowerAvailable(const char *name)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
INT32 K_FollowerUsable(INT32 followernum)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_FollowerUsable(INT32 skinnum)
|
||||
{
|
||||
// Unlike R_SkinUsable, not netsynced.
|
||||
// Solely used to prevent an invalid value being sent over the wire.
|
||||
UINT8 i;
|
||||
INT32 fid;
|
||||
|
||||
if (skinnum == -1 || demo.playback)
|
||||
{
|
||||
// Simplifies things elsewhere, since there's already plenty of checks for less-than-0...
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine if this follower is supposed to be unlockable or not
|
||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||
{
|
||||
if (unlockables[i].type != SECRET_FOLLOWER)
|
||||
continue;
|
||||
|
||||
fid = M_UnlockableFollowerNum(&unlockables[i]);
|
||||
|
||||
if (fid != skinnum)
|
||||
continue;
|
||||
|
||||
// i is now the unlockable index, we can use this later
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == MAXUNLOCKABLES)
|
||||
{
|
||||
// Didn't trip anything, so we can use this follower.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use the unlockables table directly
|
||||
return (boolean)(gamedata->unlocked[i]);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_SetFollowerByName(INT32 playernum, const char *skinname)
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,22 @@ extern followercategory_t followercategories[MAXFOLLOWERCATEGORIES];
|
|||
INT32 K_FollowerAvailable(const char *name);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_FollowerUsable(INT32 followernum);
|
||||
|
||||
Check if a follower is usable or not.
|
||||
|
||||
Input Arguments:-
|
||||
skinnum - The follower's skin ID
|
||||
|
||||
Return:-
|
||||
true if it was a valid follower,
|
||||
otherwise false.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_FollowerUsable(INT32 skinnum);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_SetFollowerByName(INT32 playernum, const char *skinname)
|
||||
|
||||
|
|
|
|||
|
|
@ -596,6 +596,9 @@ extern struct setup_chargrid_s {
|
|||
UINT8 numskins;
|
||||
} setup_chargrid[9][9];
|
||||
|
||||
extern UINT8 setup_followercategories[MAXFOLLOWERCATEGORIES][2];
|
||||
extern UINT8 setup_numfollowercategories;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CSSTEP_NONE = 0,
|
||||
|
|
|
|||
|
|
@ -981,10 +981,10 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y)
|
|||
numoptions = nummenucolors;
|
||||
break;
|
||||
case CSSTEP_FOLLOWERCATEGORY:
|
||||
numoptions = numfollowercategories+1;
|
||||
numoptions = setup_numfollowercategories+1;
|
||||
break;
|
||||
case CSSTEP_FOLLOWER:
|
||||
numoptions = followercategories[p->followercategory].numincategory;
|
||||
numoptions = setup_followercategories[p->followercategory][0];
|
||||
break;
|
||||
case CSSTEP_FOLLOWERCOLORS:
|
||||
numoptions = nummenucolors+2;
|
||||
|
|
@ -1084,7 +1084,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y)
|
|||
}
|
||||
else
|
||||
{
|
||||
fc = &followercategories[n - 1];
|
||||
fc = &followercategories[setup_followercategories[n - 1][1]];
|
||||
patch = W_CachePatchName(fc->icon, PU_CACHE);
|
||||
}
|
||||
|
||||
|
|
@ -1111,7 +1111,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y)
|
|||
n = numfollowers-1;
|
||||
if (n == startfollowern)
|
||||
break;
|
||||
if (followers[n].category == p->followercategory)
|
||||
if (followers[n].category == setup_followercategories[p->followercategory][1])
|
||||
r--;
|
||||
}
|
||||
l = r = n;
|
||||
|
|
@ -1126,7 +1126,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y)
|
|||
if (l == startfollowern)
|
||||
break;
|
||||
}
|
||||
while (followers[l].category != p->followercategory);
|
||||
while (followers[l].category != setup_followercategories[p->followercategory][1]);
|
||||
n = l;
|
||||
}
|
||||
else
|
||||
|
|
@ -1139,7 +1139,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y)
|
|||
if (r == startfollowern)
|
||||
break;
|
||||
}
|
||||
while (followers[r].category != p->followercategory);
|
||||
while (followers[r].category != setup_followercategories[p->followercategory][1]);
|
||||
n = r;
|
||||
}
|
||||
|
||||
|
|
@ -1266,7 +1266,7 @@ static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, boolean charf
|
|||
// Returns false is the follower shouldn't be rendered.
|
||||
// 'num' can be used to directly specify the follower number, but doing this will not animate it.
|
||||
// if a setup_player_t is specified instead, its data will be used to animate the follower sprite.
|
||||
static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charflip, INT32 addflags, UINT16 color, setup_player_t *p)
|
||||
static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charflip, INT32 addflags, UINT8 *colormap, setup_player_t *p)
|
||||
{
|
||||
|
||||
spritedef_t *sprdef;
|
||||
|
|
@ -1276,7 +1276,6 @@ static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charfli
|
|||
state_t *usestate;
|
||||
UINT32 useframe;
|
||||
follower_t fl;
|
||||
UINT8 *colormap = NULL;
|
||||
UINT8 rotation = (charflip ? 1 : 7);
|
||||
|
||||
if (p != NULL)
|
||||
|
|
@ -1320,13 +1319,13 @@ static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charfli
|
|||
|
||||
if (p != NULL)
|
||||
{
|
||||
sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * p->follower_timer)>>ANGLETOFINESHIFT) & FINEMASK));
|
||||
color = K_GetEffectiveFollowerColor(
|
||||
UINT16 color = K_GetEffectiveFollowerColor(
|
||||
(p->mdepth < CSSTEP_FOLLOWERCOLORS) ? fl.defaultcolor : p->followercolor,
|
||||
p->color);
|
||||
sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * p->follower_timer)>>ANGLETOFINESHIFT) & FINEMASK));
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, color, GTC_MENUCACHE);
|
||||
}
|
||||
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, color, GTC_MENUCACHE);
|
||||
V_DrawFixedPatch((x*FRACUNIT), ((y-12)*FRACUNIT) + sine, fl.scale, addflags, patch, colormap);
|
||||
|
||||
return true;
|
||||
|
|
@ -1540,6 +1539,9 @@ static void M_DrawCharSelectCursor(UINT8 num)
|
|||
INT16 x, y;
|
||||
INT16 quadx, quady;
|
||||
|
||||
if (p->mdepth < CSSTEP_ASKCHANGES)
|
||||
return;
|
||||
|
||||
quadx = 4 * (p->gridx / 3);
|
||||
quady = 4 * (p->gridy / 3);
|
||||
|
||||
|
|
@ -1583,6 +1585,7 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p)
|
|||
patch_t *card = W_CachePatchName("PR_CARD", PU_CACHE);
|
||||
patch_t *cardbot = W_CachePatchName("PR_CARDB", PU_CACHE);
|
||||
patch_t *pwrlv = W_CachePatchName("PR_PWR", PU_CACHE);
|
||||
UINT16 truecol = SKINCOLOR_BLACK;
|
||||
UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_BLACK, GTC_CACHE);
|
||||
INT32 skinnum = -1;
|
||||
INT32 powerlevel = -1;
|
||||
|
|
@ -1591,7 +1594,8 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p)
|
|||
|
||||
if (p != NULL && p->version)
|
||||
{
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, PR_GetProfileColor(p), GTC_CACHE);
|
||||
truecol = PR_GetProfileColor(p);
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, truecol, GTC_CACHE);
|
||||
strcpy(pname, p->profilename);
|
||||
skinnum = R_SkinAvailable(p->skinname);
|
||||
powerlevel = p->powerlevels[0]; // Only display race power level.
|
||||
|
|
@ -1600,7 +1604,10 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p)
|
|||
// check setup_player for colormap for the card.
|
||||
// we'll need to check again for drawing afterwards unfortunately.
|
||||
if (sp->mdepth >= CSSTEP_CHARS)
|
||||
{
|
||||
truecol = PR_GetProfileColor(p);
|
||||
colormap = R_GetTranslationColormap(skinnum, sp->color, GTC_MENUCACHE);
|
||||
}
|
||||
|
||||
// Card
|
||||
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, greyedout ? V_TRANSLUCENT : 0, card, colormap);
|
||||
|
|
@ -1634,25 +1641,34 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p)
|
|||
{
|
||||
UINT16 col = K_GetEffectiveFollowerColor(sp->followercolor, sp->color);;
|
||||
patch_t *ico = W_CachePatchName(followers[sp->followern].icon, PU_CACHE);
|
||||
UINT8 *fcolormap;
|
||||
|
||||
fcolormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
|
||||
UINT8 *fcolormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
|
||||
V_DrawMappedPatch(x+14+18, y+66, 0, ico, fcolormap);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (skinnum > -1) // otherwise, read from profile.
|
||||
{
|
||||
UINT16 col = K_GetEffectiveFollowerColor(p->followercolor, p->color);;
|
||||
UINT8 *ccolormap, *fcolormap;
|
||||
UINT16 col = K_GetEffectiveFollowerColor(p->followercolor, p->color);
|
||||
UINT8 fln = K_FollowerAvailable(p->follower);
|
||||
|
||||
if (M_DrawCharacterSprite(x-22, y+119, skinnum, false, false, 0, colormap))
|
||||
V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], colormap);
|
||||
if (R_SkinUsable(g_localplayers[0], skinnum, false))
|
||||
ccolormap = colormap;
|
||||
else
|
||||
ccolormap = R_GetTranslationColormap(TC_BLINK, truecol, GTC_MENUCACHE);
|
||||
|
||||
if (M_DrawFollowerSprite(x-22 - 16, y+119, fln, false, 0, col, NULL))
|
||||
fcolormap = R_GetTranslationColormap(
|
||||
(K_FollowerUsable(fln) ? TC_DEFAULT : TC_BLINK),
|
||||
col, GTC_MENUCACHE);
|
||||
|
||||
if (M_DrawCharacterSprite(x-22, y+119, skinnum, false, false, 0, ccolormap))
|
||||
{
|
||||
V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], ccolormap);
|
||||
}
|
||||
|
||||
if (M_DrawFollowerSprite(x-22 - 16, y+119, fln, false, 0, fcolormap, NULL))
|
||||
{
|
||||
patch_t *ico = W_CachePatchName(followers[fln].icon, PU_CACHE);
|
||||
UINT8 *fcolormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
|
||||
V_DrawMappedPatch(x+14+18, y+66, 0, ico, fcolormap);
|
||||
}
|
||||
}
|
||||
|
|
@ -1718,8 +1734,11 @@ void M_DrawCharacterSelect(void)
|
|||
{
|
||||
for (k = 0; k < setup_numplayers; k++)
|
||||
{
|
||||
if (setup_player[k].gridx == i && setup_player[k].gridy == j)
|
||||
break; // k == setup_numplayers means no one has it selected
|
||||
if (setup_player[k].mdepth < CSSTEP_ASKCHANGES)
|
||||
continue;
|
||||
if (setup_player[k].gridx != i || setup_player[k].gridy != j)
|
||||
continue;
|
||||
break; // k == setup_numplayers means no one has it selected
|
||||
}
|
||||
|
||||
skin = setup_chargrid[i][j].skinlist[setup_page];
|
||||
|
|
@ -4532,7 +4551,6 @@ void M_DrawChallenges(void)
|
|||
}
|
||||
else switch (ref->type)
|
||||
{
|
||||
// add all SECRET_ENCORE, etc up here before SECRET_SKIN
|
||||
case SECRET_SKIN:
|
||||
{
|
||||
INT32 skin = M_UnlockableSkinNum(ref);
|
||||
|
|
@ -4543,6 +4561,17 @@ void M_DrawChallenges(void)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case SECRET_FOLLOWER:
|
||||
{
|
||||
INT32 skin = M_UnlockableFollowerNum(ref);
|
||||
if (skin != -1)
|
||||
{
|
||||
UINT16 col = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value);
|
||||
colormap = R_GetTranslationColormap(skin, col, GTC_MENUCACHE);
|
||||
pat = W_CachePatchName(followers[skin].icon, PU_CACHE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
pat = W_CachePatchName(va("UN_RR00%c", ref->majorunlock ? 'B' : 'A'), PU_CACHE);
|
||||
|
|
|
|||
110
src/k_menufunc.c
110
src/k_menufunc.c
|
|
@ -2053,7 +2053,10 @@ void M_QuitSRB2(INT32 choice)
|
|||
|
||||
struct setup_chargrid_s setup_chargrid[9][9];
|
||||
setup_player_t setup_player[MAXSPLITSCREENPLAYERS];
|
||||
struct setup_explosions_s setup_explosions[48];
|
||||
struct setup_explosions_s setup_explosions[CSEXPLOSIONS];
|
||||
|
||||
UINT8 setup_followercategories[MAXFOLLOWERCATEGORIES][2];
|
||||
UINT8 setup_numfollowercategories;
|
||||
|
||||
UINT8 setup_numplayers = 0; // This variable is very important, it was extended to determine how many players exist in ALL menus.
|
||||
tic_t setup_animcounter = 0;
|
||||
|
|
@ -2065,64 +2068,61 @@ UINT8 setup_maxpage = 0; // For charsel page to identify alts easier...
|
|||
static void M_SetupProfileGridPos(setup_player_t *p)
|
||||
{
|
||||
profile_t *pr = PR_GetProfile(p->profilen);
|
||||
INT32 i;
|
||||
INT32 i = R_SkinAvailable(pr->skinname);
|
||||
INT32 alt = 0; // Hey it's my character's name!
|
||||
|
||||
// While we're here, read follower values.
|
||||
p->followern = K_FollowerAvailable(pr->follower);
|
||||
|
||||
if (p->followern < 0 || p->followern >= numfollowers || followers[p->followern].category >= numfollowercategories)
|
||||
p->followercategory = -1;
|
||||
if (p->followern < 0 || p->followern >= numfollowers || followers[p->followern].category >= numfollowercategories || !K_FollowerUsable(p->followern))
|
||||
p->followercategory = p->followern = -1;
|
||||
else
|
||||
p->followercategory = followers[p->followern].category;
|
||||
|
||||
p->followercolor = pr->followercolor;
|
||||
|
||||
// Now position the grid for skin
|
||||
for (i = 0; i < numskins; i++)
|
||||
if (!R_SkinUsable(g_localplayers[0], i, false))
|
||||
{
|
||||
if (!(strcmp(pr->skinname, skins[i].name)))
|
||||
{
|
||||
INT32 alt = 0; // Hey it's my character's name!
|
||||
p->gridx = skins[i].kartspeed-1;
|
||||
p->gridy = skins[i].kartweight-1;
|
||||
|
||||
// Now this put our cursor on the good alt
|
||||
while (setup_chargrid[p->gridx][p->gridy].skinlist[alt] != i)
|
||||
alt++;
|
||||
|
||||
p->clonenum = alt;
|
||||
p->color = PR_GetProfileColor(pr);
|
||||
return; // we're done here
|
||||
}
|
||||
i = GetSkinNumClosestToStats(skins[i].kartspeed, skins[i].kartweight, skins[i].flags, false);
|
||||
}
|
||||
|
||||
// Now position the grid for skin
|
||||
p->gridx = skins[i].kartspeed-1;
|
||||
p->gridy = skins[i].kartweight-1;
|
||||
|
||||
// Now this put our cursor on the good alt
|
||||
while (alt < setup_chargrid[p->gridx][p->gridy].numskins && setup_chargrid[p->gridx][p->gridy].skinlist[alt] != i)
|
||||
alt++;
|
||||
|
||||
p->clonenum = alt;
|
||||
p->color = PR_GetProfileColor(pr);
|
||||
}
|
||||
|
||||
static void M_SetupMidGameGridPos(setup_player_t *p, UINT8 num)
|
||||
{
|
||||
INT32 i;
|
||||
INT32 i = R_SkinAvailable(cv_skin[num].zstring);
|
||||
INT32 alt = 0; // Hey it's my character's name!
|
||||
|
||||
// While we're here, read follower values.
|
||||
p->followern = cv_follower[num].value;
|
||||
p->followercolor = cv_followercolor[num].value;
|
||||
|
||||
if (p->followern < 0 || p->followern >= numfollowers || followers[p->followern].category >= numfollowercategories || !K_FollowerUsable(p->followern))
|
||||
p->followercategory = p->followern = -1;
|
||||
else
|
||||
p->followercategory = followers[p->followern].category;
|
||||
|
||||
// Now position the grid for skin
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
if (!(strcmp(cv_skin[num].zstring, skins[i].name)))
|
||||
{
|
||||
INT32 alt = 0; // Hey it's my character's name!
|
||||
p->gridx = skins[i].kartspeed-1;
|
||||
p->gridy = skins[i].kartweight-1;
|
||||
p->gridx = skins[i].kartspeed-1;
|
||||
p->gridy = skins[i].kartweight-1;
|
||||
|
||||
// Now this put our cursor on the good alt
|
||||
while (setup_chargrid[p->gridx][p->gridy].skinlist[alt] != i)
|
||||
alt++;
|
||||
// Now this put our cursor on the good alt
|
||||
while (alt < setup_chargrid[p->gridx][p->gridy].numskins && setup_chargrid[p->gridx][p->gridy].skinlist[alt] != i)
|
||||
alt++;
|
||||
|
||||
p->clonenum = alt;
|
||||
p->color = cv_playercolor[num].value;
|
||||
return; // we're done here
|
||||
}
|
||||
}
|
||||
p->clonenum = alt;
|
||||
p->color = cv_playercolor[num].value;
|
||||
return; // we're done here
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2219,6 +2219,32 @@ void M_CharacterSelectInit(void)
|
|||
}
|
||||
}
|
||||
|
||||
setup_numfollowercategories = 0;
|
||||
for (i = 0; i < numfollowercategories; i++)
|
||||
{
|
||||
if (followercategories[i].numincategory == 0)
|
||||
continue;
|
||||
|
||||
setup_followercategories[setup_numfollowercategories][0] = 0;
|
||||
|
||||
for (j = 0; j < numfollowers; j++)
|
||||
{
|
||||
if (followers[j].category != i)
|
||||
continue;
|
||||
|
||||
if (!K_FollowerUsable(j))
|
||||
continue;
|
||||
|
||||
setup_followercategories[setup_numfollowercategories][0]++;
|
||||
setup_followercategories[setup_numfollowercategories][1] = i;
|
||||
}
|
||||
|
||||
if (!setup_followercategories[setup_numfollowercategories][0])
|
||||
continue;
|
||||
|
||||
setup_numfollowercategories++;
|
||||
}
|
||||
|
||||
setup_page = 0;
|
||||
}
|
||||
|
||||
|
|
@ -2843,7 +2869,7 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num)
|
|||
if (menucmd[num].dpad_lr > 0)
|
||||
{
|
||||
p->followercategory++;
|
||||
if (p->followercategory >= numfollowercategories)
|
||||
if (p->followercategory >= setup_numfollowercategories)
|
||||
p->followercategory = -1;
|
||||
|
||||
p->rotate = CSROTATETICS;
|
||||
|
|
@ -2854,7 +2880,7 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num)
|
|||
{
|
||||
p->followercategory--;
|
||||
if (p->followercategory < -1)
|
||||
p->followercategory = numfollowercategories-1;
|
||||
p->followercategory = setup_numfollowercategories-1;
|
||||
|
||||
p->rotate = -CSROTATETICS;
|
||||
p->delay = CSROTATETICS;
|
||||
|
|
@ -2876,7 +2902,9 @@ static void M_HandleFollowerCategoryRotate(setup_player_t *p, UINT8 num)
|
|||
if (p->followern < 0 || followers[p->followern].category != p->followercategory)
|
||||
{
|
||||
p->followern = 0;
|
||||
while (p->followern < numfollowers && followers[p->followern].category != p->followercategory)
|
||||
while (p->followern < numfollowers
|
||||
&& (followers[p->followern].category != setup_followercategories[p->followercategory][1]
|
||||
|| !K_FollowerUsable(p->followern)))
|
||||
p->followern++;
|
||||
}
|
||||
|
||||
|
|
@ -2931,7 +2959,7 @@ static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num)
|
|||
if (p->followern == startfollowern)
|
||||
break;
|
||||
}
|
||||
while (followers[p->followern].category != p->followercategory);
|
||||
while (followers[p->followern].category != setup_followercategories[p->followercategory][1] || !K_FollowerUsable(p->followern));
|
||||
|
||||
M_GetFollowerState(p);
|
||||
|
||||
|
|
@ -2949,7 +2977,7 @@ static void M_HandleFollowerRotate(setup_player_t *p, UINT8 num)
|
|||
if (p->followern == startfollowern)
|
||||
break;
|
||||
}
|
||||
while (followers[p->followern].category != p->followercategory);
|
||||
while (followers[p->followern].category != setup_followercategories[p->followercategory][1] || !K_FollowerUsable(p->followern));
|
||||
|
||||
M_GetFollowerState(p);
|
||||
|
||||
|
|
|
|||
32
src/m_cond.c
32
src/m_cond.c
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "g_game.h" // record info
|
||||
#include "r_skins.h" // numskins
|
||||
#include "k_follower.h"
|
||||
#include "r_draw.h" // R_GetColorByName
|
||||
|
||||
#include "k_pwrlv.h"
|
||||
|
|
@ -860,7 +861,7 @@ INT32 M_UnlockableSkinNum(unlockable_t *unlock)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (unlock->stringVar && strcmp(unlock->stringVar, ""))
|
||||
if (unlock->stringVar && unlock->stringVar[0])
|
||||
{
|
||||
// Get the skin from the string.
|
||||
INT32 skinnum = R_SkinAvailable(unlock->stringVar);
|
||||
|
|
@ -880,6 +881,35 @@ INT32 M_UnlockableSkinNum(unlockable_t *unlock)
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Gets the skin number for a SECRET_FOLLOWER unlockable.
|
||||
INT32 M_UnlockableFollowerNum(unlockable_t *unlock)
|
||||
{
|
||||
if (unlock->type != SECRET_FOLLOWER)
|
||||
{
|
||||
// This isn't a follower unlockable...
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (unlock->stringVar && unlock->stringVar[0])
|
||||
{
|
||||
// Get the skin from the string.
|
||||
INT32 skinnum = K_FollowerAvailable(unlock->stringVar);
|
||||
if (skinnum != -1)
|
||||
{
|
||||
return skinnum;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlock->variable >= 0 && unlock->variable < numfollowers)
|
||||
{
|
||||
// Use the number directly.
|
||||
return unlock->variable;
|
||||
}
|
||||
|
||||
// Invalid follower unlockable.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ----------------
|
||||
// Misc Emblem shit
|
||||
// ----------------
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ typedef struct
|
|||
#define SECRET_HEADER 1 // Does nothing on its own, just serves as a header for the menu
|
||||
|
||||
#define SECRET_SKIN 2 // Allow this character to be selected
|
||||
#define SECRET_WARP 3 // Selectable warp (todo Followers)
|
||||
#define SECRET_FOLLOWER 3 // Allow this follower to be selected
|
||||
|
||||
#define SECRET_EXTRAEMBLEM 4 // Extra Emblems (formerly extraemblem_t)
|
||||
|
||||
|
|
@ -201,6 +201,7 @@ UINT8 M_GotEnoughEmblems(INT32 number);
|
|||
UINT8 M_GotLowEnoughTime(INT32 tictime);
|
||||
|
||||
INT32 M_UnlockableSkinNum(unlockable_t *unlock);
|
||||
INT32 M_UnlockableFollowerNum(unlockable_t *unlock);
|
||||
INT32 M_EmblemSkinNum(emblem_t *emblem);
|
||||
|
||||
#define M_Achieved(a) ((a) >= MAXCONDITIONSETS || gamedata->achieved[a])
|
||||
|
|
|
|||
|
|
@ -505,6 +505,51 @@ void ClearFakePlayerSkin(player_t* player)
|
|||
player->fakeskin = MAXSKINS;
|
||||
}
|
||||
|
||||
// Finds a skin with the closest stats if the expected skin doesn't exist.
|
||||
INT32 GetSkinNumClosestToStats(UINT8 kartspeed, UINT8 kartweight, UINT32 flags, boolean unlock)
|
||||
{
|
||||
INT32 i, closest_skin = 0;
|
||||
UINT8 closest_stats, stat_diff;
|
||||
boolean doflagcheck = true;
|
||||
UINT32 flagcheck = flags;
|
||||
|
||||
flaglessretry:
|
||||
closest_stats = stat_diff = UINT8_MAX;
|
||||
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
if (!unlock && !R_SkinUsable(-1, i, false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
stat_diff = abs(skins[i].kartspeed - kartspeed) + abs(skins[i].kartweight - kartweight);
|
||||
if (doflagcheck && (skins[i].flags & flagcheck) != flagcheck)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (stat_diff < closest_stats)
|
||||
{
|
||||
closest_stats = stat_diff;
|
||||
closest_skin = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (stat_diff && (doflagcheck || closest_stats == UINT8_MAX))
|
||||
{
|
||||
// Just grab *any* SF_IRONMAN if we don't get it on the first pass.
|
||||
if ((flagcheck & SF_IRONMAN) && (flagcheck != SF_IRONMAN))
|
||||
{
|
||||
flagcheck = SF_IRONMAN;
|
||||
}
|
||||
|
||||
doflagcheck = false;
|
||||
|
||||
goto flaglessretry;
|
||||
}
|
||||
|
||||
return closest_skin;
|
||||
}
|
||||
|
||||
//
|
||||
// Add skins from a pwad, each skin preceded by 'S_SKIN' marker
|
||||
//
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ void SetFakePlayerSkin(player_t* player, INT32 skinnum);
|
|||
void SetRandomFakePlayerSkin(player_t* player, boolean fast);
|
||||
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);
|
||||
INT32 R_SkinAvailable(const char *name);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue