Compromise on cheats setting modified game

Instead of modifying the game, cheats now set a separate "cheats were used in this session" variable, which returns some of the old behavior.

HOWEVER, cheats will STILL allow spawning / collecting emblems & unlocking unlockables. Cheats will purely prevent saving progress. (It was always frustrating that devmode would make debugging unlockable features harder...)

Lastly, the function to set no-saving was exposed to Lua (`G_SetUsedCheats(silent)`). Just thought it'd be useful for large-scale gamedata-using mods that want to add their own cheat commands.
This commit is contained in:
Sally Coolatta 2022-02-28 12:43:00 -05:00
parent 4a520e63c6
commit a22fa1c455
13 changed files with 87 additions and 30 deletions

View file

@ -1448,6 +1448,7 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.usedCheats = (UINT8)usedCheats;
memcpy(netbuffer->u.servercfg.server_context, server_context, 8);
@ -4341,6 +4342,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
G_SetGametype(netbuffer->u.servercfg.gametype);
modifiedgame = netbuffer->u.servercfg.modifiedgame;
if (netbuffer->u.servercfg.usedCheats)
G_SetUsedCheats(true);
memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
}

View file

@ -158,6 +158,7 @@ typedef struct
UINT8 gametype;
UINT8 modifiedgame;
UINT8 usedCheats;
char server_context[8]; // Unique context id, generated at server startup.
} ATTRPACK serverconfig_pak;

View file

@ -1506,7 +1506,7 @@ void D_SRB2Main(void)
else
{
if (!M_CheckParm("-server"))
G_SetGameModified(true);
G_SetUsedCheats(true);
autostart = true;
}
}

View file

