mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'challenge-final' into 'master'
Challenge Final See merge request KartKrew/Kart!2140
This commit is contained in:
commit
bca0b48f45
10 changed files with 291 additions and 47 deletions
|
|
@ -3928,6 +3928,7 @@ void SV_StopServer(void)
|
||||||
maketic = gametic+1;
|
maketic = gametic+1;
|
||||||
neededtic = maketic;
|
neededtic = maketic;
|
||||||
serverrunning = false;
|
serverrunning = false;
|
||||||
|
titlemapinaction = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// called at singleplayer start and stopdemo
|
// called at singleplayer start and stopdemo
|
||||||
|
|
|
||||||
|
|
@ -3088,6 +3088,7 @@ static void readcondition(UINT16 set, UINT32 id, char *word2)
|
||||||
else if ((offset=0) || fastcmp(params[0], "FINISHCOOL")
|
else if ((offset=0) || fastcmp(params[0], "FINISHCOOL")
|
||||||
|| (++offset && fastcmp(params[0], "FINISHPERFECT"))
|
|| (++offset && fastcmp(params[0], "FINISHPERFECT"))
|
||||||
|| (++offset && fastcmp(params[0], "FINISHALLPRISONS"))
|
|| (++offset && fastcmp(params[0], "FINISHALLPRISONS"))
|
||||||
|
|| (++offset && fastcmp(params[0], "SURVIVE"))
|
||||||
|| (++offset && fastcmp(params[0], "NOCONTEST"))
|
|| (++offset && fastcmp(params[0], "NOCONTEST"))
|
||||||
|| (++offset && fastcmp(params[0], "SMASHUFO"))
|
|| (++offset && fastcmp(params[0], "SMASHUFO"))
|
||||||
|| (++offset && fastcmp(params[0], "CHASEDBYSPB")))
|
|| (++offset && fastcmp(params[0], "CHASEDBYSPB")))
|
||||||
|
|
|
||||||
173
src/k_menudraw.c
173
src/k_menudraw.c
|
|
@ -2837,7 +2837,7 @@ static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch)
|
||||||
|
|
||||||
if (levelsearch->cup == &dummy_lostandfound)
|
if (levelsearch->cup == &dummy_lostandfound)
|
||||||
{
|
{
|
||||||
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, y+6, 0, "Lost and Found");
|
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, y+6, 0, "Lost & Found");
|
||||||
}
|
}
|
||||||
else if (levelsearch->cup)
|
else if (levelsearch->cup)
|
||||||
{
|
{
|
||||||
|
|
@ -6389,7 +6389,7 @@ void M_DrawAddons(void)
|
||||||
|
|
||||||
// Challenges Menu
|
// Challenges Menu
|
||||||
|
|
||||||
static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili)
|
static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, UINT8 *flashmap, boolean hili)
|
||||||
{
|
{
|
||||||
#ifdef DEVELOP
|
#ifdef DEVELOP
|
||||||
extern consvar_t cv_debugchallenges;
|
extern consvar_t cv_debugchallenges;
|
||||||
|
|
@ -6710,6 +6710,21 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
|
||||||
}
|
}
|
||||||
|
|
||||||
drawborder:
|
drawborder:
|
||||||
|
|
||||||
|
if (num < MAXUNLOCKABLES && gamedata->unlockpending[num])
|
||||||
|
{
|
||||||
|
const INT32 area = (ref->majorunlock) ? 42 : 20;
|
||||||
|
INT32 val;
|
||||||
|
for (i = 0; i < area; i++)
|
||||||
|
{
|
||||||
|
val = (x + i + challengesmenu.ticker) % 40;
|
||||||
|
if (val >= 20)
|
||||||
|
val = 40 - val;
|
||||||
|
val = (val + 6)/5;
|
||||||
|
V_DrawFadeFill(x + i, y, 1, area, 0, flashmap[98 + val], 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hili)
|
if (hili)
|
||||||
{
|
{
|
||||||
boolean maj = (ref != NULL && ref->majorunlock);
|
boolean maj = (ref != NULL && ref->majorunlock);
|
||||||
|
|
@ -6719,13 +6734,11 @@ drawborder:
|
||||||
buffer[7] = (skullAnimCounter/5) ? '2' : '1';
|
buffer[7] = (skullAnimCounter/5) ? '2' : '1';
|
||||||
pat = W_CachePatchName(buffer, PU_CACHE);
|
pat = W_CachePatchName(buffer, PU_CACHE);
|
||||||
|
|
||||||
colormap = R_GetTranslationColormap(TC_DEFAULT, M_GetCvPlayerColor(0), GTC_MENUCACHE);
|
|
||||||
|
|
||||||
V_DrawFixedPatch(
|
V_DrawFixedPatch(
|
||||||
x*FRACUNIT, y*FRACUNIT,
|
x*FRACUNIT, y*FRACUNIT,
|
||||||
FRACUNIT,
|
FRACUNIT,
|
||||||
0, pat,
|
0, pat,
|
||||||
colormap
|
flashmap
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7114,6 +7127,32 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
|
||||||
NULL);
|
NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SECRET_ADDONS:
|
||||||
|
{
|
||||||
|
V_DrawFixedPatch(28*FRACUNIT, (BASEVIDHEIGHT-28)*FRACUNIT,
|
||||||
|
FRACUNIT,
|
||||||
|
0, W_CachePatchName("M_ICOADD", PU_CACHE),
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SECRET_SOUNDTEST:
|
||||||
|
{
|
||||||
|
V_DrawFixedPatch(28*FRACUNIT, (BASEVIDHEIGHT-28)*FRACUNIT,
|
||||||
|
FRACUNIT,
|
||||||
|
0, W_CachePatchName("M_ICOSTM", PU_CACHE),
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SECRET_EGGTV:
|
||||||
|
{
|
||||||
|
V_DrawFixedPatch(3*FRACUNIT, (BASEVIDHEIGHT-40)*FRACUNIT,
|
||||||
|
FRACUNIT,
|
||||||
|
0, W_CachePatchName(
|
||||||
|
va("RHTVSQN%c", (challengesmenu.ticker & 2) ? '5' : '6'),
|
||||||
|
PU_CACHE),
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SECRET_ALTTITLE:
|
case SECRET_ALTTITLE:
|
||||||
{
|
{
|
||||||
x = 8;
|
x = 8;
|
||||||
|
|
@ -7282,12 +7321,14 @@ static void M_DrawChallengeKeys(INT32 tilex, INT32 tiley)
|
||||||
|
|
||||||
fixed_t keyx = (8+offs)*FRACUNIT, keyy = 0;
|
fixed_t keyx = (8+offs)*FRACUNIT, keyy = 0;
|
||||||
|
|
||||||
|
const boolean keybuttonpress = (menumessage.active == false && M_MenuExtraHeld(pid) == true);
|
||||||
|
|
||||||
// Button prompt
|
// Button prompt
|
||||||
K_drawButton(
|
K_drawButton(
|
||||||
24 << FRACBITS,
|
24 << FRACBITS,
|
||||||
16 << FRACBITS,
|
16 << FRACBITS,
|
||||||
0, kp_button_c[1],
|
0, kp_button_c[1],
|
||||||
menumessage.active == false && M_MenuExtraHeld(pid) == true
|
keybuttonpress
|
||||||
);
|
);
|
||||||
|
|
||||||
// Metyr of rounds played that contribute to Chao Key generation
|
// Metyr of rounds played that contribute to Chao Key generation
|
||||||
|
|
@ -7334,6 +7375,20 @@ static void M_DrawChallengeKeys(INT32 tilex, INT32 tiley)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hand
|
||||||
|
if (challengesmenu.keywasadded == true)
|
||||||
|
{
|
||||||
|
INT32 handx = 32 + 16;
|
||||||
|
if (keybuttonpress == false)
|
||||||
|
{
|
||||||
|
// Only animate if it's the focus
|
||||||
|
handx -= (skullAnimCounter/5);
|
||||||
|
}
|
||||||
|
|
||||||
|
V_DrawScaledPatch(handx, 8, V_FLIP,
|
||||||
|
W_CachePatchName("M_CURSOR", PU_CACHE));
|
||||||
|
}
|
||||||
|
|
||||||
UINT8 keysbeingused = 0;
|
UINT8 keysbeingused = 0;
|
||||||
|
|
||||||
// The Chao Key swooping animation
|
// The Chao Key swooping animation
|
||||||
|
|
@ -7451,6 +7506,103 @@ static void M_DrawChallengeKeys(INT32 tilex, INT32 tiley)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void M_DrawChallengeScrollBar(UINT8 *flashmap)
|
||||||
|
{
|
||||||
|
const INT32 bary = 4, barh = 1, hiliw = 1;
|
||||||
|
|
||||||
|
if (!gamedata->challengegrid || !gamedata->challengegridwidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const INT32 barlen = gamedata->challengegridwidth*hiliw;
|
||||||
|
|
||||||
|
INT32 barx = (BASEVIDWIDTH - barlen)/2;
|
||||||
|
if (barlen > 200)
|
||||||
|
{
|
||||||
|
// TODO I DONT KNOW IF THE MATHS IS WRONG BUT WE DON'T HAVE
|
||||||
|
// 200 COLUMNS YET SO KICKING CAN DOWN THE ROAD ~toast 190324
|
||||||
|
INT32 shif = barlen - 200;
|
||||||
|
barx -= (shif/2 + (shif * challengesmenu.col)/barlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bg
|
||||||
|
V_DrawFadeFill(barx, bary, barlen, barh, 0, 31, challengetransparentstrength);
|
||||||
|
|
||||||
|
// This was a macro for experimentation
|
||||||
|
#define COLTOPIX(col) (col*hiliw)
|
||||||
|
//((col * barlen)/gamedata->challengegridwidth)
|
||||||
|
|
||||||
|
INT32 hilix, nextstep, i, completionamount, skiplevel;
|
||||||
|
|
||||||
|
// selection
|
||||||
|
hilix = COLTOPIX(challengesmenu.col);
|
||||||
|
V_DrawFill(barx + hilix, bary-1, 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
|
||||||
|
nextstep = completionamount = skiplevel = 0;
|
||||||
|
for (i = 0; ; i++)
|
||||||
|
{
|
||||||
|
INT32 prevstep = nextstep;
|
||||||
|
nextstep = (i % CHALLENGEGRIDHEIGHT);
|
||||||
|
if (prevstep >= nextstep)
|
||||||
|
{
|
||||||
|
if (completionamount > 0)
|
||||||
|
{
|
||||||
|
if (skiplevel >= mindiscouragement && completionamount == 10)
|
||||||
|
{
|
||||||
|
// awareness
|
||||||
|
completionamount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
V_DrawFadeFill(barx + hilix, bary, hiliw, barh, 0, 1, completionamount);
|
||||||
|
}
|
||||||
|
|
||||||
|
completionamount = skiplevel = 0;
|
||||||
|
hilix = i/CHALLENGEGRIDHEIGHT;
|
||||||
|
hilix = COLTOPIX(hilix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DO NOT DEREFERENCE gamedata->challengegrid[i] UNTIL AFTER THIS
|
||||||
|
if (i >= gamedata->challengegridwidth*CHALLENGEGRIDHEIGHT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (gamedata->challengegrid[i] >= MAXUNLOCKABLES)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (gamedata->unlocked[gamedata->challengegrid[i]] && completionamount != -1)
|
||||||
|
{
|
||||||
|
completionamount += (10/CHALLENGEGRIDHEIGHT);
|
||||||
|
|
||||||
|
unlockable_t *ref = &unlockables[gamedata->challengegrid[i]];
|
||||||
|
|
||||||
|
if (skiplevel < 2 && M_Achieved(ref->conditionset - 1) == false)
|
||||||
|
{
|
||||||
|
skiplevel = ref->majorunlock ? 2 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamedata->unlockpending[gamedata->challengegrid[i]] == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
INT32 val = (hilix + challengesmenu.ticker) % 40;
|
||||||
|
if (val >= 20)
|
||||||
|
val = 40 - val;
|
||||||
|
val = (val + 6)/10;
|
||||||
|
|
||||||
|
V_DrawFill(barx + hilix, bary, hiliw, barh, flashmap[99 + val]);
|
||||||
|
|
||||||
|
// The pending fill overrides everything else.
|
||||||
|
completionamount = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef COLTOPIX
|
||||||
|
}
|
||||||
|
|
||||||
void M_DrawChallenges(void)
|
void M_DrawChallenges(void)
|
||||||
{
|
{
|
||||||
INT32 x = currentMenu->x, explodex, selectx = 0, selecty = 0;
|
INT32 x = currentMenu->x, explodex, selectx = 0, selecty = 0;
|
||||||
|
|
@ -7503,6 +7655,8 @@ void M_DrawChallenges(void)
|
||||||
goto challengedesc;
|
goto challengedesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT8 *flashmap = R_GetTranslationColormap(TC_DEFAULT, M_GetCvPlayerColor(0), GTC_MENUCACHE);
|
||||||
|
|
||||||
y = currentMenu->y;
|
y = currentMenu->y;
|
||||||
|
|
||||||
V_DrawFadeFill(0, y-2, BASEVIDWIDTH, (challengesgridstep * CHALLENGEGRIDHEIGHT) + 2, 0, 31, challengetransparentstrength);
|
V_DrawFadeFill(0, y-2, BASEVIDWIDTH, (challengesgridstep * CHALLENGEGRIDHEIGHT) + 2, 0, 31, challengetransparentstrength);
|
||||||
|
|
@ -7556,7 +7710,7 @@ void M_DrawChallenges(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
M_DrawChallengeTile(i, j, x, y, false);
|
M_DrawChallengeTile(i, j, x, y, flashmap, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
x -= challengesgridstep;
|
x -= challengesgridstep;
|
||||||
|
|
@ -7571,11 +7725,14 @@ void M_DrawChallenges(void)
|
||||||
if (challengesmenu.fade)
|
if (challengesmenu.fade)
|
||||||
V_DrawFadeScreen(31, challengesmenu.fade);
|
V_DrawFadeScreen(31, challengesmenu.fade);
|
||||||
|
|
||||||
|
M_DrawChallengeScrollBar(flashmap);
|
||||||
|
|
||||||
M_DrawChallengeTile(
|
M_DrawChallengeTile(
|
||||||
challengesmenu.hilix,
|
challengesmenu.hilix,
|
||||||
challengesmenu.hiliy,
|
challengesmenu.hiliy,
|
||||||
selectx,
|
selectx,
|
||||||
selecty,
|
selecty,
|
||||||
|
flashmap,
|
||||||
true);
|
true);
|
||||||
M_DrawCharSelectExplosions(false, explodex, currentMenu->y);
|
M_DrawCharSelectExplosions(false, explodex, currentMenu->y);
|
||||||
|
|
||||||
|
|
@ -7881,7 +8038,7 @@ static void M_DrawStatsMaps(void)
|
||||||
else if (mapheaderinfo[mnum]->cup)
|
else if (mapheaderinfo[mnum]->cup)
|
||||||
str = va("%s CUP", mapheaderinfo[mnum]->cup->realname);
|
str = va("%s CUP", mapheaderinfo[mnum]->cup->realname);
|
||||||
else
|
else
|
||||||
str = "LOST AND FOUND";
|
str = "LOST & FOUND";
|
||||||
|
|
||||||
V_DrawThinString(20, y, highlightflags, str);
|
V_DrawThinString(20, y, highlightflags, str);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -733,6 +733,14 @@ void M_StartControlPanel(void)
|
||||||
{
|
{
|
||||||
if (gamestate != GS_MENU)
|
if (gamestate != GS_MENU)
|
||||||
{
|
{
|
||||||
|
if (titlemapinaction)
|
||||||
|
{
|
||||||
|
// We clear a LITTLE bit of state, but not a full D_ClearState.
|
||||||
|
// Just enough to guarantee SV_ResetServer is called before session start.
|
||||||
|
SV_StopServer();
|
||||||
|
SV_ResetServer();
|
||||||
|
}
|
||||||
|
|
||||||
G_SetGamestate(GS_MENU);
|
G_SetGamestate(GS_MENU);
|
||||||
|
|
||||||
gameaction = ga_nothing;
|
gameaction = ga_nothing;
|
||||||
|
|
|
||||||
31
src/m_cond.c
31
src/m_cond.c
|
|
@ -1125,7 +1125,7 @@ static void M_PrecacheLevelLocks(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
tempstr = va(
|
tempstr = va(
|
||||||
"Music: %s Cup %c%u %c",
|
"Music: %s CUP %c%u %c",
|
||||||
mapheaderinfo[map]->cup->realname,
|
mapheaderinfo[map]->cup->realname,
|
||||||
prefix,
|
prefix,
|
||||||
positionid + 1,
|
positionid + 1,
|
||||||
|
|
@ -1153,7 +1153,7 @@ static void M_PrecacheLevelLocks(void)
|
||||||
|
|
||||||
tempstr = va(
|
tempstr = va(
|
||||||
"Music: %s #%u %c",
|
"Music: %s #%u %c",
|
||||||
(mapheaderinfo[map]->typeoflevel & TOL_TUTORIAL) ? "Tutorial" : "Lost and Found",
|
(mapheaderinfo[map]->typeoflevel & TOL_TUTORIAL) ? "Tutorial" : "Lost & Found",
|
||||||
positionid + 1,
|
positionid + 1,
|
||||||
'A' + j // :D ?
|
'A' + j // :D ?
|
||||||
);
|
);
|
||||||
|
|
@ -1516,8 +1516,10 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
|
||||||
case UC_UNLOCKPERCENT:
|
case UC_UNLOCKPERCENT:
|
||||||
{
|
{
|
||||||
// Don't let netgame sessions intefere
|
// Don't let netgame sessions intefere
|
||||||
// (or have this give a performance hit)
|
// or have this give a performance hit
|
||||||
if (Playing())
|
// (This is formulated this way to
|
||||||
|
// perfectly eclipse M_CheckNetUnlockByID)
|
||||||
|
if (netgame || demo.playback || Playing())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
UINT16 i, unlocked = cn->extrainfo2, total = 0;
|
UINT16 i, unlocked = cn->extrainfo2, total = 0;
|
||||||
|
|
@ -1710,6 +1712,9 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
|
||||||
&& !(player->pflags & PF_NOCONTEST)
|
&& !(player->pflags & PF_NOCONTEST)
|
||||||
//&& M_NotFreePlay()
|
//&& M_NotFreePlay()
|
||||||
&& numtargets >= maptargets);
|
&& numtargets >= maptargets);
|
||||||
|
case UCRP_SURVIVE:
|
||||||
|
return (player->exiting
|
||||||
|
&& !(player->pflags & PF_NOCONTEST));
|
||||||
case UCRP_NOCONTEST:
|
case UCRP_NOCONTEST:
|
||||||
return (player->pflags & PF_NOCONTEST);
|
return (player->pflags & PF_NOCONTEST);
|
||||||
|
|
||||||
|
|
@ -2114,7 +2119,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
||||||
switch (cn->type)
|
switch (cn->type)
|
||||||
{
|
{
|
||||||
case UC_PLAYTIME: // Requires total playing time >= x
|
case UC_PLAYTIME: // Requires total playing time >= x
|
||||||
return va("play for %i:%02i:%02i",
|
return va("play the game for %i:%02i:%02i",
|
||||||
G_TicsToHours(cn->requirement),
|
G_TicsToHours(cn->requirement),
|
||||||
G_TicsToMinutes(cn->requirement, false),
|
G_TicsToMinutes(cn->requirement, false),
|
||||||
G_TicsToSeconds(cn->requirement));
|
G_TicsToSeconds(cn->requirement));
|
||||||
|
|
@ -2165,7 +2170,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
||||||
|
|
||||||
case UC_GAMECLEAR: // Requires game beaten >= x times
|
case UC_GAMECLEAR: // Requires game beaten >= x times
|
||||||
if (cn->requirement > 1)
|
if (cn->requirement > 1)
|
||||||
return va("beat game %d times", cn->requirement);
|
return va("beat the game %d times", cn->requirement);
|
||||||
else
|
else
|
||||||
return va("beat the game");
|
return va("beat the game");
|
||||||
|
|
||||||
|
|
@ -2316,7 +2321,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
||||||
}
|
}
|
||||||
|
|
||||||
case UC_TOTALMEDALS: // Requires number of emblems >= x
|
case UC_TOTALMEDALS: // Requires number of emblems >= x
|
||||||
return va("get %d medals", cn->requirement);
|
return va("get %d Medals", cn->requirement);
|
||||||
|
|
||||||
case UC_EMBLEM: // Requires emblem x to be obtained
|
case UC_EMBLEM: // Requires emblem x to be obtained
|
||||||
{
|
{
|
||||||
|
|
@ -2461,14 +2466,14 @@ static const char *M_GetConditionString(condition_t *cn)
|
||||||
case UC_ADDON:
|
case UC_ADDON:
|
||||||
if (!M_SecretUnlocked(SECRET_ADDONS, true))
|
if (!M_SecretUnlocked(SECRET_ADDONS, true))
|
||||||
return NULL;
|
return NULL;
|
||||||
return "load a custom addon into \"Dr. Robotnik's Ring Racers\"";
|
return "load a custom addon";
|
||||||
case UC_CREDITS:
|
case UC_CREDITS:
|
||||||
return "watch the developer credits all the way from start to finish";
|
return "watch the developer credits all the way from start to finish";
|
||||||
case UC_REPLAY:
|
case UC_REPLAY:
|
||||||
return "save a replay after finishing a round";
|
return "save a replay after finishing a round";
|
||||||
case UC_CRASH:
|
case UC_CRASH:
|
||||||
if (gamedata->evercrashed)
|
if (gamedata->evercrashed)
|
||||||
return "launch \"Dr. Robotnik's Ring Racers\" again after a game crash";
|
return "re-launch the game after a crash";
|
||||||
return NULL;
|
return NULL;
|
||||||
case UC_TUTORIALSKIP:
|
case UC_TUTORIALSKIP:
|
||||||
return "successfully skip the Tutorial";
|
return "successfully skip the Tutorial";
|
||||||
|
|
@ -2626,7 +2631,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
||||||
{
|
{
|
||||||
if (cup->id != cn->requirement)
|
if (cup->id != cn->requirement)
|
||||||
continue;
|
continue;
|
||||||
return va("%s%s %s Cup",
|
return va("%s%s %s CUP",
|
||||||
completetype, orbetter,
|
completetype, orbetter,
|
||||||
(M_CupLocked(cup) ? "???" : cup->realname)
|
(M_CupLocked(cup) ? "???" : cup->realname)
|
||||||
);
|
);
|
||||||
|
|
@ -2650,6 +2655,8 @@ static const char *M_GetConditionString(condition_t *cn)
|
||||||
return "finish a perfect round";
|
return "finish a perfect round";
|
||||||
case UCRP_FINISHALLPRISONS:
|
case UCRP_FINISHALLPRISONS:
|
||||||
return "break every Prison Egg";
|
return "break every Prison Egg";
|
||||||
|
case UCRP_SURVIVE:
|
||||||
|
return "survive";
|
||||||
case UCRP_NOCONTEST:
|
case UCRP_NOCONTEST:
|
||||||
return "NO CONTEST";
|
return "NO CONTEST";
|
||||||
|
|
||||||
|
|
@ -2875,8 +2882,8 @@ char *M_BuildConditionSetString(UINT16 unlockid)
|
||||||
{
|
{
|
||||||
if (lastID != cn->id)
|
if (lastID != cn->id)
|
||||||
{
|
{
|
||||||
worklen = 4;
|
worklen = 6;
|
||||||
strncat(message, "\nOR ", len);
|
strncat(message, " - OR ", len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ typedef enum
|
||||||
UCRP_FINISHCOOL, // Finish in good standing
|
UCRP_FINISHCOOL, // Finish in good standing
|
||||||
UCRP_FINISHPERFECT, // Finish a perfect race
|
UCRP_FINISHPERFECT, // Finish a perfect race
|
||||||
UCRP_FINISHALLPRISONS, // Break all prisons
|
UCRP_FINISHALLPRISONS, // Break all prisons
|
||||||
|
UCRP_SURVIVE, // Survive
|
||||||
UCRP_NOCONTEST, // No Contest
|
UCRP_NOCONTEST, // No Contest
|
||||||
|
|
||||||
UCRP_SMASHUFO, // Smash the UFO Catcher
|
UCRP_SMASHUFO, // Smash the UFO Catcher
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ static void M_ChallengesAutoFocus(UINT16 unlockid, boolean fresh)
|
||||||
{
|
{
|
||||||
UINT16 i;
|
UINT16 i;
|
||||||
INT16 work;
|
INT16 work;
|
||||||
|
boolean posisvalid = false;
|
||||||
|
|
||||||
if (unlockid >= MAXUNLOCKABLES && gamedata->pendingkeyrounds > 0
|
if (unlockid >= MAXUNLOCKABLES && gamedata->pendingkeyrounds > 0
|
||||||
&& (gamedata->chaokeys < GDMAX_CHAOKEYS))
|
&& (gamedata->chaokeys < GDMAX_CHAOKEYS))
|
||||||
|
|
@ -149,28 +150,22 @@ static void M_ChallengesAutoFocus(UINT16 unlockid, boolean fresh)
|
||||||
|
|
||||||
if (fresh && unlockid >= MAXUNLOCKABLES)
|
if (fresh && unlockid >= MAXUNLOCKABLES)
|
||||||
{
|
{
|
||||||
UINT16 selection[MAXUNLOCKABLES];
|
if (challengesmenu.currentunlock < MAXUNLOCKABLES)
|
||||||
UINT16 numunlocks = 0;
|
|
||||||
|
|
||||||
// Get a random available unlockable.
|
|
||||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
||||||
{
|
{
|
||||||
if (!unlockables[i].conditionset)
|
// Use the last selected time.
|
||||||
{
|
unlockid = challengesmenu.currentunlock;
|
||||||
continue;
|
posisvalid = true;
|
||||||
}
|
|
||||||
|
|
||||||
if (!gamedata->unlocked[i])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
selection[numunlocks++] = i;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (!numunlocks)
|
|
||||||
{
|
{
|
||||||
// ...OK, get a random unlockable.
|
UINT16 selection[MAXUNLOCKABLES];
|
||||||
|
UINT16 numunlocks = 0;
|
||||||
|
|
||||||
|
boolean triedrandomlevel = 0;
|
||||||
|
|
||||||
|
tryfreshrandom:
|
||||||
|
|
||||||
|
// Get a random available unlockable.
|
||||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||||
{
|
{
|
||||||
if (!unlockables[i].conditionset)
|
if (!unlockables[i].conditionset)
|
||||||
|
|
@ -178,13 +173,43 @@ static void M_ChallengesAutoFocus(UINT16 unlockid, boolean fresh)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise we don't care, just pick any non-blank tile
|
||||||
|
if (triedrandomlevel < 2)
|
||||||
|
{
|
||||||
|
// We try for any unlock second
|
||||||
|
if (!gamedata->unlocked[i])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triedrandomlevel == 0)
|
||||||
|
{
|
||||||
|
// We try for a pending unlock first
|
||||||
|
if (!gamedata->unlockpending[i])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
selection[numunlocks++] = i;
|
selection[numunlocks++] = i;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unlockid = selection[M_RandomKey(numunlocks)];
|
if (numunlocks == 0)
|
||||||
|
{
|
||||||
|
if (triedrandomlevel == 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
triedrandomlevel++;
|
||||||
|
goto tryfreshrandom;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlockid = selection[M_RandomKey(numunlocks)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
challengesmenu.unlockanim = (challengesmenu.pending && !challengesmenu.chaokeyadd ? 0 : MAXUNLOCKTIME);
|
||||||
|
|
||||||
if (unlockid >= MAXUNLOCKABLES)
|
if (unlockid >= MAXUNLOCKABLES)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -192,9 +217,8 @@ static void M_ChallengesAutoFocus(UINT16 unlockid, boolean fresh)
|
||||||
if (challengesmenu.unlockcondition)
|
if (challengesmenu.unlockcondition)
|
||||||
Z_Free(challengesmenu.unlockcondition);
|
Z_Free(challengesmenu.unlockcondition);
|
||||||
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);
|
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);
|
||||||
challengesmenu.unlockanim = (challengesmenu.pending && !challengesmenu.chaokeyadd ? 0 : MAXUNLOCKTIME);
|
|
||||||
|
|
||||||
if (gamedata->challengegrid == NULL || challengesmenu.extradata == NULL)
|
if (gamedata->challengegrid == NULL || challengesmenu.extradata == NULL || posisvalid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
|
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
|
||||||
|
|
@ -330,6 +354,8 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
|
||||||
|
|
||||||
if (challengesmenu.pending || desiredmenu == NULL)
|
if (challengesmenu.pending || desiredmenu == NULL)
|
||||||
{
|
{
|
||||||
|
static boolean firstopen = true;
|
||||||
|
|
||||||
challengesmenu.ticker = 0;
|
challengesmenu.ticker = 0;
|
||||||
challengesmenu.requestflip = false;
|
challengesmenu.requestflip = false;
|
||||||
challengesmenu.requestnew = false;
|
challengesmenu.requestnew = false;
|
||||||
|
|
@ -337,9 +363,14 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
|
||||||
challengesmenu.keywasadded = false;
|
challengesmenu.keywasadded = false;
|
||||||
challengesmenu.considersealedswapalert = false;
|
challengesmenu.considersealedswapalert = false;
|
||||||
challengesmenu.chaokeyhold = 0;
|
challengesmenu.chaokeyhold = 0;
|
||||||
challengesmenu.currentunlock = MAXUNLOCKABLES;
|
|
||||||
challengesmenu.unlockcondition = NULL;
|
challengesmenu.unlockcondition = NULL;
|
||||||
|
|
||||||
|
if (firstopen)
|
||||||
|
{
|
||||||
|
challengesmenu.currentunlock = MAXUNLOCKABLES;
|
||||||
|
firstopen = false;
|
||||||
|
}
|
||||||
|
|
||||||
M_PopulateChallengeGrid();
|
M_PopulateChallengeGrid();
|
||||||
if (gamedata->challengegrid)
|
if (gamedata->challengegrid)
|
||||||
{
|
{
|
||||||
|
|
@ -548,6 +579,7 @@ void M_ChallengesTick(void)
|
||||||
|
|
||||||
challengesmenu.chaokeyhold = 0;
|
challengesmenu.chaokeyhold = 0;
|
||||||
challengesmenu.unlockcount[CMC_CHAOANIM]++;
|
challengesmenu.unlockcount[CMC_CHAOANIM]++;
|
||||||
|
challengesmenu.keywasadded = false; // disappearify the Hand
|
||||||
|
|
||||||
S_StartSound(NULL, sfx_chchng);
|
S_StartSound(NULL, sfx_chchng);
|
||||||
|
|
||||||
|
|
@ -765,6 +797,21 @@ void M_ChallengesTick(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (challengesmenu.currentunlock < MAXUNLOCKABLES
|
||||||
|
&& gamedata->unlockpending[challengesmenu.currentunlock] == true)
|
||||||
|
{
|
||||||
|
UINT16 id = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
|
||||||
|
if (challengesmenu.extradata
|
||||||
|
&& challengesmenu.extradata[id].flip != (TILEFLIP_MAX/2))
|
||||||
|
{
|
||||||
|
// Only mark visited once flipped
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gamedata->unlockpending[challengesmenu.currentunlock] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -844,6 +891,8 @@ boolean M_ChallengesInputs(INT32 ch)
|
||||||
Z_Free(challengesmenu.extradata);
|
Z_Free(challengesmenu.extradata);
|
||||||
challengesmenu.extradata = NULL;
|
challengesmenu.extradata = NULL;
|
||||||
|
|
||||||
|
if (challengesmenu.unlockcondition)
|
||||||
|
Z_Free(challengesmenu.unlockcondition);
|
||||||
challengesmenu.unlockcondition = NULL;
|
challengesmenu.unlockcondition = NULL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ void M_EndModeAttackRun(void)
|
||||||
"Secret Exit",
|
"Secret Exit",
|
||||||
va(
|
va(
|
||||||
"No finish time was recorded.\n"
|
"No finish time was recorded.\n"
|
||||||
"Secrets don't work in Record modes!\n"
|
"Secrets don't work in Attack modes!\n"
|
||||||
"Try again in %s.\n",
|
"Try again in %s.\n",
|
||||||
(gametype == GT_RACE)
|
(gametype == GT_RACE)
|
||||||
? "Grand Prix or Match Race"
|
? "Grand Prix or Match Race"
|
||||||
|
|
|
||||||
21
src/p_mobj.c
21
src/p_mobj.c
|
|
@ -7007,6 +7007,23 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
||||||
{
|
{
|
||||||
trans = tr_trans50;
|
trans = tr_trans50;
|
||||||
}
|
}
|
||||||
|
// Non-RNG-advancing equivalent of Obj_SpawnEmeraldSparks
|
||||||
|
else if (leveltime % 3 == 0)
|
||||||
|
{
|
||||||
|
mobj_t *sparkle = P_SpawnMobjFromMobj(
|
||||||
|
mobj,
|
||||||
|
M_RandomRange(-mobj->radius/FRACUNIT, mobj->radius/FRACUNIT) * FRACUNIT,
|
||||||
|
M_RandomRange(-mobj->radius/FRACUNIT, mobj->radius/FRACUNIT) * FRACUNIT,
|
||||||
|
M_RandomRange(0, mobj->height/FRACUNIT) * FRACUNIT,
|
||||||
|
MT_SPARK
|
||||||
|
);
|
||||||
|
P_SetMobjStateNF(sparkle, mobjinfo[MT_EMERALDSPARK].spawnstate);
|
||||||
|
|
||||||
|
sparkle->color = mobj->color;
|
||||||
|
sparkle->momz += 6 * mapobjectscale * P_MobjFlip(mobj);
|
||||||
|
P_SetScale(sparkle, 2);
|
||||||
|
sparkle->destscale = mapobjectscale;
|
||||||
|
}
|
||||||
|
|
||||||
if (mobj->reactiontime > 0
|
if (mobj->reactiontime > 0
|
||||||
&& leveltime > starttime)
|
&& leveltime > starttime)
|
||||||
|
|
@ -13083,7 +13100,9 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj)
|
||||||
}
|
}
|
||||||
case MT_SPRAYCAN:
|
case MT_SPRAYCAN:
|
||||||
{
|
{
|
||||||
if (nummapspraycans == UINT8_MAX || tutorialchallenge == TUTORIALSKIP_INPROGRESS)
|
if (nummapspraycans == UINT8_MAX
|
||||||
|
|| modeattacking != ATTACKING_NONE
|
||||||
|
|| tutorialchallenge == TUTORIALSKIP_INPROGRESS)
|
||||||
{
|
{
|
||||||
P_RemoveMobj(mobj);
|
P_RemoveMobj(mobj);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -880,7 +880,8 @@ static void P_SpawnMapThings(boolean spawnemblems)
|
||||||
Z_Free(loopends);
|
Z_Free(loopends);
|
||||||
|
|
||||||
if (spawnemblems
|
if (spawnemblems
|
||||||
&& gametype != GT_TUTORIAL)
|
&& gametype != GT_TUTORIAL
|
||||||
|
&& !modeattacking)
|
||||||
{
|
{
|
||||||
const UINT8 recommendedcans =
|
const UINT8 recommendedcans =
|
||||||
#ifdef DEVELOP
|
#ifdef DEVELOP
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue