Merge branch 'challenges-bonnus' into 'master'

Challenges Bonnus

See merge request kart-krew-dev/ring-racers-internal!2738
This commit is contained in:
Oni VelocitOni 2025-08-19 19:39:29 +00:00
commit f8f4d6cfd6
14 changed files with 726 additions and 266 deletions

View file

@ -1051,7 +1051,14 @@ static void SendNameAndColor(const UINT8 n)
WRITESTRINGN(p, cv_playername[n].zstring, MAXPLAYERNAME); WRITESTRINGN(p, cv_playername[n].zstring, MAXPLAYERNAME);
WRITEUINT16(p, sendColor); WRITEUINT16(p, sendColor);
WRITEUINT8(p, (UINT8)cv_skin[n].value); WRITEUINT8(p, (UINT8)cv_skin[n].value);
if (horngoner)
{
WRITEINT16(p, (-1));
}
else
{
WRITEINT16(p, (INT16)cv_follower[n].value); WRITEINT16(p, (INT16)cv_follower[n].value);
}
//CONS_Printf("Sending follower id %d\n", (INT16)cv_follower[n].value); //CONS_Printf("Sending follower id %d\n", (INT16)cv_follower[n].value);
WRITEUINT16(p, sendFollowerColor); WRITEUINT16(p, sendFollowerColor);

View file

@ -32,6 +32,8 @@ follower_t followers[MAXFOLLOWERS];
INT32 numfollowercategories; INT32 numfollowercategories;
followercategory_t followercategories[MAXFOLLOWERCATEGORIES]; followercategory_t followercategories[MAXFOLLOWERCATEGORIES];
boolean horngoner = false;
CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+3]; // +3 to account for "Match", "Opposite" & NULL CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+3]; // +3 to account for "Match", "Opposite" & NULL
/*-------------------------------------------------- /*--------------------------------------------------

View file

@ -115,6 +115,8 @@ struct followercategory_t
extern INT32 numfollowercategories; extern INT32 numfollowercategories;
extern followercategory_t followercategories[MAXFOLLOWERCATEGORIES]; extern followercategory_t followercategories[MAXFOLLOWERCATEGORIES];
extern boolean horngoner;
/*-------------------------------------------------- /*--------------------------------------------------
INT32 K_FollowerAvailable(const char *name) INT32 K_FollowerAvailable(const char *name)

View file

@ -1526,7 +1526,7 @@ static void K_initKartHUD(void)
} }
} }
void K_DrawMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT16 map, const UINT8 *colormap) void K_DrawMapThumbnail2(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT16 map, const UINT8 *colormap, fixed_t accordion)
{ {
patch_t *PictureOfLevel = NULL; patch_t *PictureOfLevel = NULL;
@ -1543,58 +1543,79 @@ void K_DrawMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT1
PictureOfLevel = static_cast<patch_t*>(mapheaderinfo[map]->thumbnailPic); PictureOfLevel = static_cast<patch_t*>(mapheaderinfo[map]->thumbnailPic);
} }
K_DrawLikeMapThumbnail(x, y, width, flags, PictureOfLevel, colormap); K_DrawLikeMapThumbnail(x, y, width, flags, PictureOfLevel, colormap, accordion);
} }
void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, patch_t *patch, const UINT8 *colormap) void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, patch_t *patch, const UINT8 *colormap, fixed_t accordion)
{ {
if (flags & V_FLIP) fixed_t scale = FixedDiv(width, (320 << FRACBITS));
x += width;
V_DrawFixedPatch( if (flags & V_FLIP)
x += FixedMul(width, accordion);
V_DrawStretchyFixedPatch(
x, y, x, y,
FixedDiv(width, (320 << FRACBITS)), FixedMul(scale, accordion),
scale,
flags, flags,
patch, patch,
colormap colormap
); );
} }
void K_DrawMapAsFace(INT32 x, INT32 y, UINT32 flags, UINT16 map, const UINT8 *colormap) void K_DrawMapAsFace(INT32 x, INT32 y, UINT32 flags, UINT16 map, const UINT8 *colormap, fixed_t accordion, INT32 scalefactor)
{ {
const fixed_t iconHeight = (14 << FRACBITS); const fixed_t iconHeight = ((16 * scalefactor) - 2) << FRACBITS;
const fixed_t iconWidth = (iconHeight * 320) / 200; const fixed_t iconWidth = (iconHeight * 320) / 200;
INT32 unit = 1;
fixed_t mul = FRACUNIT; fixed_t mul = FRACUNIT;
INT32 dup = 1;
if (flags & V_NOSCALESTART) if (flags & V_NOSCALESTART)
{ {
unit = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); dup = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
mul = 1; mul = 1;
} }
INT32 hdup = (dup * accordion);
V_DrawFill( V_DrawFill(
x, x,
y, y,
16 * unit, (16 * scalefactor * hdup)/FRACUNIT,
16 * unit, 16 * scalefactor * dup,
(flags & ~V_FLIP) (flags & ~V_FLIP)
); );
INT32 xclip = ((16 * scalefactor) - 2) * dup * mul;
if (flags & V_NOSCALESTART)
{
hdup /= FRACUNIT;
}
else
{
hdup = FixedMul(hdup, mul);
xclip = FixedMul(xclip, accordion);
}
dup *= mul;
V_SetClipRect( V_SetClipRect(
(x + unit) * mul, (x * mul) + hdup,
(y + unit) * mul, (y * mul) + dup,
(14 * unit) * mul, xclip,
(14 * unit) * mul, ((16 * scalefactor) - 2) * dup,
(flags & ~V_FLIP) (flags & ~V_FLIP)
); );
K_DrawMapThumbnail( K_DrawMapThumbnail2(
((x + unit) * FRACUNIT) - (iconWidth - iconHeight)/2, (x * mul) + hdup - FixedMul(iconWidth - iconHeight, accordion)/2,
((y + unit) * FRACUNIT), (y * mul) + dup,
iconWidth, iconWidth,
flags, flags,
map, map,
colormap colormap,
accordion
); );
V_ClearClipRect(); V_ClearClipRect();

View file

@ -58,9 +58,10 @@ INT32 K_drawKartMicroTime(const char *todrawtext, INT32 workx, INT32 worky, INT3
void K_drawKart2PTimestamp(void); void K_drawKart2PTimestamp(void);
void K_drawKart4PTimestamp(void); void K_drawKart4PTimestamp(void);
void K_drawEmeraldWin(boolean overlay); void K_drawEmeraldWin(boolean overlay);
void K_DrawMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT16 map, const UINT8 *colormap); void K_DrawMapThumbnail2(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT16 map, const UINT8 *colormap, fixed_t accordion);
void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, patch_t *patch, const UINT8 *colormap); #define K_DrawMapThumbnail(x, y, w, f, m, c) K_DrawMapThumbnail2(x, y, w, f, m, c, FRACUNIT)
void K_DrawMapAsFace(INT32 x, INT32 y, UINT32 flags, UINT16 map, const UINT8 *colormap); void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, patch_t *patch, const UINT8 *colormap, fixed_t accordion);
void K_DrawMapAsFace(INT32 x, INT32 y, UINT32 flags, UINT16 map, const UINT8 *colormap, fixed_t accordion, INT32 unit);
void K_drawTargetHUD(const vector3_t *origin, player_t *player); void K_drawTargetHUD(const vector3_t *origin, player_t *player);
void K_drawButton(fixed_t x, fixed_t y, INT32 flags, patch_t *button[2], boolean pressed); void K_drawButton(fixed_t x, fixed_t y, INT32 flags, patch_t *button[2], boolean pressed);
void K_drawButtonAnim(INT32 x, INT32 y, INT32 flags, patch_t *button[2], tic_t animtic); void K_drawButtonAnim(INT32 x, INT32 y, INT32 flags, patch_t *button[2], tic_t animtic);

View file

@ -1428,6 +1428,8 @@ typedef enum
#define CHAOHOLD_END (3) #define CHAOHOLD_END (3)
#define CHAOHOLD_PADDING (CHAOHOLD_BEGIN + CHAOHOLD_END) #define CHAOHOLD_PADDING (CHAOHOLD_BEGIN + CHAOHOLD_END)
#define EASEOFFHORN 50
extern struct timeattackmenu_s { extern struct timeattackmenu_s {
tic_t ticker; // How long the menu's been open for tic_t ticker; // How long the menu's been open for
@ -1461,11 +1463,14 @@ extern struct challengesmenu_s {
UINT16 tutorialfound; UINT16 tutorialfound;
boolean requestflip; boolean requestflip;
UINT16 nowplayingtile;
UINT16 unlockcount[CMC_MAX]; UINT16 unlockcount[CMC_MAX];
UINT8 fade; UINT8 fade;
UINT8 hornposting;
boolean cache_secondrowlocked; boolean cache_secondrowlocked;
patch_t *tile_category[10][2]; patch_t *tile_category[10][2];

View file

@ -1862,6 +1862,9 @@ static boolean M_DrawFollowerSprite(INT16 x, INT16 y, INT32 num, boolean charfli
follower_t *fl; follower_t *fl;
UINT8 rotation = (charflip ? 1 : 7); UINT8 rotation = (charflip ? 1 : 7);
if (horngoner)
return false;
if (p != NULL) if (p != NULL)
followernum = p->followern; followernum = p->followern;
else else
@ -2406,7 +2409,7 @@ void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p)
V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], ccolormap); V_DrawMappedPatch(x+14, y+66, 0, faceprefix[skinnum][FACE_RANK], ccolormap);
} }
if (fln >= 0) if (!horngoner && fln >= 0)
{ {
UINT16 fcol = K_GetEffectiveFollowerColor( UINT16 fcol = K_GetEffectiveFollowerColor(
p->followercolor, p->followercolor,
@ -6722,7 +6725,6 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flash
fixed_t siz, accordion; fixed_t siz, accordion;
UINT16 id, num; UINT16 id, num;
boolean unlockedyet; boolean unlockedyet;
boolean categoryside;
id = (i * CHALLENGEGRIDHEIGHT) + j; id = (i * CHALLENGEGRIDHEIGHT) + j;
num = gamedata->challengegrid[id]; num = gamedata->challengegrid[id];
@ -6797,20 +6799,88 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flash
accordion = FRACUNIT; accordion = FRACUNIT;
if (challengesmenu.extradata[id].flip != 0 boolean categoryside = (challengesmenu.extradata[id].flip == 0);
if (!categoryside // optimised, this is not the true value with anything but instaflip
&& challengesmenu.extradata[id].flip != (TILEFLIP_MAX/2)) && challengesmenu.extradata[id].flip != (TILEFLIP_MAX/2))
{ {
angle_t bad = (FixedAngle(FixedMul(challengesmenu.extradata[id].flip * FRACUNIT + rendertimefrac, 360*FRACUNIT/TILEFLIP_MAX)) >> ANGLETOFINESHIFT) & FINEMASK; fixed_t bad = challengesmenu.extradata[id].flip * FRACUNIT + rendertimefrac;
accordion = FINECOSINE(bad); angle_t worse = (FixedAngle(FixedMul(bad, 360*FRACUNIT/TILEFLIP_MAX)) >> ANGLETOFINESHIFT) & FINEMASK;
accordion = FINECOSINE(worse);
if (accordion < 0) if (accordion < 0)
accordion = -accordion; accordion = -accordion;
// NOW we set it in an interp-friendly way
categoryside = (bad <= FRACUNIT*TILEFLIP_MAX/4
|| bad > (3*FRACUNIT*TILEFLIP_MAX)/4);
} }
pat = W_CachePatchName( pat = W_CachePatchName(
(ref->majorunlock ? "UN_BORDB" : "UN_BORDA"), (ref->majorunlock ? "UN_BORDB" : "UN_BORDA"),
PU_CACHE); PU_CACHE);
bgmap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_SILVER, GTC_MENUCACHE); UINT8 iconid = 0;
{
UINT16 bcol = SKINCOLOR_SILVER;
switch (ref->type)
{
case SECRET_SKIN:
bcol = SKINCOLOR_NOVA;
iconid = 1;
break;
case SECRET_FOLLOWER:
if (horngoner)
{
bcol = SKINCOLOR_BLACK;
}
else
{
bcol = SKINCOLOR_SAPPHIRE;
iconid = 2;
}
break;
case SECRET_COLOR:
//bcol = SKINCOLOR_SILVER;
iconid = 3;
break;
case SECRET_CUP:
bcol = SKINCOLOR_GOLD;
iconid = 4;
break;
case SECRET_MAP:
bcol = SKINCOLOR_PURPLE;
iconid = 8;
break;
case SECRET_HARDSPEED:
case SECRET_MASTERMODE:
case SECRET_ENCORE:
bcol = SKINCOLOR_RUBY;
iconid = 5;
break;
case SECRET_ONLINE:
case SECRET_ADDONS:
case SECRET_EGGTV:
case SECRET_SOUNDTEST:
case SECRET_ALTTITLE:
bcol = SKINCOLOR_BLUEBERRY;
iconid = 6;
break;
case SECRET_TIMEATTACK:
case SECRET_PRISONBREAK:
case SECRET_SPECIALATTACK:
case SECRET_SPBATTACK:
bcol = SKINCOLOR_PERIDOT;
iconid = 7;
break;
case SECRET_ALTMUSIC:
bcol = SKINCOLOR_MAGENTA;
iconid = 9;
break;
}
bgmap = R_GetTranslationColormap(TC_DEFAULT, bcol, GTC_MENUCACHE);
}
V_DrawStretchyFixedPatch( V_DrawStretchyFixedPatch(
(x*FRACUNIT) + (SHORT(pat->width)*(FRACUNIT-accordion)/2), y*FRACUNIT, (x*FRACUNIT) + (SHORT(pat->width)*(FRACUNIT-accordion)/2), y*FRACUNIT,
@ -6822,65 +6892,25 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flash
pat = missingpat; pat = missingpat;
categoryside = (challengesmenu.extradata[id].flip <= TILEFLIP_MAX/4
|| challengesmenu.extradata[id].flip > (3*TILEFLIP_MAX)/4);
#ifdef DEVELOP #ifdef DEVELOP
if (cv_debugchallenges.value) if (cv_debugchallenges.value)
{ {
// Show the content of every tile without needing to // Show the content of every tile without needing to flip them.
// flip them.
categoryside = false; categoryside = false;
} }
#endif #endif
if (categoryside) if (horngoner && ref->type == SECRET_FOLLOWER)
goto drawborder;
else if (categoryside)
{ {
char categoryid = '0'; colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_SILVER, GTC_MENUCACHE);
colormap = bgmap;
switch (ref->type) // iconid is already prepopulated because we had to draw the border
{ pat = challengesmenu.tile_category[iconid][ref->majorunlock ? 1 : 0];
case SECRET_SKIN:
categoryid = '1';
break;
case SECRET_FOLLOWER:
categoryid = '2';
break;
case SECRET_COLOR:
categoryid = '3';
break;
case SECRET_CUP:
categoryid = '4';
break;
case SECRET_MAP:
categoryid = '8';
break;
case SECRET_HARDSPEED:
case SECRET_MASTERMODE:
case SECRET_ENCORE:
categoryid = '5';
break;
case SECRET_ONLINE:
case SECRET_ADDONS:
case SECRET_EGGTV:
case SECRET_SOUNDTEST:
case SECRET_ALTTITLE:
categoryid = '6';
break;
case SECRET_TIMEATTACK:
case SECRET_PRISONBREAK:
case SECRET_SPECIALATTACK:
case SECRET_SPBATTACK:
categoryid = '7';
break;
case SECRET_ALTMUSIC:
categoryid = '9';
break;
}
pat = challengesmenu.tile_category[categoryid - '0'][ref->majorunlock ? 1 : 0];
if (pat == missingpat) if (pat == missingpat)
{ {
pat = challengesmenu.tile_category[categoryid - '0'][ref->majorunlock ? 0 : 1]; pat = challengesmenu.tile_category[iconid][ref->majorunlock ? 0 : 1];
} }
} }
else if (ref->icon != NULL && ref->icon[0]) else if (ref->icon != NULL && ref->icon[0])
@ -6893,7 +6923,7 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flash
} }
else else
{ {
UINT8 iconid = 0; iconid = 0; // reuse
switch (ref->type) switch (ref->type)
{ {
case SECRET_SKIN: case SECRET_SKIN:
@ -6930,8 +6960,42 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flash
} }
case SECRET_MAP: case SECRET_MAP:
iconid = 14; {
UINT16 mapnum = M_UnlockableMapNum(ref);
if (mapnum < nummapheaders && mapheaderinfo[mapnum]
&& (
( // Check for visitation
(mapheaderinfo[mapnum]->menuflags & LF2_NOVISITNEEDED)
|| (mapheaderinfo[mapnum]->records.mapvisited & MV_VISITED)
) && ( // Check for completion
!(mapheaderinfo[mapnum]->menuflags & LF2_FINISHNEEDED)
|| (mapheaderinfo[mapnum]->records.mapvisited & MV_BEATEN)
)
))
{
if (ref->majorunlock)
{
K_DrawMapAsFace(
(x + 5) + (32*(FRACUNIT-accordion))/(2*FRACUNIT), (y + 5),
tileflags,
mapnum,
NULL, accordion, 2
);
}
else
{
K_DrawMapAsFace(
(x + 2) + (16*(FRACUNIT-accordion))/(2*FRACUNIT), (y + 2),
tileflags,
mapnum,
NULL, accordion, 1
);
}
pat = NULL;
}
iconid = 0; //14; -- This one suits a little better for "go complete this level normally"
break; break;
}
case SECRET_ALTMUSIC: case SECRET_ALTMUSIC:
iconid = 16; iconid = 16;
break; break;
@ -7001,6 +7065,8 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flash
} }
} }
if (pat)
{
siz = (SHORT(pat->width) << FRACBITS); siz = (SHORT(pat->width) << FRACBITS);
if (!siz) if (!siz)
@ -7008,7 +7074,7 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flash
else if (ref->majorunlock) else if (ref->majorunlock)
{ {
V_DrawStretchyFixedPatch( V_DrawStretchyFixedPatch(
((x + 5)*FRACUNIT) + (32*(FRACUNIT-accordion)/2), (y + 5)*FRACUNIT, ((x + 5)*FRACUNIT) + (32*(FRACUNIT-accordion))/2, (y + 5)*FRACUNIT,
FixedDiv(32*accordion, siz), FixedDiv(32*accordion, siz),
FixedDiv(32 << FRACBITS, siz), FixedDiv(32 << FRACBITS, siz),
tileflags, pat, tileflags, pat,
@ -7018,13 +7084,14 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flash
else else
{ {
V_DrawStretchyFixedPatch( V_DrawStretchyFixedPatch(
((x + 2)*FRACUNIT) + (16*(FRACUNIT-accordion)/2), (y + 2)*FRACUNIT, ((x + 2)*FRACUNIT) + (16*(FRACUNIT-accordion))/2, (y + 2)*FRACUNIT,
FixedDiv(16*accordion, siz), FixedDiv(16*accordion, siz),
FixedDiv(16 << FRACBITS, siz), FixedDiv(16 << FRACBITS, siz),
tileflags, pat, tileflags, pat,
colormap colormap
); );
} }
}
drawborder: drawborder:
@ -7154,7 +7221,7 @@ void M_DrawCharacterIconAndEngine(INT32 x, INT32 y, UINT8 skin, UINT8 *colormap,
V_DrawFill(x+16 + (s*5), y + (w*5), 6, 6, 0); V_DrawFill(x+16 + (s*5), y + (w*5), 6, 6, 0);
} }
static void M_DrawChallengePreview(INT32 x, INT32 y) static const char* M_DrawChallengePreview(INT32 x, INT32 y)
{ {
unlockable_t *ref = NULL; unlockable_t *ref = NULL;
UINT8 *colormap = NULL; UINT8 *colormap = NULL;
@ -7162,12 +7229,9 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
if (challengesmenu.currentunlock >= MAXUNLOCKABLES) if (challengesmenu.currentunlock >= MAXUNLOCKABLES)
{ {
return; return NULL;
} }
// Okay, this is what we want to draw.
ref = &unlockables[challengesmenu.currentunlock];
// Funny question mark? // Funny question mark?
if (!gamedata->unlocked[challengesmenu.currentunlock]) if (!gamedata->unlocked[challengesmenu.currentunlock])
{ {
@ -7179,7 +7243,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
if (!sprdef->numframes) if (!sprdef->numframes)
{ {
return; return NULL;
} }
useframe = (challengesmenu.ticker / 2) % sprdef->numframes; useframe = (challengesmenu.ticker / 2) % sprdef->numframes;
@ -7193,9 +7257,14 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
} }
V_DrawFixedPatch(x*FRACUNIT, (y+2)*FRACUNIT, FRACUNIT, addflags, patch, NULL); V_DrawFixedPatch(x*FRACUNIT, (y+2)*FRACUNIT, FRACUNIT, addflags, patch, NULL);
return; return NULL;
} }
// Okay, this is what we want to draw.
ref = &unlockables[challengesmenu.currentunlock];
const char *actiontext = NULL;
switch (ref->type) switch (ref->type)
{ {
case SECRET_SKIN: case SECRET_SKIN:
@ -7207,6 +7276,19 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
colormap = R_GetTranslationColormap(skin, skins[skin]->prefcolor, GTC_MENUCACHE); colormap = R_GetTranslationColormap(skin, skins[skin]->prefcolor, GTC_MENUCACHE);
M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap); M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap);
y = (BASEVIDHEIGHT-14);
if (setup_numplayers <= 1 && cv_lastprofile[0].value != PROFILE_GUEST)
{
profile_t *pr = PR_GetProfile(cv_lastprofile[0].value);
actiontext = (pr && strcmp(pr->skinname, skins[skin]->name))
? "<a> <sky>Set on Profile"
: "<a_pressed> <gray>Set on Profile";
y -= 14;
}
for (i = 0; i < skin; i++) for (i = 0; i < skin; i++)
{ {
if (!R_SkinUsable(-1, i, false)) if (!R_SkinUsable(-1, i, false))
@ -7220,7 +7302,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
break; break;
} }
M_DrawCharacterIconAndEngine(4, BASEVIDHEIGHT-(4+16), i, colormap, skin); M_DrawCharacterIconAndEngine(4, y-6, i, colormap, skin);
} }
break; break;
} }
@ -7235,6 +7317,11 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
colormap = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_BLACK, GTC_MENUCACHE); colormap = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_BLACK, GTC_MENUCACHE);
M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap); M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap);
if (horngoner)
{
return "<a_pressed> <gray>MISSING.";
}
// Draw follower next to them // Draw follower next to them
if (fskin != -1) if (fskin != -1)
{ {
@ -7242,9 +7329,69 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
M_DrawFollowerSprite(x - 16, y, fskin, false, 0, colormap, NULL); M_DrawFollowerSprite(x - 16, y, fskin, false, 0, colormap, NULL);
y = (BASEVIDHEIGHT-14);
if (setup_numplayers <= 1 && cv_lastprofile[0].value != PROFILE_GUEST)
{
profile_t *pr = PR_GetProfile(cv_lastprofile[0].value);
if (pr && strcmp(pr->follower, followers[fskin].name))
{
actiontext = (followers[fskin].hornsound == sfx_melody)
? "<a> <aqua>Set on Profile"
: "<a> <sky>Set on Profile";
}
}
if (!actiontext)
{
if (followers[fskin].hornsound == sfx_melody)
{
actiontext = "<a_animated> <aqua>Play Ancient Melody?";
}
else if (challengesmenu.hornposting >= EASEOFFHORN)
actiontext = "<a> <red>Time to die";
else if (challengesmenu.hornposting >= (EASEOFFHORN-5))
{
if (challengesmenu.hornposting == EASEOFFHORN)
actiontext = "Time to die";
else
actiontext = "I asked politely";
actiontext = va("%s%s",
(M_MenuConfirmPressed(0)
? "<a_pressed> <yellow>"
: "<a> <red>"
), actiontext
);
}
else if (challengesmenu.hornposting >= (EASEOFFHORN-10))
{
actiontext = M_MenuConfirmPressed(0)
? "<a_pressed> <yellow>Ease off the horn"
: "<a> <orange>Ease off the horn";
}
else switch (challengesmenu.hornposting % 4)
{
default:
actiontext = "<a_animated> <sky>Say hello";
break;
case 1:
actiontext = "<a_animated> <sky>Express your feelings";
break;
case 2:
actiontext = "<a_animated> <sky>Celebrate victory";
break;
case 3:
actiontext = "<a_animated> <sky>Announce you are pressing horn";
break;
}
}
y -= 14;
if (followers[fskin].category < numfollowercategories) if (followers[fskin].category < numfollowercategories)
{ {
V_DrawFixedPatch(4*FRACUNIT, (BASEVIDHEIGHT-(4+16))*FRACUNIT, V_DrawFixedPatch(4*FRACUNIT, (y - 6)*FRACUNIT,
FRACUNIT, FRACUNIT,
0, W_CachePatchName(followercategories[followers[fskin].category].icon, PU_CACHE), 0, W_CachePatchName(followercategories[followers[fskin].category].icon, PU_CACHE),
NULL); NULL);
@ -7264,6 +7411,16 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
// Draw reference for character bathed in coloured slime // Draw reference for character bathed in coloured slime
M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap); M_DrawCharacterSprite(x, y, skin, SPR2_STIN, 7, 0, 0, colormap);
if (setup_numplayers <= 1 && cv_lastprofile[0].value != PROFILE_GUEST)
{
profile_t *pr = PR_GetProfile(cv_lastprofile[0].value);
actiontext = (pr && pr->color != colorid)
? "<a> <sky>Set on Profile"
: "<a_pressed> <gray>Set on Profile";
}
break; break;
} }
case SECRET_CUP: case SECRET_CUP:
@ -7346,6 +7503,8 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
const char *gtname = "Find your prize..."; const char *gtname = "Find your prize...";
UINT16 mapnum = M_UnlockableMapNum(ref); UINT16 mapnum = M_UnlockableMapNum(ref);
y = (BASEVIDHEIGHT-14);
if (mapnum >= nummapheaders if (mapnum >= nummapheaders
|| mapheaderinfo[mapnum] == NULL || mapheaderinfo[mapnum] == NULL
|| mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU) || mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU)
@ -7389,7 +7548,13 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
guessgt = GT_SPECIAL; guessgt = GT_SPECIAL;
} }
if (guessgt == GT_SPECIAL && !M_SecretUnlocked(SECRET_SPECIALATTACK, true)) if (setup_numplayers <= 1 && guessgt == GT_TUTORIAL)
{
// Only for 1p
actiontext = "<a_animated> <orange>Play Tutorial";
gtname = NULL;
}
else if (guessgt == GT_SPECIAL && !M_SecretUnlocked(SECRET_SPECIALATTACK, true))
{ {
gtname = "???"; gtname = "???";
} }
@ -7409,7 +7574,10 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
NULL); NULL);
} }
V_DrawThinString(1, BASEVIDHEIGHT-(9+3), 0, gtname); if (gtname)
{
V_DrawThinString(4, y, 0, gtname);
}
break; break;
} }
@ -7519,8 +7687,8 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
} }
case SECRET_ALTTITLE: case SECRET_ALTTITLE:
{ {
x = 8; x = 4;
y = BASEVIDHEIGHT-16; y = BASEVIDHEIGHT-14;
V_DrawGamemodeString(x, y - 33, 0, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_MENUCACHE), M_UseAlternateTitleScreen() ? "On" : "Off"); V_DrawGamemodeString(x, y - 33, 0, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_MENUCACHE), M_UseAlternateTitleScreen() ? "On" : "Off");
K_DrawGameControl(x, y, 0, "<a_animated> Toggle", 0, TINY_FONT, 0); K_DrawGameControl(x, y, 0, "<a_animated> Toggle", 0, TINY_FONT, 0);
@ -7537,7 +7705,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
if (map >= nummapheaders if (map >= nummapheaders
|| !mapheaderinfo[map]) || !mapheaderinfo[map])
{ {
return; break;
} }
UINT8 musicid; UINT8 musicid;
@ -7549,12 +7717,32 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
if (musicid == MAXMUSNAMES) if (musicid == MAXMUSNAMES)
{ {
return; break;
} }
const char *tune = "challenge_altmusic";
SINT8 pushed = 0;
const boolean epossible = (M_SecretUnlocked(SECRET_ENCORE, true)
&& musicid < mapheaderinfo[map]->encoremusname_size);
if (challengesmenu.nowplayingtile == ((challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy)
&& Music_Playing(tune))
{
const char *song = Music_Song(tune);
if (epossible
&& strcmp(song, mapheaderinfo[map]->encoremusname[musicid]) == 0)
pushed = -1;
else if (musicid < mapheaderinfo[map]->musname_size
&& strcmp(song, mapheaderinfo[map]->musname[musicid]) == 0)
pushed = 1;
}
// Draw CD
{
spritedef_t *sprdef = &sprites[SPR_ALTM]; spritedef_t *sprdef = &sprites[SPR_ALTM];
spriteframe_t *sprframe; spriteframe_t *sprframe;
patch_t *patch; patch_t *patch = NULL;
UINT32 addflags = 0; UINT32 addflags = 0;
x -= 10; x -= 10;
@ -7562,65 +7750,71 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
if (sprdef->numframes) if (sprdef->numframes)
{ {
sprframe = &sprdef->spriteframes[0]; #ifdef ROTSPRITE
patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); spriteinfo_t *sprinfo = &spriteinfo[SPR_ALTM];
INT32 rollangle = 0;
if (pushed != 0)
{
rollangle = (Music_Elapsed(tune) % (ROTANGLES/2))*2;
if (rendertimefrac >= FRACUNIT/2)
{
// A fun interp ability: inbetweens
rollangle++;
}
if (pushed > 0)
{
rollangle = ((ROTANGLES-1) - rollangle);
}
}
#endif
sprframe = &sprdef->spriteframes[0];
#ifdef ROTSPRITE
if (rollangle)
{
patch = Patch_GetRotatedSprite(sprframe, 0, 0, (sprframe->flip & 1), false, sprinfo, rollangle);
}
#endif
if (!patch)
{
patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
if (sprframe->flip & 1) // Only for first sprite if (sprframe->flip & 1) // Only for first sprite
{ {
addflags ^= V_FLIP; // This sprite is left/right flipped! addflags ^= V_FLIP; // This sprite is left/right flipped!
} }
}
V_DrawFixedPatch(x*FRACUNIT, (y+2)*FRACUNIT, FRACUNIT/2, addflags, patch, NULL); V_DrawFixedPatch(x*FRACUNIT, (y+2)*FRACUNIT, FRACUNIT/2, addflags, patch, NULL);
} }
x = 8;
y = BASEVIDHEIGHT-16;
const boolean thismusplaying = Music_Playing("challenge_altmusic");
boolean pushed = false;
const char *song = NULL;
if (M_SecretUnlocked(SECRET_ENCORE, true)
&& musicid < mapheaderinfo[map]->encoremusname_size)
{
if (thismusplaying)
{
song = Music_Song("challenge_altmusic");
pushed = strcmp(song, mapheaderinfo[map]->encoremusname[musicid]) == 0;
}
if (!pushed)
K_DrawGameControl(x, y, 0, "<l> <sky>E Side", 0, TINY_FONT, 0);
else
K_DrawGameControl(x, y, 0, "<l_pressed> <gray>E Side", 0, TINY_FONT, 0);
// K_drawButton(x&FRACUNIT, y*FRACUNIT, 0, kp_button_l, pushed);
// x += SHORT(kp_button_l[0]->width);
// V_DrawThinString(x, y + 1, (pushed ? V_GRAYMAP : highlightflags), "E Side");
x = 8;
y -= 10;
} }
if (musicid < mapheaderinfo[map]->musname_size) if (musicid < mapheaderinfo[map]->musname_size)
{ {
if (pushed || !thismusplaying) actiontext = (pushed > 0)
{ ? "<a_animated> <sky>Stop CD"
pushed = false; : "<a_animated> <sky>Play CD";
}
else
{
if (!song)
song = Music_Song("challenge_altmusic");
pushed = strcmp(song, mapheaderinfo[map]->musname[musicid]) == 0;
} }
if (!pushed) if (epossible)
K_DrawGameControl(x, y, 0, "<a> <sky>Play CD", 0, TINY_FONT, 0); {
const char *secondtext = (pushed < 0)
? "<l_animated> <magenta>E Stop"
: "<l_animated> <magenta>E Side";
if (actiontext)
{
// weird encoded height
actiontext = va("\x1""%s\n%s",
(pushed < 0)
? "<l_animated> <magenta>E Stop"
: "<l_animated> <magenta>E Side",
actiontext
);
}
else else
K_DrawGameControl(x, y, 0, "<a_pressed> <gray>Play CD", 0, TINY_FONT, 0); {
// K_drawButton(x*FRACUNIT, y*FRACUNIT, 0, kp_button_a[1], pushed); actiontext = secondtext;
// x += SHORT(kp_button_a[1][0]->width); }
// V_DrawThinString(x, y + 1, (pushed ? V_GRAYMAP : highlightflags), "Play CD");
} }
} }
default: default:
@ -7630,7 +7824,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
} }
if (specialmap == NEXTMAP_INVALID || !ref) if (specialmap == NEXTMAP_INVALID || !ref)
return; return actiontext;
x -= 50; x -= 50;
y = 146+2; y = 146+2;
@ -7678,6 +7872,8 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
W_CachePatchName("K_LAPE02", PU_CACHE), W_CachePatchName("K_LAPE02", PU_CACHE),
colormap); colormap);
} }
return actiontext;
} }
#define challengesgridstep 22 #define challengesgridstep 22
@ -7914,11 +8110,6 @@ static void M_DrawChallengeScrollBar(UINT8 *flashmap)
V_DrawFill(barx + hilix, bary-1, hiliw, 1, 0); V_DrawFill(barx + hilix, bary-1, hiliw, 1, 0);
V_DrawFill(barx + hilix, bary+barh, hiliw, 1, 0); V_DrawFill(barx + hilix, bary+barh, hiliw, 1, 0);
INT32 mindiscouragement = 2; // skipping major unlocks is just a LITTLE cringe
if (challengesmenu.unlockcount[CMC_PERCENT] == 100
&& challengesmenu.unlockcount[CMC_MAJORSKIPPED] == 0)
mindiscouragement = 1; // so someone looking for 101% isn't hunting forever
// unbounded so that we can do the last remaining completionamount draw // unbounded so that we can do the last remaining completionamount draw
nextstep = numincolumn = completionamount = skiplevel = 0; nextstep = numincolumn = completionamount = skiplevel = 0;
for (i = 0; ; i++) for (i = 0; ; i++)
@ -7932,7 +8123,7 @@ static void M_DrawChallengeScrollBar(UINT8 *flashmap)
if (completionamount >= numincolumn) if (completionamount >= numincolumn)
{ {
// If any have been skipped, we subtract a little for awareness... // If any have been skipped, we subtract a little for awareness...
completionamount = (skiplevel >= mindiscouragement) ? 9 : 10; completionamount = skiplevel ? 9 : 10;
} }
else else
{ {
@ -7969,6 +8160,14 @@ static void M_DrawChallengeScrollBar(UINT8 *flashmap)
} }
#endif #endif
if (i == challengesmenu.nowplayingtile && Music_Playing("challenge_altmusic"))
{
V_DrawFill(barx + hilix, bary, hiliw, barh, (challengesmenu.ticker & 2) ? 177 : 122);
// The now-playing fill overrides everything else.
completionamount = -1;
}
if (completionamount == -1) if (completionamount == -1)
continue; continue;
@ -7978,9 +8177,9 @@ static void M_DrawChallengeScrollBar(UINT8 *flashmap)
unlockable_t *ref = &unlockables[gamedata->challengegrid[i]]; unlockable_t *ref = &unlockables[gamedata->challengegrid[i]];
if (skiplevel < 2 && M_Achieved(ref->conditionset - 1) == false) if (!skiplevel && M_Achieved(ref->conditionset - 1) == false)
{ {
skiplevel = ref->majorunlock ? 2 : 1; skiplevel = 1;
} }
} }
@ -8231,9 +8430,10 @@ challengedesc:
y = BASEVIDHEIGHT-16; y = BASEVIDHEIGHT-16;
// Unlock preview // Unlock preview
M_DrawChallengePreview(x, y); const char *actiontext = M_DrawChallengePreview(x, y);
// Conditions for unlock // Conditions for unlock
// { -- please don't call va() anywhere between here...
i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy; i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
if (challengesmenu.unlockcondition != NULL if (challengesmenu.unlockcondition != NULL
@ -8246,6 +8446,25 @@ challengedesc:
{ {
V_DrawCenteredThinString(BASEVIDWIDTH/2, 120 + 32, 0, challengesmenu.unlockcondition); V_DrawCenteredThinString(BASEVIDWIDTH/2, 120 + 32, 0, challengesmenu.unlockcondition);
} }
// Extracted from M_DrawCharSelectPreview for ordering reasons
if (actiontext && actiontext[0])
{
x = 4;
y = (BASEVIDHEIGHT-14);
if (actiontext[0] < '\x5')
{
// weird encoded height, supports max 5 rows
y -= (13 * actiontext[0]);
actiontext++;
}
K_DrawGameControl(
x, y, 0,
actiontext,
0, TINY_FONT, 0
);
// } -- ...and here (since actiontext needs it)
}
} }
#undef challengetransparentstrength #undef challengetransparentstrength

View file

@ -705,7 +705,7 @@ static void Y_DrawVoteThumbnail(fixed_t center_x, fixed_t center_y, fixed_t widt
fy + fh - whiteSq + dupy, fy + fh - whiteSq + dupy,
flags | V_NOSCALESTART | ((encore == true) ? V_FLIP : 0), flags | V_NOSCALESTART | ((encore == true) ? V_FLIP : 0),
g_voteLevels[v][0], g_voteLevels[v][0],
NULL NULL, FRACUNIT, 1
); );
} }
} }

View file

@ -1655,7 +1655,12 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
case UC_TOTALMEDALS: // Requires number of emblems >= x case UC_TOTALMEDALS: // Requires number of emblems >= x
return (M_GotEnoughMedals(cn->requirement)); return (M_GotEnoughMedals(cn->requirement));
case UC_EMBLEM: // Requires emblem x to be obtained case UC_EMBLEM: // Requires emblem x to be obtained
{
INT32 i = cn->requirement-1;
if (i >= 0 && i < numemblems && emblemlocations[i].type != ET_NONE)
return gamedata->collected[cn->requirement-1]; return gamedata->collected[cn->requirement-1];
return false;
}
case UC_UNLOCKABLE: // Requires unlockable x to be obtained case UC_UNLOCKABLE: // Requires unlockable x to be obtained
return gamedata->unlocked[cn->requirement-1]; return gamedata->unlocked[cn->requirement-1];
case UC_CONDITIONSET: // requires condition set x to already be achieved case UC_CONDITIONSET: // requires condition set x to already be achieved
@ -3204,7 +3209,7 @@ static boolean M_CheckUnlockConditions(player_t *player)
{ {
UINT32 i; UINT32 i;
conditionset_t *c; conditionset_t *c;
boolean ret; boolean ret = false;
for (i = 0; i < MAXCONDITIONSETS; ++i) for (i = 0; i < MAXCONDITIONSETS; ++i)
{ {

View file

@ -82,6 +82,10 @@ static void M_UpdateChallengeGridVisuals(void)
challengesmenu.unlockcount[CMC_UNLOCKED] = 0; challengesmenu.unlockcount[CMC_UNLOCKED] = 0;
challengesmenu.unlockcount[CMC_TOTAL] = 0; challengesmenu.unlockcount[CMC_TOTAL] = 0;
challengesmenu.unlockcount[CMC_KEYED] = 0;
challengesmenu.unlockcount[CMC_MAJORSKIPPED] = 0;
//#define MAJORDISTINCTION -- The "basic" medal is basically never seen because Major challenges are usually completed last before 101%. Correct that with this
for (i = 0; i < MAXUNLOCKABLES; i++) for (i = 0; i < MAXUNLOCKABLES; i++)
{ {
@ -106,12 +110,14 @@ static void M_UpdateChallengeGridVisuals(void)
challengesmenu.unlockcount[CMC_KEYED]++; challengesmenu.unlockcount[CMC_KEYED]++;
#ifdef MAJORDISTINCTION
if (unlockables[i].majorunlock == false) if (unlockables[i].majorunlock == false)
{ {
continue; continue;
} }
challengesmenu.unlockcount[CMC_MAJORSKIPPED]++; challengesmenu.unlockcount[CMC_MAJORSKIPPED]++;
#endif
} }
challengesmenu.unlockcount[CMC_PERCENT] = challengesmenu.unlockcount[CMC_PERCENT] =
@ -125,7 +131,9 @@ static void M_UpdateChallengeGridVisuals(void)
challengesmenu.unlockcount[CMC_MEDALFILLED] = challengesmenu.unlockcount[CMC_MEDALFILLED] =
(medalheight * ( (medalheight * (
challengesmenu.unlockcount[CMC_UNLOCKED] challengesmenu.unlockcount[CMC_UNLOCKED]
#ifdef MAJORDISTINCTION
- challengesmenu.unlockcount[CMC_MAJORSKIPPED] - challengesmenu.unlockcount[CMC_MAJORSKIPPED]
#endif
)) / challengesmenu.unlockcount[CMC_TOTAL]; )) / challengesmenu.unlockcount[CMC_TOTAL];
if (challengesmenu.unlockcount[CMC_PERCENT] == 100) if (challengesmenu.unlockcount[CMC_PERCENT] == 100)
@ -135,7 +143,10 @@ static void M_UpdateChallengeGridVisuals(void)
challengesmenu.unlockcount[CMC_MEDALID] = 2; challengesmenu.unlockcount[CMC_MEDALID] = 2;
challengesmenu.unlockcount[CMC_PERCENT]++; // 101% challengesmenu.unlockcount[CMC_PERCENT]++; // 101%
} }
else if (challengesmenu.unlockcount[CMC_MAJORSKIPPED] == 0) else
#ifdef MAJORDISTINCTION
if (challengesmenu.unlockcount[CMC_MAJORSKIPPED] == 0)
#endif
{ {
challengesmenu.unlockcount[CMC_MEDALID] = 1; challengesmenu.unlockcount[CMC_MEDALID] = 1;
} }
@ -364,10 +375,13 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
if ((challengesmenu.pending = (newunlock != MAXUNLOCKABLES))) if ((challengesmenu.pending = (newunlock != MAXUNLOCKABLES)))
{ {
Music_StopAll(); Music_StopAll();
if (desiredmenu && desiredmenu != &MISC_ChallengesDef)
{
MISC_ChallengesDef.prevMenu = desiredmenu; MISC_ChallengesDef.prevMenu = desiredmenu;
} }
}
if (challengesmenu.pending || desiredmenu == NULL) if (challengesmenu.pending || desiredmenu == &MISC_ChallengesDef)
{ {
static boolean firstopen = true; static boolean firstopen = true;
@ -379,10 +393,12 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
challengesmenu.tutorialfound = NEXTMAP_INVALID; challengesmenu.tutorialfound = NEXTMAP_INVALID;
challengesmenu.chaokeyhold = 0; challengesmenu.chaokeyhold = 0;
challengesmenu.unlockcondition = NULL; challengesmenu.unlockcondition = NULL;
challengesmenu.hornposting = 0;
if (firstopen) if (firstopen)
{ {
challengesmenu.currentunlock = MAXUNLOCKABLES; challengesmenu.currentunlock = MAXUNLOCKABLES;
challengesmenu.nowplayingtile = UINT16_MAX;
firstopen = false; firstopen = false;
} }
@ -402,10 +418,15 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
if (challengesmenu.pending) if (challengesmenu.pending)
M_ChallengesAutoFocus(newunlock, true); M_ChallengesAutoFocus(newunlock, true);
else if (newunlock >= MAXUNLOCKABLES && gamedata->pendingkeyrounds > 0 else
{
if (newunlock >= MAXUNLOCKABLES && gamedata->pendingkeyrounds > 0
&& (gamedata->chaokeys < GDMAX_CHAOKEYS)) && (gamedata->chaokeys < GDMAX_CHAOKEYS))
challengesmenu.chaokeyadd = true; challengesmenu.chaokeyadd = true;
M_ChallengesAutoFocus(UINT16_MAX, true);
}
M_CacheChallengeTiles(); M_CacheChallengeTiles();
return &MISC_ChallengesDef; return &MISC_ChallengesDef;
@ -418,15 +439,22 @@ void M_Challenges(INT32 choice)
{ {
(void)choice; (void)choice;
M_InterruptMenuWithChallenges(NULL); M_InterruptMenuWithChallenges(&MISC_ChallengesDef);
MISC_ChallengesDef.prevMenu = currentMenu; MISC_ChallengesDef.prevMenu = currentMenu;
if (gamedata->challengegrid != NULL && !challengesmenu.pending) M_SetupNextMenu(&MISC_ChallengesDef, false);
{
M_ChallengesAutoFocus(UINT16_MAX, true);
} }
M_SetupNextMenu(&MISC_ChallengesDef, false); static void M_CloseChallenges(void)
{
Music_Stop("challenge_altmusic");
challengesmenu.nowplayingtile = UINT16_MAX;
Z_Free(challengesmenu.extradata);
challengesmenu.extradata = NULL;
Z_Free(challengesmenu.unlockcondition);
challengesmenu.unlockcondition = NULL;
} }
boolean M_CanKeyHiliTile(void) boolean M_CanKeyHiliTile(void)
@ -569,13 +597,20 @@ void M_ChallengesTick(void)
{ {
UINT16 id = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy; UINT16 id = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
boolean seeeveryone = challengesmenu.requestflip; boolean seeeveryone = challengesmenu.requestflip;
boolean allthewaythrough; boolean allthewaythrough = allthewaythrough = (!seeeveryone && !challengesmenu.pending);
UINT8 maxflip; UINT8 maxflip;
if (id == challengesmenu.nowplayingtile)
{
// Don't permit the active song to stop spinning
id = UINT16_MAX;
}
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++) for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
{ {
allthewaythrough = (!seeeveryone && !challengesmenu.pending && i != id); maxflip = ((allthewaythrough && i != id) ? TILEFLIP_MAX : (TILEFLIP_MAX/2));
maxflip = ((seeeveryone || !allthewaythrough) ? (TILEFLIP_MAX/2) : TILEFLIP_MAX); if ((seeeveryone || (i == id) || (i == challengesmenu.nowplayingtile) || (challengesmenu.extradata[i].flip > 0))
if ((seeeveryone || (i == id) || (challengesmenu.extradata[i].flip > 0))
&& (challengesmenu.extradata[i].flip != maxflip)) && (challengesmenu.extradata[i].flip != maxflip))
{ {
challengesmenu.extradata[i].flip++; challengesmenu.extradata[i].flip++;
@ -943,19 +978,12 @@ boolean M_ChallengesInputs(INT32 ch)
{ {
if (M_MenuBackPressed(pid) || start) if (M_MenuBackPressed(pid) || start)
{ {
Music_Stop("challenge_altmusic");
currentMenu->prevMenu = M_SpecificMenuRestore(currentMenu->prevMenu); currentMenu->prevMenu = M_SpecificMenuRestore(currentMenu->prevMenu);
M_GoBack(0); M_GoBack(0);
M_SetMenuDelay(pid); M_SetMenuDelay(pid);
Z_Free(challengesmenu.extradata); M_CloseChallenges();
challengesmenu.extradata = NULL;
if (challengesmenu.unlockcondition)
Z_Free(challengesmenu.unlockcondition);
challengesmenu.unlockcondition = NULL;
return true; return true;
} }
@ -1137,8 +1165,56 @@ boolean M_ChallengesInputs(INT32 ch)
if (challengesmenu.currentunlock < MAXUNLOCKABLES if (challengesmenu.currentunlock < MAXUNLOCKABLES
&& gamedata->unlocked[challengesmenu.currentunlock]) && gamedata->unlocked[challengesmenu.currentunlock])
{ {
unlockable_t *ref = &unlockables[challengesmenu.currentunlock];
boolean forceflip = false;
switch (unlockables[challengesmenu.currentunlock].type) switch (unlockables[challengesmenu.currentunlock].type)
{ {
case SECRET_MAP:
{
// Only for 1p
if (setup_numplayers <= 1 && M_MenuConfirmPressed(pid))
{
// Map exists...
UINT16 mapnum = M_UnlockableMapNum(ref);
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
{
// is tutorial...
INT32 guessgt = G_GuessGametypeByTOL(mapheaderinfo[mapnum]->typeoflevel);
if (guessgt == GT_TUTORIAL)
{
M_SetMenuDelay(pid);
multiplayer = true;
restoreMenu = currentMenu;
restorelevellist = levellist;
// mild hack
levellist.newgametype = guessgt;
levellist.netgame = false;
M_MenuToLevelPreamble(0, false);
D_MapChange(
mapnum+1,
guessgt,
false,
true,
1,
false,
false
);
M_CloseChallenges();
M_ClearMenus(true);
return false; // DO NOT
}
}
}
break;
}
case SECRET_ALTTITLE: case SECRET_ALTTITLE:
{ {
if (M_MenuConfirmPressed(pid)) if (M_MenuConfirmPressed(pid))
@ -1147,6 +1223,103 @@ boolean M_ChallengesInputs(INT32 ch)
CV_AddValue(&cv_alttitle, 1); CV_AddValue(&cv_alttitle, 1);
S_StartSound(NULL, sfx_s3kc3s); S_StartSound(NULL, sfx_s3kc3s);
M_SetMenuDelay(pid); M_SetMenuDelay(pid);
forceflip = true;
}
break;
}
case SECRET_SKIN:
{
if (setup_numplayers <= 1 && cv_lastprofile[0].value != PROFILE_GUEST && M_MenuConfirmPressed(pid))
{
INT32 skin = M_UnlockableSkinNum(ref);
if (skin != -1)
{
profile_t *pr = PR_GetProfile(cv_lastprofile[0].value);
if (pr && strcmp(pr->skinname, skins[skin]->name))
{
strcpy(pr->skinname, skins[skin]->name);
CV_Set(&cv_skin[0], skins[skin]->name);
S_StartSound(NULL, sfx_s3k63);
S_StartSound(NULL, skins[skin]->soundsid[S_sfx[sfx_kattk1].skinsound]);
M_SetMenuDelay(pid);
forceflip = true;
}
}
}
break;
}
case SECRET_FOLLOWER:
{
if (!horngoner && M_MenuConfirmPressed(pid))
{
INT32 fskin = M_UnlockableFollowerNum(ref);
if (fskin != -1)
{
if (setup_numplayers <= 1 && cv_lastprofile[0].value != PROFILE_GUEST)
{
profile_t *pr = PR_GetProfile(cv_lastprofile[0].value);
if (pr && strcmp(pr->follower, followers[fskin].name))
{
strcpy(pr->follower, followers[fskin].name);
CV_Set(&cv_follower[0], followers[fskin].name);
challengesmenu.hornposting = 0;
S_StartSound(NULL, sfx_s3k63);
forceflip = true;
}
}
if (!forceflip)
challengesmenu.hornposting++;
if (challengesmenu.hornposting > EASEOFFHORN)
{
challengesmenu.hornposting = 0;
horngoner = true;
S_StartSound(NULL, sfx_s3k72);
}
else
{
S_StartSound(NULL, followers[fskin].hornsound);
}
M_SetMenuDelay(pid);
forceflip = true;
}
}
break;
}
case SECRET_COLOR:
{
if (setup_numplayers <= 1 && cv_lastprofile[0].value != PROFILE_GUEST && M_MenuConfirmPressed(pid))
{
INT32 colorid = M_UnlockableColorNum(ref);
if (colorid != SKINCOLOR_NONE)
{
profile_t *pr = PR_GetProfile(cv_lastprofile[0].value);
if (pr && pr->color != colorid)
{
pr->color = colorid;
CV_SetValue(&cv_playercolor[0], colorid);
if (setup_numplayers)
{
G_SetPlayerGamepadIndicatorToPlayerColor(0);
}
S_StartSound(NULL, sfx_s3k63);
M_SetMenuDelay(pid);
forceflip = true;
}
}
} }
break; break;
} }
@ -1167,7 +1340,7 @@ boolean M_ChallengesInputs(INT32 ch)
{ {
const char *trymusname = NULL; const char *trymusname = NULL;
UINT16 map = M_UnlockableMapNum(&unlockables[challengesmenu.currentunlock]); UINT16 map = M_UnlockableMapNum(ref);
if (map >= nummapheaders if (map >= nummapheaders
|| !mapheaderinfo[map]) || !mapheaderinfo[map])
{ {
@ -1196,15 +1369,18 @@ boolean M_ChallengesInputs(INT32 ch)
if (trymusname) if (trymusname)
{ {
if (!Music_Playing("challenge_altmusic") const char *tune = "challenge_altmusic";
|| strcmp(Music_Song("challenge_altmusic"), trymusname)) if (!Music_Playing(tune)
|| strcmp(Music_Song(tune), trymusname))
{ {
Music_Remap("challenge_altmusic", trymusname); Music_Remap(tune, trymusname);
Music_Play("challenge_altmusic"); Music_Play(tune);
challengesmenu.nowplayingtile = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
} }
else else
{ {
Music_Stop("challenge_altmusic"); Music_Stop(tune);
challengesmenu.nowplayingtile = UINT16_MAX;
} }
M_SetMenuDelay(pid); M_SetMenuDelay(pid);
@ -1217,6 +1393,16 @@ boolean M_ChallengesInputs(INT32 ch)
break; break;
} }
if (forceflip)
{
UINT16 id = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
// This construction helps pressing too early
if (challengesmenu.extradata[id].flip <= TILEFLIP_MAX/2)
{
challengesmenu.extradata[id].flip = 1 + (TILEFLIP_MAX/2);
}
}
return true; return true;
} }
} }

View file

@ -109,6 +109,11 @@ static void M_ProfileEditApply(void)
if (belongsto > -1 && belongsto < MAXSPLITSCREENPLAYERS) if (belongsto > -1 && belongsto < MAXSPLITSCREENPLAYERS)
{ {
PR_ApplyProfileToggles(optionsmenu.profilen, belongsto); PR_ApplyProfileToggles(optionsmenu.profilen, belongsto);
if (gamestate == GS_MENU)
{
// Safe to apply skin, etc here.
PR_ApplyProfileLight(optionsmenu.profilen, belongsto);
}
} }
// Reapply player 1's real profile ID. // Reapply player 1's real profile ID.

View file

@ -304,47 +304,6 @@ void M_CharacterSelectInit(void)
memset(setup_explosions, 0, sizeof(setup_explosions)); memset(setup_explosions, 0, sizeof(setup_explosions));
setup_animcounter = 0; setup_animcounter = 0;
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
// Default to no follower / match colour.
setup_player[i].followern = -1;
setup_player[i].followercategory = -1;
setup_player[i].followercolor = SKINCOLOR_NONE;
setup_player[i].profilen_slide.start = 0;
setup_player[i].profilen_slide.dist = 0;
// If we're on prpfile select, skip straight to CSSTEP_CHARS
// do the same if we're midgame, but make sure to consider splitscreen properly.
if (optionsmenu.profile && i == 0)
{
setup_player[i].profilen = optionsmenu.profilen;
//PR_ApplyProfileLight(setup_player[i].profilen, 0);
M_SetupProfileGridPos(&setup_player[i]);
setup_player[i].mdepth = CSSTEP_CHARS;
}
else
{
// Set default selected profile to the last used profile for each player:
// (Make sure we don't overshoot it somehow if we deleted profiles or whatnot)
setup_player[i].profilen = min(cv_lastprofile[i].value, PR_GetNumProfiles());
if (gamestate != GS_MENU && i <= splitscreen)
{
M_SetupMidGameGridPos(&setup_player[i], i);
setup_player[i].mdepth = CSSTEP_CHARS;
}
else
{
// Un-set devices
G_SetDeviceForPlayer(i, -1);
#ifdef CHARSELECT_DEVICEDEBUG
CONS_Printf("M_CharacterSelectInit: Device for %d set to %d\n", i, -1);
#endif
}
}
}
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
{ {
UINT8 x = skins[i]->kartspeed-1; UINT8 x = skins[i]->kartspeed-1;
@ -391,6 +350,47 @@ void M_CharacterSelectInit(void)
} }
setup_page = 0; setup_page = 0;
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
// Default to no follower / match colour.
setup_player[i].followern = -1;
setup_player[i].followercategory = -1;
setup_player[i].followercolor = SKINCOLOR_NONE;
setup_player[i].profilen_slide.start = 0;
setup_player[i].profilen_slide.dist = 0;
// If we're on prpfile select, skip straight to CSSTEP_CHARS
// do the same if we're midgame, but make sure to consider splitscreen properly.
if (optionsmenu.profile && i == 0)
{
setup_player[i].profilen = optionsmenu.profilen;
//PR_ApplyProfileLight(setup_player[i].profilen, 0);
M_SetupProfileGridPos(&setup_player[i]);
setup_player[i].mdepth = CSSTEP_CHARS;
}
else
{
// Set default selected profile to the last used profile for each player:
// (Make sure we don't overshoot it somehow if we deleted profiles or whatnot)
setup_player[i].profilen = min(cv_lastprofile[i].value, PR_GetNumProfiles());
if (gamestate != GS_MENU && i <= splitscreen)
{
M_SetupMidGameGridPos(&setup_player[i], i);
setup_player[i].mdepth = CSSTEP_CHARS;
}
else
{
// Un-set devices
G_SetDeviceForPlayer(i, -1);
#ifdef CHARSELECT_DEVICEDEBUG
CONS_Printf("M_CharacterSelectInit: Device for %d set to %d\n", i, -1);
#endif
}
}
}
} }
@ -777,7 +777,7 @@ static boolean M_HandleBeginningColors(setup_player_t *p)
static void M_HandleBeginningFollowers(setup_player_t *p) static void M_HandleBeginningFollowers(setup_player_t *p)
{ {
if (setup_numfollowercategories == 0) if (horngoner || setup_numfollowercategories == 0)
{ {
p->followern = -1; p->followern = -1;
M_HandlePlayerFinalise(p); M_HandlePlayerFinalise(p);
@ -1392,7 +1392,9 @@ static void M_MPConfirmCharacterSelection(void)
CV_StealthSetValue(&cv_playercolor[i], col); CV_StealthSetValue(&cv_playercolor[i], col);
// follower // follower
if (setup_player[i].followern < 0) if (horngoner)
;
else if (setup_player[i].followern < 0)
CV_StealthSet(&cv_follower[i], "None"); CV_StealthSet(&cv_follower[i], "None");
else else
CV_StealthSet(&cv_follower[i], followers[setup_player[i].followern].name); CV_StealthSet(&cv_follower[i], followers[setup_player[i].followern].name);
@ -1457,9 +1459,12 @@ void M_CharacterSelectTick(void)
strcpy(optionsmenu.profile->skinname, skins[setup_player[0].skin]->name); strcpy(optionsmenu.profile->skinname, skins[setup_player[0].skin]->name);
optionsmenu.profile->color = setup_player[0].color; optionsmenu.profile->color = setup_player[0].color;
if (!horngoner) // so you don't lose your choice after annoying the game
{
// save follower // save follower
strcpy(optionsmenu.profile->follower, followers[setup_player[0].followern].name); strcpy(optionsmenu.profile->follower, followers[setup_player[0].followern].name);
optionsmenu.profile->followercolor = setup_player[0].followercolor; optionsmenu.profile->followercolor = setup_player[0].followercolor;
}
// reset setup_player // reset setup_player
memset(setup_player, 0, sizeof(setup_player)); memset(setup_player, 0, sizeof(setup_player));
@ -1475,7 +1480,9 @@ void M_CharacterSelectTick(void)
CV_StealthSet(&cv_skin[i], skins[setup_player[i].skin]->name); CV_StealthSet(&cv_skin[i], skins[setup_player[i].skin]->name);
CV_StealthSetValue(&cv_playercolor[i], setup_player[i].color); CV_StealthSetValue(&cv_playercolor[i], setup_player[i].color);
if (setup_player[i].followern < 0) if (horngoner)
;
else if (setup_player[i].followern < 0)
CV_StealthSet(&cv_follower[i], "None"); CV_StealthSet(&cv_follower[i], "None");
else else
CV_StealthSet(&cv_follower[i], followers[setup_player[i].followern].name); CV_StealthSet(&cv_follower[i], followers[setup_player[i].followern].name);

View file

@ -8099,7 +8099,7 @@ static void P_InitPlayers(void)
skin = 0; skin = 0;
} }
if (netgame) if (netgame || horngoner)
; // shouldn't happen but at least attempt to sync if it does ; // shouldn't happen but at least attempt to sync if it does
else for (i = 0; i < numfollowers; i++) else for (i = 0; i < numfollowers; i++)
{ {

View file

@ -1615,7 +1615,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
x - 9, y - 13, x - 9, y - 13,
(baseflags|((menuqueue.entries[i].encore) ? V_FLIP : 0)), (baseflags|((menuqueue.entries[i].encore) ? V_FLIP : 0)),
menuqueue.entries[i].mapnum, menuqueue.entries[i].mapnum,
NULL NULL, FRACUNIT, 1
); );
x += 24; x += 24;