From fd63db0aaff3488cde8374235297b7d14a027aff Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 18 Aug 2017 00:58:16 +0100 Subject: [PATCH 01/12] Starting lives revamp, per the 2.2 priorities topic list! * Each time you die, the number of game overs you've had is counted. * Your save file updates to record this. * The number of startinglives is determined by the number of times you'ved game-overed, with the maximum being infinity lives (thereby providing a cap on the number of game overs you can go through in a typical game). Requires a new patch.dta, but I'm not uploading that yet because not happy with the icon we've got going for infinity lives on the save select menu. --- src/doomstat.h | 4 ++ src/g_game.c | 116 ++++++++++++++++++++++++++++++++++++++++++++----- src/g_game.h | 2 + src/hu_stuff.c | 6 ++- src/hu_stuff.h | 1 + src/m_menu.c | 12 +++-- src/m_menu.h | 1 - src/p_inter.c | 9 +++- src/p_saveg.c | 14 +++--- src/p_saveg.h | 1 + src/p_setup.c | 1 + src/p_user.c | 12 +++-- src/st_stuff.c | 85 +++++++++++++++--------------------- 13 files changed, 184 insertions(+), 80 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index a24bad79d..a172eae43 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -45,6 +45,10 @@ extern INT32 cursaveslot; extern INT16 lastmaploaded; extern boolean gamecomplete; +#define maxgameovers 13 +extern UINT8 numgameovers; +extern SINT8 startinglivesbalance[maxgameovers+1]; + #define PRECIP_NONE 0 #define PRECIP_STORM 1 #define PRECIP_SNOW 2 diff --git a/src/g_game.c b/src/g_game.c index e996938ab..e16816e44 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -81,6 +81,9 @@ INT32 cursaveslot = -1; // Auto-save 1p savegame slot INT16 lastmaploaded = 0; // Last map the game loaded boolean gamecomplete = false; +UINT8 numgameovers = 0; // for startinglives balance +SINT8 startinglivesbalance[maxgameovers+1] = {3, 5, 7, 9, 12, 15, 20, 25, 30, 40, 50, 75, 99, 0x7F}; + UINT16 mainwads = 0; boolean modifiedgame; // Set if homebrew PWAD stuff has been added. boolean savemoddata = false; @@ -3130,7 +3133,7 @@ static void G_DoContinued(void) token = 0; // Reset # of lives - pl->lives = (ultimatemode) ? 1 : 3; + pl->lives = (ultimatemode) ? 1 : startinglivesbalance[numgameovers]; D_MapChange(gamemap, gametype, ultimatemode, false, 0, false, false); @@ -3614,13 +3617,13 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) // G_SaveGame // Saves your game. // -void G_SaveGame(UINT32 savegameslot) +void G_SaveGame(UINT32 slot) { boolean saved; char savename[256] = ""; const char *backup; - sprintf(savename, savegamename, savegameslot); + sprintf(savename, savegamename, slot); backup = va("%s",savename); // save during evaluation or credits? game's over, folks! @@ -3656,9 +3659,103 @@ void G_SaveGame(UINT32 savegameslot) if (cv_debug && saved) CONS_Printf(M_GetText("Game saved.\n")); else if (!saved) - CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, savegameslot, savegamename); + CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, savegamename); } +#define BADSAVE goto cleanup; +#define CHECKPOS if (save_p >= end_p) BADSAVE +void G_SaveGameOver(UINT32 slot) +{ + boolean saved = false; + size_t length; + char vcheck[VERSIONSIZE]; + char savename[255]; + const char *backup; + + sprintf(savename, savegamename, slot); + backup = va("%s",savename); + + length = FIL_ReadFile(savename, &savebuffer); + if (!length) + { + CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); + return; + } + + { + char temp[sizeof(timeattackfolder)]; + INT32 fake; // Dummy variable + UINT8 *end_p = savebuffer + length; + UINT8 *lives_p; + SINT8 pllives; + + save_p = savebuffer; + // Version check + memset(vcheck, 0, sizeof (vcheck)); + sprintf(vcheck, "version %d", VERSION); +#ifndef SAVEGAMES_OTHERVERSIONS + if (strcmp((const char *)save_p, (const char *)vcheck)) + BADSAVE; +#endif + save_p += VERSIONSIZE; + + // P_UnArchiveMisc() + fake = READINT16(save_p); + CHECKPOS + (void)READUINT16(save_p); // emeralds + CHECKPOS + READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to + if (strcmp(temp, timeattackfolder)) BADSAVE + CHECKPOS + (void)READUINT8(save_p); + CHECKPOS + (void)READUINT8(save_p); + CHECKPOS + + WRITEUINT8(save_p, numgameovers); + CHECKPOS + + lives_p = save_p; + pllives = READSINT8(save_p); // lives + CHECKPOS + if (pllives < startinglivesbalance[numgameovers]) + { + pllives = startinglivesbalance[numgameovers]; + WRITESINT8(lives_p, pllives); + } + + (void)READINT32(save_p); // Score + CHECKPOS + (void)READINT32(save_p); // continues + + if (fake & (1<<10)) + { + CHECKPOS + (void)READUINT8(save_p); + CHECKPOS + (void)READUINT8(save_p); // because why not. + } + + // File end marker check + CHECKPOS + if (READUINT8(save_p) != 0x1d) BADSAVE; + + // done + saved = FIL_WriteFile(backup, savebuffer, length); + } + +cleanup: + if (cv_debug && saved) + CONS_Printf(M_GetText("Game saved.\n")); + else if (!saved) + CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, savegamename); + Z_Free(savebuffer); + save_p = savebuffer = NULL; + +} +#undef CHECKPOS +#undef BADSAVE + // // G_DeferedInitNew // Can be called by the startup code or the menu task, @@ -3722,7 +3819,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean if (resetplayer) { // Clear a bunch of variables - tokenlist = token = sstimer = redscore = bluescore = lastmap = 0; + numgameovers = tokenlist = token = sstimer = redscore = bluescore = lastmap = 0; countdown = countdown2 = 0; for (i = 0; i < MAXPLAYERS; i++) @@ -3737,15 +3834,10 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean players[i].lives = cv_startinglives.value; players[i].continues = 0; } - else if (pultmode) - { - players[i].lives = 1; - players[i].continues = 0; - } else { - players[i].lives = 3; - players[i].continues = 1; + players[i].lives = (pultmode) ? 1 : startinglivesbalance[0]; + players[i].continues = (pultmode) ? 0 : 1; } if (!((netgame || multiplayer) && (FLS))) diff --git a/src/g_game.h b/src/g_game.h index 72a6f3d6e..4ac78ab10 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -116,6 +116,8 @@ void G_SaveGameData(void); void G_SaveGame(UINT32 slot); +void G_SaveGameOver(UINT32 slot); + // Only called by startup code. void G_RecordDemo(const char *name); void G_RecordMetal(void); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e92b96995..b49d3eb96 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -83,6 +83,7 @@ patch_t *rmatcico; patch_t *bmatcico; patch_t *tagico; patch_t *tallminus; +patch_t *tallinfin; //------------------------------------------- // coop hud @@ -235,6 +236,7 @@ void HU_LoadGraphics(void) // minus for negative tallnums tallminus = (patch_t *)W_CachePatchName("STTMINUS", PU_HUDGFX); + tallinfin = (patch_t *)W_CachePatchName("STTINFIN", PU_HUDGFX); // cache the crosshairs, don't bother to know which one is being used, // just cache all 3, they're so small anyway. @@ -1250,7 +1252,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I } } - if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3))) //show lives + if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != 0x7f)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|(greycheck ? V_60TRANS : 0), va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) { @@ -1388,7 +1390,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline | (greycheck ? V_TRANSLUCENT : 0) | V_ALLOWLOWERCASE, name); - if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3))) //show lives + if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != 0x7f)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) V_DrawSmallScaledPatch(x-28, y-4, 0, tagico); diff --git a/src/hu_stuff.h b/src/hu_stuff.h index e757db85a..2dbeb556d 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -71,6 +71,7 @@ extern patch_t *rmatcico; extern patch_t *bmatcico; extern patch_t *tagico; extern patch_t *tallminus; +extern patch_t *tallinfin; extern patch_t *tokenicon; // set true when entering a chat message diff --git a/src/m_menu.c b/src/m_menu.c index 64255e71a..af3b0c7ca 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6097,7 +6097,10 @@ static void M_DrawLoadGameData(void) // Use the big face pic for lives, duh. :3 V_DrawScaledPatch(ecks + 12, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); - V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); + if (savegameinfo[saveSlotSelected].lives == 0x7F) + V_DrawScaledPatch(ecks + 40 - 18, 172, 0, tallinfin); + else + V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); // Absolute ridiculousness, condensed into another function. V_DrawContinueIcon(ecks + 58, 182, 0, savegameinfo[saveSlotSelected].skinnum, savegameinfo[saveSlotSelected].skincolor); @@ -6291,10 +6294,11 @@ static void M_ReadSavegameInfo(UINT32 slot) savegameinfo[slot].skinnum = READUINT8(save_p); CHECKPOS - (void)READINT32(save_p); // Score - + (void)READUINT8(save_p); // numgameovers CHECKPOS - savegameinfo[slot].lives = READINT32(save_p); // lives + savegameinfo[slot].lives = READSINT8(save_p); // lives + CHECKPOS + (void)READINT32(save_p); // Score CHECKPOS savegameinfo[slot].continues = READINT32(save_p); // continues diff --git a/src/m_menu.h b/src/m_menu.h index 53dc266d1..2d2d3378b 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -226,7 +226,6 @@ typedef struct INT32 lives; INT32 continues; INT32 gamemap; - UINT8 netgame; } saveinfo_t; extern description_t description[32]; diff --git a/src/p_inter.c b/src/p_inter.c index d2101ca57..284003c31 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2259,7 +2259,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if ((target->player->lives <= 1) && (netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value == 0)) ; - else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) + else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) && (target->player->lives != 0x7f) && G_GametypeUsesLives()) { target->player->lives -= 1; // Lose a life Tails 03-11-2000 @@ -2289,6 +2289,13 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget S_StopMusic(); // Stop the Music! Tails 03-14-2000 S_ChangeMusicInternal("_gover", false); // Yousa dead now, Okieday? Tails 03-14-2000 } + + if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && numgameovers < maxgameovers) + { + numgameovers++; + if ((!modifiedgame || savemoddata) && cursaveslot >= 0) + G_SaveGameOver((UINT32)cursaveslot); + } } } target->player->playerstate = PST_DEAD; diff --git a/src/p_saveg.c b/src/p_saveg.c index 2d3412e65..9e1206c49 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -64,15 +64,16 @@ typedef enum static inline void P_ArchivePlayer(void) { const player_t *player = &players[consoleplayer]; - INT32 pllives = player->lives; - if (pllives < 3) // Bump up to 3 lives if the player - pllives = 3; // has less than that. + SINT8 pllives = player->lives; + if (pllives < startinglivesbalance[numgameovers]) // Bump up to 3 lives if the player + pllives = startinglivesbalance[numgameovers]; // has less than that. WRITEUINT8(save_p, player->skincolor); WRITEUINT8(save_p, player->skin); + WRITEUINT8(save_p, numgameovers); + WRITESINT8(save_p, pllives); WRITEUINT32(save_p, player->score); - WRITEINT32(save_p, pllives); WRITEINT32(save_p, player->continues); if (botskin) @@ -90,8 +91,9 @@ static inline void P_UnArchivePlayer(void) savedata.skincolor = READUINT8(save_p); savedata.skin = READUINT8(save_p); - savedata.score = READINT32(save_p); - savedata.lives = READINT32(save_p); + savedata.numgameovers = READUINT8(save_p); + savedata.lives = READSINT8(save_p); + savedata.score = READUINT32(save_p); savedata.continues = READINT32(save_p); if (savedata.botcolor) diff --git a/src/p_saveg.h b/src/p_saveg.h index 3670d3503..376552c95 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -38,6 +38,7 @@ typedef struct INT32 lives; INT32 continues; UINT16 emeralds; + UINT8 numgameovers; } savedata_t; extern savedata_t savedata; diff --git a/src/p_setup.c b/src/p_setup.c index 9c4bede74..c131f6677 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3026,6 +3026,7 @@ boolean P_SetupLevel(boolean skipprecip) if (savedata.lives > 0) { + numgameovers = savedata.numgameovers; players[consoleplayer].continues = savedata.continues; players[consoleplayer].lives = savedata.lives; players[consoleplayer].score = savedata.score; diff --git a/src/p_user.c b/src/p_user.c index 09cafa0b3..482bcc65d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -950,6 +950,8 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) // void P_GivePlayerLives(player_t *player, INT32 numlives) { + if (player->lives == 0x7f) return; + player->lives += numlives; if (player->lives > 99) @@ -1153,7 +1155,9 @@ void P_PlayLivesJingle(player_t *player) if (player && !P_IsLocalPlayer(player)) return; - if (gametype == GT_COOP && (netgame || multiplayer) && cv_cooplives.value == 0) + if ((player && player->lives == 0x7f) + || (!player && &players[consoleplayer] && players[consoleplayer].lives == 0x7f) + || (gametype == GT_COOP && (netgame || multiplayer) && cv_cooplives.value == 0)) S_StartSound(NULL, sfx_lose); else if (use1upSound) S_StartSound(NULL, sfx_oneup); @@ -8160,7 +8164,8 @@ boolean P_GetLives(player_t *player) INT32 i, maxlivesplayer = -1, livescheck = 1; if (!(netgame || multiplayer) || (gametype != GT_COOP) - || (cv_cooplives.value == 1)) + || (cv_cooplives.value == 1) + || (player->lives == 0x7f)) return true; if ((cv_cooplives.value == 2 || cv_cooplives.value == 0) && player->lives > 0) @@ -8187,7 +8192,8 @@ boolean P_GetLives(player_t *player) { if (cv_cooplives.value == 2 && (P_IsLocalPlayer(player) || P_IsLocalPlayer(&players[maxlivesplayer]))) S_StartSound(NULL, sfx_jshard); // placeholder - players[maxlivesplayer].lives--; + if (players[maxlivesplayer].lives != 0x7f) + players[maxlivesplayer].lives--; player->lives++; if (player->lives < 1) player->lives = 1; diff --git a/src/st_stuff.c b/src/st_stuff.c index 4515495af..ceef586a4 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -684,6 +684,8 @@ static inline void ST_drawRings(void) static void ST_drawLives(void) { const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayer] ? V_SPLITSCREEN : 0); + INT32 livescount; + boolean notgreyedout; if (!stplyr->skincolor) return; // Just joined a server, skin isn't loaded yet! @@ -723,66 +725,47 @@ static void ST_drawLives(void) V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, stlivex); // lives number - if ((netgame || multiplayer) && gametype == GT_COOP) + if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) { - switch (cv_cooplives.value) + INT32 i; + livescount = 0; + notgreyedout = (stplyr->lives > 0); + for (i = 0; i < MAXPLAYERS; i++) { - case 0: - V_DrawCharacter(hudinfo[HUD_LIVESNUM].x - 8, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), '\x16' | 0x80 | V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, false); - return; - case 3: - { - INT32 i, sum = 0; - boolean canrespawn = (stplyr->lives > 0); - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; + if (!playeringame[i]) + continue; - if (players[i].lives < 1) - continue; + if (players[i].lives < 1) + continue; - if (players[i].lives > 1) - canrespawn = true; + if (players[i].lives > 1) + notgreyedout = true; - sum += (players[i].lives); - } - V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|(canrespawn ? V_HUDTRANS : V_HUDTRANSHALF)|v_splitflag, - va("%d",sum)); - return; - } -#if 0 // render the number of lives you COULD steal - case 2: - { - INT32 i, sum = 0; - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - if (&players[i] == stplyr) - continue; - - if (players[i].lives < 2) - continue; - - sum += (players[i].lives - 1); - } - V_DrawString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANSHALF|v_splitflag, va("/%d",sum)); - } - // intentional fallthrough -#endif - default: - // don't return so the SP one can be drawn below + if (players[i].lives == 0x7f) + { + livescount = 0x7f; break; + } + else if (livescount < 99) + livescount += (players[i].lives); } } + else + { + livescount = stplyr->lives; + notgreyedout = true; + } - V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, - va("%d",stplyr->lives)); + if (livescount == 0x7f) + V_DrawCharacter(hudinfo[HUD_LIVESNUM].x - 8, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), '\x16' | 0x80 | V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, false); + else + { + if (livescount > 99) + livescount = 99; + V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), + V_SNAPTOLEFT|V_SNAPTOBOTTOM|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF)|v_splitflag, + ((livescount > 99) ? "!!" : va("%d",livescount))); + } } static void ST_drawLevelTitle(void) From 42211f02b45de766051a6b1ec68cf38489cb2aba Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 20 Aug 2017 13:14:17 +0100 Subject: [PATCH 02/12] * Per Mystic's request, only set the number of lives in the save file if you actually use a continue, or completely wipe out your lives and continues. * Fix a bug where I got emeralds and mapnumbers mixed up when checking for the "there's a tailsbot" flag. * Consider a save with an invalid skin an invalid save, rather than allowing its continued presence. --- src/g_game.c | 13 +++++++++---- src/g_game.h | 2 +- src/m_menu.c | 4 +++- src/p_inter.c | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index e16816e44..7ee7ccfbf 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3132,6 +3132,9 @@ static void G_DoContinued(void) tokenlist = 0; token = 0; + if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && (!modifiedgame || savemoddata) && cursaveslot >= 0) + G_SaveGameOver((UINT32)cursaveslot, true); + // Reset # of lives pl->lives = (ultimatemode) ? 1 : startinglivesbalance[numgameovers]; @@ -3664,7 +3667,7 @@ void G_SaveGame(UINT32 slot) #define BADSAVE goto cleanup; #define CHECKPOS if (save_p >= end_p) BADSAVE -void G_SaveGameOver(UINT32 slot) +void G_SaveGameOver(UINT32 slot, boolean modifylives) { boolean saved = false; size_t length; @@ -3700,12 +3703,14 @@ void G_SaveGameOver(UINT32 slot) save_p += VERSIONSIZE; // P_UnArchiveMisc() - fake = READINT16(save_p); + (void)READINT16(save_p); CHECKPOS - (void)READUINT16(save_p); // emeralds + fake = READUINT16(save_p)-357; // emeralds CHECKPOS READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to if (strcmp(temp, timeattackfolder)) BADSAVE + + // P_UnArchivePlayer() CHECKPOS (void)READUINT8(save_p); CHECKPOS @@ -3718,7 +3723,7 @@ void G_SaveGameOver(UINT32 slot) lives_p = save_p; pllives = READSINT8(save_p); // lives CHECKPOS - if (pllives < startinglivesbalance[numgameovers]) + if (modifylives && pllives < startinglivesbalance[numgameovers]) { pllives = startinglivesbalance[numgameovers]; WRITESINT8(lives_p, pllives); diff --git a/src/g_game.h b/src/g_game.h index 4ac78ab10..de04e2846 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -116,7 +116,7 @@ void G_SaveGameData(void); void G_SaveGame(UINT32 slot); -void G_SaveGameOver(UINT32 slot); +void G_SaveGameOver(UINT32 slot, boolean modifylives); // Only called by startup code. void G_RecordDemo(const char *name); diff --git a/src/m_menu.c b/src/m_menu.c index af3b0c7ca..36b0bc54e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6098,7 +6098,7 @@ static void M_DrawLoadGameData(void) // Use the big face pic for lives, duh. :3 V_DrawScaledPatch(ecks + 12, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); if (savegameinfo[saveSlotSelected].lives == 0x7F) - V_DrawScaledPatch(ecks + 40 - 18, 172, 0, tallinfin); + V_DrawScaledPatch(ecks + 40 - 17, 172, 0, tallinfin); else V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); @@ -6290,8 +6290,10 @@ static void M_ReadSavegameInfo(UINT32 slot) // P_UnArchivePlayer() CHECKPOS savegameinfo[slot].skincolor = READUINT8(save_p); + CHECKPOS savegameinfo[slot].skinnum = READUINT8(save_p); + if (savegameinfo[slot].skinnum >= numskins) BADSAVE CHECKPOS (void)READUINT8(save_p); // numgameovers diff --git a/src/p_inter.c b/src/p_inter.c index 284003c31..f356c642c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2294,7 +2294,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { numgameovers++; if ((!modifiedgame || savemoddata) && cursaveslot >= 0) - G_SaveGameOver((UINT32)cursaveslot); + G_SaveGameOver((UINT32)cursaveslot, (target->player->continues <= 0)); } } } From 706eb5efeb224e8d9f5a4c7140568b2fffde5703 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 20 Aug 2017 23:18:47 +0100 Subject: [PATCH 03/12] * New, pretty save select! Requires patch.dta to really appreciate. * Changed the save format a little more, since I had free reign over it. * Modified the string drawing functions to not awkwardly clip at the very edges of the screen, considering the relevant patch drawing functions avoid out-of-range memory writes. --- src/f_finale.c | 6 +- src/g_game.c | 88 +------- src/m_menu.c | 533 ++++++++++++++++++++++++++++++------------------- src/m_menu.h | 5 +- src/p_inter.c | 2 +- src/p_saveg.c | 31 +-- src/p_saveg.h | 2 - src/p_setup.c | 11 +- src/v_video.c | 8 +- 9 files changed, 357 insertions(+), 329 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index db497daf7..e9d3524b8 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1114,7 +1114,7 @@ void F_StartCredits(void) M_ClearMenus(true); // Save the second we enter the credits - if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot >= 0) + if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) G_SaveGame((UINT32)cursaveslot); if (creditscutscene) @@ -1252,7 +1252,7 @@ static boolean drawemblem = false, drawchaosemblem = false; void F_StartGameEvaluation(void) { // Credits option in secrets menu - if (cursaveslot == -2) + if (cursaveslot == -1) { F_StartGameEnd(); return; @@ -1266,7 +1266,7 @@ void F_StartGameEvaluation(void) // Save the second we enter the evaluation // We need to do this again! Remember, it's possible a mod designed skipped // the credits sequence! - if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot >= 0) + if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) G_SaveGame((UINT32)cursaveslot); gameaction = ga_nothing; diff --git a/src/g_game.c b/src/g_game.c index 7ee7ccfbf..dd0a8acb3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -76,7 +76,7 @@ INT16 gamemap = 1; INT16 maptol; UINT8 globalweather = 0; INT32 curWeather = PRECIP_NONE; -INT32 cursaveslot = -1; // Auto-save 1p savegame slot +INT32 cursaveslot = 0; // Auto-save 1p savegame slot //INT16 lastmapsaved = 0; // Last map we auto-saved at INT16 lastmaploaded = 0; // Last map the game loaded boolean gamecomplete = false; @@ -3132,7 +3132,7 @@ static void G_DoContinued(void) tokenlist = 0; token = 0; - if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && (!modifiedgame || savemoddata) && cursaveslot >= 0) + if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && (!modifiedgame || savemoddata) && cursaveslot > 0) G_SaveGameOver((UINT32)cursaveslot, true); // Reset # of lives @@ -3475,59 +3475,6 @@ void G_SaveGameData(void) #define VERSIONSIZE 16 -#ifdef SAVEGAMES_OTHERVERSIONS -static INT16 startonmapnum = 0; - -// -// User wants to load a savegame from a different version? -// -static void M_ForceLoadGameResponse(INT32 ch) -{ - if (ch != 'y' && ch != KEY_ENTER) - { - //refused - Z_Free(savebuffer); - save_p = savebuffer = NULL; - startonmapnum = 0; - M_SetupNextMenu(&SP_LoadDef); - return; - } - - // pick up where we left off. - save_p += VERSIONSIZE; - if (!P_LoadGame(startonmapnum)) - { - M_ClearMenus(true); // so ESC backs out to title - M_StartMessage(M_GetText("Savegame file corrupted\n\nPress ESC\n"), NULL, MM_NOTHING); - Command_ExitGame_f(); - Z_Free(savebuffer); - save_p = savebuffer = NULL; - startonmapnum = 0; - - // no cheating! - memset(&savedata, 0, sizeof(savedata)); - return; - } - - // done - Z_Free(savebuffer); - save_p = savebuffer = NULL; - startonmapnum = 0; - - //set cursaveslot to -1 so nothing gets saved. - cursaveslot = -1; - - displayplayer = consoleplayer; - multiplayer = splitscreen = false; - - if (setsizeneeded) - R_ExecuteSetViewSize(); - - M_ClearMenus(true); - CON_ToggleOff(); -} -#endif - // // G_InitFromSavegame // Can be called by the startup code or the menu task. @@ -3687,7 +3634,6 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) { char temp[sizeof(timeattackfolder)]; - INT32 fake; // Dummy variable UINT8 *end_p = savebuffer + length; UINT8 *lives_p; SINT8 pllives; @@ -3696,25 +3642,20 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, "version %d", VERSION); -#ifndef SAVEGAMES_OTHERVERSIONS - if (strcmp((const char *)save_p, (const char *)vcheck)) - BADSAVE; -#endif + if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE save_p += VERSIONSIZE; // P_UnArchiveMisc() (void)READINT16(save_p); CHECKPOS - fake = READUINT16(save_p)-357; // emeralds + (void)READUINT16(save_p); // emeralds CHECKPOS READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to if (strcmp(temp, timeattackfolder)) BADSAVE // P_UnArchivePlayer() CHECKPOS - (void)READUINT8(save_p); - CHECKPOS - (void)READUINT8(save_p); + (void)READUINT16(save_p); CHECKPOS WRITEUINT8(save_p, numgameovers); @@ -3733,14 +3674,6 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) CHECKPOS (void)READINT32(save_p); // continues - if (fake & (1<<10)) - { - CHECKPOS - (void)READUINT8(save_p); - CHECKPOS - (void)READUINT8(save_p); // because why not. - } - // File end marker check CHECKPOS if (READUINT8(save_p) != 0x1d) BADSAVE; @@ -3768,7 +3701,7 @@ cleanup: // void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, boolean SSSG, boolean FLS) { - UINT8 color = 0; + UINT8 color = skins[pickedchar].prefcolor; paused = false; if (demoplayback) @@ -3780,10 +3713,8 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, b if (savedata.lives > 0) { - color = savedata.skincolor; - botskin = savedata.botskin; - botcolor = savedata.botcolor; - botingame = (botskin != 0); + if ((botingame = ((botskin = savedata.botskin) != 0))) + botcolor = skins[botskin-1].prefcolor; } else if (splitscreen != SSSG) { @@ -3791,8 +3722,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, b SplitScreen_OnChange(); } - if (!color) - color = skins[pickedchar].prefcolor; + color = skins[pickedchar].prefcolor; SetPlayerSkinByNum(consoleplayer, pickedchar); CV_StealthSet(&cv_skin, skins[pickedchar].name); CV_StealthSetValue(&cv_playercolor, color); diff --git a/src/m_menu.c b/src/m_menu.c index 36b0bc54e..471012b9b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -172,7 +172,8 @@ static char joystickInfo[8][25]; static UINT32 serverlistpage; #endif -static saveinfo_t savegameinfo[MAXSAVEGAMES]; // Extra info about the save games. +static UINT8 numsaves = 0; +static saveinfo_t* savegameinfo = NULL; // Extra info about the save games. INT16 startmap; // Mario, NiGHTS, or just a plain old normal game? @@ -4406,12 +4407,12 @@ static void M_DrawLevelPlatterMenu(void) V_DrawScaledPatch(lsbasex + cursorx-17, lsbasey+50+lsoffs[0], 0, W_CachePatchName("M_CURSOR", PU_CACHE)); // handle movement of cursor box - if (abs(lsoffs[0]) > 1) + if (lsoffs[0] > 1 || lsoffs[0] < -1) lsoffs[0] = 2*lsoffs[0]/3; else lsoffs[0] = 0; - if (abs(lsoffs[1]) > 1) + if (lsoffs[1] > 1 || lsoffs[1] < -1) lsoffs[1] = 2*lsoffs[1]/3; else lsoffs[1] = 0; @@ -5395,7 +5396,7 @@ static void M_LevelSelectWarp(INT32 choice) G_LoadGame((UINT32)cursaveslot, startmap); else { - cursaveslot = -1; + cursaveslot = 0; M_SetupChoosePlayer(0); } } @@ -5970,7 +5971,7 @@ static void M_CustomWarp(INT32 choice) static void M_Credits(INT32 choice) { (void)choice; - cursaveslot = -2; + cursaveslot = -1; M_ClearMenus(true); F_StartCredits(); } @@ -6028,152 +6029,264 @@ static void M_LoadGameLevelSelect(INT32 choice) // LOAD GAME MENU // ============== -static INT32 saveSlotSelected = 0; -static short menumovedir = 0; +static INT32 saveSlotSelected = 1; +static INT32 loadgamescroll = 0; +static UINT8 loadgameoffset = 0; static void M_DrawLoadGameData(void) { - INT32 ecks; - INT32 i; + INT32 i, savetodraw, x, y; + skin_t *charskin = NULL; - ecks = SP_LoadDef.x + 24; - M_DrawTextBox(SP_LoadDef.x-12,144, 24, 4); - - if (saveSlotSelected == NOSAVESLOT) // last slot is play without saving + for (i = -2; i <= 2; i++) { - if (ultimate_selectable) + savetodraw = (saveSlotSelected + i + numsaves)%numsaves; + x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*90); + y = 33 + 9; + { - V_DrawCenteredString(ecks + 68, 144, V_ORANGEMAP, "ULTIMATE MODE"); - V_DrawCenteredString(ecks + 68, 156, 0, "NO RINGS, NO ONE-UPS,"); - V_DrawCenteredString(ecks + 68, 164, 0, "NO CONTINUES, ONE LIFE,"); - V_DrawCenteredString(ecks + 68, 172, 0, "FINAL DESTINATION."); + INT32 diff = x - (BASEVIDWIDTH/2 - 42); + if (diff < 0) + diff = -diff; + diff = (42 - diff)/3 - loadgameoffset; + if (diff < 0) + diff = 0; + y -= diff; } - else - { - V_DrawCenteredString(ecks + 68, 144, V_ORANGEMAP, "PLAY WITHOUT SAVING"); - V_DrawCenteredString(ecks + 68, 156, 0, "THIS GAME WILL NOT BE"); - V_DrawCenteredString(ecks + 68, 164, 0, "SAVED, BUT YOU CAN STILL"); - V_DrawCenteredString(ecks + 68, 172, 0, "GET EMBLEMS AND SECRETS."); - } - return; - } - - if (savegameinfo[saveSlotSelected].lives == -42) // Empty - { - V_DrawCenteredString(ecks + 68, 160, 0, "NO DATA"); - return; - } - - if (savegameinfo[saveSlotSelected].lives == -666) // savegame is bad - { - V_DrawCenteredString(ecks + 68, 144, V_REDMAP, "CORRUPT SAVE FILE"); - V_DrawCenteredString(ecks + 68, 156, 0, "THIS SAVE FILE"); - V_DrawCenteredString(ecks + 68, 164, 0, "CAN NOT BE LOADED."); - V_DrawCenteredString(ecks + 68, 172, 0, "DELETE USING BACKSPACE."); - return; - } - - // Draw the back sprite, it looks ugly if we don't - V_DrawScaledPatch(SP_LoadDef.x, 144+8, 0, livesback); - if (savegameinfo[saveSlotSelected].skincolor == 0) - V_DrawScaledPatch(SP_LoadDef.x,144+8,0,W_CachePatchName(skins[savegameinfo[saveSlotSelected].skinnum].face, PU_CACHE)); - else - { - UINT8 *colormap = R_GetTranslationColormap(savegameinfo[saveSlotSelected].skinnum, savegameinfo[saveSlotSelected].skincolor, 0); - V_DrawMappedPatch(SP_LoadDef.x,144+8,0,W_CachePatchName(skins[savegameinfo[saveSlotSelected].skinnum].face, PU_CACHE), colormap); - } - - V_DrawString(ecks + 12, 152, 0, savegameinfo[saveSlotSelected].playername); - -#ifdef SAVEGAMES_OTHERVERSIONS - if (savegameinfo[saveSlotSelected].gamemap & 16384) - V_DrawCenteredString(ecks + 68, 144, V_REDMAP, "OUTDATED SAVE FILE!"); -#endif - - if (savegameinfo[saveSlotSelected].gamemap & 8192) - V_DrawString(ecks + 12, 160, V_GREENMAP, "CLEAR!"); - else - V_DrawString(ecks + 12, 160, 0, va("%s", savegameinfo[saveSlotSelected].levelname)); - - // Use the big face pic for lives, duh. :3 - V_DrawScaledPatch(ecks + 12, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); - if (savegameinfo[saveSlotSelected].lives == 0x7F) - V_DrawScaledPatch(ecks + 40 - 17, 172, 0, tallinfin); - else - V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); - - // Absolute ridiculousness, condensed into another function. - V_DrawContinueIcon(ecks + 58, 182, 0, savegameinfo[saveSlotSelected].skinnum, savegameinfo[saveSlotSelected].skincolor); - V_DrawScaledPatch(ecks + 68, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); - V_DrawTallNum(ecks + 96, 172, 0, savegameinfo[saveSlotSelected].continues); - - for (i = 0; i < 7; ++i) - { - if (savegameinfo[saveSlotSelected].numemeralds & (1 << i)) - V_DrawScaledPatch(ecks + 104 + (i * 8), 172, 0, tinyemeraldpics[i]); - } -} - -#define LOADBARHEIGHT SP_LoadDef.y + (LINEHEIGHT * (j+1)) + ymod -#define CURSORHEIGHT SP_LoadDef.y + (LINEHEIGHT*3) - 1 -static void M_DrawLoad(void) -{ - INT32 i, j; - INT32 ymod = 0, offset = 0; - - M_DrawMenuTitle(); - - if (menumovedir != 0) //movement illusion - { - ymod = (-(LINEHEIGHT/4))*menumovedir; - offset = ((menumovedir > 0) ? -1 : 1); - } - - V_DrawCenteredString(BASEVIDWIDTH/2, 40, 0, "Press backspace to delete a save."); - - for (i = MAXSAVEGAMES + saveSlotSelected - 2 + offset, j = 0;i <= MAXSAVEGAMES + saveSlotSelected + 2 + offset; i++, j++) - { - if ((menumovedir < 0 && j == 4) || (menumovedir > 0 && j == 0)) - continue; //this helps give the illusion of movement - - M_DrawSaveLoadBorder(SP_LoadDef.x, LOADBARHEIGHT); - - if ((i%MAXSAVEGAMES) == NOSAVESLOT) // play without saving + + if (savetodraw == 0) { + V_DrawSmallScaledPatch(x, y, 0, + W_CachePatchName("SAVENONE", PU_CACHE)); + x += 2; + y += 1; + V_DrawString(x, y, + ((savetodraw == saveSlotSelected) ? V_YELLOWMAP : 0), + "NO FILE"); + if (savetodraw == saveSlotSelected) + V_DrawFill(x, y+9, 80, 1, yellowmap[3]); + y += 11; + V_DrawSmallScaledPatch(x, y, V_STATIC, + W_CachePatchName("BLACKLVL", PU_CACHE)); + y += 41; if (ultimate_selectable) - V_DrawCenteredString(SP_LoadDef.x+92, LOADBARHEIGHT - 1, V_ORANGEMAP, "ULTIMATE MODE"); + V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "ULTIMATE."); else - V_DrawCenteredString(SP_LoadDef.x+92, LOADBARHEIGHT - 1, V_ORANGEMAP, "PLAY WITHOUT SAVING"); + V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "DON'T SAVE!"); continue; } - if (savegameinfo[i%MAXSAVEGAMES].lives == -42) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, V_TRANSLUCENT, "NO DATA"); - else if (savegameinfo[i%MAXSAVEGAMES].lives == -666) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, V_REDMAP, "CORRUPT SAVE FILE"); - else if (savegameinfo[i%MAXSAVEGAMES].gamemap & 8192) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, V_GREENMAP, "CLEAR!"); - else - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, 0, va("%s", savegameinfo[i%MAXSAVEGAMES].levelname)); + savetodraw--; - //Draw the save slot number on the right side - V_DrawRightAlignedString(SP_LoadDef.x+192, LOADBARHEIGHT - 1, 0, va("%d",(i%MAXSAVEGAMES) + 1)); + // signpost background + { + UINT8 col; + if (savegameinfo[savetodraw].botskin == 3) // & knuckles + col = 105; + else if (savegameinfo[savetodraw].botskin) // tailsbot or custom + col = 134; + else if (savegameinfo[savetodraw].lives == -42) + col = 26; + else if (savegameinfo[savetodraw].lives == -666) + col = 47; + else + { + charskin = &skins[savegameinfo[savetodraw].skinnum]; + col = (charskin->prefcolor - 1)*2; + col = Color_Index[Color_Opposite[col]-1][Color_Opposite[col+1]]; + } + + V_DrawFill(x+6, y+64, 72, 50, col); + } + + V_DrawSmallScaledPatch(x, y, 0, + W_CachePatchName("SAVEBACK", PU_CACHE)); + x += 2; + y += 1; + V_DrawString(x, y, + ((savetodraw == saveSlotSelected-1) ? V_YELLOWMAP : 0), + va("FILE %d", savetodraw+1)); + if (savetodraw == saveSlotSelected-1) + V_DrawFill(x, y+9, 80, 1, yellowmap[3]); + y += 11; + + // level image area + { + patch_t *patch; + INT32 flags = 0; + + if ((savegameinfo[savetodraw].lives == -42) + || (savegameinfo[savetodraw].lives == -666)) + { + patch = W_CachePatchName("BLACKLVL", PU_CACHE); + flags = V_STATIC; + } + else if (savegameinfo[savetodraw].gamemap & 8192) + patch = W_CachePatchName("GAMEDONE", PU_CACHE); + else + { + lumpnum_t lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName((savegameinfo[savetodraw].gamemap) & 8191))); + if (lumpnum != LUMPERROR) + patch = W_CachePatchNum(lumpnum, PU_CACHE); + else + patch = W_CachePatchName("BLANKLVL", PU_CACHE); + } + + V_DrawSmallScaledPatch(x, y, flags, patch); + + y += 41; + + if (savegameinfo[savetodraw].lives == -42) + V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "NEW GAME"); + else if (savegameinfo[savetodraw].lives == -666) + V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "CAN'T LOAD!"); + else if (savegameinfo[savetodraw].gamemap & 8192) + V_DrawRightAlignedThinString(x + 79, y, V_GREENMAP, "CLEAR!"); + else + V_DrawRightAlignedThinString(x + 79, y, V_YELLOWMAP, savegameinfo[savetodraw].levelname); + } + + if ((savegameinfo[savetodraw].lives == -42) + || (savegameinfo[savetodraw].lives == -666)) + continue; + + y += 51; + + // character heads, lives, and continues + { + spritedef_t *sprdef; + spriteframe_t *sprframe; + patch_t *patch; + UINT8 *colormap = NULL; + + INT32 tempx = (x+40)<sprites[SPR2_SIGN]; + if (!sprdef->numframes) + goto skipbot; + colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin, charbotskin->prefcolor, 0); + sprframe = &sprdef->spriteframes[0]; + patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + + V_DrawFixedPatch( + tempx + (18<highresscale, + 0, patch, colormap); + + Z_Free(colormap); + + tempx -= (15<sprites[SPR2_SIGN]; + colormap = R_GetTranslationColormap(savegameinfo[savetodraw].skinnum, charskin->prefcolor, 0); + if (!sprdef->numframes) + goto skipsign; + sprframe = &sprdef->spriteframes[0]; + patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + + V_DrawFixedPatch( + tempx, + tempy, + charskin->highresscale, + flip, patch, colormap); + +skipsign: + y += 25; + + tempx = x + 10; + if (savegameinfo[savetodraw].lives != 0x7f + && savegameinfo[savetodraw].lives > 9) + tempx -= 4; + + if (!charskin) // shut up compiler + goto skiplife; + + // lives + sprdef = &charskin->sprites[SPR2_LIFE]; + if (!sprdef->numframes) + goto skiplife; + sprframe = &sprdef->spriteframes[0]; + patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + + V_DrawFixedPatch( + (tempx + 4)<highresscale/2, + 0, patch, colormap); +skiplife: + if (colormap) + Z_Free(colormap); + + patch = W_CachePatchName("STLIVEX", PU_CACHE); + + V_DrawScaledPatch(tempx + 9, y + 2, 0, patch); + tempx += 16; + if (savegameinfo[savetodraw].lives == 0x7f) + V_DrawCharacter(tempx, y + 1, '\x16', false); + else + V_DrawString(tempx, y, 0, va("%d", savegameinfo[savetodraw].lives)); + + tempx = x + 47; + if (savegameinfo[savetodraw].continues > 9) + tempx -= 4; + + // continues + if (savegameinfo[savetodraw].continues > 0) + { + V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTSAVE", PU_CACHE)); + V_DrawScaledPatch(tempx + 9, y + 2, 0, patch); + V_DrawString(tempx + 16, y, 0, va("%d", savegameinfo[savetodraw].continues)); + } + else + { + V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTNONE", PU_CACHE)); + V_DrawScaledPatch(tempx + 9, y + 2, 0, W_CachePatchName("STNONEX", PU_CACHE)); + V_DrawString(tempx + 16, y, V_GRAYMAP, "0"); + } + } + + x += 6; + y -= 12; + + // tiny emeralds + { + INT32 j; + for (j = 0; j < 7; ++j) + { + if (savegameinfo[savetodraw].numemeralds & (1 << j)) + V_DrawScaledPatch(x, y, 0, tinyemeraldpics[j]); + x += 10; + } + } } +} - //Draw cursors on both sides. - V_DrawScaledPatch( 32, CURSORHEIGHT, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); - V_DrawScaledPatch(274, CURSORHEIGHT, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); +static void M_DrawLoad(void) +{ + M_DrawMenuTitle(); + + if (loadgamescroll > 1 || loadgamescroll < -1) + loadgamescroll = 2*loadgamescroll/3; + else + loadgamescroll = 0; + + if (loadgameoffset > 1) + loadgameoffset = 2*loadgameoffset/3; + else + loadgameoffset = 0; M_DrawLoadGameData(); - - //finishing the movement illusion - if (menumovedir) - menumovedir += ((menumovedir > 0) ? 1 : -1); - if (abs(menumovedir) > 3) - menumovedir = 0; } -#undef LOADBARHEIGHT -#undef CURSORHEIGHT // // User wants to load this game @@ -6185,7 +6298,7 @@ static void M_LoadSelect(INT32 choice) if (saveSlotSelected == NOSAVESLOT) //last slot is play without saving { M_NewGame(); - cursaveslot = -1; + cursaveslot = 0; return; } @@ -6194,8 +6307,8 @@ static void M_LoadSelect(INT32 choice) // This slot is empty, so start a new game here. M_NewGame(); } - else if (savegameinfo[saveSlotSelected].gamemap & 8192) // Completed - M_LoadGameLevelSelect(saveSlotSelected + 1); + else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed + M_LoadGameLevelSelect(0); else G_LoadGame((UINT32)saveSlotSelected, 0); @@ -6217,12 +6330,11 @@ static void M_ReadSavegameInfo(UINT32 slot) INT32 fake; // Dummy variable char temp[sizeof(timeattackfolder)]; char vcheck[VERSIONSIZE]; -#ifdef SAVEGAMES_OTHERVERSIONS - boolean oldversion = false; -#endif sprintf(savename, savegamename, slot); + slot--; + length = FIL_ReadFile(savename, &savebuffer); if (length == 0) { @@ -6238,14 +6350,7 @@ static void M_ReadSavegameInfo(UINT32 slot) // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, "version %d", VERSION); - if (strcmp((const char *)save_p, (const char *)vcheck)) - { -#ifdef SAVEGAMES_OTHERVERSIONS - oldversion = true; -#else - BADSAVE // Incompatible versions? -#endif - } + if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE save_p += VERSIONSIZE; // dearchive all the modifications @@ -6267,20 +6372,10 @@ static void M_ReadSavegameInfo(UINT32 slot) savegameinfo[slot].actnum = mapheaderinfo[(fake-1) & 8191]->actnum; } -#ifdef SAVEGAMES_OTHERVERSIONS - if (oldversion) - { - if (fake == 24) //meh, let's count old Clear! saves too - fake |= 8192; - fake |= 16384; // marker for outdated version - } -#endif savegameinfo[slot].gamemap = fake; CHECKPOS - fake = READUINT16(save_p)-357; // emeralds - - savegameinfo[slot].numemeralds = (UINT8)fake; + savegameinfo[slot].numemeralds = READUINT16(save_p)-357; // emeralds CHECKPOS READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to @@ -6289,11 +6384,15 @@ static void M_ReadSavegameInfo(UINT32 slot) // P_UnArchivePlayer() CHECKPOS - savegameinfo[slot].skincolor = READUINT8(save_p); - - CHECKPOS - savegameinfo[slot].skinnum = READUINT8(save_p); - if (savegameinfo[slot].skinnum >= numskins) BADSAVE + fake = READUINT16(save_p); + savegameinfo[slot].skinnum = fake & ((1<<5) - 1); + if (savegameinfo[slot].skinnum >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].skinnum)) + BADSAVE + savegameinfo[slot].botskin = fake >> 5; + if (savegameinfo[slot].botskin-1 >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) + savegameinfo[slot].botskin = 0; CHECKPOS (void)READUINT8(save_p); // numgameovers @@ -6304,27 +6403,6 @@ static void M_ReadSavegameInfo(UINT32 slot) CHECKPOS savegameinfo[slot].continues = READINT32(save_p); // continues - if (fake & (1<<10)) - { - CHECKPOS - savegameinfo[slot].botskin = READUINT8(save_p); - if (savegameinfo[slot].botskin-1 >= numskins) - savegameinfo[slot].botskin = 0; - CHECKPOS - savegameinfo[slot].botcolor = READUINT8(save_p); // because why not. - } - else - savegameinfo[slot].botskin = 0; - - if (savegameinfo[slot].botskin) - snprintf(savegameinfo[slot].playername, 32, "%s & %s", - skins[savegameinfo[slot].skinnum].realname, - skins[savegameinfo[slot].botskin-1].realname); - else - strcpy(savegameinfo[slot].playername, skins[savegameinfo[slot].skinnum].realname); - - savegameinfo[slot].playername[31] = 0; - // File end marker check CHECKPOS if (READUINT8(save_p) != 0x1d) BADSAVE; @@ -6343,21 +6421,45 @@ static void M_ReadSavegameInfo(UINT32 slot) static void M_ReadSaveStrings(void) { FILE *handle; - UINT32 i; + SINT8 i; char name[256]; + boolean nofile[MAXSAVEGAMES-1]; + UINT8 tolerance = 0; - for (i = 0; i < MAXSAVEGAMES; i++) + loadgamescroll = 0; + loadgameoffset = 14; + + for (i = 1; ((i < MAXSAVEGAMES) && ((i <= saveSlotSelected) || (tolerance < 3))); i++) // slot 0 is no save { snprintf(name, sizeof name, savegamename, i); name[sizeof name - 1] = '\0'; handle = fopen(name, "rb"); - if (handle == NULL) + if ((nofile[i-1] = (handle == NULL))) { - savegameinfo[i].lives = -42; + tolerance++; continue; } fclose(handle); + tolerance = 0; + } + + if (savegameinfo) + Z_Free(savegameinfo); + savegameinfo = NULL; + + numsaves = i; + savegameinfo = Z_Realloc(savegameinfo, numsaves*sizeof(saveinfo_t), PU_STATIC, NULL); + if (!savegameinfo) + I_Error("Insufficient memory to prepare save platter"); + + for (; i > 0; i--) + { + if (nofile[i-1] == true) + { + savegameinfo[i-1].lives = -42; + continue; + } M_ReadSavegameInfo(i); } } @@ -6377,8 +6479,8 @@ static void M_SaveGameDeleteResponse(INT32 ch) name[sizeof name - 1] = '\0'; remove(name); - // Refresh savegame menu info - M_ReadSaveStrings(); + S_StartSound(NULL, sfx_bewar1+M_RandomKey(4)); // Bweh heh he + M_ReadSaveStrings(); // reload the menu } static void M_HandleLoadSave(INT32 choice) @@ -6387,26 +6489,33 @@ static void M_HandleLoadSave(INT32 choice) switch (choice) { - case KEY_DOWNARROW: - S_StartSound(NULL, sfx_menu1); + case KEY_RIGHTARROW: + S_StartSound(NULL, sfx_s3kb7); ++saveSlotSelected; - if (saveSlotSelected >= MAXSAVEGAMES) - saveSlotSelected -= MAXSAVEGAMES; - menumovedir = 1; + if (saveSlotSelected >= numsaves) + saveSlotSelected -= numsaves; + loadgamescroll = 90; break; - case KEY_UPARROW: - S_StartSound(NULL, sfx_menu1); + case KEY_LEFTARROW: + S_StartSound(NULL, sfx_s3kb7); --saveSlotSelected; if (saveSlotSelected < 0) - saveSlotSelected += MAXSAVEGAMES; - menumovedir = -1; + saveSlotSelected += numsaves; + loadgamescroll = -90; break; case KEY_ENTER: - S_StartSound(NULL, sfx_menu1); - if (savegameinfo[saveSlotSelected].lives != -666) // don't allow loading of "bad saves" + if (savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" + { + S_StartSound(NULL, sfx_menu1); M_LoadSelect(saveSlotSelected); + } + else if (!loadgameoffset) + { + S_StartSound(NULL, sfx_s3kb2); + loadgameoffset = 14; + } break; case KEY_ESCAPE: @@ -6414,11 +6523,19 @@ static void M_HandleLoadSave(INT32 choice) break; case KEY_BACKSPACE: - S_StartSound(NULL, sfx_menu1); // Don't allow people to 'delete' "Play without Saving." // Nor allow people to 'delete' slots with no saves in them. - if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected].lives != -42) + if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected-1].lives != -42) + { + loadgamescroll = 0; + S_StartSound(NULL, sfx_skid); M_StartMessage(M_GetText("Are you sure you want to delete\nthis save game?\n\n(Press 'Y' to confirm)\n"),M_SaveGameDeleteResponse,MM_YESNO); + } + else if (!loadgameoffset) + { + S_StartSound(NULL, sfx_s3kb2); + loadgameoffset = 14; + } break; } if (exitmenu) @@ -6427,6 +6544,8 @@ static void M_HandleLoadSave(INT32 choice) M_SetupNextMenu(currentMenu->prevMenu); else M_ClearMenus(true); + Z_Free(savegameinfo); + savegameinfo = NULL; } } @@ -6451,9 +6570,9 @@ void M_ForceSaveSlotSelected(INT32 sslot) return; // Figure out whether to display up movement or down movement - menumovedir = (saveSlotSelected - sslot) > 0 ? -1 : 1; + /*menumovedir = (saveSlotSelected - sslot) > 0 ? -1 : 1; if (abs(saveSlotSelected - sslot) > (MAXSAVEGAMES>>1)) - menumovedir *= -1; + menumovedir *= -1;*/ saveSlotSelected = sslot; } @@ -6724,7 +6843,7 @@ static void M_ChoosePlayer(INT32 choice) } if (startmap != spstage_start) - cursaveslot = -1; + cursaveslot = 0; //lastmapsaved = 0; gamecomplete = false; @@ -6735,6 +6854,10 @@ static void M_ChoosePlayer(INT32 choice) if (levelselect.rows) Z_Free(levelselect.rows); levelselect.rows = NULL; + + if (savegameinfo) + Z_Free(savegameinfo); + savegameinfo = NULL; } // =============== diff --git a/src/m_menu.h b/src/m_menu.h index 2d2d3378b..e30724041 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -215,13 +215,10 @@ typedef struct // savegame struct for save game menu typedef struct { - char playername[32]; char levelname[32]; UINT8 actnum; - UINT8 skincolor; UINT8 skinnum; UINT8 botskin; - UINT8 botcolor; UINT8 numemeralds; INT32 lives; INT32 continues; @@ -237,7 +234,7 @@ extern INT16 startmap; extern INT32 ultimate_selectable; #define MAXSAVEGAMES 31 //note: last save game is "no save" -#define NOSAVESLOT MAXSAVEGAMES-1 //slot where Play Without Saving appears +#define NOSAVESLOT 0 //slot where Play Without Saving appears void M_ForceSaveSlotSelected(INT32 sslot); diff --git a/src/p_inter.c b/src/p_inter.c index f356c642c..5eee6a18e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2293,7 +2293,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && numgameovers < maxgameovers) { numgameovers++; - if ((!modifiedgame || savemoddata) && cursaveslot >= 0) + if ((!modifiedgame || savemoddata) && cursaveslot > 0) G_SaveGameOver((UINT32)cursaveslot, (target->player->continues <= 0)); } } diff --git a/src/p_saveg.c b/src/p_saveg.c index 9e1206c49..840f546af 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -64,23 +64,16 @@ typedef enum static inline void P_ArchivePlayer(void) { const player_t *player = &players[consoleplayer]; + INT16 skininfo = player->skin + (botskin<<5); SINT8 pllives = player->lives; if (pllives < startinglivesbalance[numgameovers]) // Bump up to 3 lives if the player pllives = startinglivesbalance[numgameovers]; // has less than that. - WRITEUINT8(save_p, player->skincolor); - WRITEUINT8(save_p, player->skin); - + WRITEUINT16(save_p, skininfo); WRITEUINT8(save_p, numgameovers); WRITESINT8(save_p, pllives); WRITEUINT32(save_p, player->score); WRITEINT32(save_p, player->continues); - - if (botskin) - { - WRITEUINT8(save_p, botskin); - WRITEUINT8(save_p, botcolor); - } } // @@ -88,23 +81,14 @@ static inline void P_ArchivePlayer(void) // static inline void P_UnArchivePlayer(void) { - savedata.skincolor = READUINT8(save_p); - savedata.skin = READUINT8(save_p); + INT16 skininfo = READUINT16(save_p); + savedata.skin = skininfo & ((1<<5) - 1); + savedata.botskin = skininfo >> 5; savedata.numgameovers = READUINT8(save_p); savedata.lives = READSINT8(save_p); savedata.score = READUINT32(save_p); savedata.continues = READINT32(save_p); - - if (savedata.botcolor) - { - savedata.botskin = READUINT8(save_p); - if (savedata.botskin-1 >= numskins) - savedata.botskin = 0; - savedata.botcolor = READUINT8(save_p); - } - else - savedata.botskin = 0; } // @@ -3164,7 +3148,7 @@ static inline void P_ArchiveMisc(void) //lastmapsaved = gamemap; lastmaploaded = gamemap; - WRITEUINT16(save_p, (botskin ? (emeralds|(1<<10)) : emeralds)+357); + WRITEUINT16(save_p, emeralds+357); WRITESTRINGN(save_p, timeattackfolder, sizeof(timeattackfolder)); } @@ -3194,9 +3178,6 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) token = 0; savedata.emeralds = READUINT16(save_p)-357; - if (savedata.emeralds & (1<<10)) - savedata.botcolor = 0xFF; - savedata.emeralds &= 0xff; READSTRINGN(save_p, testname, sizeof(testname)); diff --git a/src/p_saveg.h b/src/p_saveg.h index 376552c95..5960660ab 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -30,10 +30,8 @@ mobj_t *P_FindNewPosition(UINT32 oldposition); typedef struct { - UINT8 skincolor; UINT8 skin; UINT8 botskin; - UINT8 botcolor; INT32 score; INT32 lives; INT32 continues; diff --git a/src/p_setup.c b/src/p_setup.c index c131f6677..1a8c3e5ba 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3019,7 +3019,7 @@ boolean P_SetupLevel(boolean skipprecip) P_RunCachedActions(); if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || players[consoleplayer].lives <= 0) - && (!modifiedgame || savemoddata) && cursaveslot >= 0 && CanSaveLevel(gamemap)) + && (!modifiedgame || savemoddata) && cursaveslot > 0 && CanSaveLevel(gamemap)) G_SaveGame((UINT32)cursaveslot); lastmaploaded = gamemap; // HAS to be set after saving!! @@ -3030,9 +3030,8 @@ boolean P_SetupLevel(boolean skipprecip) players[consoleplayer].continues = savedata.continues; players[consoleplayer].lives = savedata.lives; players[consoleplayer].score = savedata.score; - botskin = savedata.botskin; - botcolor = savedata.botcolor; - botingame = (savedata.botskin != 0); + if ((botingame = ((botskin = savedata.botskin) != 0))) + botcolor = skins[botskin-1].prefcolor; emeralds = savedata.emeralds; savedata.lives = 0; } @@ -3201,8 +3200,8 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) ST_Start(); // Prevent savefile cheating - if (cursaveslot >= 0) - cursaveslot = -1; + if (cursaveslot > 0) + cursaveslot = 0; if (replacedcurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer)) { diff --git a/src/v_video.c b/src/v_video.c index 6ac101f2d..b07237d74 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1422,9 +1422,9 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) else w = SHORT(hu_font[c]->width) * dupx; - if (cx + w > scrwidth) + if (cx > scrwidth) break; - if (cx < 0) //left boundary check + if (cx + w < 0) //left boundary check { cx += w; continue; @@ -1628,9 +1628,9 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) else w = (SHORT(tny_font[c]->width) * dupx); - if (cx + w > scrwidth) + if (cx > scrwidth) break; - if (cx < 0) //left boundary check + if (cx + w < 0) //left boundary check { cx += w; continue; From 6e7605e4f3a16d35dceccaa1b73af545e8702fe5 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 21 Aug 2017 16:02:13 +0100 Subject: [PATCH 04/12] * Add new graphics for the no save and ultimate slots, and make the invalid files look a little different. * Push big endsign images downwards. * Add a way to disable the ultimate slot. * BwehHehHe() --- src/m_menu.c | 111 +++++++++++++++++++++++++++++++++------------------ src/m_menu.h | 2 + 2 files changed, 74 insertions(+), 39 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 471012b9b..480ec7ca2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4094,6 +4094,24 @@ static boolean M_PrepareLevelPlatter(INT32 gt) mapnum++; } +#ifdef SYMMETRICAL_PLATTER + // horizontally space out rows with missing right sides + for (; row >= 0; row--) + { + if (!levelselect.rows[row].maplist[2] // no right side + && levelselect.rows[row].maplist[0] && levelselect.rows[row].maplist[1]) // all the left filled in + { + levelselect.rows[row].maplist[2] = levelselect.rows[row].maplist[1]; + STRBUFCPY(levelselect.rows[row].mapnames[2], levelselect.rows[row].mapnames[1]); + levelselect.rows[row].mapavailable[2] = levelselect.rows[row].mapavailable[1]; + + levelselect.rows[row].maplist[1] = -1; // diamond + levelselect.rows[row].mapnames[1][0] = '\0'; + levelselect.rows[row].mapavailable[1] = false; + } + } +#endif + if (levselp[0][0]) // never going to have some provided but not all, saves individually checking { W_UnlockCachedPatch(levselp[0][0]); @@ -4231,7 +4249,7 @@ static void M_HandleLevelPlatter(INT32 choice) else if (!lsoffs[0]) // prevent sound spam { lsoffs[0] = -8; - S_StartSound(NULL,sfx_s3kb2); + S_StartSound(NULL,sfx_lose); } break; @@ -4277,7 +4295,7 @@ static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, bo patch_t *patch; INT32 map = levelselect.rows[row].maplist[col]; - if (!map) + if (map <= 0) return; // A 564x100 image of the level as entry MAPxxW @@ -4318,7 +4336,7 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea patch_t *patch; INT32 map = levelselect.rows[row].maplist[col]; - if (!map) + if (map <= 0) return; // A 160x100 image of the level as entry MAPxxP @@ -4403,7 +4421,7 @@ static void M_DrawLevelPlatterMenu(void) // draw cursor box V_DrawSmallScaledPatch(lsbasex + cursorx + lsoffs[1], lsbasey, 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)])); - if (levelselect.rows[lsrow].maplist[lscol]) + if (levelselect.rows[lsrow].maplist[lscol] > 0) V_DrawScaledPatch(lsbasex + cursorx-17, lsbasey+50+lsoffs[0], 0, W_CachePatchName("M_CURSOR", PU_CACHE)); // handle movement of cursor box @@ -6057,7 +6075,7 @@ static void M_DrawLoadGameData(void) if (savetodraw == 0) { V_DrawSmallScaledPatch(x, y, 0, - W_CachePatchName("SAVENONE", PU_CACHE)); + W_CachePatchName(((ultimate_selectable) ? "ULTIMATE" : "SAVENONE"), PU_CACHE)); x += 2; y += 1; V_DrawString(x, y, @@ -6067,7 +6085,7 @@ static void M_DrawLoadGameData(void) V_DrawFill(x, y+9, 80, 1, yellowmap[3]); y += 11; V_DrawSmallScaledPatch(x, y, V_STATIC, - W_CachePatchName("BLACKLVL", PU_CACHE)); + W_CachePatchName("BLACXLVL", PU_CACHE)); y += 41; if (ultimate_selectable) V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "ULTIMATE."); @@ -6078,25 +6096,33 @@ static void M_DrawLoadGameData(void) savetodraw--; + if (savegameinfo[savetodraw].lives > 0) + charskin = &skins[savegameinfo[savetodraw].skinnum]; + // signpost background { UINT8 col; - if (savegameinfo[savetodraw].botskin == 3) // & knuckles - col = 105; - else if (savegameinfo[savetodraw].botskin) // tailsbot or custom - col = 134; - else if (savegameinfo[savetodraw].lives == -42) - col = 26; - else if (savegameinfo[savetodraw].lives == -666) - col = 47; + if (savegameinfo[savetodraw].lives == -666) + { + V_DrawSmallScaledPatch(x+2, y+64, 0, + W_CachePatchName("BLANKLVL", PU_CACHE)); + } else { - charskin = &skins[savegameinfo[savetodraw].skinnum]; - col = (charskin->prefcolor - 1)*2; - col = Color_Index[Color_Opposite[col]-1][Color_Opposite[col+1]]; - } + if (savegameinfo[savetodraw].lives == -42) + col = 26; + else if (savegameinfo[savetodraw].botskin == 3) // & knuckles + col = 105; + else if (savegameinfo[savetodraw].botskin) // tailsbot or custom + col = 134; + else + { + col = (charskin->prefcolor - 1)*2; + col = Color_Index[Color_Opposite[col]-1][Color_Opposite[col+1]]; + } - V_DrawFill(x+6, y+64, 72, 50, col); + V_DrawFill(x+6, y+64, 72, 50, col); + } } V_DrawSmallScaledPatch(x, y, 0, @@ -6150,7 +6176,20 @@ static void M_DrawLoadGameData(void) || (savegameinfo[savetodraw].lives == -666)) continue; - y += 51; + y += 64; + + // tiny emeralds + { + INT32 j, workx = x + 6; + for (j = 0; j < 7; ++j) + { + if (savegameinfo[savetodraw].numemeralds & (1 << j)) + V_DrawScaledPatch(workx, y, 0, tinyemeraldpics[j]); + workx += 10; + } + } + + y -= 13; // character heads, lives, and continues { @@ -6159,7 +6198,7 @@ static void M_DrawLoadGameData(void) patch_t *patch; UINT8 *colormap = NULL; - INT32 tempx = (x+40)<spriteframes[0]; patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + if ((calc = SHORT(patch->topoffset) - 42) > 0) + tempy += ((4+calc)< Date: Tue, 22 Aug 2017 21:02:33 +0100 Subject: [PATCH 05/12] * Fix an issue where valid savefiles would be hidden because there were at least three unused slots between that and the last visible save. In the process, made sure there were at least three slots visible at all times, but never show extras not needed to show all the saves. * Optimisations in a bunch of places, including to static * Fix some visual errors with text and patches near the edges of the screen in non-standard resolutions. --- src/m_menu.c | 120 ++++++++++++++++++++++++++------------------------ src/v_video.c | 92 ++++++++++++++++++++++++-------------- 2 files changed, 121 insertions(+), 91 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 480ec7ca2..214755651 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -174,6 +174,7 @@ static UINT32 serverlistpage; static UINT8 numsaves = 0; static saveinfo_t* savegameinfo = NULL; // Extra info about the save games. +static patch_t *savselp[7]; INT16 startmap; // Mario, NiGHTS, or just a plain old normal game? @@ -223,7 +224,7 @@ static INT32 lsoffs[2]; #define lshli levelselectselect[2] #define lshseperation 101 -#define lsbasevseperation 62 +#define lsbasevseperation (62*vid.height)/(BASEVIDHEIGHT*vid.dupy) //62 #define lsheadingheight 16 #define getheadingoffset(row) (levelselect.rows[row].header[0] ? lsheadingheight : 0) #define lsvseperation(row) lsbasevseperation + getheadingoffset(row) @@ -4280,14 +4281,10 @@ void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlig y += lsheadingheight - 12; V_DrawString(19, y, (headerhighlight ? V_YELLOWMAP : 0)|(allowlowercase ? V_ALLOWLOWERCASE : 0), header); y += 9; - if ((y >= 0) && (y < 200)) - { - V_DrawFill(19, y, 281, 1, (headerhighlight ? yellowmap[3] : 3)); - V_DrawFill(300, y, 1, 1, 26); - } + V_DrawFill(19, y, 281, 1, (headerhighlight ? yellowmap[3] : 3)); + V_DrawFill(300, y, 1, 1, 26); y++; - if ((y >= 0) && (y < 200)) - V_DrawFill(19, y, 282, 1, 26); + V_DrawFill(19, y, 282, 1, 26); } static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolean highlight) @@ -4311,22 +4308,9 @@ static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, bo V_DrawSmallScaledPatch(x, y, 0, patch); } - if ((y+50) < 200) - { - INT32 topy = (y+50), h = 8; - - if (topy < 0) - { - h += topy; - topy = 0; - } - else if (topy + h >= 200) - h = 200 - y; - if (h > 0) - V_DrawFill(x, topy, 282, h, - ((mapheaderinfo[map-1]->unlockrequired < 0) - ? 159 : 63)); - } + V_DrawFill(x, y+50, 282, 8, + ((mapheaderinfo[map-1]->unlockrequired < 0) + ? 159 : 63)); V_DrawString(x, y+50, (highlight ? V_YELLOWMAP : 0), levelselect.rows[row].mapnames[col]); } @@ -4352,22 +4336,9 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea V_DrawSmallScaledPatch(x, y, 0, patch); } - if ((y+50) < 200) - { - INT32 topy = (y+50), h = 8; - - if (topy < 0) - { - h += topy; - topy = 0; - } - else if (topy + h >= 200) - h = 200 - y; - if (h > 0) - V_DrawFill(x, topy, 80, h, - ((mapheaderinfo[map-1]->unlockrequired < 0) - ? 159 : 63)); - } + V_DrawFill(x, y+50, 80, 8, + ((mapheaderinfo[map-1]->unlockrequired < 0) + ? 159 : 63)); if (strlen(levelselect.rows[row].mapnames[col]) > 6) // "AERIAL GARDEN" vs "ACT 18" - "THE ACT" intentionally compressed V_DrawThinString(x, y+50, (highlight ? V_YELLOWMAP : 0), levelselect.rows[row].mapnames[col]); @@ -6053,13 +6024,16 @@ static UINT8 loadgameoffset = 0; static void M_DrawLoadGameData(void) { - INT32 i, savetodraw, x, y; + INT32 i, savetodraw, x, y, hsep = 90; skin_t *charskin = NULL; + if (vid.width != BASEVIDWIDTH*vid.dupx) + hsep = (hsep*vid.width)/(BASEVIDWIDTH*vid.dupx); + for (i = -2; i <= 2; i++) { savetodraw = (saveSlotSelected + i + numsaves)%numsaves; - x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*90); + x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*hsep); y = 33 + 9; { @@ -6075,7 +6049,7 @@ static void M_DrawLoadGameData(void) if (savetodraw == 0) { V_DrawSmallScaledPatch(x, y, 0, - W_CachePatchName(((ultimate_selectable) ? "ULTIMATE" : "SAVENONE"), PU_CACHE)); + savselp[((ultimate_selectable) ? 2 : 1)]); x += 2; y += 1; V_DrawString(x, y, @@ -6084,8 +6058,7 @@ static void M_DrawLoadGameData(void) if (savetodraw == saveSlotSelected) V_DrawFill(x, y+9, 80, 1, yellowmap[3]); y += 11; - V_DrawSmallScaledPatch(x, y, V_STATIC, - W_CachePatchName("BLACXLVL", PU_CACHE)); + V_DrawSmallScaledPatch(x, y, V_STATIC, savselp[4]); y += 41; if (ultimate_selectable) V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "ULTIMATE."); @@ -6104,8 +6077,7 @@ static void M_DrawLoadGameData(void) UINT8 col; if (savegameinfo[savetodraw].lives == -666) { - V_DrawSmallScaledPatch(x+2, y+64, 0, - W_CachePatchName("BLANKLVL", PU_CACHE)); + V_DrawSmallScaledPatch(x+2, y+64, 0, savselp[5]); } else { @@ -6125,8 +6097,7 @@ static void M_DrawLoadGameData(void) } } - V_DrawSmallScaledPatch(x, y, 0, - W_CachePatchName("SAVEBACK", PU_CACHE)); + V_DrawSmallScaledPatch(x, y, 0, savselp[0]); x += 2; y += 1; V_DrawString(x, y, @@ -6144,18 +6115,18 @@ static void M_DrawLoadGameData(void) if ((savegameinfo[savetodraw].lives == -42) || (savegameinfo[savetodraw].lives == -666)) { - patch = W_CachePatchName("BLACKLVL", PU_CACHE); + patch = savselp[3]; flags = V_STATIC; } else if (savegameinfo[savetodraw].gamemap & 8192) - patch = W_CachePatchName("GAMEDONE", PU_CACHE); + patch = savselp[6]; else { lumpnum_t lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName((savegameinfo[savetodraw].gamemap) & 8191))); if (lumpnum != LUMPERROR) patch = W_CachePatchNum(lumpnum, PU_CACHE); else - patch = W_CachePatchName("BLANKLVL", PU_CACHE); + patch = savselp[5]; } V_DrawSmallScaledPatch(x, y, flags, patch); @@ -6451,30 +6422,42 @@ static void M_ReadSaveStrings(void) SINT8 i; char name[256]; boolean nofile[MAXSAVEGAMES-1]; - UINT8 tolerance = 0; + SINT8 tolerance = 3; // empty slots at any time + UINT8 lastseen = 0; loadgamescroll = 0; loadgameoffset = 14; - for (i = 1; ((i < MAXSAVEGAMES) && ((i <= saveSlotSelected) || (tolerance < 3))); i++) // slot 0 is no save + for (i = 1; (i < MAXSAVEGAMES); i++) // slot 0 is no save { snprintf(name, sizeof name, savegamename, i); name[sizeof name - 1] = '\0'; handle = fopen(name, "rb"); if ((nofile[i-1] = (handle == NULL))) - { - tolerance++; continue; - } fclose(handle); - tolerance = 0; + lastseen = i; } if (savegameinfo) Z_Free(savegameinfo); savegameinfo = NULL; + if (lastseen < saveSlotSelected) + lastseen = saveSlotSelected; + + i = lastseen; + + for (; (lastseen > 0 && tolerance); lastseen--) + { + if (nofile[lastseen-1]) + tolerance--; + } + + if ((i += tolerance+1) > MAXSAVEGAMES) // show 3 empty slots at minimum + i = MAXSAVEGAMES; + numsaves = i; savegameinfo = Z_Realloc(savegameinfo, numsaves*sizeof(saveinfo_t), PU_STATIC, NULL); if (!savegameinfo) @@ -6489,6 +6472,27 @@ static void M_ReadSaveStrings(void) } M_ReadSavegameInfo(i); } + + if (savselp[0]) // never going to have some provided but not all, saves individually checking + { + W_UnlockCachedPatch(savselp[0]); + W_UnlockCachedPatch(savselp[1]); + W_UnlockCachedPatch(savselp[2]); + + W_UnlockCachedPatch(savselp[3]); + W_UnlockCachedPatch(savselp[4]); + W_UnlockCachedPatch(savselp[5]); + W_UnlockCachedPatch(savselp[6]); + } + + savselp[0] = W_CachePatchName("SAVEBACK", PU_STATIC); + savselp[1] = W_CachePatchName("SAVENONE", PU_STATIC); + savselp[2] = W_CachePatchName("ULTIMATE", PU_STATIC); + + savselp[3] = W_CachePatchName("BLACKLVL", PU_STATIC); + savselp[4] = W_CachePatchName("BLACXLVL", PU_STATIC); + savselp[5] = W_CachePatchName("BLANKLVW", PU_STATIC); + savselp[6] = W_CachePatchName("GAMEDONE", PU_STATIC); } // diff --git a/src/v_video.c b/src/v_video.c index b07237d74..d965a0939 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -524,12 +524,20 @@ static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fix { return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); } + +static UINT8 staticstep[2] = {0, 0}; + static inline UINT8 staticpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { UINT8 val = source[ofs>>FRACBITS]; (void)dest; + if ((++staticstep[1]) >= 4) + { + staticstep[1] = 0; + staticstep[0] = M_RandomFixed(); + } if (val < 7) return val; - return M_RandomKey(7+1)+(val-7);//M_RandomByte(); + return ((staticstep[0]>>staticstep[1])&7)+(val-7); } // Draws a patch scaled to arbitrary size. @@ -660,30 +668,10 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t y = FixedMul(y,dupy<>= FRACBITS; y >>= FRACBITS; - desttop += (y*vid.width) + x; // Center it if necessary if (!(scrn & V_SCALEPATCHMASK)) { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) - desttop += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)) * vid.width; - else if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } // if it's meant to cover the whole screen, black out the rest if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) { @@ -691,7 +679,29 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t source = (const UINT8 *)(column) + 3; V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); } + + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (scrn & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(scrn & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) + y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); + else if (scrn & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(scrn & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } } + + desttop += (y*vid.width) + x; } if (pscale != FRACUNIT) // scale width properly @@ -1346,7 +1356,7 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string) // void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) { - INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0; + INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0; const char *ch = string; INT32 charflags = 0; const UINT8 *colormap = NULL; @@ -1362,7 +1372,11 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) scrwidth = vid.width; } else + { dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } charflags = (option & V_CHARCOLORMASK); @@ -1422,9 +1436,9 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) else w = SHORT(hu_font[c]->width) * dupx; - if (cx > scrwidth) + if (cx+left > scrwidth) break; - if (cx + w < 0) //left boundary check + if (cx+left + w < 0) //left boundary check { cx += w; continue; @@ -1455,7 +1469,7 @@ void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string // void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) { - INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0; + INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0; const char *ch = string; INT32 charflags = 0; const UINT8 *colormap = NULL; @@ -1471,7 +1485,11 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) scrwidth = vid.width; } else + { dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } charflags = (option & V_CHARCOLORMASK); @@ -1529,9 +1547,9 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) } else w = SHORT(hu_font[c]->width) * dupx / 2; - if (cx + w > scrwidth) + if (cx+left > scrwidth) break; - if (cx < 0) //left boundary check + if (cx+left + w < 0) //left boundary check { cx += w; continue; @@ -1556,7 +1574,7 @@ void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *s // void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) { - INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH; + INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0; const char *ch = string; INT32 charflags = 0; const UINT8 *colormap = NULL; @@ -1572,7 +1590,11 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) scrwidth = vid.width; } else + { dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } charflags = (option & V_CHARCOLORMASK); @@ -1628,9 +1650,9 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) else w = (SHORT(tny_font[c]->width) * dupx); - if (cx > scrwidth) + if (cx+left > scrwidth) break; - if (cx + w < 0) //left boundary check + if (cx+left + w < 0) //left boundary check { cx += w; continue; @@ -1653,7 +1675,7 @@ void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *st void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) { fixed_t cx = x, cy = y; - INT32 w, c, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0; + INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0; const char *ch = string; INT32 spacewidth = 4, charwidth = 0; @@ -1667,7 +1689,11 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) scrwidth = vid.width; } else + { dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } switch (option & V_SPACINGMASK) { @@ -1720,9 +1746,9 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) else w = SHORT(hu_font[c]->width) * dupx; - if ((cx>>FRACBITS) + w > scrwidth) + if ((cx>>FRACBITS)+left > scrwidth) break; - if (cx < 0) //left boundary check + if (cx+left + w < 0) //left boundary check { cx += w< Date: Tue, 22 Aug 2017 21:12:02 +0100 Subject: [PATCH 06/12] woops lmao --- src/v_video.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index d965a0939..9858e118f 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -525,19 +525,20 @@ static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fix return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); } -static UINT8 staticstep[2] = {0, 0}; +static UINT8 staticstep = 0; +static fixed_t staticval = 0; static inline UINT8 staticpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { UINT8 val = source[ofs>>FRACBITS]; (void)dest; - if ((++staticstep[1]) >= 4) + if ((++staticstep) >= 4) { - staticstep[1] = 0; - staticstep[0] = M_RandomFixed(); + staticstep = 0; + staticval = M_RandomFixed(); } if (val < 7) return val; - return ((staticstep[0]>>staticstep[1])&7)+(val-7); + return ((staticval>>staticstep)&7)+(val-7); } // Draws a patch scaled to arbitrary size. From 673fbc3ec275c87caced266880c2d46a3a6fd514 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 22 Aug 2017 23:47:25 +0100 Subject: [PATCH 07/12] * Make the delete save message include the save number. * Update/improve ultimate mode interaction experience a little. https://cdn.discordapp.com/attachments/293238104096112641/349685399200727041/srb20027.png --- src/m_cheat.c | 2 +- src/m_menu.c | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index f988c0fd5..7650e0742 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -61,7 +61,7 @@ static UINT8 cheatf_ultimate(void) if (menuactive && (currentMenu != &MainDef && currentMenu != &SP_LoadDef)) return 0; // Only on the main menu, or the save select! - S_StartSound(0, sfx_itemup); + BwehHehHe(); ultimate_selectable = (!ultimate_selectable); // If on the save select, move to what is now Ultimate Mode! diff --git a/src/m_menu.c b/src/m_menu.c index 214755651..c338a6185 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6514,6 +6514,17 @@ static void M_SaveGameDeleteResponse(INT32 ch) M_ReadSaveStrings(); // reload the menu } +static void M_SaveGameUltimateResponse(INT32 ch) +{ + if (ch != 'y' && ch != KEY_ENTER) + return; + + S_StartSound(NULL, sfx_menu1); + M_LoadSelect(saveSlotSelected); + SP_PlayerDef.prevMenu = MessageDef.prevMenu; + MessageDef.prevMenu = &SP_PlayerDef; +} + static void M_HandleLoadSave(INT32 choice) { boolean exitmenu = false; // exit to previous menu @@ -6537,8 +6548,15 @@ static void M_HandleLoadSave(INT32 choice) break; case KEY_ENTER: - if (savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" + if (ultimate_selectable && saveSlotSelected == NOSAVESLOT) { + loadgamescroll = 0; + S_StartSound(NULL, sfx_skid); + M_StartMessage("Are you sure you want to play\n\x85ultimate mode\x80? It isn't remotely fair,\nand you don't even get an emblem for it.\n\n(Press 'Y' to confirm)\n",M_SaveGameUltimateResponse,MM_YESNO); + } + else if (savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" + { + loadgamescroll = 0; S_StartSound(NULL, sfx_menu1); M_LoadSelect(saveSlotSelected); } @@ -6560,14 +6578,14 @@ static void M_HandleLoadSave(INT32 choice) { loadgamescroll = 0; S_StartSound(NULL, sfx_skid); - M_StartMessage(M_GetText("Are you sure you want to delete\nthis save game?\n\n(Press 'Y' to confirm)\n"),M_SaveGameDeleteResponse,MM_YESNO); + M_StartMessage(va("Are you sure you want to delete\nsave file %d?\n\n(Press 'Y' to confirm)\n", saveSlotSelected),M_SaveGameDeleteResponse,MM_YESNO); } else if (!loadgameoffset) { if (saveSlotSelected == NOSAVESLOT && ultimate_selectable) { ultimate_selectable = false; - BwehHehHe(); + S_StartSound(NULL, sfx_strpst); } else S_StartSound(NULL, sfx_lose); @@ -6602,14 +6620,15 @@ static void M_LoadGame(INT32 choice) // void M_ForceSaveSlotSelected(INT32 sslot) { - // Already there? Out of bounds? Whatever, then! - if (sslot == saveSlotSelected || sslot >= MAXSAVEGAMES) + loadgameoffset = 14; + + // Already there? Whatever, then! + if (sslot == saveSlotSelected) return; - // Figure out whether to display up movement or down movement - /*menumovedir = (saveSlotSelected - sslot) > 0 ? -1 : 1; - if (abs(saveSlotSelected - sslot) > (MAXSAVEGAMES>>1)) - menumovedir *= -1;*/ + loadgamescroll = 90; + if (saveSlotSelected <= numsaves/2) + loadgamescroll = -loadgamescroll; saveSlotSelected = sslot; } From a81c3ca115b6cbc2158caed6d98d27616057804c Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 23 Aug 2017 17:41:16 +0100 Subject: [PATCH 08/12] Update V_DrawCroppedPatch to match V_DrawFixedPatch's fixes. --- src/v_video.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index 9858e118f..b0d8fc52b 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -808,28 +808,10 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ y = FixedMul(y,dupy<>= FRACBITS; y >>= FRACBITS; - desttop += (y*vid.width) + x; // Center it if necessary if (!(scrn & V_SCALEPATCHMASK)) { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } // if it's meant to cover the whole screen, black out the rest if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) { @@ -837,7 +819,29 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ source = (const UINT8 *)(column) + 3; V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); } + + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (scrn & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(scrn & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) + y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); + else if (scrn & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(scrn & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } } + + desttop += (y*vid.width) + x; } for (col = sx<>FRACBITS) < SHORT(patch->width) && (col>>FRACBITS) < w; col += colfrac, ++x, desttop++) From 00c62e6d882d553ce724eef045e0a3fe2f8602a9 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 23 Aug 2017 22:05:11 +0100 Subject: [PATCH 09/12] * Removed unused info from struct as part of clean up. * Made botskin being invalid make the entire save invalid. --- src/m_menu.c | 22 ++++++++++++++-------- src/m_menu.h | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index c338a6185..06c235b97 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6079,6 +6079,18 @@ static void M_DrawLoadGameData(void) { V_DrawSmallScaledPatch(x+2, y+64, 0, savselp[5]); } +#ifndef PERFECTSAVE // disabled, don't touch + else if ((savegameinfo[savetodraw].skinnum == 1) + && (savegameinfo[savetodraw].lives == 99) + && (savegameinfo[savetodraw].gamemap & 8192) + && (savegameinfo[savetodraw].numgameovers == 0) + && (savegameinfo[savetodraw].numemeralds == (1<<7 - 1)) // perfect save + { + V_DrawFill(x+6, y+64, 72, 50, 134); + V_DrawFill(x+6, y+74, 72, 30, 201); + V_DrawFill(x+6, y+84, 72, 10, 1); + } +#endif else { if (savegameinfo[savetodraw].lives == -42) @@ -6360,15 +6372,9 @@ static void M_ReadSavegameInfo(UINT32 slot) if (((fake-1) & 8191) >= NUMMAPS) BADSAVE if(!mapheaderinfo[(fake-1) & 8191]) - { savegameinfo[slot].levelname[0] = '\0'; - savegameinfo[slot].actnum = 0; - } else - { strcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl); - savegameinfo[slot].actnum = mapheaderinfo[(fake-1) & 8191]->actnum; - } savegameinfo[slot].gamemap = fake; @@ -6390,10 +6396,10 @@ static void M_ReadSavegameInfo(UINT32 slot) savegameinfo[slot].botskin = fake >> 5; if (savegameinfo[slot].botskin-1 >= numskins || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) - savegameinfo[slot].botskin = 0; + BADSAVE CHECKPOS - (void)READUINT8(save_p); // numgameovers + savegameinfo[slot].numgameovers = READUINT8(save_p); // numgameovers CHECKPOS savegameinfo[slot].lives = READSINT8(save_p); // lives CHECKPOS diff --git a/src/m_menu.h b/src/m_menu.h index 6646aa4af..8040b63e6 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -216,10 +216,10 @@ typedef struct typedef struct { char levelname[32]; - UINT8 actnum; UINT8 skinnum; UINT8 botskin; UINT8 numemeralds; + UINT8 numgameovers; INT32 lives; INT32 continues; INT32 gamemap; From 16395f4dd2be44bbff79f10aa42530efabfc02e7 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 24 Aug 2017 21:29:29 +0100 Subject: [PATCH 10/12] Final corrections. Branch should be ready to merge now. --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 06c235b97..3f0b981e6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6084,7 +6084,7 @@ static void M_DrawLoadGameData(void) && (savegameinfo[savetodraw].lives == 99) && (savegameinfo[savetodraw].gamemap & 8192) && (savegameinfo[savetodraw].numgameovers == 0) - && (savegameinfo[savetodraw].numemeralds == (1<<7 - 1)) // perfect save + && (savegameinfo[savetodraw].numemeralds == ((1<<7) - 1))) // perfect save { V_DrawFill(x+6, y+64, 72, 50, 134); V_DrawFill(x+6, y+74, 72, 30, 201); From 9641196374b9b0a0724a7e1e3b83dc8e52d5a170 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 25 Aug 2017 00:40:45 +0100 Subject: [PATCH 11/12] * Fixed bug with wide blank select pic being used instead of the normal one. * Added length cap to savegame's zone name. * Refactor to level select's zone name length cap code. --- src/m_menu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 3f0b981e6..a158cd955 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4063,10 +4063,10 @@ static boolean M_PrepareLevelPlatter(INT32 gt) if (actnum) sprintf(mapname, "%s %d", mapheaderinfo[mapnum]->lvlttl, actnum); else - sprintf(mapname, "%s", mapheaderinfo[mapnum]->lvlttl); + strcpy(mapname, mapheaderinfo[mapnum]->lvlttl); if (strlen(mapname) >= 17) - sprintf(mapname+17-3, "..."); + strcpy(mapname+17-3, "..."); strcpy(levelselect.rows[row].mapnames[col], (const char *)mapname); } @@ -6374,7 +6374,12 @@ static void M_ReadSavegameInfo(UINT32 slot) if(!mapheaderinfo[(fake-1) & 8191]) savegameinfo[slot].levelname[0] = '\0'; else - strcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl); + { + strlcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl, 17+1); + + if (strlen(mapheaderinfo[(fake-1) & 8191]->lvlttl) >= 17) + strcpy(savegameinfo[slot].levelname+17-3, "..."); + } savegameinfo[slot].gamemap = fake; @@ -6497,7 +6502,7 @@ static void M_ReadSaveStrings(void) savselp[3] = W_CachePatchName("BLACKLVL", PU_STATIC); savselp[4] = W_CachePatchName("BLACXLVL", PU_STATIC); - savselp[5] = W_CachePatchName("BLANKLVW", PU_STATIC); + savselp[5] = W_CachePatchName("BLANKLVL", PU_STATIC); savselp[6] = W_CachePatchName("GAMEDONE", PU_STATIC); } From d6701edcb6922f8d84cc4b2390f0dc233851b87e Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 27 Aug 2017 18:46:53 +0100 Subject: [PATCH 12/12] Don't allow creating a new save when it wouldn't end up making a save file (ie, modified game without savemoddata). --- src/m_menu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index a158cd955..b983546cc 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2582,7 +2582,7 @@ boolean M_Responder(event_t *ev) { if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && modifiedgame && !savemoddata) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_skid); M_StartMessage(M_GetText("This cannot be done in a modified game.\n\n(Press a key)\n"), NULL, MM_NOTHING); return true; } @@ -6565,7 +6565,13 @@ static void M_HandleLoadSave(INT32 choice) S_StartSound(NULL, sfx_skid); M_StartMessage("Are you sure you want to play\n\x85ultimate mode\x80? It isn't remotely fair,\nand you don't even get an emblem for it.\n\n(Press 'Y' to confirm)\n",M_SaveGameUltimateResponse,MM_YESNO); } - else if (savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" + else if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected-1].lives == -42 && !(!modifiedgame || savemoddata)) + { + loadgamescroll = 0; + S_StartSound(NULL, sfx_skid); + M_StartMessage(M_GetText("This cannot be done in a modified game.\n\n(Press a key)\n"), NULL, MM_NOTHING); + } + else if (saveSlotSelected == NOSAVESLOT || savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" { loadgamescroll = 0; S_StartSound(NULL, sfx_menu1);