- implemented the 'god' cheat as a network command.

This was mainly chosen as something simple to get the basics set up.
This commit is contained in:
Christoph Oelckers 2020-09-03 00:29:17 +02:00
parent 66d8eae8e1
commit 66bf8113b8
28 changed files with 532 additions and 350 deletions

View file

@ -778,6 +778,7 @@ set (PCH_SOURCES
build/src/voxmodel.cpp build/src/voxmodel.cpp
core/movie/playmve.cpp core/movie/playmve.cpp
core/cheats.cpp
core/cheathandler.cpp core/cheathandler.cpp
core/mathutil.cpp core/mathutil.cpp
core/rts.cpp core/rts.cpp

View file

@ -99,6 +99,7 @@ struct GameInterface : ::GameInterface
void DrawBackground() override; void DrawBackground() override;
void Startup() override; void Startup() override;
void Render() override; void Render() override;
const char* GenericCheat(int player, int cheat) override;
GameStats getStats() override; GameStats getStats() override;
}; };

View file

@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "view.h" #include "view.h"
#include "gstrings.h" #include "gstrings.h"
#include "cheathandler.h" #include "cheathandler.h"
#include "d_protocol.h"
BEGIN_BLD_NS BEGIN_BLD_NS
@ -46,13 +47,10 @@ void sub_5A928(void)
buttonMap.ClearButton(i); buttonMap.ClearButton(i);
} }
void SetGodMode(bool god) const char *SetGodMode(bool god)
{ {
playerSetGodMode(gMe, god); playerSetGodMode(gMe, god);
if (gMe->godMode) return gMe->godMode? GStrings("TXTB_GODMODE") : GStrings("TXTB_NOTGODMODE");
viewSetMessage(GStrings("TXTB_GODMODE"));
else
viewSetMessage(GStrings("TXTB_NOTGODMODE"));
} }
void SetClipMode(bool noclip) void SetClipMode(bool noclip)
@ -318,13 +316,13 @@ void ProcessCheat(CHEATCODE nCheatCode, char* pzArgs)
SetClipMode(!gNoClip); SetClipMode(!gNoClip);
break; break;
case kCheatMpkfa: case kCheatMpkfa:
SetGodMode(!gMe->godMode); viewSetMessage(SetGodMode(!gMe->godMode));
break; break;
case kCheatCapInMyAss: case kCheatCapInMyAss:
SetGodMode(false); viewSetMessage(SetGodMode(false));
break; break;
case kCheatNoCapInMyAss: case kCheatNoCapInMyAss:
SetGodMode(true); viewSetMessage(SetGodMode(true));
break; break;
case kCheatIdaho: case kCheatIdaho:
SetWeapons(true); SetWeapons(true);
@ -457,6 +455,25 @@ void ProcessCheat(CHEATCODE nCheatCode, char* pzArgs)
bPlayerCheated = true; bPlayerCheated = true;
} }
const char* GameInterface::GenericCheat(int player, int cheat)
{
switch (cheat)
{
case CHT_GOD:
return SetGodMode(!gMe->godMode);
case CHT_GODOFF:
return SetGodMode(false);
case CHT_GODON:
return SetGodMode(true);
default:
return nullptr;
}
}
template<CHEATCODE code> bool doCheat(cheatseq_t *c) template<CHEATCODE code> bool doCheat(cheatseq_t *c)
{ {
ProcessCheat(code, (char*)c->Args); ProcessCheat(code, (char*)c->Args);
@ -465,42 +482,42 @@ template<CHEATCODE code> bool doCheat(cheatseq_t *c)
static cheatseq_t s_CheatInfo[] = { static cheatseq_t s_CheatInfo[] = {
{"MPKFA", doCheat<kCheatMpkfa>, 0 }, // MPKFA (Invincibility) {"MPKFA", "god" }, // MPKFA (Invincibility)
{"CAPINMYASS", doCheat<kCheatCapInMyAss>, 0 }, // CAPINMYASS (Disable invincibility ) {"CAPINMYASS", "godoff" }, // CAPINMYASS (Disable invincibility )
{"NOCAPINMYASS", doCheat<kCheatNoCapInMyAss>, 0 }, // NOCAPINMYASS (Invincibility) {"NOCAPINMYASS", "godon" }, // NOCAPINMYASS (Invincibility)
{"I WANNA BE LIKE KEVIN", doCheat<kCheatNoCapInMyAss>, 0 }, // I WANNA BE LIKE KEVIN (Invincibility) {"I WANNA BE LIKE KEVIN", "godon" }, // I WANNA BE LIKE KEVIN (Invincibility)
{"IDAHO", doCheat<kCheatIdaho>, 0 }, // IDAHO (All weapons and full ammo) {"IDAHO", nullptr, doCheat<kCheatIdaho>, 0 }, // IDAHO (All weapons and full ammo)
{"MONTANA", doCheat<kCheatMontana>, 0 }, // MONTANA (All weapons, full ammo and all items) {"MONTANA", nullptr, doCheat<kCheatMontana>, 0 }, // MONTANA (All weapons, full ammo and all items)
{"GRISWOLD", doCheat<kCheatGriswold>, 0 }, // GRISWOLD (Full armor (same effect as getting super armor)) {"GRISWOLD", nullptr, doCheat<kCheatGriswold>, 0 }, // GRISWOLD (Full armor (same effect as getting super armor))
{"EDMARK", doCheat<kCheatEdmark>, 0 }, // EDMARK (Does a lot of fire damage to you (if you have 200HP and 200 fire armor then you can survive). Displays the message "THOSE WERE THE DAYS".) {"EDMARK", nullptr, doCheat<kCheatEdmark>, 0 }, // EDMARK (Does a lot of fire damage to you (if you have 200HP and 200 fire armor then you can survive). Displays the message "THOSE WERE THE DAYS".)
{"TEQUILA", doCheat<kCheatTequila>, 0 }, // TEQUILA (Guns akimbo power-up) {"TEQUILA", nullptr, doCheat<kCheatTequila>, 0 }, // TEQUILA (Guns akimbo power-up)
{"BUNZ", doCheat<kCheatBunz>, 0 }, // BUNZ (All weapons, full ammo, and guns akimbo power-up) {"BUNZ", nullptr, doCheat<kCheatBunz>, 0 }, // BUNZ (All weapons, full ammo, and guns akimbo power-up)
{"FUNKY SHOES", doCheat<kCheatFunkyShoes>, 0 }, // FUNKY SHOES (Gives jump boots item and activates it) {"FUNKY SHOES", nullptr, doCheat<kCheatFunkyShoes>, 0 }, // FUNKY SHOES (Gives jump boots item and activates it)
{"GATEKEEPER", doCheat<kCheatGateKeeper>, 0 }, // GATEKEEPER (Sets the you cheated flag to true, at the end of the level you will see that you have cheated) {"GATEKEEPER", nullptr, doCheat<kCheatGateKeeper>, 0 }, // GATEKEEPER (Sets the you cheated flag to true, at the end of the level you will see that you have cheated)
{"KEYMASTER", doCheat<kCheatKeyMaster>, 0 }, // KEYMASTER (All keys) {"KEYMASTER", nullptr, doCheat<kCheatKeyMaster>, 0 }, // KEYMASTER (All keys)
{"JOJO", doCheat<kCheatJoJo>, 0 }, // JOJO (Drunk mode (same effect as getting bitten by red spider)) {"JOJO", nullptr, doCheat<kCheatJoJo>, 0 }, // JOJO (Drunk mode (same effect as getting bitten by red spider))
{"SATCHEL", doCheat<kCheatSatchel>, 0 }, // SATCHEL (Full inventory) {"SATCHEL", nullptr, doCheat<kCheatSatchel>, 0 }, // SATCHEL (Full inventory)
{"SPORK", doCheat<kCheatSpork>, 0 }, // SPORK (200% health (same effect as getting life seed)) {"SPORK", nullptr, doCheat<kCheatSpork>, 0 }, // SPORK (200% health (same effect as getting life seed))
{"ONERING", doCheat<kCheatOneRing>, 0 }, // ONERING (Cloak of invisibility power-up) {"ONERING", nullptr, doCheat<kCheatOneRing>, 0 }, // ONERING (Cloak of invisibility power-up)
{"MARIO###", doCheat<kCheatMario>, 0 }, // MARIO (Warp to level E M, e.g.: MARIO 1 3 will take you to Phantom Express) {"MARIO###", nullptr, doCheat<kCheatMario>, 0 }, // MARIO (Warp to level E M, e.g.: MARIO 1 3 will take you to Phantom Express)
{"CALGON", doCheat<kCheatCalgon>, 0 }, // CALGON (Jumps to next level or can be used like MARIO with parameters) {"CALGON", nullptr, doCheat<kCheatCalgon>, 0 }, // CALGON (Jumps to next level or can be used like MARIO with parameters)
{"KEVORKIAN", doCheat<kCheatKevorkian>, 0 }, // KEVORKIAN (Does a lot of physical damage to you (if you have 200HP and 200 fire armor then you can survive). Displays the message "KEVORKIAN APPROVES".) {"KEVORKIAN", nullptr, doCheat<kCheatKevorkian>, 0 }, // KEVORKIAN (Does a lot of physical damage to you (if you have 200HP and 200 fire armor then you can survive). Displays the message "KEVORKIAN APPROVES".)
{"MCGEE", doCheat<kCheatMcGee>, 0 }, // MCGEE (Sets you on fire. Displays the message "YOU'RE FIRED".) {"MCGEE", nullptr, doCheat<kCheatMcGee>, 0 }, // MCGEE (Sets you on fire. Displays the message "YOU'RE FIRED".)
{"KRUEGER", doCheat<kCheatKrueger>, 0 }, // KRUEGER (200% health, but sets you on fire. Displays the message "FLAME RETARDANT".) {"KRUEGER", nullptr, doCheat<kCheatKrueger>, 0 }, // KRUEGER (200% health, but sets you on fire. Displays the message "FLAME RETARDANT".)
{"CHEESEHEAD", doCheat<kCheatCheeseHead>, 0 }, // CHEESEHEAD (100% diving suit) {"CHEESEHEAD", nullptr, doCheat<kCheatCheeseHead>, 0 }, // CHEESEHEAD (100% diving suit)
{"COUSTEAU", doCheat<kCheatCousteau>, 0 }, // COUSTEAU (200% health and diving suit) {"COUSTEAU", nullptr, doCheat<kCheatCousteau>, 0 }, // COUSTEAU (200% health and diving suit)
{"VOORHEES", doCheat<kCheatVoorhees>, 0 }, // VOORHEES (Death mask power-up) {"VOORHEES", nullptr, doCheat<kCheatVoorhees>, 0 }, // VOORHEES (Death mask power-up)
{"LARA CROFT", doCheat<kCheatLaraCroft>, 0 }, // LARA CROFT (All weapons and infinite ammo. Displays the message "LARA RULES". Typing it the second time will lose all weapons and ammo.) {"LARA CROFT", nullptr, doCheat<kCheatLaraCroft>, 0 }, // LARA CROFT (All weapons and infinite ammo. Displays the message "LARA RULES". Typing it the second time will lose all weapons and ammo.)
{"HONGKONG", doCheat<kCheatHongKong>, 0 }, // HONGKONG (All weapons and infinite ammo) {"HONGKONG", nullptr, doCheat<kCheatHongKong>, 0 }, // HONGKONG (All weapons and infinite ammo)
{"FRANKENSTEIN", doCheat<kCheatFrankenstein>, 0 }, // FRANKENSTEIN (100% med-kit) {"FRANKENSTEIN", nullptr, doCheat<kCheatFrankenstein>, 0 }, // FRANKENSTEIN (100% med-kit)
{"STERNO", doCheat<kCheatSterno>, 0 }, // STERNO (Temporary blindness (same effect as getting bitten by green spider)) {"STERNO", nullptr, doCheat<kCheatSterno>, 0 }, // STERNO (Temporary blindness (same effect as getting bitten by green spider))
{"CLARICE", doCheat<kCheatClarice>, 0 }, // CLARICE (Gives 100% body armor, 100% fire armor, 100% spirit armor) {"CLARICE", nullptr, doCheat<kCheatClarice>, 0 }, // CLARICE (Gives 100% body armor, 100% fire armor, 100% spirit armor)
{"FORK YOU", doCheat<kCheatForkYou>, 0 }, // FORK YOU (Drunk mode, 1HP, no armor, no weapons, no ammo, no items, no keys, no map, guns akimbo power-up) {"FORK YOU", nullptr, doCheat<kCheatForkYou>, 0 }, // FORK YOU (Drunk mode, 1HP, no armor, no weapons, no ammo, no items, no keys, no map, guns akimbo power-up)
{"LIEBERMAN", doCheat<kCheatLieberMan>, 0 }, // LIEBERMAN (Sets the you cheated flag to true, at the end of the level you will see that you have cheated) {"LIEBERMAN", nullptr, doCheat<kCheatLieberMan>, 0 }, // LIEBERMAN (Sets the you cheated flag to true, at the end of the level you will see that you have cheated)
{"EVA GALLI", doCheat<kCheatEvaGalli>, 0 }, // EVA GALLI (Disable/enable clipping (grant the ability to walk through walls)) {"EVA GALLI", nullptr, doCheat<kCheatEvaGalli>, 0 }, // EVA GALLI (Disable/enable clipping (grant the ability to walk through walls))
{"RATE", doCheat<kCheatRate>, 1 }, // RATE (Display frame rate (doesn't count as a cheat)) {"RATE", nullptr, doCheat<kCheatRate>, 1 }, // RATE (Display frame rate (doesn't count as a cheat))
{"GOONIES", doCheat<kCheatGoonies>, 0 }, // GOONIES (Enable full map. Displays the message "YOU HAVE THE MAP".) {"GOONIES", nullptr, doCheat<kCheatGoonies>, 0 }, // GOONIES (Enable full map. Displays the message "YOU HAVE THE MAP".)
//{"SPIELBERG", doCheat<kCheatSpielberg, 1 }, // SPIELBERG (Disables all cheats. If number values corresponding to a level and episode number are entered after the cheat word (i.e. "spielberg 1 3" for Phantom Express), you will be spawned to said level and the game will begin recording a demo from your actions.) //{"SPIELBERG", nullptr, doCheat<kCheatSpielberg, 1 }, // SPIELBERG (Disables all cheats. If number values corresponding to a level and episode number are entered after the cheat word (i.e. "spielberg 1 3" for Phantom Express), you will be spawned to said level and the game will begin recording a demo from your actions.)
}; };

View file

@ -42,7 +42,8 @@ enum MESSAGE_PRIORITY {
enum CHEATCODE enum CHEATCODE
{ {
kCheatNone = 0, kCheatNone = 0,
kCheat1, // refills ammo, no cheat code for it
kCheat1 = 1000, // refills ammo, no cheat code for it
kCheatGriswold, kCheatGriswold,
kCheatSatchel, kCheatSatchel,
kCheatEvaGalli, kCheatEvaGalli,
@ -90,7 +91,6 @@ void SetWeapons(bool stat);
void SetToys(bool stat); void SetToys(bool stat);
void SetArmor(bool stat); void SetArmor(bool stat);
void SetKeys(bool stat); void SetKeys(bool stat);
void SetGodMode(bool god);
void SetClipMode(bool noclip); void SetClipMode(bool noclip);
END_BLD_NS END_BLD_NS

View file

@ -129,19 +129,6 @@ static int osdcmd_give(CCmdFuncPtr parm)
return CCMD_SHOWHELP; return CCMD_SHOWHELP;
} }
static int osdcmd_god(CCmdFuncPtr)
{
if (numplayers == 1 && gamestate == GS_LEVEL)
{
SetGodMode(!gMe->godMode);
bPlayerCheated = true;
}
else
Printf("god: Not in a single-player game.\n");
return CCMD_OK;
}
static int osdcmd_noclip(CCmdFuncPtr) static int osdcmd_noclip(CCmdFuncPtr)
{ {
if (numplayers == 1 && gamestate == GS_LEVEL) if (numplayers == 1 && gamestate == GS_LEVEL)
@ -249,7 +236,6 @@ int32_t registerosdcommands(void)
{ {
C_RegisterFunction("map","map <mapname>: loads the given map", osdcmd_map); C_RegisterFunction("map","map <mapname>: loads the given map", osdcmd_map);
C_RegisterFunction("give","give <all|health|weapons|ammo|armor|keys|inventory>: gives requested item", osdcmd_give); C_RegisterFunction("give","give <all|health|weapons|ammo|armor|keys|inventory>: gives requested item", osdcmd_give);
C_RegisterFunction("god","god: toggles god mode", osdcmd_god);
C_RegisterFunction("noclip","noclip: toggles clipping mode", osdcmd_noclip); C_RegisterFunction("noclip","noclip: toggles clipping mode", osdcmd_noclip);
C_RegisterFunction("levelwarp","levelwarp <e> <m>: warp to episode 'e' and map 'm'", osdcmd_levelwarp); C_RegisterFunction("levelwarp","levelwarp <e> <m>: warp to episode 'e' and map 'm'", osdcmd_levelwarp);
C_RegisterFunction("warptocoords","warptocoords [x] [y] [z] [ang] (optional) [horiz] (optional): warps the player to the specified coordinates",osdcmd_warptocoords); C_RegisterFunction("warptocoords","warptocoords [x] [y] [z] [ang] (optional) [horiz] (optional): warps the player to the specified coordinates",osdcmd_warptocoords);

View file

@ -607,8 +607,9 @@ void playerSetRace(PLAYER *pPlayer, int nLifeMode)
pDudeInfo->at70[i] = mulscale8(Handicap[gProfile[pPlayer->nPlayer].skill], pDudeInfo->startDamage[i]); pDudeInfo->at70[i] = mulscale8(Handicap[gProfile[pPlayer->nPlayer].skill], pDudeInfo->startDamage[i]);
} }
void playerSetGodMode(PLAYER *pPlayer, char bGodMode) void playerSetGodMode(PLAYER *pPlayer, bool bGodMode)
{ {
if (pPlayer->godMode == bGodMode) return;
if (bGodMode) if (bGodMode)
{ {
for (int i = 0; i < 7; i++) for (int i = 0; i < 7; i++)

View file

@ -269,7 +269,7 @@ void packPrevItem(PLAYER *pPlayer);
void packNextItem(PLAYER *pPlayer); void packNextItem(PLAYER *pPlayer);
char playerSeqPlaying(PLAYER *pPlayer, int nSeq); char playerSeqPlaying(PLAYER *pPlayer, int nSeq);
void playerSetRace(PLAYER *pPlayer, int nLifeMode); void playerSetRace(PLAYER *pPlayer, int nLifeMode);
void playerSetGodMode(PLAYER *pPlayer, char bGodMode); void playerSetGodMode(PLAYER *pPlayer, bool bGodMode);
void playerResetInertia(PLAYER *pPlayer); void playerResetInertia(PLAYER *pPlayer);
void playerCorrectInertia(PLAYER *pPlayer, vec3_t const *oldpos); void playerCorrectInertia(PLAYER *pPlayer, vec3_t const *oldpos);
void playerStart(int nPlayer, int bNewLevel = 0); void playerStart(int nPlayer, int bNewLevel = 0);

View file

@ -59,7 +59,7 @@ extern bool ParsingKeyConf, UnsafeExecutionContext;
extern FString StoredWarp; // [RH] +warp at the command line extern FString StoredWarp; // [RH] +warp at the command line
extern bool CheckCheatmode (bool printmsg = true); extern bool CheckCheatmode (bool printmsg = true, bool sponly = false);
FExecList *C_ParseCmdLineParams(FExecList *exec); FExecList *C_ParseCmdLineParams(FExecList *exec);

View file

@ -1,27 +1,37 @@
//----------------------------------------------------------------------------- /*
// ** cheathandler.cpp
** Generic Cheat code.
**
**---------------------------------------------------------------------------
// Copyright 1999-2016 Randy Heit // Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers // Copyright 2002-2020 Christoph Oelckers
// ** All rights reserved.
// This program is free software: you can redistribute it and/or modify **
// it under the terms of the GNU General Public License as published by ** Redistribution and use in source and binary forms, with or without
// the Free Software Foundation, either version 3 of the License, or ** modification, are permitted provided that the following conditions
// (at your option) any later version. ** are met:
// **
// This program is distributed in the hope that it will be useful, ** 1. Redistributions of source code must retain the above copyright
// but WITHOUT ANY WARRANTY; without even the implied warranty of ** notice, this list of conditions and the following disclaimer.
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 2. Redistributions in binary form must reproduce the above copyright
// GNU General Public License for more details. ** notice, this list of conditions and the following disclaimer in the
// ** documentation and/or other materials provided with the distribution.
// You should have received a copy of the GNU General Public License ** 3. The name of the author may not be used to endorse or promote products
// along with this program. If not, see http://www.gnu.org/licenses/ ** derived from this software without specific prior written permission.
// **
//----------------------------------------------------------------------------- ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
// ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// DESCRIPTION: ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// Generic Cheat code. ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
// ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
//----------------------------------------------------------------------------- ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OFf
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "c_cvars.h" #include "c_cvars.h"
#include "c_dispatch.h" #include "c_dispatch.h"
@ -122,7 +132,7 @@ bool Cheat_Responder (event_t *ev)
void PlaybackCheat(const char *p) void PlaybackCheat(const char *p)
{ {
if (gi->CheatAllowed(false)) if (!CheckCheatmode(true))
{ {
event_t ev = { EV_KeyDown, 0, 0, -1 }; event_t ev = { EV_KeyDown, 0, 0, -1 };
Cheat_Responder(&ev); // Reset the parser by passing a non-existent key. Cheat_Responder(&ev); // Reset the parser by passing a non-existent key.
@ -135,9 +145,6 @@ void PlaybackCheat(const char *p)
ev.data2 = -1; ev.data2 = -1;
Cheat_Responder(&ev); Cheat_Responder(&ev);
} }
else
Printf("activatecheat: Cheats not allowed.\n");
} }
CCMD(activatecheat) CCMD(activatecheat)

View file

@ -3,6 +3,7 @@
struct cheatseq_t struct cheatseq_t
{ {
const char *Sequence; const char *Sequence;
const char* ccmd;
bool (*Handler)(cheatseq_t *); bool (*Handler)(cheatseq_t *);
uint8_t DontCheck; uint8_t DontCheck;
// This is working data for processing the cheat // This is working data for processing the cheat

124
source/core/cheats.cpp Normal file
View file

@ -0,0 +1,124 @@
/*
** cheats.cpp
** Common cheat code
**
**---------------------------------------------------------------------------
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2020 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OFf
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "gamestruct.h"
#include "printf.h"
#include "c_cvars.h"
#include "cheathandler.h"
#include "c_dispatch.h"
#include "d_net.h"
#include "gamestate.h"
#include "mmulti.h"
#include "gstrings.h"
CVAR(Bool, sv_cheats, true, CVAR_ARCHIVE|CVAR_SERVERINFO)
CVAR(Bool, cl_blockcheats, false, 0)
bool CheckCheatmode (bool printmsg, bool sponly)
{
if ((sponly && netgame) || gamestate != GS_LEVEL)
{
if (printmsg) Printf ("Not in a singleplayer game.\n");
return true;
}
else if ((netgame /*|| deathmatch*/) && (!sv_cheats))
{
if (printmsg) Printf ("sv_cheats must be true to enable this command.\n");
return true;
}
else if (cl_blockcheats != 0)
{
if (printmsg && cl_blockcheats == 1) Printf ("cl_blockcheats is turned on and disabled this command.\n");
return true;
}
else
{
const char *gamemsg = gi->CheckCheatMode(); // give the game anopportuity to add its own blocks.
if (printmsg && gamemsg)
{
Printf("%s\n", gamemsg);
return true;
}
return false;
}
}
void genericCheat(int player, uint8_t** stream, bool skip)
{
int cheat = ReadByte(stream);
if (skip) return;
const char *msg = gi->GenericCheat(player, cheat);
if (!msg || !*msg) // Don't print blank lines.
return;
if (player == myconnectindex)
Printf("%s\n", msg);
else
{
FString message = GStrings("TXT_X_CHEATS");
//message.Substitute("%s", player->userinfo.GetName()); // fixme - make globally accessible
Printf("%s: %s\n", message.GetChars(), msg);
}
}
CCMD(god)
{
if (!CheckCheatmode(true, true)) // Right now the god cheat is a global setting in some games and not a player property. This should be changed.
{
Net_WriteByte(DEM_GENERICCHEAT);
Net_WriteByte(CHT_GOD);
}
}
CCMD(godon)
{
if (!CheckCheatmode(true, true))
{
Net_WriteByte(DEM_GENERICCHEAT);
Net_WriteByte(CHT_GODON);
}
}
CCMD(godoff)
{
if (!CheckCheatmode(true, true))
{
Net_WriteByte(DEM_GENERICCHEAT);
Net_WriteByte(CHT_GODOFF);
}
}

10
source/core/cheats.h Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
#include "c_cvars.h"
EXTERN_CVAR(Bool, sv_cheats)
void genericCheat(int player, uint8_t** stream, bool skip);

View file

@ -51,6 +51,7 @@
#include "i_time.h" #include "i_time.h"
#include "d_ticcmd.h" #include "d_ticcmd.h"
#include "m_random.h" #include "m_random.h"
#include "cheats.h"
extern bool pauseext; extern bool pauseext;
extern int gametic; extern int gametic;
@ -1660,6 +1661,10 @@ bool D_CheckNetGame (void)
const char *v; const char *v;
int i; int i;
// First install the global net command handlers
Net_SetCommandHandler(DEM_GENERICCHEAT, genericCheat);
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXNETNODES; i++)
{ {
nodeingame[i] = false; nodeingame[i] = false;
@ -1947,7 +1952,7 @@ void Net_DoCommand (int cmd, uint8_t **stream, int player)
assert(cmd >= 0 && cmd < DEM_MAX); assert(cmd >= 0 && cmd < DEM_MAX);
if (cmd >= 0 && cmd < DEM_MAX && nethandlers[cmd]) if (cmd >= 0 && cmd < DEM_MAX && nethandlers[cmd])
{ {
nethandlers[cmd](stream, false); nethandlers[cmd](player, stream, false);
} }
else else
I_Error("Unknown net command: %d", cmd); I_Error("Unknown net command: %d", cmd);
@ -1958,7 +1963,7 @@ void Net_SkipCommand (int cmd, uint8_t **stream)
{ {
if (cmd >= 0 && cmd < DEM_MAX && nethandlers[cmd]) if (cmd >= 0 && cmd < DEM_MAX && nethandlers[cmd])
{ {
nethandlers[cmd](stream, true); nethandlers[cmd](0, stream, true);
} }
} }

View file

@ -168,9 +168,9 @@ int UnpackUserCmd (InputPacket *ucmd, const InputPacket *basis, uint8_t **stream
if (flags & UCMDF_SIDEMOVE) if (flags & UCMDF_SIDEMOVE)
ucmd->svel = ReadWord (stream); ucmd->svel = ReadWord (stream);
if (flags & UCMDF_UPMOVE) if (flags & UCMDF_UPMOVE)
ucmd->q16horiz = ReadWord (stream); ucmd->q16horiz = ReadLong (stream);
if (flags & UCMDF_ROLL) if (flags & UCMDF_ROLL)
ucmd->q16ang = ReadWord (stream); ucmd->q16ang = ReadLong (stream);
} }
return int(*stream - start); return int(*stream - start);

View file

@ -88,12 +88,21 @@ enum EDemoCommand
DEM_BAD, // 0 Bad command DEM_BAD, // 0 Bad command
DEM_USERCMD, DEM_USERCMD,
DEM_EMPTYUSERCMD, DEM_EMPTYUSERCMD,
DEM_CHEAT_GOD, DEM_GENERICCHEAT,
DEM_MAX DEM_MAX
}; };
typedef void(*NetCommandHandler)(uint8_t **stream, bool skip); enum ECheat
{
// must contain all cheats from all games
CHT_NONE,
CHT_GOD,
CHT_GODON,
CHT_GODOFF
};
typedef void(*NetCommandHandler)(int player, uint8_t **stream, bool skip);
void Net_SetCommandHandler(EDemoCommand cmd, NetCommandHandler handler) noexcept; void Net_SetCommandHandler(EDemoCommand cmd, NetCommandHandler handler) noexcept;
@ -111,8 +120,8 @@ int SkipTicCmd (uint8_t **stream, int count);
void ReadTicCmd (uint8_t **stream, int player, int tic); void ReadTicCmd (uint8_t **stream, int player, int tic);
void RunNetSpecs (int player, int buf); void RunNetSpecs (int player, int buf);
int Readuint8_t (uint8_t **stream); int ReadByte (uint8_t **stream);
int Reauint32_t (uint8_t **stream); int ReadShort (uint8_t **stream);
int ReadLong (uint8_t **stream); int ReadLong (uint8_t **stream);
float ReadFloat (uint8_t **stream); float ReadFloat (uint8_t **stream);
char *ReadString (uint8_t **stream); char *ReadString (uint8_t **stream);

View file

@ -1132,12 +1132,6 @@ CCMD (togglemsg)
} }
} }
// Just a placeholder for now.
bool CheckCheatmode(bool printmsg)
{
return gi->CheatAllowed(printmsg);
}
bool OkForLocalization(FTextureID texnum, const char* substitute) bool OkForLocalization(FTextureID texnum, const char* substitute)
{ {
return false; return false;

View file

@ -8,6 +8,8 @@ bool System_WantGuiCapture(); // During playing this tells us whether the game m
#include "stats.h" #include "stats.h"
#include "packet.h" #include "packet.h"
class FSerializer;
struct GameStats struct GameStats
{ {
int kill, tkill; int kill, tkill;
@ -89,7 +91,6 @@ struct GameInterface
virtual void QuitToTitle() {} virtual void QuitToTitle() {}
virtual void SetAmbience(bool on) {} virtual void SetAmbience(bool on) {}
virtual FString GetCoordString() { return "'stat coord' not implemented"; } virtual FString GetCoordString() { return "'stat coord' not implemented"; }
virtual bool CheatAllowed(bool printmsg) { return true; }
virtual void ExitFromMenu() { throw CExitEvent(0); } virtual void ExitFromMenu() { throw CExitEvent(0); }
virtual ReservedSpace GetReservedScreenSpace(int viewsize) { return { 0, 0 }; } virtual ReservedSpace GetReservedScreenSpace(int viewsize) { return { 0, 0 }; }
virtual void ResetFollowPos(bool) {} virtual void ResetFollowPos(bool) {}
@ -101,6 +102,8 @@ struct GameInterface
virtual void Render() {} virtual void Render() {}
virtual void Ticker() {} virtual void Ticker() {}
virtual int GetPlayerChecksum(int pnum) { return 0x12345678 + pnum; } virtual int GetPlayerChecksum(int pnum) { return 0x12345678 + pnum; }
virtual const char *CheckCheatMode() { return nullptr; }
virtual const char* GenericCheat(int player, int cheat) = 0;
virtual FString statFPS() virtual FString statFPS()
{ {

View file

@ -46,6 +46,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "c_console.h" #include "c_console.h"
#include "cheathandler.h" #include "cheathandler.h"
#include "inputstate.h" #include "inputstate.h"
#include "d_protocol.h"
#include "core/menu/menu.h" #include "core/menu/menu.h"
BEGIN_PS_NS BEGIN_PS_NS
@ -195,6 +196,39 @@ void ShutDown(void)
//UnInitFX(); //UnInitFX();
} }
static const char* GodCheat(int nPlayer, int state)
{
if (state == -1)
{
if (PlayerList[nPlayer].invincibility >= 0)
PlayerList[nPlayer].invincibility = -1;
else
PlayerList[nPlayer].invincibility = 0;
}
else PlayerList[nPlayer].invincibility = -state;
return GStrings(PlayerList[nPlayer].invincibility ? "TXT_EX_DEITYON" : "TXT_EX_DEITYOFF");
}
const char* GameInterface::GenericCheat(int player, int cheat)
{
switch (cheat)
{
case CHT_GOD:
return GodCheat(player, -1);
case CHT_GODOFF:
return GodCheat(player, 0);
case CHT_GODON:
return GodCheat(player, 1);
default:
return nullptr;
}
}
static bool HollyCheat(cheatseq_t* c) static bool HollyCheat(cheatseq_t* c)
{ {
// Do the closest thing to this cheat that's available. // Do the closest thing to this cheat that's available.
@ -214,12 +248,6 @@ static bool CopCheat(cheatseq_t* c)
return true; return true;
} }
static bool GodCheat(cheatseq_t* c)
{
lLocalCodes |= kButtonCheatGodMode;
return true;
}
static bool LiteCheat(cheatseq_t* c) static bool LiteCheat(cheatseq_t* c)
{ {
Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_FLASHES")); Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_FLASHES"));
@ -289,17 +317,17 @@ static bool CoordCheat(cheatseq_t* c)
static cheatseq_t excheats[] = { static cheatseq_t excheats[] = {
{"holly", HollyCheat, 0}, {"holly", nullptr, HollyCheat, 0},
{"kimberly", KimberlyCheat, 0}, {"kimberly", nullptr, KimberlyCheat, 0},
{"lobocop", CopCheat, 0}, {"lobocop", nullptr, CopCheat, 0},
{"lobodeity", GodCheat, 0}, {"lobodeity", "god" },
{"lobolite", LiteCheat, 0}, {"lobolite", nullptr, LiteCheat, 0},
{"lobopick", KeyCheat, 0}, {"lobopick", nullptr, KeyCheat, 0},
{"loboslip", SlipCheat, 0}, {"loboslip", nullptr, SlipCheat, 0},
{"lobosnake", SnakeCheat, 0}, {"lobosnake", nullptr, SnakeCheat, 0},
{"lobosphere", SphereCheat, 0}, {"lobosphere", nullptr, SphereCheat, 0},
{"loboswag", SwagCheat, 0}, {"loboswag", nullptr, SwagCheat, 0},
{"loboxy", CoordCheat, true}, {"loboxy", nullptr, CoordCheat, true},
}; };

View file

@ -254,6 +254,7 @@ struct GameInterface : ::GameInterface
void Render() override; void Render() override;
void GetInput(InputPacket* packet) override; void GetInput(InputPacket* packet) override;
void Startup() override; void Startup() override;
const char* GenericCheat(int player, int cheat) override;
::GameStats getStats() override; ::GameStats getStats() override;
}; };

View file

@ -235,7 +235,7 @@ void UseHeart(short nPlayer)
// invincibility // invincibility
void UseScarab(short nPlayer) void UseScarab(short nPlayer)
{ {
if (PlayerList[nPlayer].invincibility < 900) { if (PlayerList[nPlayer].invincibility > 0 && PlayerList[nPlayer].invincibility < 900) {
PlayerList[nPlayer].invincibility = 900; PlayerList[nPlayer].invincibility = 900;
} }

View file

@ -34,19 +34,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
BEGIN_PS_NS BEGIN_PS_NS
static int osdcmd_god(CCmdFuncPtr)
{
if (!nNetPlayerCount && !bInDemo)
{
lLocalCodes |= kButtonCheatGodMode;
}
else
Printf("god: Not in a single-player game.\n");
return CCMD_OK;
}
bool SlipCheat(cheatseq_t* c); bool SlipCheat(cheatseq_t* c);
static int osdcmd_noclip(CCmdFuncPtr) static int osdcmd_noclip(CCmdFuncPtr)
@ -225,7 +212,6 @@ int32_t registerosdcommands(void)
C_RegisterFunction("map","map <mapname>: loads the given map", osdcmd_map); C_RegisterFunction("map","map <mapname>: loads the given map", osdcmd_map);
C_RegisterFunction("exitmap", "exits current map", osdcmd_exitmap); C_RegisterFunction("exitmap", "exits current map", osdcmd_exitmap);
C_RegisterFunction("doors", "opens/closes doors", osdcmd_doors); C_RegisterFunction("doors", "opens/closes doors", osdcmd_doors);
C_RegisterFunction("god","god: toggles god mode", osdcmd_god);
C_RegisterFunction("noclip","noclip: toggles clipping mode", osdcmd_noclip); C_RegisterFunction("noclip","noclip: toggles clipping mode", osdcmd_noclip);
C_RegisterFunction("spawn","spawn <creaturetype>: spawns a creature",osdcmd_spawn); C_RegisterFunction("spawn","spawn <creaturetype>: spawns a creature",osdcmd_spawn);
C_RegisterFunction("warptocoords","warptocoords [x] [y] [z] [ang] (optional) [horiz] (optional): warps the player to the specified coordinates",osdcmd_warptocoords); C_RegisterFunction("warptocoords","warptocoords [x] [y] [z] [ang] (optional) [horiz] (optional): warps the player to the specified coordinates",osdcmd_warptocoords);

View file

@ -1281,29 +1281,7 @@ loc_1AB8E:
uint16_t buttons = sPlayerInput[nPlayer].buttons; uint16_t buttons = sPlayerInput[nPlayer].buttons;
auto actions = sPlayerInput[nPlayer].actions; auto actions = sPlayerInput[nPlayer].actions;
if (buttons & kButtonCheatGodMode) // LOBODEITY cheat if (buttons & kButtonCheatGuns) // LOBOCOP cheat
{
char strDeity[96]; // TODO - reduce in size?
const char *strDMode = NULL;
if (PlayerList[nPlayer].invincibility >= 0)
{
PlayerList[nPlayer].invincibility = -1;
strDMode = "ON";
}
else
{
PlayerList[nPlayer].invincibility = 0;
strDMode = "OFF";
}
sPlayerInput[nPlayer].buttons &= 0xBF;
sprintf(strDeity, "Deity mode %s for player", strDMode);
StatusMessage(150, strDeity);
}
else if (buttons & kButtonCheatGuns) // LOBOCOP cheat
{ {
FillWeapons(nPlayer); FillWeapons(nPlayer);
StatusMessage(150, "All weapons loaded for player"); StatusMessage(150, "All weapons loaded for player");

View file

@ -120,16 +120,6 @@ static int ccmd_map(CCmdFuncPtr parm)
return CCMD_OK; return CCMD_OK;
} }
static int ccmd_god(CCmdFuncPtr)
{
if (numplayers == 1 && ps[myconnectindex].gm & MODE_GAME)
cheatGod(nullptr);
else
Printf("god: Not in a single-player game.\n");
return CCMD_OK;
}
static int ccmd_noclip(CCmdFuncPtr) static int ccmd_noclip(CCmdFuncPtr)
{ {
if (numplayers == 1 && ps[myconnectindex].gm & MODE_GAME) if (numplayers == 1 && ps[myconnectindex].gm & MODE_GAME)
@ -333,7 +323,6 @@ int registerosdcommands(void)
C_RegisterFunction("map","map <mapname>: warp to the given map, identified by its name", ccmd_map); C_RegisterFunction("map","map <mapname>: warp to the given map, identified by its name", ccmd_map);
C_RegisterFunction("levelwarp","levelwarp <e> <m>: warp to episode 'e' and map 'm'", ccmd_levelwarp); C_RegisterFunction("levelwarp","levelwarp <e> <m>: warp to episode 'e' and map 'm'", ccmd_levelwarp);
C_RegisterFunction("give","give <all|health|weapons|ammo|armor|keys|inventory>: gives requested item", ccmd_give); C_RegisterFunction("give","give <all|health|weapons|ammo|armor|keys|inventory>: gives requested item", ccmd_give);
C_RegisterFunction("god","god: toggles god mode", ccmd_god);
C_RegisterFunction("noclip","noclip: toggles clipping mode", ccmd_noclip); C_RegisterFunction("noclip","noclip: toggles clipping mode", ccmd_noclip);
C_RegisterFunction("restartmap", "restartmap: restarts the current map", ccmd_restartmap); C_RegisterFunction("restartmap", "restartmap: restarts the current map", ccmd_restartmap);
C_RegisterFunction("spawn","spawn <picnum> [palnum] [cstat] [ang] [x y z]: spawns a sprite with the given properties",ccmd_spawn); C_RegisterFunction("spawn","spawn <picnum> [palnum] [cstat] [ang] [x y z]: spawns a sprite with the given properties",ccmd_spawn);

View file

@ -41,19 +41,78 @@ source as it is released.
#include "c_dispatch.h" #include "c_dispatch.h"
EXTERN_CVAR(Int, developer) EXTERN_CVAR(Int, developer)
EXTERN_CVAR(Bool, sv_cheats)
BEGIN_DUKE_NS BEGIN_DUKE_NS
bool GameInterface::CheatAllowed(bool printmsg) const char *GameInterface::CheckCheatMode()
{ {
if (ud.player_skill == 4 || (isRR() && ud.player_skill > 3) || (isRRRA() && ps[myconnectindex].nocheat)) if (sv_cheats && (ud.player_skill == 4 || (isRR() && ud.player_skill > 3) || (isRRRA() && ps[myconnectindex].nocheat)))
{ {
if (printmsg) FTA(22, &ps[myconnectindex]); return quoteMgr.GetQuote(QUOTE_CHEATS_DISABLED);
return false;
} }
return true; return nullptr;
} }
const char *cheatGod(int myconnectindex, int state)
{
if (state == -1) state = 1 - ud.god;
ud.god = state;
sprite[ps[myconnectindex].i].extra = max_player_health;
hittype[ps[myconnectindex].i].extra = 0;
if (ud.god)
{
if (isRRRA()) S_PlaySound(218, CHAN_AUTO, CHANF_UI);
sprite[ps[myconnectindex].i].cstat = 257;
hittype[ps[myconnectindex].i].temp_data[0] = 0;
hittype[ps[myconnectindex].i].temp_data[1] = 0;
hittype[ps[myconnectindex].i].temp_data[2] = 0;
hittype[ps[myconnectindex].i].temp_data[3] = 0;
hittype[ps[myconnectindex].i].temp_data[4] = 0;
hittype[ps[myconnectindex].i].temp_data[5] = 0;
sprite[ps[myconnectindex].i].hitag = 0;
sprite[ps[myconnectindex].i].lotag = 0;
sprite[ps[myconnectindex].i].pal =
ps[myconnectindex].palookup;
return quoteMgr.GetQuote(QUOTE_CHEAT_GODMODE_ON);
}
else
{
ud.god = 0;
sprite[ps[myconnectindex].i].extra = max_player_health;
hittype[ps[myconnectindex].i].extra = -1;
ps[myconnectindex].last_extra = max_player_health;
return quoteMgr.GetQuote(QUOTE_CHEAT_GODMODE_OFF);
}
}
const char* GameInterface::GenericCheat(int player, int cheat)
{
switch (cheat)
{
case CHT_GOD:
return cheatGod(player, -1);
case CHT_GODOFF:
return cheatGod(player, 0);
case CHT_GODON:
return cheatGod(player, 1);
default:
return nullptr;
}
}
bool cheatWeapons(cheatseq_t *s) bool cheatWeapons(cheatseq_t *s)
{ {
int weaponLimit = (VOLUMEONE) ? SHRINKER_WEAPON : MAX_WEAPONS; int weaponLimit = (VOLUMEONE) ? SHRINKER_WEAPON : MAX_WEAPONS;
@ -124,43 +183,6 @@ static bool cheatAllen(cheatseq_t *)
return true; return true;
} }
bool cheatGod(cheatseq_t *)
{
ud.god = 1-ud.god;
if(ud.god)
{
if (isRRRA()) S_PlaySound(218, CHAN_AUTO, CHANF_UI);
sprite[ps[myconnectindex].i].cstat = 257;
hittype[ps[myconnectindex].i].temp_data[0] = 0;
hittype[ps[myconnectindex].i].temp_data[1] = 0;
hittype[ps[myconnectindex].i].temp_data[2] = 0;
hittype[ps[myconnectindex].i].temp_data[3] = 0;
hittype[ps[myconnectindex].i].temp_data[4] = 0;
hittype[ps[myconnectindex].i].temp_data[5] = 0;
sprite[ps[myconnectindex].i].hitag = 0;
sprite[ps[myconnectindex].i].lotag = 0;
sprite[ps[myconnectindex].i].pal =
ps[myconnectindex].palookup;
FTA(17,&ps[myconnectindex]);
}
else
{
ud.god = 0;
sprite[ps[myconnectindex].i].extra = max_player_health;
hittype[ps[myconnectindex].i].extra = -1;
ps[myconnectindex].last_extra = max_player_health;
FTA(18,&ps[myconnectindex]);
}
sprite[ps[myconnectindex].i].extra = max_player_health;
hittype[ps[myconnectindex].i].extra = 0;
return true;
}
bool cheatStuff(cheatseq_t *) bool cheatStuff(cheatseq_t *)
{ {
cheatWeapons(nullptr); cheatWeapons(nullptr);
@ -418,115 +440,115 @@ static bool cheatKfc(cheatseq_t *)
} }
static cheatseq_t dukecheats[] = { static cheatseq_t dukecheats[] = {
{ "dncornholio", cheatGod }, { "dncornholio", "god" },
{ "dnstuff", cheatStuff }, { "dnstuff", nullptr, cheatStuff },
{ "dnscotty###", cheatLevel }, { "dnscotty###", nullptr, cheatLevel },
{ "dncoords", cheatCoord, 1 }, { "dncoords", nullptr, cheatCoord, 1 },
{ "dnview", cheatView, 1 }, { "dnview", nullptr, cheatView, 1 },
{ "dntime", cheatTime, 1 }, { "dntime", nullptr, cheatTime, 1 },
{ "dnunlock", cheatUnlock }, { "dnunlock", nullptr, cheatUnlock },
{ "dncashman", cheatCashman }, { "dncashman", nullptr, cheatCashman },
{ "dnitems", cheatItems }, { "dnitems", nullptr, cheatItems },
{ "dnrate", cheatRate, 1 }, { "dnrate", nullptr, cheatRate, 1 },
{ "dnskill#", cheatSkill }, { "dnskill#", nullptr, cheatSkill },
{ "dnbeta", cheatBeta }, { "dnbeta", nullptr, cheatBeta },
{ "dnhyper", cheatHyper }, { "dnhyper", nullptr, cheatHyper },
{ "dnmonsters", cheatMonsters }, { "dnmonsters", nullptr, cheatMonsters },
{ "dntodd", cheatTodd }, { "dntodd", nullptr, cheatTodd },
{ "dnshowmap", cheatMap }, { "dnshowmap", nullptr, cheatMap },
{ "dnkroz", cheatGod }, { "dnkroz", "god" },
{ "dnallen", cheatAllen }, { "dnallen", nullptr, cheatAllen },
{ "dnclip", cheatClip }, { "dnclip", nullptr, cheatClip },
{ "dnweapons", cheatWeapons }, { "dnweapons", nullptr, cheatWeapons },
{ "dninventory", cheatInventory }, { "dninventory", nullptr, cheatInventory },
{ "dnkeys", cheatKeys }, { "dnkeys", nullptr, cheatKeys },
{ "dndebug", cheatDebug, 1 }, { "dndebug", nullptr, cheatDebug, 1 },
{ "dncgs", cheatKill }, { "dncgs", nullptr, cheatKill },
}; };
static cheatseq_t ww2cheats[] = static cheatseq_t ww2cheats[] =
{ {
// Use the same code prefix as EDuke because 'ww' is not usable here. Since the cheat parser eats input after the second key, this could easily cause interference for WASD users. // Use the same code prefix as EDuke because 'ww' is not usable here. Since the cheat parser eats input after the second key, this could easily cause interference for WASD users.
{ "gi2god", cheatGod }, { "gi2god", "god" },
{ "gi2blood", cheatStuff }, { "gi2blood", nullptr, cheatStuff },
{ "gi2level###", cheatLevel }, { "gi2level###", nullptr, cheatLevel },
{ "gi2coords", cheatCoord, 1 }, { "gi2coords", nullptr, cheatCoord, 1 },
{ "gi2view", cheatView, 1 }, { "gi2view", nullptr, cheatView, 1 },
{ "gi2time", cheatTime, 1 }, { "gi2time", nullptr, cheatTime, 1 },
{ "gi2rate", cheatRate, 1 }, { "gi2rate", nullptr, cheatRate, 1 },
{ "gi2skill", cheatSkill }, { "gi2skill", nullptr, cheatSkill },
{ "gi2enemies", cheatMonsters }, { "gi2enemies", nullptr, cheatMonsters },
{ "gi2matt", cheatTodd }, { "gi2matt", nullptr, cheatTodd },
{ "gi2showmap", cheatMap }, { "gi2showmap", nullptr, cheatMap },
{ "gi2ryan", cheatGod }, { "gi2ryan", "god" },
{ "gi2clip", cheatClip }, { "gi2clip", nullptr, cheatClip },
{ "gi2weapons", cheatWeapons }, { "gi2weapons", nullptr, cheatWeapons },
{ "gi2inventory", cheatInventory }, { "gi2inventory", nullptr, cheatInventory },
{ "gi2debug", cheatDebug, 1 }, { "gi2debug", nullptr, cheatDebug, 1 },
{ "gi2cgs", cheatKill }, { "gi2cgs", nullptr, cheatKill },
}; };
static cheatseq_t namcheats[] = { static cheatseq_t namcheats[] = {
{ "nvacaleb", cheatGod }, { "nvacaleb", "god" },
{ "nvablood", cheatStuff }, { "nvablood", nullptr, cheatStuff },
{ "nvalevel###", cheatLevel }, { "nvalevel###", nullptr, cheatLevel },
{ "nvacoords", cheatCoord, 1 }, { "nvacoords", nullptr, cheatCoord, 1 },
{ "nvaview", cheatView, 1 }, { "nvaview", nullptr, cheatView, 1 },
{ "nvatime", cheatTime, 1 }, { "nvatime", nullptr, cheatTime, 1 },
{ "nvarate", cheatRate, 1 }, { "nvarate", nullptr, cheatRate, 1 },
{ "nvaskill", cheatSkill }, { "nvaskill", nullptr, cheatSkill },
{ "nvahyper", cheatHyper }, { "nvahyper", nullptr, cheatHyper },
{ "nvaenemies", cheatMonsters }, { "nvaenemies", nullptr, cheatMonsters },
{ "nvamatt", cheatTodd }, { "nvamatt", nullptr, cheatTodd },
{ "nvashowmap", cheatMap }, { "nvashowmap", nullptr, cheatMap },
{ "nvagod", cheatGod }, { "nvagod", "god" },
{ "nvaclip", cheatClip }, { "nvaclip", nullptr, cheatClip },
{ "nvaweapons", cheatWeapons }, { "nvaweapons", nullptr, cheatWeapons },
{ "nvainventory", cheatInventory }, { "nvainventory",nullptr, cheatInventory },
{ "nvadebug", cheatDebug, 1 }, { "nvadebug", nullptr, cheatDebug, 1 },
{ "nvacgs", cheatKill }, { "nvacgs", nullptr, cheatKill },
}; };
static cheatseq_t rrcheats[] = { static cheatseq_t rrcheats[] = {
{ "rdhounddog", cheatGod }, { "rdhounddog", "god" },
{ "rdall", cheatStuff }, { "rdall", nullptr, cheatStuff },
{ "rdmeadow###", cheatLevel }, { "rdmeadow###", nullptr, cheatLevel },
{ "rdyerat", cheatCoord, 1 }, { "rdyerat", nullptr, cheatCoord, 1 },
{ "rdview", cheatView, 1 }, { "rdview", nullptr, cheatView, 1 },
{ "rdtime", cheatTime, 1 }, { "rdtime", nullptr, cheatTime, 1 },
{ "rdunlock", cheatUnlock }, { "rdunlock", nullptr, cheatUnlock },
{ "rdcluck", cheatCashman }, { "rdcluck", nullptr, cheatCashman },
{ "rditems", cheatItems }, { "rditems", nullptr, cheatItems },
{ "rdrate", cheatRate, 1 }, { "rdrate", nullptr, cheatRate, 1 },
{ "rdskill#", cheatSkill }, { "rdskill#", nullptr, cheatSkill },
{ "rdteachers", cheatBeta }, { "rdteachers", nullptr, cheatBeta },
{ "rdmoonshine", cheatHyper }, { "rdmoonshine", nullptr, cheatHyper },
{ "rdcritters", cheatMonsters }, { "rdcritters", nullptr, cheatMonsters },
{ "rdrafael", cheatTodd }, { "rdrafael", nullptr, cheatTodd },
{ "rdshowmap", cheatMap }, { "rdshowmap", nullptr, cheatMap },
{ "rdelvis", cheatGod }, { "rdelvis", "god" },
{ "rdclip", cheatClip }, { "rdclip", nullptr, cheatClip },
{ "rdguns", cheatWeapons }, { "rdguns", nullptr, cheatWeapons },
{ "rdinventory", cheatInventory }, { "rdinventory", nullptr, cheatInventory },
{ "rdkeys", cheatKeys }, { "rdkeys", nullptr, cheatKeys },
{ "rddebug", cheatDebug, 1 }, { "rddebug", nullptr, cheatDebug, 1 },
{ "rdcgs", cheatKill }, // 23 for RR { "rdcgs", nullptr, cheatKill }, // 23 for RR
// RRRA only! // RRRA only!
{ "rdjoseph", cheatMotorcycle }, { "rdjoseph", nullptr, cheatMotorcycle },
{ "rdmrbill", cheatKill }, { "rdmrbill", nullptr, cheatKill },
{ "rdtony", cheatTony }, { "rdtony", nullptr, cheatTony },
{ "rdgary", cheatGary }, { "rdgary", nullptr, cheatGary },
{ "rdrhett", cheatRhett }, { "rdrhett", nullptr, cheatRhett },
{ "rdaaron", cheatAaron }, { "rdaaron", nullptr, cheatAaron },
{ "rdnocheat", cheatNocheat }, { "rdnocheat", nullptr, cheatNocheat },
{ "rdwoleslagle", cheatDrink }, { "rdwoleslagle",nullptr, cheatDrink },
{ "rdmikael", cheatStuff }, { "rdmikael", nullptr, cheatStuff },
{ "rdgreg", cheatSeasick }, { "rdgreg", nullptr, cheatSeasick },
//"rdnoah", // no-op //"rdnoah", nullptr, // no-op
{ "rdarijit", cheatBoat }, { "rdarijit", nullptr, cheatBoat },
{ "rddonut", cheatBoat }, { "rddonut", nullptr, cheatBoat },
{ "rdkfc", cheatKfc }, { "rdkfc", nullptr, cheatKfc },
{ "rdvan", cheatVan }, { "rdvan", nullptr, cheatVan },
}; };
void InitCheats() void InitCheats()

View file

@ -47,7 +47,6 @@ struct GameInterface : public ::GameInterface
void SerializeGameState(FSerializer& arc) override; void SerializeGameState(FSerializer& arc) override;
void QuitToTitle() override; void QuitToTitle() override;
FString GetCoordString() override; FString GetCoordString() override;
bool CheatAllowed(bool printmsg) override;
void ExitFromMenu() override; void ExitFromMenu() override;
ReservedSpace GetReservedScreenSpace(int viewsize) override; ReservedSpace GetReservedScreenSpace(int viewsize) override;
void DrawPlayerSprite(const DVector2& origin, bool onteam) override; void DrawPlayerSprite(const DVector2& origin, bool onteam) override;
@ -58,6 +57,8 @@ struct GameInterface : public ::GameInterface
void DrawBackground() override; void DrawBackground() override;
void Render() override; void Render() override;
void Ticker() override; void Ticker() override;
const char* GenericCheat(int player, int cheat) override;
const char* CheckCheatMode();
}; };

View file

@ -37,6 +37,8 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
#include "gamecontrol.h" #include "gamecontrol.h"
#include "gstrings.h" #include "gstrings.h"
#include "cheathandler.h" #include "cheathandler.h"
#include "d_protocol.h"
#include "cheats.h"
//#include "inv.h" //#include "inv.h"
BEGIN_SW_NS BEGIN_SW_NS
@ -54,7 +56,7 @@ static PLAYERp checkCheat(cheatseq_t* c)
if (CommEnabled) if (CommEnabled)
return nullptr; return nullptr;
if (Skill >= 3 && !c->DontCheck) if (Skill >= 3 && !c->DontCheck && !sv_cheats)
{ {
PutStringInfo(&Player[screenpeek], GStrings("TXTS_TOOSKILLFUL")); PutStringInfo(&Player[screenpeek], GStrings("TXTS_TOOSKILLFUL"));
return nullptr; return nullptr;
@ -63,6 +65,38 @@ static PLAYERp checkCheat(cheatseq_t* c)
return &Player[screenpeek]; return &Player[screenpeek];
} }
const char *GameInterface::CheckCheatMode()
{
if (Skill >= 3 && !sv_cheats)
{
return GStrings("TXTS_TOOSKILLFUL");
}
return nullptr;
}
const char *GameInterface::GenericCheat(int player, int cheat)
{
switch (cheat)
{
case CHT_GOD:
GodMode ^= 1; // fixme: Make god mode a player property.
return GStrings(GodMode ? "GOD MODE: ON" : "GOD MODE: OFF");
case CHT_GODOFF:
GodMode = 0; // fixme: Make god mode a player property.
return GStrings("GOD MODE: OFF");
case CHT_GODON:
GodMode = 1; // fixme: Make god mode a player property.
return GStrings("GOD MODE: ON");
default:
return nullptr;
}
}
bool RestartCheat(cheatseq_t* c) bool RestartCheat(cheatseq_t* c)
{ {
if (!checkCheat(c)) return false; if (!checkCheat(c)) return false;
@ -180,19 +214,6 @@ bool AmmoCheat(cheatseq_t* c)
return true; return true;
} }
bool GodCheat(cheatseq_t* c)
{
PLAYERp pp;
if (!(pp = checkCheat(c))) return false;
//
// GOD mode
//
GodMode ^= 1;
PutStringInfo(pp, GStrings(GodMode? "GOD MODE: ON" : "GOD MODE: OFF"));
return true;
}
bool ClipCheat(cheatseq_t* c) bool ClipCheat(cheatseq_t* c)
{ {
PLAYERp pp; PLAYERp pp;
@ -403,28 +424,29 @@ bool KeysCheat(cheatseq_t* c)
bool EveryCheatToggle(cheatseq_t* c) bool EveryCheatToggle(cheatseq_t* c)
{ {
EveryCheat ^= 1; EveryCheat ^= 1;
return WeaponCheat(c) && GodCheat(c) && ItemCheat(c); C_DoCommand("god");
return WeaponCheat(c) && ItemCheat(c);
} }
// The prefix was changed from 'sw' to 'lw' so that it doesn't contain two keys of the WASD control scheme, which interferes with input control. // The prefix was changed from 'sw' to 'lw' so that it doesn't contain two keys of the WASD control scheme, which interferes with input control.
static cheatseq_t swcheats[] = { static cheatseq_t swcheats[] = {
{"lwgod", GodCheat, 0}, {"lwgod", "god" },
{"lwchan", GodCheat, 0}, {"lwchan", "god" },
{"lwgimme", ItemCheat, 0}, {"lwgimme", nullptr, ItemCheat, 0},
{"lwmedic", HealCheat, 0}, {"lwmedic", nullptr, HealCheat, 0},
{"lwkey#", KeyCheat, 0}, {"lwkey#", nullptr, KeyCheat, 0},
{"lwkeys", KeysCheat, 0}, {"lwkeys", nullptr, KeysCheat, 0},
{"lwammo", AmmoCheat, 0}, {"lwammo", nullptr, AmmoCheat, 0},
{"lwarmor", ArmorCheat, 0}, {"lwarmor", nullptr, ArmorCheat, 0},
{"lwitems", ItemCheat, 0}, {"lwitems", nullptr, ItemCheat, 0},
{"lwguns", WeaponCheat, 0}, {"lwguns", nullptr, WeaponCheat, 0},
{"lwtrek##", WarpCheat, 0}, {"lwtrek##", nullptr, WarpCheat, 0},
{"lwgreed", EveryCheatToggle, 0}, {"lwgreed", nullptr, EveryCheatToggle, 0},
{"lwghost", ClipCheat, 0}, {"lwghost", nullptr, ClipCheat, 0},
{"lwstart", RestartCheat, 0}, {"lwstart", nullptr, RestartCheat, 0},
{"lwloc", LocCheat, 0}, {"lwloc", nullptr, LocCheat, 0},
{"lwmap", MapCheat, 0}, {"lwmap", nullptr, MapCheat, 0},
{"lwroom", RoomCheat, true}, // Room above room dbug {"lwroom", nullptr, RoomCheat, true}, // Room above room dbug
}; };

View file

@ -2226,6 +2226,9 @@ struct GameInterface : ::GameInterface
void Ticker(void) override; void Ticker(void) override;
void Render() override; void Render() override;
void Startup() override; void Startup() override;
const char *CheckCheatMode() override;
const char* GenericCheat(int player, int cheat) override;
GameStats getStats() override; GameStats getStats() override;
}; };

View file

@ -100,12 +100,6 @@ static int osdcmd_map(CCmdFuncPtr parm)
return CCMD_OK; return CCMD_OK;
} }
static int osdcmd_god(CCmdFuncPtr)
{
C_DoCommand("activatecheat lwgod");
return CCMD_OK;
}
static int osdcmd_noclip(CCmdFuncPtr) static int osdcmd_noclip(CCmdFuncPtr)
{ {
C_DoCommand("activatecheat lwghost"); C_DoCommand("activatecheat lwghost");
@ -299,7 +293,6 @@ int32_t registerosdcommands(void)
{ {
C_RegisterFunction("map","map <mapfile>: loads the given map", osdcmd_map); C_RegisterFunction("map","map <mapfile>: loads the given map", osdcmd_map);
C_RegisterFunction("give","give <all|health|weapons|ammo|armor|keys|inventory>: gives requested item", osdcmd_give); C_RegisterFunction("give","give <all|health|weapons|ammo|armor|keys|inventory>: gives requested item", osdcmd_give);
C_RegisterFunction("god","god: toggles god mode", osdcmd_god);
C_RegisterFunction("bunny", "bunny: toggles bunny rocket mode", osdcmd_bunny); C_RegisterFunction("bunny", "bunny: toggles bunny rocket mode", osdcmd_bunny);
C_RegisterFunction("mirror_debug", "mirror [mirrornum]: print mirror debug info", osdcmd_mirror); C_RegisterFunction("mirror_debug", "mirror [mirrornum]: print mirror debug info", osdcmd_mirror);
C_RegisterFunction("noclip","noclip: toggles clipping mode", osdcmd_noclip); C_RegisterFunction("noclip","noclip: toggles clipping mode", osdcmd_noclip);