mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-04-28 13:01:56 +00:00
Tutorial Recommendation hints for GP cup select
One new parameter on cupheader_t that can only be set in mainwads If specified hint condition has been achieved, identifies from the actual unlock condition what Tutorial it should surface in a popup. Funny question mark
This commit is contained in:
parent
5de0539316
commit
c3131f697e
5 changed files with 184 additions and 62 deletions
|
|
@ -4114,6 +4114,18 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
|
||||||
deh_warning("You must define a custom gamedata to use \"%s\"", word);
|
deh_warning("You must define a custom gamedata to use \"%s\"", word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (fastcmp(word, "HINTCONDITION"))
|
||||||
|
{
|
||||||
|
if (!mainwads || (refreshdirmenu & REFRESHDIR_GAMEDATA))
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
cup->hintcondition = i-1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deh_warning("You must define a custom gamedata to use \"%s\"", word);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
deh_warning("%s Cup: unknown word '%s'", cup->name, word);
|
deh_warning("%s Cup: unknown word '%s'", cup->name, word);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -495,6 +495,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
|
||||||
cup->monitor = 1;
|
cup->monitor = 1;
|
||||||
cup->id = numkartcupheaders;
|
cup->id = numkartcupheaders;
|
||||||
cup->cache_cuplock = MAXUNLOCKABLES;
|
cup->cache_cuplock = MAXUNLOCKABLES;
|
||||||
|
cup->hintcondition = MAXCONDITIONSETS;
|
||||||
for (i = 0; i < CUPCACHE_MAX; i++)
|
for (i = 0; i < CUPCACHE_MAX; i++)
|
||||||
cup->cachedlevels[i] = NEXTMAP_INVALID;
|
cup->cachedlevels[i] = NEXTMAP_INVALID;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -449,10 +449,12 @@ struct cupheader_t
|
||||||
UINT8 numbonus; ///< Number of bonus stages defined
|
UINT8 numbonus; ///< Number of bonus stages defined
|
||||||
UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald)
|
UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald)
|
||||||
|
|
||||||
|
// Modifiable in mainwads only
|
||||||
boolean playcredits; ///< Play the credits?
|
boolean playcredits; ///< Play the credits?
|
||||||
|
UINT16 hintcondition; ///< Hint condition for 2.4 Super Cup
|
||||||
|
|
||||||
|
// Truly internal data
|
||||||
UINT16 cache_cuplock; ///< Cached Unlockable ID
|
UINT16 cache_cuplock; ///< Cached Unlockable ID
|
||||||
|
|
||||||
cupwindata_t windata[4]; ///< Data for cup visitation
|
cupwindata_t windata[4]; ///< Data for cup visitation
|
||||||
cupheader_t *next; ///< Next cup in linked list
|
cupheader_t *next; ///< Next cup in linked list
|
||||||
};
|
};
|
||||||
|
|
|
||||||
117
src/k_menudraw.c
117
src/k_menudraw.c
|
|
@ -3217,111 +3217,108 @@ void M_DrawCupSelect(void)
|
||||||
INT16 cy = M_EaseWithTransition(Easing_Linear, 5 * 30);
|
INT16 cy = M_EaseWithTransition(Easing_Linear, 5 * 30);
|
||||||
cupwindata_t *windata = NULL;
|
cupwindata_t *windata = NULL;
|
||||||
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
|
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
|
||||||
|
boolean isLocked;
|
||||||
|
const boolean isGP = (templevelsearch.grandprix && (cv_dummygpdifficulty.value >= 0 && cv_dummygpdifficulty.value < KARTGP_MAX));
|
||||||
|
const UINT8 numrows = (cupgrid.cache_secondrowlocked ? 1 : CUPMENU_ROWS);
|
||||||
|
|
||||||
for (i = 0; i < CUPMENU_COLUMNS; i++)
|
for (i = 0; i < CUPMENU_COLUMNS; i++)
|
||||||
{
|
{
|
||||||
x = 14 + (i*42);
|
x = 14 + (i*42);
|
||||||
|
y = 20 - cy;
|
||||||
|
if (cupgrid.cache_secondrowlocked == true)
|
||||||
|
y += 28;
|
||||||
|
|
||||||
for (j = 0; j < (cupgrid.cache_secondrowlocked ? 1 : CUPMENU_ROWS); j++)
|
for (j = 0; j < numrows; j++)
|
||||||
{
|
{
|
||||||
size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
|
const size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
|
||||||
|
|
||||||
if (!cupgrid.builtgrid[id])
|
if (!cupgrid.builtgrid[id])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
templevelsearch.cup = cupgrid.builtgrid[id];
|
templevelsearch.cup = cupgrid.builtgrid[id];
|
||||||
|
|
||||||
y = 20 + (j*44) - cy;
|
|
||||||
if (cupgrid.cache_secondrowlocked == true)
|
|
||||||
y += 28;
|
|
||||||
|
|
||||||
const boolean isGP = (templevelsearch.grandprix && (cv_dummygpdifficulty.value >= 0 && cv_dummygpdifficulty.value < KARTGP_MAX));
|
|
||||||
if (isGP)
|
if (isGP)
|
||||||
{
|
|
||||||
windata = &templevelsearch.cup->windata[cv_dummygpdifficulty.value];
|
windata = &templevelsearch.cup->windata[cv_dummygpdifficulty.value];
|
||||||
}
|
|
||||||
|
isLocked = (M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID);
|
||||||
|
|
||||||
M_DrawCup(
|
M_DrawCup(
|
||||||
templevelsearch.cup,
|
templevelsearch.cup,
|
||||||
x * FRACUNIT, y * FRACUNIT,
|
x * FRACUNIT, y * FRACUNIT,
|
||||||
(M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID) ? ((cupgrid.previewanim % 4) + 1) : 0,
|
isLocked ? ((cupgrid.previewanim % 4) + 1) : 0,
|
||||||
isGP,
|
isGP,
|
||||||
windata ? windata->best_placement : 0
|
windata ? windata->best_placement : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
if (templevelsearch.grandprix == true
|
if (!isGP || id == CUPMENU_CURSORID)
|
||||||
&& templevelsearch.cup == cupsavedata.cup
|
;
|
||||||
|
else if (isLocked)
|
||||||
|
{
|
||||||
|
if (templevelsearch.cup->hintcondition != MAXCONDITIONSETS
|
||||||
|
&& M_Achieved(templevelsearch.cup->hintcondition))
|
||||||
|
{
|
||||||
|
// Super Cup tutorial hint.
|
||||||
|
V_DrawScaledPatch(x + (32-10), y + (32-9), 0, W_CachePatchName("UN_HNT2A", PU_CACHE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (templevelsearch.cup == cupsavedata.cup
|
||||||
&& id != CUPMENU_CURSORID)
|
&& id != CUPMENU_CURSORID)
|
||||||
{
|
{
|
||||||
|
// GP backup notif.
|
||||||
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP1", PU_CACHE));
|
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP1", PU_CACHE));
|
||||||
}
|
}
|
||||||
|
|
||||||
// used to be 8 + (j*100) - (30*menutransition.tics)
|
// used to be 8 + (j*100) - (30*menutransition.tics)
|
||||||
// but one-row mode means y has to be changed
|
// but one-row mode means y has to be changed
|
||||||
// this is the difference between y and that
|
// this is the difference between y and that
|
||||||
if (j == 0)
|
|
||||||
{
|
|
||||||
y -= 12; // (8) - (20)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
y += 44; //(8 + 100) - (20 + 44)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (windata)
|
if (windata)
|
||||||
{
|
{
|
||||||
if (cv_reducevfx.value)
|
M_DrawCupWinData(
|
||||||
{
|
x,
|
||||||
M_DrawCupWinData(
|
y + (j ? 44 : -12),
|
||||||
x,
|
templevelsearch.cup,
|
||||||
y,
|
cv_dummygpdifficulty.value,
|
||||||
templevelsearch.cup,
|
(!cv_reducevfx.value && (cupgrid.previewanim & 1)),
|
||||||
cv_dummygpdifficulty.value,
|
false
|
||||||
false,
|
);
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
M_DrawCupWinData(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
templevelsearch.cup,
|
|
||||||
cv_dummygpdifficulty.value,
|
|
||||||
(cupgrid.previewanim & 1),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
y += 44;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
x = 14 + (cupgrid.x*42);
|
||||||
fixed_t tx = Easing_Linear(M_DueFrac(cupgrid.xslide.start, CUPMENU_SLIDETIME), cupgrid.xslide.dist * FRACUNIT, 0);
|
y = 20 + (cupgrid.y*44) - cy;
|
||||||
fixed_t ty = Easing_Linear(M_DueFrac(cupgrid.yslide.start, CUPMENU_SLIDETIME), cupgrid.yslide.dist * FRACUNIT, 0);
|
|
||||||
|
|
||||||
x = 14 + (cupgrid.x*42*FRACUNIT - tx) / FRACUNIT;
|
|
||||||
y = 20 + (cupgrid.y*44*FRACUNIT - ty) / FRACUNIT - cy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cupgrid.cache_secondrowlocked == true)
|
if (cupgrid.cache_secondrowlocked == true)
|
||||||
y += 28;
|
y += 28;
|
||||||
|
|
||||||
V_DrawScaledPatch(x - 4, y - 1, 0, W_CachePatchName("CUPCURS", PU_CACHE));
|
// Interpolated cursor
|
||||||
|
{
|
||||||
|
fixed_t tx = Easing_Linear(M_DueFrac(cupgrid.xslide.start, CUPMENU_SLIDETIME), cupgrid.xslide.dist * FRACUNIT, 0)/FRACUNIT;
|
||||||
|
fixed_t ty = Easing_Linear(M_DueFrac(cupgrid.yslide.start, CUPMENU_SLIDETIME), cupgrid.yslide.dist * FRACUNIT, 0)/FRACUNIT;
|
||||||
|
|
||||||
|
V_DrawScaledPatch((x - 4) - tx, (y - 1) - ty, 0, W_CachePatchName("CUPCURS", PU_CACHE));
|
||||||
|
}
|
||||||
|
|
||||||
templevelsearch.cup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
templevelsearch.cup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||||
|
|
||||||
if (templevelsearch.grandprix == true
|
if (!isGP)
|
||||||
&& templevelsearch.cup != NULL
|
;
|
||||||
|
else if (M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID)
|
||||||
|
{
|
||||||
|
if (templevelsearch.cup->hintcondition != MAXCONDITIONSETS
|
||||||
|
&& M_Achieved(templevelsearch.cup->hintcondition))
|
||||||
|
{
|
||||||
|
// Super Cup tutorial hint.
|
||||||
|
V_DrawScaledPatch(x + (32-10), y + (32-9), 0, W_CachePatchName("UN_HNT1A", PU_CACHE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (templevelsearch.cup != NULL
|
||||||
&& templevelsearch.cup == cupsavedata.cup)
|
&& templevelsearch.cup == cupsavedata.cup)
|
||||||
{
|
{
|
||||||
V_DrawScaledPatch(
|
// GP backup hint.
|
||||||
14 + (cupgrid.x*42) + 32,
|
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP2", PU_CACHE));
|
||||||
20 + (cupgrid.y*44) + 32
|
|
||||||
+ ((cupgrid.cache_secondrowlocked == true) ? 28 : 0),
|
|
||||||
0,
|
|
||||||
W_CachePatchName("CUPBKUP2", PU_CACHE)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INT16 ty = M_EaseWithTransition(Easing_Linear, 5 * 24);
|
INT16 ty = M_EaseWithTransition(Easing_Linear, 5 * 24);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include "../../k_podium.h" // K_StartCeremony
|
#include "../../k_podium.h" // K_StartCeremony
|
||||||
#include "../../m_misc.h" // FIL_FileExists
|
#include "../../m_misc.h" // FIL_FileExists
|
||||||
#include "../../d_main.h" // D_ClearState
|
#include "../../d_main.h" // D_ClearState
|
||||||
|
#include "../../m_cond.h" // Condition Sets
|
||||||
|
|
||||||
menuitem_t PLAY_CupSelect[] =
|
menuitem_t PLAY_CupSelect[] =
|
||||||
{
|
{
|
||||||
|
|
@ -161,6 +162,114 @@ static void M_StartCup(UINT8 entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT16 cupselecttutorial_hack = NEXTMAP_INVALID;
|
||||||
|
|
||||||
|
static void M_GPTutorialResponse(INT32 choice)
|
||||||
|
{
|
||||||
|
if (choice != MA_YES)
|
||||||
|
return;
|
||||||
|
|
||||||
|
multiplayer = true;
|
||||||
|
|
||||||
|
restoreMenu = &PLAY_CupSelectDef;
|
||||||
|
restorelevellist = levellist;
|
||||||
|
|
||||||
|
// mild hack
|
||||||
|
levellist.newgametype = GT_TUTORIAL;
|
||||||
|
levellist.netgame = false;
|
||||||
|
M_MenuToLevelPreamble(0, false);
|
||||||
|
|
||||||
|
D_MapChange(
|
||||||
|
cupselecttutorial_hack+1,
|
||||||
|
levellist.newgametype,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
M_ClearMenus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean M_GPTutorialRecommendation(cupheader_t *cup)
|
||||||
|
{
|
||||||
|
// Only applies to GP.
|
||||||
|
if (levellist.levelsearch.grandprix == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Does this not have a Tutorial Recommendation?
|
||||||
|
if (cup->cache_cuplock >= MAXUNLOCKABLES
|
||||||
|
|| cup->hintcondition == MAXCONDITIONSETS
|
||||||
|
|| !M_Achieved(cup->hintcondition))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Does the thing have no condition?
|
||||||
|
const UINT16 condition = unlockables[cup->cache_cuplock].conditionset;
|
||||||
|
if (condition == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const conditionset_t *c = &conditionSets[condition-1];
|
||||||
|
UINT32 i;
|
||||||
|
INT32 mapnum = NEXTMAP_INVALID;
|
||||||
|
|
||||||
|
// Identify the map to visit/beat.
|
||||||
|
for (i = 0; i < c->numconditions; ++i)
|
||||||
|
{
|
||||||
|
if (c->condition[i].type < UC_MAPVISITED || c->condition[i].type > UC_MAPBEATEN)
|
||||||
|
continue;
|
||||||
|
mapnum = c->condition[i].requirement;
|
||||||
|
if (mapnum < 0 || mapnum >= nummapheaders)
|
||||||
|
continue;
|
||||||
|
if (!mapheaderinfo[mapnum])
|
||||||
|
continue;
|
||||||
|
if (G_GuessGametypeByTOL(mapheaderinfo[mapnum]->typeoflevel) != GT_TUTORIAL)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Didn't find one?
|
||||||
|
if (i == c->numconditions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Not unlocked?
|
||||||
|
if (M_MapLocked(mapnum+1))
|
||||||
|
{
|
||||||
|
M_StartMessage(
|
||||||
|
"Recommended Learning",
|
||||||
|
"This Cup will test skills that\n"
|
||||||
|
"a ""\x86""currently locked ""\x87""Tutorial\x80 teaches.\n"
|
||||||
|
"\n"
|
||||||
|
"Come back when you've made progress elsewhere.",
|
||||||
|
NULL, MM_NOTHING, NULL, NULL
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is kind of a hack.
|
||||||
|
cupselecttutorial_hack = mapnum;
|
||||||
|
|
||||||
|
M_StartMessage(
|
||||||
|
"Recommended Learning",
|
||||||
|
va(
|
||||||
|
"This Cup will test skills that\n"
|
||||||
|
"the ""\x87""%s Tutorial\x80 teaches.\n"
|
||||||
|
"\n"
|
||||||
|
"%s\n",
|
||||||
|
mapheaderinfo[mapnum]->menuttl,
|
||||||
|
(setup_numplayers > 1
|
||||||
|
? "You're encouraged to play it later."
|
||||||
|
: "Would you like to play it now?"
|
||||||
|
)),
|
||||||
|
setup_numplayers > 1 ? NULL : M_GPTutorialResponse,
|
||||||
|
setup_numplayers > 1 ? MM_NOTHING : MM_YESNO,
|
||||||
|
setup_numplayers > 1 ? NULL : "Yes, let's go",
|
||||||
|
setup_numplayers > 1 ? "Got it!" : "Not right now"
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void M_GPBackup(INT32 choice)
|
static void M_GPBackup(INT32 choice)
|
||||||
{
|
{
|
||||||
if (choice == MA_YES)
|
if (choice == MA_YES)
|
||||||
|
|
@ -271,7 +380,8 @@ void M_CupSelectHandler(INT32 choice)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
S_StartSound(NULL, sfx_s3kb2);
|
if (!M_GPTutorialRecommendation(newcup))
|
||||||
|
S_StartSound(NULL, sfx_s3kb2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue