diff --git a/src/doom/doomstat.h b/src/doom/doomstat.h index 655b3b04..070f8069 100644 --- a/src/doom/doomstat.h +++ b/src/doom/doomstat.h @@ -247,6 +247,9 @@ extern wbstartstruct_t wminfo; // File handling stuff. extern char *savegamedir; +extern char savename[256]; + +extern void G_ClearSavename (void); // if true, load all graphics at level load extern boolean precache; diff --git a/src/doom/g_game.c b/src/doom/g_game.c index 6bf51024..82a74c36 100644 --- a/src/doom/g_game.c +++ b/src/doom/g_game.c @@ -213,7 +213,7 @@ static int joystrafemove; static boolean joyarray[MAX_JOY_BUTTONS + 1]; static boolean *joybuttons = &joyarray[1]; // allow [-1] -static char savename[256]; // [crispy] moved here, made static +char savename[256]; // [crispy] moved here static int savegameslot; static char savedescription[32]; @@ -1702,6 +1702,13 @@ void G_DeathMatchSpawnPlayer (int playernum) P_SpawnPlayer (&playerstarts[playernum]); } +// [crispy] clear the "savename" variable, +// i.e. restart level from scratch upon resurrection +void G_ClearSavename (void) +{ + M_StringCopy(savename, "", sizeof(savename)); +} + // // G_DoReborn // @@ -2176,6 +2183,18 @@ void G_DoLoadGame (void) // draw the pattern into the back screen R_FillBackScreen (); + + // [crispy] if the player is dead in this savegame, + // do not consider it for reload + if (players[consoleplayer].health <= 0) + G_ClearSavename(); + + // [JN] If "On death action" is set to "last save", + // then prevent holded "use" button to work for next few tics. + // This fixes imidiate pressing on wall upon reloading + // a save game, if "use" button is kept pressed. + if (singleplayer && gp_death_use_action == 1) + players[consoleplayer].usedown = true; } @@ -2262,6 +2281,7 @@ void G_DoSaveGame (void) gameaction = ga_nothing; M_StringCopy(savedescription, "", sizeof(savedescription)); + M_StringCopy(savename, savegame_file, sizeof(savename)); CT_SetMessage(&players[consoleplayer], DEH_String(GGSAVED), false, NULL); @@ -2288,6 +2308,7 @@ G_DeferedInitNew d_skill = skill; d_episode = episode; d_map = map; + G_ClearSavename(); gameaction = ga_newgame; // [crispy] if a new game is started during demo recording, start a new demo diff --git a/src/doom/m_menu.c b/src/doom/m_menu.c index e32eeead..ff52b572 100644 --- a/src/doom/m_menu.c +++ b/src/doom/m_menu.c @@ -698,6 +698,7 @@ static void M_ID_DefaulSkill (int choice); static void M_ID_PistolStart (int choice); static void M_ID_RevealedSecrets (int choice); static void M_ID_FlipLevels (int choice); +static void M_ID_OnDeathAction (int choice); static void M_ID_DemoTimer (int choice); static void M_ID_TimerDirection (int choice); static void M_ID_ProgressBar (int choice); @@ -3479,6 +3480,7 @@ static menuitem_t ID_Menu_Gameplay_3[]= { M_LFRT, "DEFAULT SKILL LEVEL", M_ID_DefaulSkill, 'd' }, { M_LFRT, "REPORT REVEALED SECRETS", M_ID_RevealedSecrets, 'r' }, { M_LFRT, "FLIP LEVELS HORIZONTALLY", M_ID_FlipLevels, 'f' }, + { M_LFRT, "ON DEATH ACTION", M_ID_OnDeathAction, 'o' }, { M_SKIP, "", 0, '\0' }, { M_LFRT, "SHOW DEMO TIMER", M_ID_DemoTimer, 's' }, { M_LFRT, "TIMER DIRECTION", M_ID_TimerDirection, 't' }, @@ -3489,7 +3491,6 @@ static menuitem_t ID_Menu_Gameplay_3[]= { M_LFRT, "IMPROVED HIT DETECTION", M_ID_BlockmapFix, 'i' }, { M_LFRT, "VERTICAL AIMING", M_ID_VerticalAiming, 'v' }, { M_SKIP, "", 0, '\0' }, - { M_SKIP, "", 0, '\0' }, { M_SWTC, "", /*FIRST PAGE >*/ M_Choose_ID_Gameplay_1, 'n' }, { M_SWTC, "", /*< PREV PAGE*/ M_Choose_ID_Gameplay_2, 'p' }, }; @@ -3533,47 +3534,53 @@ static void M_Draw_ID_Gameplay_3 (void) M_WriteText (M_ItemRightAlign(str), 36, str, M_Item_Glow(2, gp_flip_levels ? GLOW_GREEN : GLOW_DARKRED)); - M_WriteTextCentered(45, "DEMOS", cr[CR_YELLOW]); + // On death action + sprintf(str, gp_death_use_action == 1 ? "LAST SAVE" : + gp_death_use_action == 2 ? "NOTHING" : "DEFAULT"); + M_WriteText (M_ItemRightAlign(str), 45, str, + M_Item_Glow(3, gp_death_use_action ? GLOW_GREEN : GLOW_DARKRED)); + + M_WriteTextCentered(54, "DEMOS", cr[CR_YELLOW]); // Demo timer sprintf(str, demo_timer == 1 ? "PLAYBACK" : demo_timer == 2 ? "RECORDING" : demo_timer == 3 ? "ALWAYS" : "OFF"); - M_WriteText (M_ItemRightAlign(str), 54, str, - M_Item_Glow(4, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); + M_WriteText (M_ItemRightAlign(str), 63, str, + M_Item_Glow(5, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); // Timer direction sprintf(str, demo_timerdir ? "BACKWARD" : "FORWARD"); - M_WriteText (M_ItemRightAlign(str), 63, str, - M_Item_Glow(5, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); + M_WriteText (M_ItemRightAlign(str), 72, str, + M_Item_Glow(6, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); // Progress bar sprintf(str, demo_bar ? "ON" : "OFF"); - M_WriteText (M_ItemRightAlign(str), 72, str, - M_Item_Glow(6, demo_bar ? GLOW_GREEN : GLOW_DARKRED)); + M_WriteText (M_ItemRightAlign(str), 81, str, + M_Item_Glow(7, demo_bar ? GLOW_GREEN : GLOW_DARKRED)); // Play internal demos sprintf(str, demo_internal ? "ON" : "OFF"); - M_WriteText (M_ItemRightAlign(str), 81, str, - M_Item_Glow(7, demo_internal ? GLOW_DARKRED : GLOW_GREEN)); + M_WriteText (M_ItemRightAlign(str), 90, str, + M_Item_Glow(8, demo_internal ? GLOW_DARKRED : GLOW_GREEN)); - M_WriteTextCentered(90, "COMPATIBILITY-BREAKING", cr[CR_YELLOW]); + M_WriteTextCentered(99, "COMPATIBILITY-BREAKING", cr[CR_YELLOW]); // Pistol start game mode sprintf(str, compat_pistol_start ? "ON" : "OFF"); - M_WriteText (M_ItemRightAlign(str), 99, str, - M_Item_Glow(9, compat_pistol_start ? GLOW_GREEN : GLOW_DARKRED)); + M_WriteText (M_ItemRightAlign(str), 108, str, + M_Item_Glow(10, compat_pistol_start ? GLOW_GREEN : GLOW_DARKRED)); // Improved hit detection sprintf(str, compat_blockmap_fix ? "ON" : "OFF"); - M_WriteText (M_ItemRightAlign(str), 108, str, - M_Item_Glow(10, compat_blockmap_fix ? GLOW_GREEN : GLOW_DARKRED)); + M_WriteText (M_ItemRightAlign(str), 117, str, + M_Item_Glow(11, compat_blockmap_fix ? GLOW_GREEN : GLOW_DARKRED)); // Vertical aiming sprintf(str, compat_vertical_aiming == 1 ? "DIRECT" : compat_vertical_aiming == 2 ? "BOTH" : "AUTOAIM"); - M_WriteText (M_ItemRightAlign(str), 117, str, - M_Item_Glow(11, compat_vertical_aiming ? GLOW_GREEN : GLOW_DARKRED)); + M_WriteText (M_ItemRightAlign(str), 126, str, + M_Item_Glow(12, compat_vertical_aiming ? GLOW_GREEN : GLOW_DARKRED)); M_WriteText (ID_MENU_LEFTOFFSET_BIG, 144, "FIRST PAGE >", M_Item_Glow(14, GLOW_LIGHTGRAY)); @@ -3613,6 +3620,11 @@ static void M_ID_FlipLevels (int choice) S_UpdateStereoSeparation(); } +static void M_ID_OnDeathAction (int choice) +{ + gp_death_use_action = M_INT_Slider(gp_death_use_action, 0, 2, choice, false); +} + static void M_ID_DemoTimer (int choice) { demo_timer = M_INT_Slider(demo_timer, 0, 3, choice, false); @@ -4202,6 +4214,7 @@ static void M_ID_ApplyResetHook (void) gp_default_skill = 2; gp_revealed_secrets = 0; gp_flip_levels = 0; + gp_death_use_action = 0; // Demos demo_timer = 0; diff --git a/src/doom/p_user.c b/src/doom/p_user.c index fc2cac83..df285e8f 100644 --- a/src/doom/p_user.c +++ b/src/doom/p_user.c @@ -291,7 +291,36 @@ void P_DeathThink (player_t* player) if (player->cmd.buttons & BT_USE) - player->playerstate = PST_REBORN; + { + if (demorecording || demoplayback || netgame) + { + player->playerstate = PST_REBORN; + } + else + { + // [JN] "On death action", mostly taken from Crispy Doom and Woof. + switch (gp_death_use_action) + { + case 0: // Default (reload the level from scratch) + gameaction = ga_loadlevel; + G_ClearSavename(); + break; + case 1: // Load last save + if (*savename) + { + gameaction = ga_loadgame; + } + else + { + player->playerstate = PST_REBORN; + } + break; + case 2: // Nothing + default: + break; + } + } + } } diff --git a/src/heretic/doomdef.h b/src/heretic/doomdef.h index 496cacab..d8d153a3 100644 --- a/src/heretic/doomdef.h +++ b/src/heretic/doomdef.h @@ -758,6 +758,9 @@ uint16_t SV_ReadWord(void); uint32_t SV_ReadLong(void); extern char *savegamedir; +extern char savename[256]; + +extern void G_ClearSavename (void); // [crispy] support up to 8 pages of savegames extern int savepage; diff --git a/src/heretic/g_game.c b/src/heretic/g_game.c index b7f7c147..30237f21 100644 --- a/src/heretic/g_game.c +++ b/src/heretic/g_game.c @@ -141,6 +141,7 @@ boolean precache = true; // if true, load all graphics at start // TODO: Heretic uses 16-bit shorts for consistency? byte consistancy[MAXPLAYERS][BACKUPTICS]; char *savegamedir; +char savename[256]; boolean testcontrols = false; int testcontrols_mousespeed; @@ -1894,6 +1895,13 @@ void G_DeathMatchSpawnPlayer(int playernum) P_SpawnPlayer(&playerstarts[playernum]); } +// [crispy] clear the "savename" variable, +// i.e. restart level from scratch upon resurrection +void G_ClearSavename (void) +{ + M_StringCopy(savename, "", sizeof(savename)); +} + /* ==================== = @@ -2146,11 +2154,9 @@ void G_DoWorldDone(void) // //--------------------------------------------------------------------------- -static char *savename = NULL; - void G_LoadGame(char *name) { - savename = M_StringDuplicate(name); + M_StringCopy(savename, name, sizeof(savename)); gameaction = ga_loadgame; } @@ -2179,8 +2185,12 @@ void G_DoLoadGame(void) SV_OpenRead(savename); + // [JN] Do not erase save data, + // it will be needed for "On death action" feature. + /* free(savename); savename = NULL; + */ // Skip the description field SV_Read(savestr, SAVESTRINGSIZE); @@ -2249,6 +2259,18 @@ void G_DoLoadGame(void) // Draw the pattern into the back screen R_FillBackScreen(); + + // [crispy] if the player is dead in this savegame, + // do not consider it for reload + if (players[consoleplayer].health <= 0) + G_ClearSavename(); + + // [JN] If "On death action" is set to "last save", + // then prevent holded "use" button to work for next few tics. + // This fixes imidiate pressing on wall upon reloading + // a save game, if "use" button is kept pressed. + if (singleplayer && gp_death_use_action == 1) + players[consoleplayer].usedown = true; } @@ -2271,6 +2293,7 @@ void G_DeferedInitNew(skill_t skill, int episode, int map) d_skill = skill; d_episode = episode; d_map = map; + G_ClearSavename(); gameaction = ga_newgame; // [crispy] if a new game is started during demo recording, start a new demo @@ -3157,6 +3180,7 @@ void G_DoSaveGame(void) gameaction = ga_nothing; savedescription[0] = 0; + M_StringCopy(savename, filename, sizeof(savename)); CT_SetMessage(&players[consoleplayer], DEH_String(TXT_GAMESAVED), true, NULL); free(filename); diff --git a/src/heretic/mn_menu.c b/src/heretic/mn_menu.c index 61bba90c..2cf9998b 100644 --- a/src/heretic/mn_menu.c +++ b/src/heretic/mn_menu.c @@ -561,6 +561,7 @@ static void M_Draw_ID_Gameplay_3 (void); static void M_ID_DefaulSkill (int choice); static void M_ID_RevealedSecrets (int choice); static void M_ID_FlipLevels (int choice); +static void M_ID_OnDeathAction (int choice); static void M_ID_DemoTimer (int choice); static void M_ID_TimerDirection (int choice); static void M_ID_ProgressBar (int choice); @@ -2865,8 +2866,8 @@ static MenuItem_t ID_Menu_Gameplay_1[] = { { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, { ITT_LRFUNC, "SHAPE", M_ID_Crosshair, 0, MENU_NONE }, { ITT_LRFUNC, "INDICATION", M_ID_CrosshairColor, 0, MENU_NONE }, - { ITT_SETMENU, "", /*NEXT PAGE >*/ NULL, 0, MENU_ID_GAMEPLAY2 }, - { ITT_SETMENU, "", /*< PREV PAGE*/ NULL, 0, MENU_ID_GAMEPLAY3 }, + { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, + { ITT_SETMENU, "", /* NEXT PAGE */ NULL, 0, MENU_ID_GAMEPLAY2 }, }; static Menu_t ID_Def_Gameplay_1 = { @@ -2948,14 +2949,12 @@ static void M_Draw_ID_Gameplay_1 (void) M_Item_Glow(10, !xhair_draw ? GLOW_DARKRED : xhair_color ? GLOW_GREEN : GLOW_DARKRED)); - MN_DrTextA("NEXT PAGE", ID_MENU_LEFTOFFSET_BIG, 130, - M_Item_Glow(11, GLOW_DARKGRAY)); - MN_DrTextA("LAST PAGE", ID_MENU_LEFTOFFSET_BIG, 140, + MN_DrTextA("NEXT PAGE", ID_MENU_LEFTOFFSET_BIG, 140, M_Item_Glow(12, GLOW_DARKGRAY)); // Footer sprintf(str, "PAGE 1/3"); - MN_DrTextA(str, M_ItemRightAlign(str), 140, cr[CR_GRAY]); + MN_DrTextA(str, M_ItemRightAlign(str), 140, M_Item_Glow(12, GLOW_DARKGRAY)); } static void M_ID_Brightmaps (int choice) @@ -3037,8 +3036,8 @@ static MenuItem_t ID_Menu_Gameplay_2[] = { { ITT_LRFUNC, "WEAPON ATTACK ALIGNMENT", M_ID_WeaponAlignment, 0, MENU_NONE }, { ITT_LRFUNC, "IMITATE PLAYER'S BREATHING", M_ID_Breathing, 0, MENU_NONE }, { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, - { ITT_SETMENU, "", /*LAST PAGE >*/ NULL, 0, MENU_ID_GAMEPLAY3 }, - { ITT_SETMENU, "", /*< FIRST PAGE*/ NULL, 0, MENU_ID_GAMEPLAY1 }, + { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, + { ITT_SETMENU, "", /* LAST PAGE */ NULL, 0, MENU_ID_GAMEPLAY3 }, }; static Menu_t ID_Def_Gameplay_2 = { @@ -3107,14 +3106,12 @@ static void M_Draw_ID_Gameplay_2 (void) MN_DrTextA(str, M_ItemRightAlign(str), 110, M_Item_Glow(9, phys_breathing ? GLOW_GREEN : GLOW_DARKRED)); - MN_DrTextA("LAST PAGE", ID_MENU_LEFTOFFSET_BIG, 130, - M_Item_Glow(11, GLOW_DARKGRAY)); - MN_DrTextA("FIRST PAGE", ID_MENU_LEFTOFFSET_BIG, 140, + MN_DrTextA("LAST PAGE", ID_MENU_LEFTOFFSET_BIG, 140, M_Item_Glow(12, GLOW_DARKGRAY)); // Footer sprintf(str, "PAGE 2/3"); - MN_DrTextA(str, M_ItemRightAlign(str), 140, cr[CR_GRAY]); + MN_DrTextA(str, M_ItemRightAlign(str), 140, M_Item_Glow(12, GLOW_DARKGRAY)); } static void M_ID_ColoredSBar (int choice) @@ -3166,6 +3163,7 @@ static MenuItem_t ID_Menu_Gameplay_3[] = { { ITT_LRFUNC, "DEFAULT SKILL LEVEL", M_ID_DefaulSkill, 0, MENU_NONE }, { ITT_LRFUNC, "REPORT REVEALED SECRETS", M_ID_RevealedSecrets,0, MENU_NONE }, { ITT_LRFUNC, "FLIP LEVELS HORIZONTALLY", M_ID_FlipLevels, 0, MENU_NONE }, + { ITT_LRFUNC, "ON DEATH ACTION", M_ID_OnDeathAction, 0, MENU_NONE }, { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, { ITT_LRFUNC, "SHOW DEMO TIMER", M_ID_DemoTimer, 0, MENU_NONE }, { ITT_LRFUNC, "TIMER DIRECTION", M_ID_TimerDirection, 0, MENU_NONE }, @@ -3174,8 +3172,7 @@ static MenuItem_t ID_Menu_Gameplay_3[] = { { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, { ITT_LRFUNC, "WAND START GAME MODE", M_ID_PistolStart, 0, MENU_NONE }, { ITT_LRFUNC, "IMPROVED HIT DETECTION", M_ID_BlockmapFix, 0, MENU_NONE }, - { ITT_SETMENU, "", /*FIRST PAGE >*/ NULL, 0, MENU_ID_GAMEPLAY1 }, - { ITT_SETMENU, "", /*< PREV PAGE*/ NULL, 0, MENU_ID_GAMEPLAY2 }, + { ITT_SETMENU, "", /* FIRST PAGE */ NULL, 0, MENU_ID_GAMEPLAY1 }, }; static Menu_t ID_Def_Gameplay_3 = { @@ -3210,50 +3207,54 @@ static void M_Draw_ID_Gameplay_3 (void) MN_DrTextA(str, M_ItemRightAlign(str), 40, M_Item_Glow(2, gp_flip_levels ? GLOW_GREEN : GLOW_DARKRED)); - MN_DrTextACentered("DEMOS", 50, cr[CR_YELLOW]); + // On death action + sprintf(str, gp_death_use_action == 1 ? "LAST SAVE" : + gp_death_use_action == 2 ? "NOTHING" : "DEFAULT"); + MN_DrTextA(str, M_ItemRightAlign(str), 50, + M_Item_Glow(3, gp_death_use_action ? GLOW_GREEN : GLOW_DARKRED)); + + MN_DrTextACentered("DEMOS", 60, cr[CR_YELLOW]); // Show Demo timer sprintf(str, demo_timer == 1 ? "PLAYBACK" : demo_timer == 2 ? "RECORDING" : demo_timer == 3 ? "ALWAYS" : "OFF"); - MN_DrTextA(str, M_ItemRightAlign(str), 60, - M_Item_Glow(4, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); + MN_DrTextA(str, M_ItemRightAlign(str), 70, + M_Item_Glow(5, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); // Timer direction sprintf(str, demo_timerdir ? "BACKWARD" : "FORWARD"); - MN_DrTextA(str, M_ItemRightAlign(str), 70, - M_Item_Glow(5, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); + MN_DrTextA(str, M_ItemRightAlign(str), 80, + M_Item_Glow(6, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); // Show progress bar sprintf(str, demo_bar ? "ON" : "OFF"); - MN_DrTextA(str, M_ItemRightAlign(str), 80, - M_Item_Glow(6, demo_bar ? GLOW_GREEN : GLOW_DARKRED)); + MN_DrTextA(str, M_ItemRightAlign(str), 90, + M_Item_Glow(7, demo_bar ? GLOW_GREEN : GLOW_DARKRED)); // Play internal demos sprintf(str, demo_internal ? "ON" : "OFF"); - MN_DrTextA(str, M_ItemRightAlign(str), 90, - M_Item_Glow(7, demo_internal ? GLOW_DARKRED : GLOW_GREEN)); + MN_DrTextA(str, M_ItemRightAlign(str), 100, + M_Item_Glow(8, demo_internal ? GLOW_DARKRED : GLOW_GREEN)); - MN_DrTextACentered("COMPATIBILITY-BREAKING", 100, cr[CR_YELLOW]); + MN_DrTextACentered("COMPATIBILITY-BREAKING", 110, cr[CR_YELLOW]); // Wand start game mode sprintf(str, compat_pistol_start ? "ON" : "OFF"); - MN_DrTextA(str, M_ItemRightAlign(str), 110, - M_Item_Glow(9, compat_pistol_start ? GLOW_GREEN : GLOW_DARKRED)); + MN_DrTextA(str, M_ItemRightAlign(str), 120, + M_Item_Glow(10, compat_pistol_start ? GLOW_GREEN : GLOW_DARKRED)); // Improved hit detection sprintf(str, compat_blockmap_fix ? "ON" : "OFF"); - MN_DrTextA(str, M_ItemRightAlign(str), 120, - M_Item_Glow(10, compat_blockmap_fix ? GLOW_GREEN : GLOW_DARKRED)); + MN_DrTextA(str, M_ItemRightAlign(str), 130, + M_Item_Glow(11, compat_blockmap_fix ? GLOW_GREEN : GLOW_DARKRED)); - MN_DrTextA("FIRST PAGE", ID_MENU_LEFTOFFSET_BIG, 130, - M_Item_Glow(11, GLOW_DARKGRAY)); - MN_DrTextA("PREV PAGE", ID_MENU_LEFTOFFSET_BIG, 140, + MN_DrTextA("FIRST PAGE", ID_MENU_LEFTOFFSET_BIG, 140, M_Item_Glow(12, GLOW_DARKGRAY)); // Footer sprintf(str, "PAGE 3/3"); - MN_DrTextA(str, M_ItemRightAlign(str), 140, cr[CR_GRAY]); + MN_DrTextA(str, M_ItemRightAlign(str), 140, M_Item_Glow(12, GLOW_DARKGRAY)); } static void M_ID_DefaulSkill (int choice) @@ -3275,6 +3276,11 @@ static void M_ID_FlipLevels (int choice) R_ExecuteSetViewSize(); } +static void M_ID_OnDeathAction (int choice) +{ + gp_death_use_action = M_INT_Slider(gp_death_use_action, 0, 2, choice, false); +} + static void M_ID_DemoTimer (int choice) { demo_timer = M_INT_Slider(demo_timer, 0, 3, choice, false); @@ -3958,6 +3964,7 @@ static void M_ID_ApplyResetHook (void) gp_default_skill = 2; gp_revealed_secrets = 0; gp_flip_levels = 0; + gp_death_use_action = 0; // Demos demo_timer = 0; diff --git a/src/heretic/p_user.c b/src/heretic/p_user.c index efedc1e8..67d3fa72 100644 --- a/src/heretic/p_user.c +++ b/src/heretic/p_user.c @@ -435,6 +435,10 @@ void P_DeathThink(player_t * player) if (player->cmd.buttons & BT_USE) { + // [JN] "On death action", mostly taken from Crispy Doom and Woof. + if (demorecording || demoplayback || netgame || gp_death_use_action == 0) + { + // Default (reload the level from scratch) if (player == &players[consoleplayer]) { #ifndef CRISPY_TRUECOLOR @@ -451,6 +455,38 @@ void P_DeathThink(player_t * player) // Let the mobj know the player has entered the reborn state. Some // mobjs need to know when it's ok to remove themselves. player->mo->special2.i = 666; + G_ClearSavename(); + } + else + { + if (gp_death_use_action == 1) + { + // Load last save + if (*savename) + { + gameaction = ga_loadgame; + } + else + { +#ifndef CRISPY_TRUECOLOR + I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE)); +#else + I_SetPalette(0); +#endif + inv_ptr = 0; + curpos = 0; + newtorch = 0; + newtorchdelta = 0; + player->playerstate = PST_REBORN; + player->mo->special2.i = 666; + } + } + else + if (gp_death_use_action == 2) + { + // Nothing, i.e. no-op, disallow reborn action + } + } } } diff --git a/src/hexen/g_game.c b/src/hexen/g_game.c index 806c9903..3175ca0b 100644 --- a/src/hexen/g_game.c +++ b/src/hexen/g_game.c @@ -174,6 +174,7 @@ static int crl_camzspeed; int savegameslot; char savedescription[32]; +char savename[256]; int inventoryTics; @@ -1834,6 +1835,13 @@ void G_DeathMatchSpawnPlayer(int playernum) P_SpawnPlayer(&playerstarts[0][playernum]); } +// [crispy] clear the "savename" variable, +// i.e. restart level from scratch upon resurrection +void G_ClearSavename (void) +{ + M_StringCopy(savename, "", sizeof(savename)); +} + //========================================================================== // // G_DoReborn @@ -2187,6 +2195,18 @@ void G_DoLoadGame(void) // Draw the pattern into the back screen R_FillBackScreen(); + + // [crispy] if the player is dead in this savegame, + // do not consider it for reload + if (players[consoleplayer].health <= 0) + G_ClearSavename(); + + // [JN] If "On death action" is set to "last save", + // then prevent holded "use" button to work for next few tics. + // This fixes imidiate pressing on wall upon reloading + // a save game, if "use" button is kept pressed. + if (singleplayer && gp_death_use_action == 1) + players[consoleplayer].usedown = true; } //========================================================================== @@ -2351,6 +2371,7 @@ void G_InitNew(skill_t skill, int episode, int map) //memset (netcmds,0,sizeof(netcmds)); G_DoLoadLevel(); + G_ClearSavename(); } /* diff --git a/src/hexen/h2def.h b/src/hexen/h2def.h index 5f39ecad..f46545d1 100644 --- a/src/hexen/h2def.h +++ b/src/hexen/h2def.h @@ -913,6 +913,9 @@ extern int savepage; // [crispy] extern char *SavePath; +extern char savename[256]; +extern void G_ClearSavename (void); + void SV_SaveGame(int slot, const char *description); void SV_SaveMap(boolean savePlayers); void SV_LoadGame(int slot); diff --git a/src/hexen/mn_menu.c b/src/hexen/mn_menu.c index ad326ff8..270728de 100644 --- a/src/hexen/mn_menu.c +++ b/src/hexen/mn_menu.c @@ -558,6 +558,7 @@ static void M_ID_Breathing (int choice); static void M_ID_DefaultClass (int choice); static void M_ID_DefaultSkill (int choice); static void M_ID_FlipLevels (int choice); +static void M_ID_OnDeathAction (int choice); static void M_ID_DemoTimer (int choice); static void M_ID_TimerDirection (int choice); static void M_ID_ProgressBar (int choice); @@ -2999,13 +3000,13 @@ static MenuItem_t ID_Menu_Gameplay_2[] = { { ITT_LRFUNC, "DEFAULT PLAYER CLASS", M_ID_DefaultClass, 0, MENU_NONE }, { ITT_LRFUNC, "DEFAULT SKILL LEVEL", M_ID_DefaultSkill, 0, MENU_NONE }, { ITT_LRFUNC, "FLIP LEVELS HORIZONTALLY", M_ID_FlipLevels, 0, MENU_NONE }, + { ITT_LRFUNC, "ON DEATH ACTION", M_ID_OnDeathAction, 0, MENU_NONE }, { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, { ITT_LRFUNC, "SHOW DEMO TIMER", M_ID_DemoTimer, 0, MENU_NONE }, { ITT_LRFUNC, "TIMER DIRECTION", M_ID_TimerDirection, 0, MENU_NONE }, { ITT_LRFUNC, "SHOW PROGRESS BAR", M_ID_ProgressBar, 0, MENU_NONE }, { ITT_LRFUNC, "PLAY INTERNAL DEMOS", M_ID_InternalDemos, 0, MENU_NONE }, { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, - { ITT_EMPTY, NULL, NULL, 0, MENU_NONE }, { ITT_SETMENU, "", /*PREVIOUS PAGE >*/ NULL, 0, MENU_ID_GAMEPLAY1 }, }; @@ -3053,29 +3054,35 @@ static void M_Draw_ID_Gameplay_2 (void) MN_DrTextA(str, M_ItemRightAlign(str), 70, M_Item_Glow(5, gp_flip_levels ? GLOW_GREEN : GLOW_DARKRED)); - MN_DrTextACentered("DEMOS", 80, cr[CR_YELLOW]); + // On death action + sprintf(str, gp_death_use_action == 1 ? "LAST SAVE" : + gp_death_use_action == 2 ? "NOTHING" : "DEFAULT"); + MN_DrTextA(str, M_ItemRightAlign(str), 80, + M_Item_Glow(6, gp_death_use_action ? GLOW_GREEN : GLOW_DARKRED)); + + MN_DrTextACentered("DEMOS", 90, cr[CR_YELLOW]); // Show Demo timer sprintf(str, demo_timer == 1 ? "PLAYBACK" : demo_timer == 2 ? "RECORDING" : demo_timer == 3 ? "ALWAYS" : "OFF"); - MN_DrTextA(str, M_ItemRightAlign(str), 90, - M_Item_Glow(7, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); + MN_DrTextA(str, M_ItemRightAlign(str), 100, + M_Item_Glow(8, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); // Timer direction sprintf(str, demo_timerdir ? "BACKWARD" : "FORWARD"); - MN_DrTextA(str, M_ItemRightAlign(str), 100, - M_Item_Glow(8, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); + MN_DrTextA(str, M_ItemRightAlign(str), 110, + M_Item_Glow(9, demo_timer ? GLOW_GREEN : GLOW_DARKRED)); // Show progress bar sprintf(str, demo_bar ? "ON" : "OFF"); - MN_DrTextA(str, M_ItemRightAlign(str), 110, - M_Item_Glow(9, demo_bar ? GLOW_GREEN : GLOW_DARKRED)); + MN_DrTextA(str, M_ItemRightAlign(str), 120, + M_Item_Glow(10, demo_bar ? GLOW_GREEN : GLOW_DARKRED)); // Play internal demos sprintf(str, demo_internal ? "ON" : "OFF"); - MN_DrTextA(str, M_ItemRightAlign(str), 120, - M_Item_Glow(10, demo_internal ? GLOW_DARKRED : GLOW_GREEN)); + MN_DrTextA(str, M_ItemRightAlign(str), 130, + M_Item_Glow(11, demo_internal ? GLOW_DARKRED : GLOW_GREEN)); MN_DrTextA("PREVIOUS PAGE", ID_MENU_LEFTOFFSET, 150, M_Item_Glow(13, GLOW_DARKGRAY)); @@ -3115,6 +3122,11 @@ static void M_ID_FlipLevels (int choice) R_ExecuteSetViewSize(); } +static void M_ID_OnDeathAction (int choice) +{ + gp_death_use_action = M_INT_Slider(gp_death_use_action, 0, 2, choice, false); +} + static void M_ID_DemoTimer (int choice) { demo_timer = M_INT_Slider(demo_timer, 0, 3, choice, false); @@ -3233,6 +3245,7 @@ static void M_ID_ApplyResetHook (void) gp_default_class = 0; gp_default_skill = 2; gp_flip_levels = 0; + gp_death_use_action = 0; // Demos demo_timer = 0; diff --git a/src/hexen/p_user.c b/src/hexen/p_user.c index ccbd9eb5..8b5cb742 100644 --- a/src/hexen/p_user.c +++ b/src/hexen/p_user.c @@ -459,6 +459,9 @@ void P_DeathThink(player_t * player) if (player->cmd.buttons & BT_USE) { + // [JN] "On death action", mostly taken from Crispy Doom and Woof. + if (demorecording || demoplayback || netgame || gp_death_use_action == 0) + { if (player == &players[consoleplayer]) { #ifndef CRISPY_TRUECOLOR @@ -480,6 +483,38 @@ void P_DeathThink(player_t * player) // Let the mobj know the player has entered the reborn state. Some // mobjs need to know when it's ok to remove themselves. player->mo->special2.i = 666; + G_ClearSavename(); + } + else + { + if (gp_death_use_action == 1) + { + // Load last save + if (*savename) + { + gameaction = ga_loadgame; + } + else + { +#ifndef CRISPY_TRUECOLOR + I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE)); +#else + I_SetPalette(0); +#endif + inv_ptr = 0; + curpos = 0; + newtorch = 0; + newtorchdelta = 0; + player->playerstate = PST_REBORN; + player->mo->special2.i = 666; + } + } + else + if (gp_death_use_action == 2) + { + // Nothing, i.e. no-op, disallow reborn action + } + } } } diff --git a/src/hexen/sv_save.c b/src/hexen/sv_save.c index 7c265fef..91943945 100644 --- a/src/hexen/sv_save.c +++ b/src/hexen/sv_save.c @@ -2073,6 +2073,8 @@ void SV_SaveMap(boolean savePlayers) ArchiveMisc(); // [JN] Archive automap marks. ArchiveAutomap(); + + M_StringCopy(savename, fileName, sizeof(savename)); // Place a termination marker SV_WriteLong(ASEG_END); @@ -2113,6 +2115,7 @@ void SV_LoadGame(int slot) // Create the name M_snprintf(fileName, sizeof(fileName), "%shex%d.sav", SavePath, BASE_SLOT); + M_StringCopy(savename, fileName, sizeof(savename)); // Load the file SV_OpenRead(fileName); diff --git a/src/id_vars.c b/src/id_vars.c index 4115aa84..73869099 100644 --- a/src/id_vars.c +++ b/src/id_vars.c @@ -150,6 +150,7 @@ int gp_default_class = 0; int gp_default_skill = 2; int gp_revealed_secrets = 0; int gp_flip_levels = 0; +int gp_death_use_action = 0; // Demos int demo_timer = 0; @@ -341,6 +342,7 @@ void ID_BindVariables (GameMission_t mission) M_BindIntVariable("gp_revealed_secrets", &gp_revealed_secrets); } M_BindIntVariable("gp_flip_levels", &gp_flip_levels); + M_BindIntVariable("gp_death_use_action", &gp_death_use_action); // Demos M_BindIntVariable("demo_timer", &demo_timer); diff --git a/src/id_vars.h b/src/id_vars.h index 51fb28e7..0dfaf19d 100644 --- a/src/id_vars.h +++ b/src/id_vars.h @@ -125,6 +125,7 @@ extern int gp_default_skill; extern int gp_revealed_secrets; extern int phys_breathing; extern int gp_flip_levels; +extern int gp_death_use_action; // Demos extern int demo_timer; diff --git a/src/m_config.c b/src/m_config.c index 8c5ec7a8..88baf8c8 100644 --- a/src/m_config.c +++ b/src/m_config.c @@ -547,6 +547,7 @@ static default_t doom_defaults_list[] = CONFIG_VARIABLE_INT(gp_default_skill), CONFIG_VARIABLE_INT(gp_revealed_secrets), CONFIG_VARIABLE_INT(gp_flip_levels), + CONFIG_VARIABLE_INT(gp_death_use_action), // Demos CONFIG_VARIABLE_INT(demo_timer),