mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-02 22:22:55 +00:00
(This commit does not compile. Sound test and tunes command code needs to be ported after this.) This is a big one. Here's the rundown: The old music system was very direct, much of the time just a proxy to the real sound API in i_sound.h. You could change the music on command, but there wasn't a consistent way to prevent some music from playing over others. P_RestoreMusic is one example of needing to address this problem. The jingles system was intended as another solution. Furthermore, sound test (Stereo) has its own needs. I am removing all of that. Music handling in general is now a very deliberate system, kind of similar to jingles. In the new system, "tunes" are registered. The tune stores info such as whether it should loop or fade out. Most of the configuration is intended to be initialized only ONCE. Tunes can be mapped to an actual music lump. They can be remapped at any time too. Tunes are also configured with a priority number. This determines which tune is heard, if multiple are supposed to be playing at a time. You can even tell a tune how long it should play, so it's unnecessary to track this with bespoke timers.
850 lines
20 KiB
C
850 lines
20 KiB
C
/// \file menus/extras-challenges.c
|
|
/// \brief Challenges.
|
|
|
|
#include "../k_menu.h"
|
|
#include "../m_cond.h" // Condition Sets
|
|
#include "../m_random.h" // And just some randomness for the exits.
|
|
#include "../music.h"
|
|
#include "../z_zone.h"
|
|
#include "../r_skins.h"
|
|
#include "../s_sound.h"
|
|
|
|
//#define CHAOKEYDEBUG
|
|
|
|
menuitem_t MISC_ChallengesStatsDummyMenu[] =
|
|
{
|
|
{IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0},
|
|
};
|
|
|
|
menu_t MISC_ChallengesDef = {
|
|
sizeof (MISC_ChallengesStatsDummyMenu)/sizeof (menuitem_t),
|
|
&MainDef,
|
|
0,
|
|
MISC_ChallengesStatsDummyMenu,
|
|
BASEVIDWIDTH/2, 30,
|
|
0, 0,
|
|
0,
|
|
"UNLOCK",
|
|
98, 0,
|
|
M_DrawChallenges,
|
|
M_ChallengesTick,
|
|
NULL,
|
|
NULL,
|
|
M_ChallengesInputs,
|
|
};
|
|
|
|
// This must be defined here so it can take sizeof
|
|
// MISC_ChallengesStatsDummyMenu :V
|
|
menu_t MISC_StatisticsDef = {
|
|
sizeof (MISC_ChallengesStatsDummyMenu)/sizeof (menuitem_t),
|
|
&MainDef,
|
|
0,
|
|
MISC_ChallengesStatsDummyMenu,
|
|
280, 185,
|
|
0, 0,
|
|
0,
|
|
"EXTRAS",
|
|
98, 0,
|
|
M_DrawStatistics,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
M_StatisticsInputs,
|
|
};
|
|
|
|
struct challengesmenu_s challengesmenu;
|
|
|
|
static void M_ChallengesAutoFocus(UINT16 unlockid, boolean fresh)
|
|
{
|
|
UINT16 i;
|
|
INT16 work;
|
|
|
|
if (unlockid >= MAXUNLOCKABLES && gamedata->pendingkeyrounds > 0
|
|
&& (gamedata->chaokeys < GDMAX_CHAOKEYS))
|
|
challengesmenu.chaokeyadd = true;
|
|
|
|
if (fresh && unlockid >= MAXUNLOCKABLES)
|
|
{
|
|
UINT16 selection[MAXUNLOCKABLES];
|
|
UINT16 numunlocks = 0;
|
|
|
|
// Get a random available unlockable.
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!gamedata->unlocked[i])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
selection[numunlocks++] = i;
|
|
}
|
|
|
|
if (!numunlocks)
|
|
{
|
|
// ...OK, get a random unlockable.
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
selection[numunlocks++] = i;
|
|
}
|
|
}
|
|
|
|
unlockid = selection[M_RandomKey(numunlocks)];
|
|
}
|
|
|
|
if (unlockid >= MAXUNLOCKABLES)
|
|
return;
|
|
|
|
challengesmenu.currentunlock = unlockid;
|
|
if (challengesmenu.unlockcondition)
|
|
Z_Free(challengesmenu.unlockcondition);
|
|
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);
|
|
challengesmenu.unlockanim = (challengesmenu.pending && !challengesmenu.chaokeyadd ? 0 : MAXUNLOCKTIME);
|
|
|
|
if (gamedata->challengegrid == NULL || challengesmenu.extradata == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
|
|
{
|
|
if (gamedata->challengegrid[i] != unlockid)
|
|
{
|
|
// Not what we're looking for.
|
|
continue;
|
|
}
|
|
|
|
if (challengesmenu.extradata[i].flags & CHE_CONNECTEDLEFT)
|
|
{
|
|
// no need to check for CHE_CONNECTEDUP in linear iteration
|
|
continue;
|
|
}
|
|
|
|
// Helper calculation for non-fresh scrolling.
|
|
work = (challengesmenu.col + challengesmenu.focusx);
|
|
|
|
challengesmenu.col = challengesmenu.hilix = i/CHALLENGEGRIDHEIGHT;
|
|
challengesmenu.row = challengesmenu.hiliy = i%CHALLENGEGRIDHEIGHT;
|
|
|
|
// Begin animation
|
|
if (challengesmenu.pending)
|
|
{
|
|
challengesmenu.extradata[i].flip = (TILEFLIP_MAX/2);
|
|
}
|
|
|
|
if (fresh)
|
|
{
|
|
// We're just entering the menu. Immediately jump to the desired position...
|
|
challengesmenu.focusx = 0;
|
|
// ...and since the menu is even-width, randomly select whether it's left or right of center.
|
|
if (!unlockables[unlockid].majorunlock
|
|
&& M_RandomChance(FRACUNIT/2))
|
|
challengesmenu.focusx--;
|
|
}
|
|
else
|
|
{
|
|
// We're jumping between multiple unlocks in sequence. Get the difference (looped from -range/2 < work <= range/2).
|
|
work -= challengesmenu.col;
|
|
if (work <= -gamedata->challengegridwidth/2)
|
|
work += gamedata->challengegridwidth;
|
|
else if (work >= gamedata->challengegridwidth/2)
|
|
work -= gamedata->challengegridwidth;
|
|
|
|
if (work > 0)
|
|
{
|
|
// We only need to scroll as far as the rightward edge.
|
|
if (unlockables[unlockid].majorunlock)
|
|
{
|
|
work--;
|
|
challengesmenu.col++;
|
|
if (challengesmenu.col >= gamedata->challengegridwidth)
|
|
challengesmenu.col = 0;
|
|
}
|
|
|
|
// Offset right, scroll left?
|
|
if (work > LEFTUNLOCKSCROLL)
|
|
{
|
|
work -= LEFTUNLOCKSCROLL;
|
|
challengesmenu.focusx = LEFTUNLOCKSCROLL;
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.focusx = work;
|
|
work = 0;
|
|
}
|
|
}
|
|
else if (work < 0)
|
|
{
|
|
// Offset left, scroll right?
|
|
if (work < -RIGHTUNLOCKSCROLL)
|
|
{
|
|
challengesmenu.focusx = -RIGHTUNLOCKSCROLL;
|
|
work += RIGHTUNLOCKSCROLL;
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.focusx = work;
|
|
work = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We're right where we want to be.
|
|
challengesmenu.focusx = 0;
|
|
}
|
|
|
|
// And put the pixel-based scrolling in play, too.
|
|
challengesmenu.offset = -work*16;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
|
|
{
|
|
UINT16 i, newunlock;
|
|
|
|
if (Playing())
|
|
return desiredmenu;
|
|
|
|
M_UpdateUnlockablesAndExtraEmblems(false, true);
|
|
|
|
newunlock = M_GetNextAchievedUnlock(true);
|
|
|
|
if ((challengesmenu.pending = (newunlock != MAXUNLOCKABLES)))
|
|
{
|
|
Music_StopAll();
|
|
MISC_ChallengesDef.prevMenu = desiredmenu;
|
|
}
|
|
|
|
if (challengesmenu.pending || desiredmenu == NULL)
|
|
{
|
|
challengesmenu.ticker = 0;
|
|
challengesmenu.requestflip = false;
|
|
challengesmenu.requestnew = false;
|
|
challengesmenu.chaokeyadd = false;
|
|
challengesmenu.chaokeyhold = 0;
|
|
challengesmenu.currentunlock = MAXUNLOCKABLES;
|
|
challengesmenu.unlockcondition = NULL;
|
|
|
|
M_PopulateChallengeGrid();
|
|
if (gamedata->challengegrid)
|
|
{
|
|
challengesmenu.extradata = Z_Calloc(
|
|
(gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT * sizeof(challengegridextradata_t)),
|
|
PU_STATIC, NULL);
|
|
M_UpdateChallengeGridExtraData(challengesmenu.extradata);
|
|
}
|
|
|
|
memset(setup_explosions, 0, sizeof(setup_explosions));
|
|
memset(&challengesmenu.unlockcount, 0, sizeof(challengesmenu.unlockcount));
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
challengesmenu.unlockcount[CC_TOTAL]++;
|
|
|
|
if (!gamedata->unlocked[i])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
challengesmenu.unlockcount[CC_UNLOCKED]++;
|
|
}
|
|
|
|
if (challengesmenu.pending)
|
|
M_ChallengesAutoFocus(newunlock, true);
|
|
else if (newunlock >= MAXUNLOCKABLES && gamedata->pendingkeyrounds > 0
|
|
&& (gamedata->chaokeys < GDMAX_CHAOKEYS))
|
|
challengesmenu.chaokeyadd = true;
|
|
|
|
return &MISC_ChallengesDef;
|
|
}
|
|
|
|
return desiredmenu;
|
|
}
|
|
|
|
void M_Challenges(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
|
|
M_InterruptMenuWithChallenges(NULL);
|
|
MISC_ChallengesDef.prevMenu = currentMenu;
|
|
|
|
if (gamedata->challengegrid != NULL && !challengesmenu.pending)
|
|
{
|
|
M_ChallengesAutoFocus(UINT16_MAX, true);
|
|
}
|
|
|
|
M_SetupNextMenu(&MISC_ChallengesDef, false);
|
|
}
|
|
|
|
static boolean M_CanKeyHiliTile(boolean devskip)
|
|
{
|
|
// No keys to do it with?
|
|
if (gamedata->chaokeys == 0 && !devskip)
|
|
return false;
|
|
|
|
// No tile data?
|
|
if (challengesmenu.extradata == NULL)
|
|
return false;
|
|
|
|
// No selected tile?
|
|
if (challengesmenu.currentunlock >= MAXUNLOCKABLES)
|
|
return false;
|
|
|
|
// Already unlocked?
|
|
if (gamedata->unlocked[challengesmenu.currentunlock] == true)
|
|
return false;
|
|
|
|
// Marked as unskippable?
|
|
if (unlockables[challengesmenu.currentunlock].majorunlock == true && !devskip)
|
|
return false;
|
|
|
|
UINT16 i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
|
|
|
|
// Not a hinted tile OR a fresh board.
|
|
if (!(challengesmenu.extradata[i].flags & CHE_HINT)
|
|
&& (challengesmenu.unlockcount[CC_UNLOCKED] + challengesmenu.unlockcount[CC_TALLY] > 0)
|
|
&& !devskip)
|
|
return false;
|
|
|
|
// All good!
|
|
return true;
|
|
}
|
|
|
|
void M_ChallengesTick(void)
|
|
{
|
|
const UINT8 pid = 0;
|
|
UINT16 i;
|
|
UINT16 newunlock = MAXUNLOCKABLES;
|
|
|
|
// Ticking
|
|
challengesmenu.ticker++;
|
|
challengesmenu.offset /= 2;
|
|
for (i = 0; i < CSEXPLOSIONS; i++)
|
|
{
|
|
if (setup_explosions[i].tics > 0)
|
|
setup_explosions[i].tics--;
|
|
}
|
|
for (i = CC_ANIM; i < CC_MAX; i++)
|
|
{
|
|
if (challengesmenu.unlockcount[i] > 0)
|
|
challengesmenu.unlockcount[i]--;
|
|
}
|
|
M_CupSelectTick();
|
|
|
|
// Update tile flip state.
|
|
if (challengesmenu.extradata != NULL)
|
|
{
|
|
UINT16 id = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
|
|
boolean seeeveryone = challengesmenu.requestflip;
|
|
boolean allthewaythrough;
|
|
UINT8 maxflip;
|
|
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
|
|
{
|
|
allthewaythrough = (!seeeveryone && !challengesmenu.pending && i != id);
|
|
maxflip = ((seeeveryone || !allthewaythrough) ? (TILEFLIP_MAX/2) : TILEFLIP_MAX);
|
|
if ((seeeveryone || (i == id) || (challengesmenu.extradata[i].flip > 0))
|
|
&& (challengesmenu.extradata[i].flip != maxflip))
|
|
{
|
|
challengesmenu.extradata[i].flip++;
|
|
if (challengesmenu.extradata[i].flip >= TILEFLIP_MAX)
|
|
{
|
|
challengesmenu.extradata[i].flip = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (challengesmenu.chaokeyhold)
|
|
{
|
|
boolean devskip = false;
|
|
#ifdef DEVELOP
|
|
devskip = M_MenuButtonHeld(pid, MBT_Z);
|
|
#endif
|
|
// A little messy, but don't freak out, this is just so devs don't crash the game on non-tiles
|
|
if ((devskip || M_MenuExtraHeld(pid)) && M_CanKeyHiliTile(devskip))
|
|
{
|
|
// Not pressed just this frame?
|
|
if (!M_MenuExtraPressed(pid))
|
|
{
|
|
challengesmenu.chaokeyhold++;
|
|
|
|
if (challengesmenu.chaokeyhold > CHAOHOLD_MAX)
|
|
{
|
|
#ifndef CHAOKEYDEBUG
|
|
gamedata->chaokeys--;
|
|
#endif
|
|
challengesmenu.chaokeyhold = 0;
|
|
challengesmenu.unlockcount[CC_CHAOANIM]++;
|
|
|
|
S_StartSound(NULL, sfx_chchng);
|
|
|
|
challengesmenu.pending = true;
|
|
//M_ChallengesAutoFocus(challengesmenu.currentunlock, false);
|
|
challengesmenu.unlockanim = UNLOCKTIME-1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.chaokeyhold = 0;
|
|
challengesmenu.unlockcount[CC_CHAONOPE] = 6;
|
|
S_StartSound(NULL, sfx_s3k7b); //sfx_s3kb2
|
|
}
|
|
}
|
|
|
|
if ((challengesmenu.pending || challengesmenu.chaokeyhold) && challengesmenu.fade < 5)
|
|
{
|
|
// Fade increase.
|
|
challengesmenu.fade++;
|
|
}
|
|
else if (challengesmenu.chaokeyadd == true)
|
|
{
|
|
if (challengesmenu.ticker <= 5)
|
|
; // recreate the slight delay the unlock fades provide
|
|
else if (gamedata->pendingkeyrounds == 0)
|
|
{
|
|
gamedata->keyspending = 0;
|
|
gamedata->pendingkeyroundoffset %= GDCONVERT_ROUNDSTOKEY;
|
|
|
|
challengesmenu.chaokeyadd = false;
|
|
challengesmenu.requestnew = true;
|
|
}
|
|
else if (gamedata->chaokeys >= GDMAX_CHAOKEYS)
|
|
{
|
|
// The above condition will run on the next tic because of this set
|
|
gamedata->pendingkeyrounds = 0;
|
|
gamedata->pendingkeyroundoffset = 0;
|
|
}
|
|
else
|
|
{
|
|
UINT32 keyexchange = gamedata->keyspending;
|
|
|
|
if (keyexchange > gamedata->pendingkeyrounds)
|
|
{
|
|
keyexchange = 1;
|
|
}
|
|
else if (keyexchange >= GDCONVERT_ROUNDSTOKEY/2)
|
|
{
|
|
keyexchange = GDCONVERT_ROUNDSTOKEY/2;
|
|
}
|
|
|
|
keyexchange |= 1; // guarantee an odd delta for the sake of the sound
|
|
|
|
gamedata->pendingkeyrounds -= keyexchange;
|
|
gamedata->pendingkeyroundoffset += keyexchange;
|
|
|
|
if (!(gamedata->pendingkeyrounds & 1))
|
|
{
|
|
S_StartSound(NULL, sfx_ptally);
|
|
}
|
|
|
|
if (gamedata->pendingkeyroundoffset >= GDCONVERT_ROUNDSTOKEY)
|
|
{
|
|
gamedata->pendingkeyroundoffset %= GDCONVERT_ROUNDSTOKEY;
|
|
|
|
if (gamedata->keyspending > 0)
|
|
{
|
|
S_StartSound(NULL, sfx_achiev);
|
|
gamedata->keyspending--;
|
|
gamedata->chaokeys++;
|
|
challengesmenu.unlockcount[CC_CHAOANIM]++;
|
|
|
|
if (gamedata->musicstate < GDMUSIC_KEYG)
|
|
gamedata->musicstate = GDMUSIC_KEYG;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (challengesmenu.requestnew)
|
|
{
|
|
// The menu apparatus is requesting a new unlock.
|
|
challengesmenu.requestnew = false;
|
|
if ((newunlock = M_GetNextAchievedUnlock(false)) != MAXUNLOCKABLES)
|
|
{
|
|
// We got one!
|
|
M_ChallengesAutoFocus(newunlock, false);
|
|
}
|
|
else if (gamedata->pendingkeyrounds > 0
|
|
&& (gamedata->chaokeys < GDMAX_CHAOKEYS))
|
|
{
|
|
// Get ready to finish with pending chao key round tallying.
|
|
challengesmenu.chaokeyadd = true;
|
|
}
|
|
else
|
|
{
|
|
// All done! Let's save the unlocks we've busted open.
|
|
challengesmenu.pending = challengesmenu.chaokeyadd = false;
|
|
G_SaveGameData();
|
|
}
|
|
}
|
|
else if (challengesmenu.pending)
|
|
{
|
|
tic_t nexttime = M_MenuExtraHeld(pid) ? (UNLOCKTIME*2) : MAXUNLOCKTIME;
|
|
|
|
if (++challengesmenu.unlockanim >= nexttime)
|
|
{
|
|
challengesmenu.requestnew = true;
|
|
}
|
|
|
|
if (challengesmenu.currentunlock < MAXUNLOCKABLES
|
|
&& challengesmenu.unlockanim == UNLOCKTIME)
|
|
{
|
|
// Unlock animation... also tied directly to the actual unlock!
|
|
gamedata->unlocked[challengesmenu.currentunlock] = true;
|
|
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
|
|
|
// Update shown description just in case..?
|
|
if (challengesmenu.unlockcondition)
|
|
Z_Free(challengesmenu.unlockcondition);
|
|
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);
|
|
|
|
challengesmenu.unlockcount[CC_TALLY]++;
|
|
challengesmenu.unlockcount[CC_ANIM]++;
|
|
|
|
if (challengesmenu.extradata)
|
|
{
|
|
unlockable_t *ref;
|
|
UINT16 bombcolor;
|
|
|
|
M_UpdateChallengeGridExtraData(challengesmenu.extradata);
|
|
|
|
ref = &unlockables[challengesmenu.currentunlock];
|
|
bombcolor = SKINCOLOR_NONE;
|
|
|
|
if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors)
|
|
{
|
|
bombcolor = ref->color;
|
|
}
|
|
else switch (ref->type)
|
|
{
|
|
case SECRET_SKIN:
|
|
{
|
|
INT32 skin = M_UnlockableSkinNum(ref);
|
|
if (skin != -1)
|
|
{
|
|
bombcolor = skins[skin].prefcolor;
|
|
}
|
|
break;
|
|
}
|
|
case SECRET_FOLLOWER:
|
|
{
|
|
INT32 fskin = M_UnlockableFollowerNum(ref);
|
|
if (fskin != -1)
|
|
{
|
|
INT32 psk = R_SkinAvailable(cv_skin[0].string);
|
|
if (psk == -1)
|
|
psk = 0;
|
|
bombcolor = K_GetEffectiveFollowerColor(followers[fskin].defaultcolor, &followers[fskin], cv_playercolor[0].value, &skins[psk]);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (bombcolor == SKINCOLOR_NONE)
|
|
{
|
|
bombcolor = cv_playercolor[0].value;
|
|
if (bombcolor == SKINCOLOR_NONE)
|
|
{
|
|
INT32 psk = R_SkinAvailable(cv_skin[0].string);
|
|
if (psk == -1)
|
|
psk = 0;
|
|
bombcolor = skins[psk].prefcolor;
|
|
}
|
|
}
|
|
|
|
i = (ref->majorunlock && M_RandomChance(FRACUNIT/2)) ? 1 : 0;
|
|
M_SetupReadyExplosions(false, challengesmenu.hilix, challengesmenu.hiliy+i, bombcolor);
|
|
if (ref->majorunlock)
|
|
{
|
|
M_SetupReadyExplosions(false, challengesmenu.hilix+1, challengesmenu.hiliy+(1-i), bombcolor);
|
|
}
|
|
|
|
S_StartSound(NULL, sfx_s3k4e);
|
|
}
|
|
}
|
|
}
|
|
else if (!challengesmenu.chaokeyhold)
|
|
{
|
|
|
|
// Tick down the tally. (currently not visible)
|
|
/*if ((challengesmenu.ticker & 1)
|
|
&& challengesmenu.unlockcount[CC_TALLY] > 0)
|
|
{
|
|
challengesmenu.unlockcount[CC_TALLY]--;
|
|
challengesmenu.unlockcount[CC_UNLOCKED]++;
|
|
}*/
|
|
|
|
if (challengesmenu.fade > 0)
|
|
{
|
|
// Fade decrease.
|
|
if (--challengesmenu.fade == 0)
|
|
{
|
|
// Play music the moment control returns.
|
|
M_PlayMenuJam();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
boolean M_ChallengesInputs(INT32 ch)
|
|
{
|
|
const UINT8 pid = 0;
|
|
UINT16 i;
|
|
const boolean start = M_MenuButtonPressed(pid, MBT_START);
|
|
const boolean move = (menucmd[pid].dpad_ud != 0 || menucmd[pid].dpad_lr != 0);
|
|
(void) ch;
|
|
|
|
if (challengesmenu.fade || challengesmenu.chaokeyadd || challengesmenu.chaokeyhold)
|
|
{
|
|
;
|
|
}
|
|
else if (M_MenuExtraPressed(pid))
|
|
{
|
|
if (M_CanKeyHiliTile(false))
|
|
{
|
|
challengesmenu.chaokeyhold = 1;
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.unlockcount[CC_CHAONOPE] = 6;
|
|
S_StartSound(NULL, sfx_s3k7b); //sfx_s3kb2
|
|
|
|
#ifdef CHAOKEYDEBUG
|
|
if (challengesmenu.currentunlock < MAXUNLOCKABLES && challengesmenu.unlockanim >= UNLOCKTIME && gamedata->unlocked[challengesmenu.currentunlock] == true)
|
|
{
|
|
gamedata->unlocked[challengesmenu.currentunlock] = gamedata->unlockpending[challengesmenu.currentunlock] = false;
|
|
|
|
if (challengesmenu.unlockcount[CC_TALLY] > 0)
|
|
challengesmenu.unlockcount[CC_TALLY]--;
|
|
else
|
|
challengesmenu.unlockcount[CC_UNLOCKED]--;
|
|
}
|
|
#endif
|
|
}
|
|
return true;
|
|
}
|
|
#ifdef DEVELOP
|
|
else if (M_MenuButtonPressed(pid, MBT_Z))
|
|
{
|
|
challengesmenu.chaokeyhold = 1;
|
|
return true;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
if (M_MenuBackPressed(pid) || start)
|
|
{
|
|
currentMenu->prevMenu = M_SpecificMenuRestore(currentMenu->prevMenu);
|
|
|
|
M_GoBack(0);
|
|
M_SetMenuDelay(pid);
|
|
|
|
Z_Free(challengesmenu.extradata);
|
|
challengesmenu.extradata = NULL;
|
|
|
|
challengesmenu.unlockcondition = NULL;
|
|
|
|
return true;
|
|
}
|
|
|
|
if (M_MenuButtonPressed(pid, MBT_R))
|
|
{
|
|
challengesmenu.requestflip ^= true;
|
|
|
|
return true;
|
|
}
|
|
|
|
if (challengesmenu.extradata != NULL && move)
|
|
{
|
|
challengesmenu.requestflip = false;
|
|
|
|
// Determine movement around the grid
|
|
// For right/down movement, we can pre-determine the number of steps based on extradata.
|
|
// For left/up movement, we can't - we have to be ready to iterate twice, and break early if we don't run into a large tile.
|
|
|
|
if (menucmd[pid].dpad_ud > 0)
|
|
{
|
|
i = 2;
|
|
while (i > 0)
|
|
{
|
|
if (challengesmenu.row < CHALLENGEGRIDHEIGHT-1)
|
|
{
|
|
challengesmenu.row++;
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.row = 0;
|
|
}
|
|
if (!(challengesmenu.extradata[
|
|
(challengesmenu.col * CHALLENGEGRIDHEIGHT)
|
|
+ challengesmenu.row
|
|
].flags & CHE_CONNECTEDUP))
|
|
{
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
S_StartSound(NULL, sfx_s3k5b);
|
|
M_SetMenuDelay(pid);
|
|
}
|
|
else if (menucmd[pid].dpad_ud < 0)
|
|
{
|
|
i = (challengesmenu.extradata[
|
|
(challengesmenu.col * CHALLENGEGRIDHEIGHT)
|
|
+ challengesmenu.row
|
|
].flags & CHE_CONNECTEDUP) ? 2 : 1;
|
|
while (i > 0)
|
|
{
|
|
if (challengesmenu.row > 0)
|
|
{
|
|
challengesmenu.row--;
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.row = CHALLENGEGRIDHEIGHT-1;
|
|
}
|
|
i--;
|
|
}
|
|
S_StartSound(NULL, sfx_s3k5b);
|
|
M_SetMenuDelay(pid);
|
|
}
|
|
|
|
if (menucmd[pid].dpad_lr > 0)
|
|
{
|
|
i = 2;
|
|
while (i > 0)
|
|
{
|
|
// Slide the focus counter to movement, if we can.
|
|
if (challengesmenu.focusx > -RIGHTUNLOCKSCROLL)
|
|
{
|
|
challengesmenu.focusx--;
|
|
}
|
|
|
|
// Step the actual column right.
|
|
if (challengesmenu.col < gamedata->challengegridwidth-1)
|
|
{
|
|
challengesmenu.col++;
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.col = 0;
|
|
}
|
|
|
|
if (!(challengesmenu.extradata[
|
|
(challengesmenu.col * CHALLENGEGRIDHEIGHT)
|
|
+ challengesmenu.row
|
|
].flags & CHE_CONNECTEDLEFT))
|
|
{
|
|
break;
|
|
}
|
|
|
|
i--;
|
|
}
|
|
S_StartSound(NULL, sfx_s3k5b);
|
|
M_SetMenuDelay(pid);
|
|
}
|
|
else if (menucmd[pid].dpad_lr < 0)
|
|
{
|
|
i = (challengesmenu.extradata[
|
|
(challengesmenu.col * CHALLENGEGRIDHEIGHT)
|
|
+ challengesmenu.row
|
|
].flags & CHE_CONNECTEDLEFT) ? 2 : 1;
|
|
while (i > 0)
|
|
{
|
|
// Slide the focus counter to movement, if we can.
|
|
if (challengesmenu.focusx < LEFTUNLOCKSCROLL)
|
|
{
|
|
challengesmenu.focusx++;
|
|
}
|
|
|
|
// Step the actual column left.
|
|
if (challengesmenu.col > 0)
|
|
{
|
|
challengesmenu.col--;
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.col = gamedata->challengegridwidth-1;
|
|
}
|
|
|
|
i--;
|
|
}
|
|
S_StartSound(NULL, sfx_s3k5b);
|
|
M_SetMenuDelay(pid);
|
|
}
|
|
|
|
// After movement has been determined, figure out the current selection.
|
|
i = (challengesmenu.col * CHALLENGEGRIDHEIGHT) + challengesmenu.row;
|
|
challengesmenu.currentunlock = (gamedata->challengegrid[i]);
|
|
if (challengesmenu.unlockcondition)
|
|
Z_Free(challengesmenu.unlockcondition);
|
|
challengesmenu.unlockcondition = M_BuildConditionSetString(challengesmenu.currentunlock);
|
|
|
|
challengesmenu.hilix = challengesmenu.col;
|
|
challengesmenu.hiliy = challengesmenu.row;
|
|
|
|
if (challengesmenu.currentunlock < MAXUNLOCKABLES
|
|
&& unlockables[challengesmenu.currentunlock].majorunlock)
|
|
{
|
|
// Adjust highlight coordinates up/to the left for large tiles.
|
|
|
|
if (challengesmenu.hiliy > 0 && (challengesmenu.extradata[i].flags & CHE_CONNECTEDUP))
|
|
{
|
|
challengesmenu.hiliy--;
|
|
}
|
|
|
|
if ((challengesmenu.extradata[i].flags & CHE_CONNECTEDLEFT))
|
|
{
|
|
if (challengesmenu.hilix > 0)
|
|
{
|
|
challengesmenu.hilix--;
|
|
}
|
|
else
|
|
{
|
|
challengesmenu.hilix = gamedata->challengegridwidth-1;
|
|
}
|
|
}
|
|
|
|
//i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (M_MenuConfirmPressed(pid)
|
|
&& challengesmenu.currentunlock < MAXUNLOCKABLES
|
|
&& gamedata->unlocked[challengesmenu.currentunlock])
|
|
{
|
|
switch (unlockables[challengesmenu.currentunlock].type)
|
|
{
|
|
case SECRET_ALTTITLE:
|
|
CV_AddValue(&cv_alttitle, 1);
|
|
S_StartSound(NULL, sfx_s3kc3s);
|
|
M_SetMenuDelay(pid);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|