diff --git a/src/d_player.h b/src/d_player.h index f23e2933..243ad402 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -223,6 +223,9 @@ typedef struct player_s int num_visitedlevels; level_t *visitedlevels; + // Last used weapon (last readyweapon). + weapontype_t lastweapon; + } player_t; diff --git a/src/doomstat.h b/src/doomstat.h index 6d595068..51211d1b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -69,6 +69,7 @@ extern char *MAPNAME(int e, int m); extern boolean modifiedgame; extern boolean have_ssg; +#define ALLOW_SSG (gamemode == commercial || CRITICAL(have_ssg)) // compatibility with old engines (monster behavior, metrics, etc.) extern int compatibility, default_compatibility; // killough 1/31/98 diff --git a/src/g_game.c b/src/g_game.c index 46240db7..9ba6929e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -162,6 +162,7 @@ boolean padlook = false; // killough 4/13/98: Make clock rate adjustable by scale factor int realtic_clock_rate = 100; static boolean doom_weapon_toggles; +static boolean full_weapon_cycle; complevel_t force_complevel, default_complevel; @@ -241,7 +242,7 @@ static boolean WeaponSelectable(weapontype_t weapon) { // Can't select the super shotgun in Doom 1. - if (weapon == wp_supershotgun && !have_ssg) + if (weapon == wp_supershotgun && !ALLOW_SSG) { return false; } @@ -318,6 +319,46 @@ static int G_NextWeapon(int direction) return weapon_order_table[i].weapon_num; } +static weapontype_t LastWeapon(void) +{ + const weapontype_t weapon = players[consoleplayer].lastweapon; + + if (weapon < wp_fist || weapon >= NUMWEAPONS || !WeaponSelectable(weapon)) + { + return wp_nochange; + } + + if (demo_compatibility && weapon == wp_supershotgun) + { + return wp_shotgun; + } + + return weapon; +} + +static weapontype_t WeaponSSG(void) +{ + const player_t *player = &players[consoleplayer]; + + if (!ALLOW_SSG || !player->weaponowned[wp_supershotgun]) + { + return wp_nochange; + } + + if (!demo_compatibility) + { + return wp_supershotgun; + } + + if (player->pendingweapon != wp_supershotgun + && player->readyweapon != wp_supershotgun) + { + return wp_shotgun; + } + + return wp_nochange; +} + // [FG] toggle demo warp mode void G_EnableWarp(boolean warp) { @@ -554,6 +595,57 @@ void G_PrepGyroTiccmd(void) } } +static void AdjustWeaponSelection(int *newweapon) +{ + // killough 3/22/98: For network and demo consistency with the + // new weapons preferences, we must do the weapons switches here + // instead of in p_user.c. But for old demos we must do it in + // p_user.c according to the old rules. Therefore demo_compatibility + // determines where the weapons switch is made. + + // killough 2/8/98: + // Allow user to switch to fist even if they have chainsaw. + // Switch to fist or chainsaw based on preferences. + // Switch to shotgun or SSG based on preferences. + // + // killough 10/98: make SG/SSG and Fist/Chainsaw + // weapon toggles optional + + const player_t *player = &players[consoleplayer]; + + // only select chainsaw from '1' if it's owned, it's + // not already in use, and the player prefers it or + // the fist is already in use, or the player does not + // have the berserker strength. + + if (*newweapon == wp_fist + && player->weaponowned[wp_chainsaw] + && player->readyweapon != wp_chainsaw + && (player->readyweapon == wp_fist + || !player->powers[pw_strength] + || P_WeaponPreferred(wp_chainsaw, wp_fist))) + { + *newweapon = wp_chainsaw; + } + + // Select SSG from '3' only if it's owned and the player + // does not have a shotgun, or if the shotgun is already + // in use, or if the SSG is not already in use and the + // player prefers it. + + if (*newweapon == wp_shotgun && ALLOW_SSG + && player->weaponowned[wp_supershotgun] + && (!player->weaponowned[wp_shotgun] + || player->readyweapon == wp_shotgun + || (player->readyweapon != wp_supershotgun + && P_WeaponPreferred(wp_supershotgun, wp_shotgun)))) + { + *newweapon = wp_supershotgun; + } + + // killough 2/8/98, 3/22/98 -- end of weapon selection changes +} + static boolean FilterDeathUseAction(void) { if (players[consoleplayer].playerstate & PST_DEAD) @@ -765,12 +857,22 @@ void G_BuildTiccmd(ticcmd_t* cmd) boom_weapon_state_injection = false; newweapon = P_SwitchWeapon(&players[consoleplayer]); // phares } + else if (M_InputGameActive(input_lastweapon)) + { + newweapon = LastWeapon(); + } + else if (gamestate == GS_LEVEL && next_weapon != 0) + { + // [FG] prev/next weapon keys and buttons + newweapon = G_NextWeapon(next_weapon); + + if (!demo_compatibility && !full_weapon_cycle) + { + AdjustWeaponSelection(&newweapon); + } + } else { // phares 02/26/98: Added gamemode checks - // [FG] prev/next weapon keys and buttons - if (gamestate == GS_LEVEL && next_weapon != 0) - newweapon = G_NextWeapon(next_weapon); - else newweapon = M_InputGameActive(input_weapon1) ? wp_fist : // killough 5/2/98: reformatted M_InputGameActive(input_weapon2) ? wp_pistol : @@ -780,53 +882,13 @@ void G_BuildTiccmd(ticcmd_t* cmd) M_InputGameActive(input_weapon6) && gamemode != shareware ? wp_plasma : M_InputGameActive(input_weapon7) && gamemode != shareware ? wp_bfg : M_InputGameActive(input_weapon8) ? wp_chainsaw : - M_InputGameActive(input_weapon9) && !demo_compatibility && have_ssg ? wp_supershotgun : + M_InputGameActive(input_weapon9) ? WeaponSSG() : wp_nochange; - // killough 3/22/98: For network and demo consistency with the - // new weapons preferences, we must do the weapons switches here - // instead of in p_user.c. But for old demos we must do it in - // p_user.c according to the old rules. Therefore demo_compatibility - // determines where the weapons switch is made. - - // killough 2/8/98: - // Allow user to switch to fist even if they have chainsaw. - // Switch to fist or chainsaw based on preferences. - // Switch to shotgun or SSG based on preferences. - // - // killough 10/98: make SG/SSG and Fist/Chainsaw - // weapon toggles optional - if (!demo_compatibility && doom_weapon_toggles) { - const player_t *player = &players[consoleplayer]; - - // only select chainsaw from '1' if it's owned, it's - // not already in use, and the player prefers it or - // the fist is already in use, or the player does not - // have the berserker strength. - - if (newweapon==wp_fist && player->weaponowned[wp_chainsaw] && - player->readyweapon!=wp_chainsaw && - (player->readyweapon==wp_fist || - !player->powers[pw_strength] || - P_WeaponPreferred(wp_chainsaw, wp_fist))) - newweapon = wp_chainsaw; - - // Select SSG from '3' only if it's owned and the player - // does not have a shotgun, or if the shotgun is already - // in use, or if the SSG is not already in use and the - // player prefers it. - - if (newweapon == wp_shotgun && have_ssg && - player->weaponowned[wp_supershotgun] && - (!player->weaponowned[wp_shotgun] || - player->readyweapon == wp_shotgun || - (player->readyweapon != wp_supershotgun && - P_WeaponPreferred(wp_supershotgun, wp_shotgun)))) - newweapon = wp_supershotgun; + AdjustWeaponSelection(&newweapon); } - // killough 2/8/98, 3/22/98 -- end of weapon selection changes } if (newweapon != wp_nochange) @@ -2914,6 +2976,7 @@ void G_PlayerReborn(int player) p->usedown = p->attackdown = true; // don't do anything immediately p->playerstate = PST_LIVE; p->health = initial_health; // Ty 03/12/98 - use dehacked values + p->lastweapon = wp_fist; p->readyweapon = p->pendingweapon = wp_pistol; p->weaponowned[wp_fist] = true; p->weaponowned[wp_pistol] = true; @@ -4706,6 +4769,9 @@ void G_BindWeapVariables(void) M_BindBool("doom_weapon_toggles", &doom_weapon_toggles, NULL, true, ss_weap, wad_no, "Allow toggling between SG/SSG and Fist/Chainsaw"); + M_BindBool("full_weapon_cycle", &full_weapon_cycle, NULL, + false, ss_weap, wad_no, + "Cycle through all weapons"); M_BindBool("player_bobbing", &default_player_bobbing, &player_bobbing, true, ss_none, wad_no, "Physical player bobbing (affects compatibility)"); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 1fe3acde..94da286a 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1006,7 +1006,7 @@ static void HU_widget_build_weapon (void) break; case retail: case registered: - if (w >= wp_supershotgun && !have_ssg) + if (w >= wp_supershotgun && !ALLOW_SSG) ok = 0; break; default: diff --git a/src/m_cheat.c b/src/m_cheat.c index 24c4183a..a8ef67eb 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -541,7 +541,7 @@ static void cheat_fa() // You can't own weapons that aren't in the game // phares 02/27/98 for (i=0;iweaponowned[i] = true; for (i=0;iweaponowned[wp_supershotgun] && have_ssg && + if (player->weaponowned[wp_supershotgun] && ALLOW_SSG && player->ammo[am_shell] >= (demo_compatibility ? 3 : 2)) newweapon = wp_supershotgun; break; @@ -588,6 +588,7 @@ void A_Lower(player_t *player, pspdef_t *psp) if (player->pendingweapon < NUMWEAPONS || !mbf21) { + player->lastweapon = player->readyweapon; player->readyweapon = player->pendingweapon; } diff --git a/src/p_saveg.c b/src/p_saveg.c index 04e37f02..febdd22d 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -989,11 +989,15 @@ static void saveg_read_player_t(player_t *str) level.map = saveg_read32(); array_push(str->visitedlevels, level); } + + // [Woof!]: weapontype_t lastweapon; + str->lastweapon = saveg_read_enum(); } else { str->num_visitedlevels = 0; array_clear(str->visitedlevels); + str->lastweapon = wp_nochange; } } @@ -1158,6 +1162,9 @@ static void saveg_write_player_t(player_t *str) saveg_write32(level->episode); saveg_write32(level->map); } + + // [Woof!]: weapontype_t lastweapon; + saveg_write_enum(str->lastweapon); } diff --git a/src/p_user.c b/src/p_user.c index 98f22801..3ead7f88 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -478,7 +478,7 @@ void P_PlayerThink (player_t* player) (player->readyweapon != wp_chainsaw || !player->powers[pw_strength])) newweapon = wp_chainsaw; - if (have_ssg && + if (ALLOW_SSG && newweapon == wp_shotgun && player->weaponowned[wp_supershotgun] && player->readyweapon != wp_supershotgun)