@ -1877,7 +1877,7 @@ static void Command_Map_f(void)
const char *gametypename;
boolean newresetplayers;
boolean mustmodifygame;
boolean wouldSetCheats;
INT32 newmapnum;
@ -1898,11 +1898,11 @@ static void Command_Map_f(void)
option_gametype = COM_CheckPartialParm("-g");
newresetplayers = ! COM_CheckParm("-noresetplayers");
mustmodifygame =
!( netgame || multiplayer ) &&
(!modifiedgame || savemoddata );
wouldSetCheats =
!( netgame || multiplayer ) &&
!( usedCheats );
if (mustmodifygame && !option_force)
if (wouldSetCheats && !option_force)
{
/* May want to be more descriptive? */
CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n"));
@ -1956,9 +1956,9 @@ static void Command_Map_f(void)
return;
}
if (mustmodifygame && option_force)
if (wouldSetCheats && option_force)
{
G_SetGameModified(false);
G_SetUsedCheats(false);
}
// new gametype value
@ -4259,7 +4259,7 @@ static void Ringslinger_OnChange(void)
}
if (cv_ringslinger.value) // Only if it's been turned on
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
static void Gravity_OnChange(void)
@ -4280,7 +4280,7 @@ static void Gravity_OnChange(void)
#endif
if (!CV_IsSetToDefault(&cv_gravity))
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
gravity = cv_gravity.value;
}
@ -4596,7 +4596,7 @@ static void Fishcake_OnChange(void)
// so don't make modifiedgame always on!
if (cv_debug)
{
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
else if (cv_debug != cv_fishcake.value)

View file

@ -75,6 +75,7 @@ extern SINT8 startinglivesbalance[maxgameovers+1];
extern boolean modifiedgame;
extern UINT16 mainwads;
extern boolean savemoddata; // This mod saves time/emblem data.
extern boolean usedCheats;
extern boolean disableSpeedAdjust; // Don't alter the duration of player states if true
extern boolean imcontinuing; // Temporary flag while continuing
extern boolean metalrecording;

View file

@ -96,6 +96,7 @@ SINT8 startinglivesbalance[maxgameovers+1] = {3, 5, 7, 9, 12, 15, 20, 25, 30, 40
UINT16 mainwads = 0;
boolean modifiedgame; // Set if homebrew PWAD stuff has been added.
boolean savemoddata = false;
boolean usedCheats = false; // Set when a gamedata-preventing cheat command is used.
UINT8 paused;
UINT8 modeattacking = ATTACKING_NONE;
boolean disableSpeedAdjust = false;
@ -764,6 +765,23 @@ void G_SetGameModified(boolean silent)
Command_ExitGame_f();
}
void G_SetUsedCheats(boolean silent)
{
if (usedCheats)
return;
usedCheats = true;
if (!silent)
CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to save progress.\n"));
// If in record attack recording, cancel it.
if (modeattacking)
M_EndModeAttackRun();
else if (marathonmode)
Command_ExitGame_f();
}
/** Builds an original game map name from a map number.
* The complexity is due to MAPA0-MAPZZ.
*
@ -3894,7 +3912,7 @@ static void G_HandleSaveLevel(void)
remove(liveeventbackup);
cursaveslot = 0;
}
else if (!(netgame || multiplayer || ultimatemode || demorecording || metalrecording || modeattacking))
else if (!usedCheats && !(netgame || multiplayer || ultimatemode || demorecording || metalrecording || modeattacking))
{
G_SaveGame((UINT32)cursaveslot, spstage_start);
}
@ -3902,7 +3920,7 @@ static void G_HandleSaveLevel(void)
}
// and doing THIS here means you don't lose your progress if you close the game mid-intermission
else if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking)
&& cursaveslot > 0 && CanSaveLevel(lastmap+1))
&& !usedCheats && cursaveslot > 0 && CanSaveLevel(lastmap+1))
{
G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages
}
@ -4181,7 +4199,7 @@ static void G_DoContinued(void)
tokenlist = 0;
token = 0;
if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && cursaveslot > 0)
if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && !usedCheats && cursaveslot > 0)
{
G_SaveGameOver((UINT32)cursaveslot, true);
}
@ -4480,6 +4498,13 @@ void G_SaveGameData(void)
return;
}
if (usedCheats)
{
free(savebuffer);
save_p = savebuffer = NULL;
return;
}
// Version test
WRITEUINT32(save_p, GAMEDATA_ID);

View file

@ -243,6 +243,7 @@ void G_LoadGameData(void);
void G_LoadGameSettings(void);
void G_SetGameModified(boolean silent);
void G_SetUsedCheats(boolean silent);
void G_SetGamestate(gamestate_t newstate);

View file

@ -3612,6 +3612,16 @@ static int lib_gRemovePlayer(lua_State *L)
}
static int lib_gSetUsedCheats(lua_State *L)
{
// Let large-scale level packs using Lua be able to add cheat commands.
boolean silent = lua_optboolean(L, 1);
//NOHUD
//INLEVEL
G_SetUsedCheats(silent);
return 0;
}
static int Lcheckmapnumber (lua_State *L, int idx, const char *fun)
{
if (ISINLEVEL)
@ -4213,6 +4223,7 @@ static luaL_Reg lib[] = {
{"G_AddGametype", lib_gAddGametype},
{"G_AddPlayer", lib_gAddPlayer},
{"G_RemovePlayer", lib_gRemovePlayer},
{"G_SetUsedCheats", lib_gSetUsedCheats},
{"G_BuildMapName",lib_gBuildMapName},
{"G_BuildMapTitle",lib_gBuildMapTitle},
{"G_FindMap",lib_gFindMap},

View file

@ -204,6 +204,9 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"modifiedgame")) {
lua_pushboolean(L, modifiedgame && !savemoddata);
return 1;
} else if (fastcmp(word,"usedCheats")) {
lua_pushboolean(L, usedCheats);
return 1;
} else if (fastcmp(word,"menuactive")) {
lua_pushboolean(L, menuactive);
return 1;

View file

@ -81,7 +81,7 @@ static UINT8 cheatf_warp(void)
S_StartSound(0, sfx_itemup);
// Temporarily unlock stuff.
G_SetGameModified(false);
G_SetUsedCheats(false);
unlockables[31].unlocked = true; // credits
unlockables[30].unlocked = true; // sound test
unlockables[28].unlocked = true; // level select
@ -106,7 +106,7 @@ static UINT8 cheatf_devmode(void)
S_StartSound(0, sfx_itemup);
// Just unlock all the things and turn on -debug and console devmode.
G_SetGameModified(false);
G_SetUsedCheats(false);
for (i = 0; i < MAXUNLOCKABLES; i++)
unlockables[i].unlocked = true;
devparm = true;
@ -275,7 +275,7 @@ void Command_CheatNoClip_f(void)
plyr->pflags ^= PF_NOCLIP;
CONS_Printf(M_GetText("No Clipping %s\n"), plyr->pflags & PF_NOCLIP ? M_GetText("On") : M_GetText("Off"));
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
void Command_CheatGod_f(void)
@ -290,7 +290,7 @@ void Command_CheatGod_f(void)
plyr->pflags ^= PF_GODMODE;
CONS_Printf(M_GetText("Cheese Mode %s\n"), plyr->pflags & PF_GODMODE ? M_GetText("On") : M_GetText("Off"));
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
void Command_CheatNoTarget_f(void)
@ -305,7 +305,7 @@ void Command_CheatNoTarget_f(void)
plyr->pflags ^= PF_INVIS;
CONS_Printf(M_GetText("SEP Field %s\n"), plyr->pflags & PF_INVIS ? M_GetText("On") : M_GetText("Off"));
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
void Command_Scale_f(void)
@ -879,7 +879,7 @@ void Command_Devmode_f(void)
return;
}
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
void Command_Setrings_f(void)
@ -905,7 +905,7 @@ void Command_Setrings_f(void)
// no totalsphere addition to revert
}
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
}
@ -928,7 +928,7 @@ void Command_Setlives_f(void)
P_GivePlayerLives(&players[consoleplayer], atoi(COM_Argv(1)));
}
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
}
@ -955,7 +955,7 @@ void Command_Setcontinues_f(void)
players[consoleplayer].continues = numcontinues;
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
}
@ -1446,7 +1446,7 @@ void Command_ObjectPlace_f(void)
REQUIRE_SINGLEPLAYER;
REQUIRE_NOULTIMATE;
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
silent = COM_CheckParm("-silent");

View file

@ -7082,7 +7082,7 @@ static void M_AllowSuper(INT32 choice)
M_StartMessage(M_GetText("You are now capable of turning super.\nRemember to get all the emeralds!\n"),NULL,MM_NOTHING);
SR_PandorasBox[6].status = IT_GRAYEDOUT;
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
static void M_GetAllEmeralds(INT32 choice)
@ -7093,7 +7093,7 @@ static void M_GetAllEmeralds(INT32 choice)
M_StartMessage(M_GetText("You now have all 7 emeralds.\nUse them wisely.\nWith great power comes great ring drain.\n"),NULL,MM_NOTHING);
SR_PandorasBox[7].status = IT_GRAYEDOUT;
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
static void M_DestroyRobotsResponse(INT32 ch)
@ -7104,7 +7104,7 @@ static void M_DestroyRobotsResponse(INT32 ch)
// Destroy all robots
P_DestroyRobots();
G_SetGameModified(multiplayer);
G_SetUsedCheats(false);
}
static void M_DestroyRobots(INT32 choice)
@ -8703,6 +8703,12 @@ static void M_DrawLoad(void)
loadgameoffset = 0;
M_DrawLoadGameData();
if (usedCheats)
{
V_DrawCenteredThinString(BASEVIDWIDTH/2, 184, 0, "\x85WARNING:\x80 Cheats have been activated.");
V_DrawCenteredThinString(BASEVIDWIDTH/2, 192, 0, "Progress will not be saved.");
}
}
//
@ -9004,12 +9010,18 @@ static void M_HandleLoadSave(INT32 choice)
break;
case KEY_ENTER:
if (ultimate_selectable && saveSlotSelected == NOSAVESLOT)
if (ultimate_selectable && saveSlotSelected == NOSAVESLOT && !usedCheats)
{
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 (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected-1].lives == -42 && usedCheats)
{
loadgamescroll = 0;
S_StartSound(NULL, sfx_skid);
M_StartMessage(M_GetText("This cannot be done in a cheated 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;

View file

@ -2583,7 +2583,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 (cursaveslot > 0)
if (!usedCheats && cursaveslot > 0)
G_SaveGameOver((UINT32)cursaveslot, (target->player->continues <= 0));
}
}

View file

@ -7764,7 +7764,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
{
// I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020
if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || marathonmode)
&& cursaveslot > 0)
&& !usedCheats && cursaveslot > 0)
{
G_SaveGame((UINT32)cursaveslot, gamemap);
}