mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-18 11:32:24 +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);
|
||||
}
|
||||
}
|
||||
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
|
||||
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->id = numkartcupheaders;
|
||||
cup->cache_cuplock = MAXUNLOCKABLES;
|
||||
cup->hintcondition = MAXCONDITIONSETS;
|
||||
for (i = 0; i < CUPCACHE_MAX; i++)
|
||||
cup->cachedlevels[i] = NEXTMAP_INVALID;
|
||||
|
||||
|
|
|
|||
|
|
@ -449,10 +449,12 @@ struct cupheader_t
|
|||
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)
|
||||
|
||||
// Modifiable in mainwads only
|
||||
boolean playcredits; ///< Play the credits?
|
||||
UINT16 hintcondition; ///< Hint condition for 2.4 Super Cup
|
||||
|
||||
// Truly internal data
|
||||
UINT16 cache_cuplock; ///< Cached Unlockable ID
|
||||
|
||||
cupwindata_t windata[4]; ///< Data for cup visitation
|
||||
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);
|
||||
cupwindata_t *windata = NULL;
|
||||
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++)
|
||||
{
|
||||
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])
|
||||
break;
|
||||
|
||||
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)
|
||||
{
|
||||
windata = &templevelsearch.cup->windata[cv_dummygpdifficulty.value];
|
||||
}
|
||||
|
||||
isLocked = (M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID);
|
||||
|
||||
M_DrawCup(
|
||||
templevelsearch.cup,
|
||||
x * FRACUNIT, y * FRACUNIT,
|
||||
(M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID) ? ((cupgrid.previewanim % 4) + 1) : 0,
|
||||
isLocked ? ((cupgrid.previewanim % 4) + 1) : 0,
|
||||
isGP,
|
||||
windata ? windata->best_placement : 0
|
||||
);
|
||||
|
||||
if (templevelsearch.grandprix == true
|
||||
&& templevelsearch.cup == cupsavedata.cup
|
||||
if (!isGP || id == CUPMENU_CURSORID)
|
||||
;
|
||||
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)
|
||||
{
|
||||
// GP backup notif.
|
||||
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP1", PU_CACHE));
|
||||
}
|
||||
|
||||
// used to be 8 + (j*100) - (30*menutransition.tics)
|
||||
// but one-row mode means y has to be changed
|
||||
// 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 (cv_reducevfx.value)
|
||||
{
|
||||
M_DrawCupWinData(
|
||||
x,
|
||||
y,
|
||||
templevelsearch.cup,
|
||||
cv_dummygpdifficulty.value,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_DrawCupWinData(
|
||||
x,
|
||||
y,
|
||||
templevelsearch.cup,
|
||||
cv_dummygpdifficulty.value,
|
||||
(cupgrid.previewanim & 1),
|
||||
false
|
||||
);
|
||||
}
|
||||
M_DrawCupWinData(
|
||||
x,
|
||||
y + (j ? 44 : -12),
|
||||
templevelsearch.cup,
|
||||
cv_dummygpdifficulty.value,
|
||||
(!cv_reducevfx.value && (cupgrid.previewanim & 1)),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
y += 44;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
fixed_t tx = Easing_Linear(M_DueFrac(cupgrid.xslide.start, CUPMENU_SLIDETIME), cupgrid.xslide.dist * FRACUNIT, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
x = 14 + (cupgrid.x*42);
|
||||
y = 20 + (cupgrid.y*44) - cy;
|
||||
if (cupgrid.cache_secondrowlocked == true)
|
||||
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];
|
||||
|
||||
if (templevelsearch.grandprix == true
|
||||
&& templevelsearch.cup != NULL
|
||||
if (!isGP)
|
||||
;
|
||||
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)
|
||||
{
|
||||
V_DrawScaledPatch(
|
||||
14 + (cupgrid.x*42) + 32,
|
||||
20 + (cupgrid.y*44) + 32
|
||||
+ ((cupgrid.cache_secondrowlocked == true) ? 28 : 0),
|
||||
0,
|
||||
W_CachePatchName("CUPBKUP2", PU_CACHE)
|
||||
);
|
||||
// GP backup hint.
|
||||
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP2", PU_CACHE));
|
||||
}
|
||||
|
||||
INT16 ty = M_EaseWithTransition(Easing_Linear, 5 * 24);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "../../k_podium.h" // K_StartCeremony
|
||||
#include "../../m_misc.h" // FIL_FileExists
|
||||
#include "../../d_main.h" // D_ClearState
|
||||
#include "../../m_cond.h" // Condition Sets
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue