Cup definitions, updated menu to use them

This commit is contained in:
TehRealSalt 2019-10-04 22:44:19 -04:00
parent 94e8fddd46
commit 32bdd10dbf
7 changed files with 313 additions and 59 deletions

View file

@ -1397,6 +1397,100 @@ static void readlevelheader(MYFILE *f, INT32 num)
Z_Free(s);
}
static void readcupheader(MYFILE *f, cupheader_t *cup)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
INT32 i;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
// First remove trailing newline, if there is one
tmp = strchr(s, '\n');
if (tmp)
*tmp = '\0';
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
// Set / reset word, because some things (Lua.) move it
word = s;
// Get the part before the " = "
tmp = strchr(s, '=');
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
word2 = tmp += 2;
i = atoi(word2); // used for numerical settings
strupr(word2);
if (fastcmp(word, "ICON"))
{
deh_strlcpy(cup->icon, word2,
sizeof(cup->icon), va("%s Cup: icon", cup->name));
}
else if (fastcmp(word, "LEVELLIST"))
{
cup->numlevels = 0;
tmp = strtok(word2,",");
do {
INT32 map = atoi(tmp);
if (tmp[0] >= 'A' && tmp[0] <= 'Z' && tmp[2] == '\0')
map = M_MapNumber(tmp[0], tmp[1]);
if (!map)
break;
if (cup->numlevels >= MAXLEVELLIST)
deh_warning("%s Cup: reached max levellist (%d)\n", cup->name, MAXLEVELLIST);
cup->levellist[cup->numlevels] = map;
cup->numlevels++;
} while((tmp = strtok(NULL,",")) != NULL);
}
else if (fastcmp(word, "BONUSGAME"))
{
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
i = M_MapNumber(word2[0], word2[1]);
cup->bonusgame = (INT16)i;
}
else if (fastcmp(word, "SPECIALSTAGE"))
{
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
i = M_MapNumber(word2[0], word2[1]);
cup->specialstage = (INT16)i;
}
else if (fastcmp(word, "EMERALDNUM"))
{
cup->emeraldnum = (INT16)i;
}
else
deh_warning("%s Cup: unknown word '%s'", cup->name, word);
}
} while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
}
static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
{
char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL);
@ -3558,6 +3652,42 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
}
DEH_WriteUndoline(word, word2, UNDO_HEADER);
}
else if (fastcmp(word, "CUP"))
{
cupheader_t *cup = kartcupheaders;
cupheader_t *prev = NULL;
while (cup)
{
if (fastcmp(cup->name, word2))
{
// mark as a major mod if it replaces an already-existing cup
G_SetGameModified(multiplayer, true);
break;
}
prev = cup;
cup = cup->next;
}
// Nothing found, add to the end.
if (!cup)
{
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
if (prev != NULL)
prev->next = cup;
if (kartcupheaders == NULL)
kartcupheaders = cup;
numkartcupheaders++;
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
}
readcupheader(f, cup);
DEH_WriteUndoline(word, word2, UNDO_HEADER);
}
else if (fastcmp(word, "CUTSCENE"))
{
if (i > 0 && i < 129)

View file

@ -291,6 +291,24 @@ typedef struct
extern mapheader_t* mapheaderinfo[NUMMAPS];
#define MAXLEVELLIST 5
typedef struct cupheader_s
{
UINT16 id; ///< Cup ID
char name[15]; ///< Cup title (14 chars)
char icon[9]; ///< Name of the icon patch
INT16 levellist[MAXLEVELLIST]; ///< List of levels that belong to this cup
UINT8 numlevels; ///< Number of levels defined in levellist
INT16 bonusgame; ///< Map number to use for bonus game
INT16 specialstage; ///< Map number to use for special stage
UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald)
struct cupheader_s *next; ///< Next cup in linked list
} cupheader_t;
extern cupheader_t *kartcupheaders; // Start of cup linked list
extern UINT16 numkartcupheaders;
enum TypeOfLevel
{
TOL_SP = 0x01, ///< Single Player

View file

@ -153,6 +153,10 @@ struct quake quake;
// Map Header Information
mapheader_t* mapheaderinfo[NUMMAPS] = {NULL};
// Kart cup definitions
cupheader_t *kartcupheaders = NULL;
UINT16 numkartcupheaders = 0;
static boolean exitgame = false;
static boolean retrying = false;

View file

@ -292,26 +292,33 @@ boolean M_CharacterSelectQuit(void);
#define CUPS_MAX (NUMMAPS / CUPS_MAPSPERCUP)
#define CUPS_PAGES (CUPS_MAX / (CUPS_COLUMNS * CUPS_ROWS))
#define CUPID (levellist_cupgrid.x + (levellist_cupgrid.y * CUPS_COLUMNS))
extern cupheader_t *selectedcup;
extern INT16 selectedcupnum;
extern struct levellist_cupgrid_s {
UINT8 numcups;
SINT8 x, y;
SINT8 pageno;
tic_t previewanim;
boolean grandprix; // Setup grand prix server after picking
} levellist_cupgrid;
extern struct levellist_scroll_s {
SINT8 cupid;
SINT8 cursor;
UINT16 y;
UINT16 dest;
boolean timeattack; // Setup time attack menu after picking
} levellist_scroll;
boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt);
void M_LevelSelectInit(INT32 choice);
INT32 M_CountLevelsToShowInList(INT32 gt);
INT32 M_GetFirstLevelInList(INT32 gt);
void M_LevelSelectInit(INT32 choice);
void M_CupSelectHandler(INT32 choice);
void M_CupSelectTick(void);
void M_LevelSelectHandler(INT32 choice);
void M_LevelSelectTick(void);

View file

@ -85,13 +85,13 @@ menu_t PLAY_GamemodesDef = KARTGAMEMODEMENU(PLAY_GamemodesMenu, &PLAY_MainDef);
menuitem_t PLAY_RaceGamemodesMenu[] =
{
{IT_STRING | IT_CALL, "Grand Prix", "Compete for the best rank over five races!",
NULL, M_LevelSelectInit, 0, 0},
NULL, M_LevelSelectInit, 2, GT_RACE},
{IT_STRING | IT_CALL, "Match Race", "Play by your own rules in a specialized, single race!",
NULL, M_LevelSelectInit, 1, 0},
NULL, M_LevelSelectInit, 0, GT_RACE},
{IT_STRING | IT_CALL, "Time Attack", "Record your best time on any track!",
NULL, M_LevelSelectInit, 2, 0},
NULL, M_LevelSelectInit, 1, GT_RACE},
{IT_STRING | IT_CALL, "Back", NULL, NULL, M_GoBack, 0, 0},
};
@ -157,10 +157,10 @@ menu_t PLAY_TimeAttackDef = {
menuitem_t PLAY_BattleGamemodesMenu[] =
{
{IT_STRING | IT_CALL, "Survival", "It's last hedgehog standing in this free-for-all!",
NULL, M_LevelSelectInit, 3, 0},
NULL, M_LevelSelectInit, 0, GT_MATCH},
{IT_STRING | IT_CALL, "Time Attack", "Bust up all of the capsules in record time!",
NULL, M_LevelSelectInit, 4, 0},
NULL, M_LevelSelectInit, 1, GT_MATCH},
{IT_STRING | IT_CALL, "Back", NULL, NULL, M_GoBack, 0, 0},
};

View file

@ -875,20 +875,18 @@ void M_DrawCharacterSelect(void)
// LEVEL SELECT
static void M_DrawCupPreview(INT16 y, UINT8 cupnum)
static void M_DrawCupPreview(INT16 y, cupheader_t *cup)
{
UINT8 i;
INT16 x = -(levellist_cupgrid.previewanim % 82);
V_DrawFill(0, y, BASEVIDWIDTH, 54, 31);
for (i = 0; i < 5; i++)
for (i = 0; i < cup->numlevels; i++)
{
lumpnum_t lumpnum;
patch_t *PictureOfLevel;
UINT8 lvloff = (i + (levellist_cupgrid.previewanim / 82)) % 5;
UINT8 lvloff = (i + (levellist_cupgrid.previewanim / 82)) % cup->numlevels;
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(1 + (cupnum * 5) + lvloff)));
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cup->levellist[lvloff] )));
if (lumpnum != LUMPERROR)
PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE);
else
@ -901,6 +899,14 @@ static void M_DrawCupPreview(INT16 y, UINT8 cupnum)
void M_DrawCupSelect(void)
{
UINT8 i, j;
cupheader_t *cup = kartcupheaders;
while (cup)
{
if (cup->id == CUPID)
break;
cup = cup->next;
}
for (i = 0; i < CUPS_COLUMNS; i++)
{
@ -915,10 +921,14 @@ void M_DrawCupSelect(void)
0, W_CachePatchName("CUPCURS", PU_CACHE)
);
V_DrawFill(0, 146 + (12*menutransition.tics), BASEVIDWIDTH, 54, 31);
V_DrawScaledPatch(0, 120 - (12*menutransition.tics), 0, W_CachePatchName("MENUHINT", PU_CACHE));
M_DrawCupPreview(146 + (12*menutransition.tics), levellist_cupgrid.x + (levellist_cupgrid.y * CUPS_COLUMNS));
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, 126 - (12*menutransition.tics), 0, "SNEAKER CUP");
if (cup)
{
M_DrawCupPreview(146 + (12*menutransition.tics), cup);
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, 126 - (12*menutransition.tics), 0, va("%s Cup", cup->name));
}
}
static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map)
@ -930,7 +940,7 @@ static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map)
INT16 x2 = x;
UINT8 i;
if (!mapheaderinfo[map]->lvlttl[0])
if (!mapheaderinfo[map] || !mapheaderinfo[map]->lvlttl[0])
return;
if (mapheaderinfo[map]->zonttl[0])
@ -1035,7 +1045,8 @@ static void M_DrawLevelSelectBlock(INT16 x, INT16 y, INT16 map, boolean redblink
void M_DrawLevelSelect(void)
{
UINT8 i;
INT16 i;
INT16 start = M_GetFirstLevelInList(cv_newgametype.value)-1;
INT16 t = (32*menutransition.tics), tay = 0;
INT16 y = 80 - (12 * levellist_scroll.y);
boolean tatransition = (menutransition.startmenu == &PLAY_TimeAttackDef || menutransition.endmenu == &PLAY_TimeAttackDef);
@ -1046,10 +1057,16 @@ void M_DrawLevelSelect(void)
tay = t/2;
}
for (i = 0; i < 5; i++)
for (i = 0; i < M_CountLevelsToShowInList(cv_newgametype.value); i++)
{
INT16 map = 1 + (levellist_scroll.cupid * 5) + i;
INT16 lvlx = t, lvly = y;
INT16 map = start + i;
while (!M_CanShowLevelInList(map, cv_newgametype.value) && map < NUMMAPS)
map++;
if (map >= NUMMAPS)
break;
if (i == levellist_scroll.cursor && tatransition)
{
@ -1066,7 +1083,10 @@ void M_DrawLevelSelect(void)
}
V_DrawScaledPatch(0, tay, 0, W_CachePatchName("MENUHINT", PU_CACHE));
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, 6+tay, 0, "SNEAKER CUP");
if (selectedcup)
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, 6+tay, 0, va("%s Cup", selectedcup->name));
else
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, 6+tay, 0, va("%s Mode", Gametype_Names[cv_newgametype.value]));
}
void M_DrawTimeAttack(void)

View file

@ -2017,16 +2017,6 @@ boolean M_CharacterSelectQuit(void)
// LEVEL SELECT
#if 0
// Call before showing any level-select menus
static void M_PrepareLevelSelect(void)
{
if (levellistmode != LLM_CREATESERVER)
CV_SetValue(&cv_nextmap, M_GetFirstLevelInList());
else
Newgametype_OnChange(); // Make sure to start on an appropriate map if wads have been added
}
//
// M_CanShowLevelInList
//
@ -2055,10 +2045,17 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt)
if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE))
{
if (levellist_cup != -1)
if (selectedcup && selectedcup->numlevels)
{
if (mapnum < (1 + ((levellist_cup-1) * 5))
|| mapnum > (6 + ((levellist_cup-1) * 5))
UINT8 i;
for (i = 0; i < selectedcup->numlevels; i++)
{
if (mapnum == selectedcup->levellist[i])
break;
}
if (i == selectedcup->numlevels)
return false;
}
@ -2069,75 +2066,95 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt)
return false;
}
static INT32 M_CountLevelsToShowInList(void)
INT32 M_CountLevelsToShowInList(INT32 gt)
{
INT32 mapnum, count = 0;
for (mapnum = 0; mapnum < NUMMAPS; mapnum++)
if (M_CanShowLevelInList(mapnum, -1))
if (M_CanShowLevelInList(mapnum, gt))
count++;
return count;
}
static INT32 M_GetFirstLevelInList(void)
INT32 M_GetFirstLevelInList(INT32 gt)
{
INT32 mapnum;
for (mapnum = 0; mapnum < NUMMAPS; mapnum++)
if (M_CanShowLevelInList(mapnum, -1))
if (M_CanShowLevelInList(mapnum, gt))
return mapnum + 1;
return 1;
}
#endif
cupheader_t *selectedcup = NULL;
struct levellist_cupgrid_s levellist_cupgrid;
struct levellist_scroll_s levellist_scroll;
static void M_LevelSelectScrollDest(void)
{
UINT16 m = M_CountLevelsToShowInList(cv_newgametype.value)-1;
levellist_scroll.dest = (6*levellist_scroll.cursor);
if (levellist_scroll.dest < 3)
levellist_scroll.dest = 3;
if (levellist_scroll.dest > (6*4)-3)
levellist_scroll.dest = (6*4)-3;
if (levellist_scroll.dest > (6*m)-3)
levellist_scroll.dest = (6*m)-3;
}
void M_LevelSelectInit(INT32 choice)
{
UINT8 selecttype = currentMenu->menuitems[itemOn].mvar1;
(void)choice;
switch (selecttype)
switch (currentMenu->menuitems[itemOn].mvar1)
{
case 0:
levellist_cupgrid.grandprix = false;
levellist_scroll.timeattack = false;
break;
case 1:
levellist_cupgrid.grandprix = false;
levellist_scroll.timeattack = true;
break;
case 2:
CV_StealthSetValue(&cv_newgametype, GT_RACE);
levellist_cupgrid.grandprix = true;
levellist_scroll.timeattack = false;
break;
default:
break;
CONS_Alert(CONS_WARNING, "Bad level select init\n");
return;
}
CV_StealthSetValue(&cv_newgametype, currentMenu->menuitems[itemOn].mvar2);
PLAY_CupSelectDef.prevMenu = currentMenu;
if (cv_newgametype.value != GT_RACE)
{
PLAY_LevelSelectDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_LevelSelectDef, false);
}
else
if (cv_newgametype.value == GT_RACE)
{
PLAY_LevelSelectDef.prevMenu = &PLAY_CupSelectDef;
M_SetupNextMenu(&PLAY_CupSelectDef, false);
}
else
{
selectedcup = NULL;
PLAY_LevelSelectDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_LevelSelectDef, false);
}
}
void M_CupSelectHandler(INT32 choice)
{
UINT8 selcup = levellist_cupgrid.x + (levellist_cupgrid.y * CUPS_COLUMNS);
cupheader_t *newcup = kartcupheaders;
while (newcup)
{
CONS_Printf("%d == %d?\n", newcup->id, CUPID);
if (newcup->id == CUPID)
break;
newcup = newcup->next;
}
switch (choice)
{
@ -2178,10 +2195,13 @@ void M_CupSelectHandler(INT32 choice)
S_StartSound(NULL, sfx_s3k5b);
break;
case KEY_ENTER:
if (levellist_scroll.cupid != selcup) // Keep cursor position if you select the same cup again
if (!newcup)
break;
if (!selectedcup || newcup->id != selectedcup->id) // Keep cursor position if you select the same cup again
{
levellist_scroll.cursor = 0;
levellist_scroll.cupid = selcup;
selectedcup = newcup;
}
M_LevelSelectScrollDest();
@ -2208,6 +2228,10 @@ void M_CupSelectTick(void)
void M_LevelSelectHandler(INT32 choice)
{
INT16 start = M_GetFirstLevelInList(cv_newgametype.value)-1;
INT16 maxlevels = M_CountLevelsToShowInList(cv_newgametype.value);
INT16 map = start;
if (levellist_scroll.y != levellist_scroll.dest)
return;
@ -2216,18 +2240,69 @@ void M_LevelSelectHandler(INT32 choice)
case KEY_UPARROW:
levellist_scroll.cursor--;
if (levellist_scroll.cursor < 0)
levellist_scroll.cursor = 4;
levellist_scroll.cursor = maxlevels-1;
S_StartSound(NULL, sfx_s3k5b);
break;
case KEY_DOWNARROW:
levellist_scroll.cursor++;
if (levellist_scroll.cursor > 4)
if (levellist_scroll.cursor >= maxlevels)
levellist_scroll.cursor = 0;
S_StartSound(NULL, sfx_s3k5b);
break;
case KEY_ENTER:
CV_SetValue(&cv_nextmap, 1 + (levellist_scroll.cupid * 5) + levellist_scroll.cursor);
M_SetupNextMenu(&PLAY_TimeAttackDef, false);
map = start + levellist_scroll.cursor;
while (!M_CanShowLevelInList(map, cv_newgametype.value) && map < NUMMAPS)
map++;
if (map >= NUMMAPS)
break;
CV_SetValue(&cv_nextmap, map);
if (levellist_scroll.timeattack)
M_SetupNextMenu(&PLAY_TimeAttackDef, false);
else
{
UINT8 ssplayers = cv_splitplayers.value-1;
netgame = false;
multiplayer = true;
strncpy(connectedservername, cv_servername.string, MAXSERVERNAME);
// Still need to reset devmode
cv_debug = 0;
if (strlen(cv_dummyjoinpassword.string) > 0)
D_SetJoinPassword(cv_dummyjoinpassword.string);
else
joinpasswordset = false;
if (demo.playback)
G_StopDemo();
if (metalrecording)
G_StopMetalDemo();
if (!cv_nextmap.value)
CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, 0, false, NULL)+1);
if (cv_maxplayers.value < ssplayers+1)
CV_SetValue(&cv_maxplayers, ssplayers+1);
if (splitscreen != ssplayers)
{
splitscreen = ssplayers;
SplitScreen_OnChange();
}
paused = false;
SV_StartSinglePlayerServer();
multiplayer = true; // yeah, SV_StartSinglePlayerServer clobbers this...
D_MapChange(cv_nextmap.value, cv_newgametype.value, (cv_kartencore.value == 1), 1, 1, false, false);
M_ClearMenus(true);
}
S_StartSound(NULL, sfx_s3k63);
break;
case KEY_ESCAPE: