raze-gles/source/games/duke/src/cheats.cpp
Christoph Oelckers 3e5e956b72 - run most cheats through the network.
The remaining excpetions are the "give" CCMD and any level change action.
Unfortunately the implementation of most cheats is not multiplayer safe so right now it'd only be useful for demo recording (assuming that worked to begin with... ;))
2020-09-03 01:32:51 +02:00

485 lines
15 KiB
C++

//-------------------------------------------------------------------------
/*
Copyright (C) 1996, 2003 - 3D Realms Entertainment
Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements)
Copyright (C) 2017-2019 Nuke.YKT
Copyright (C) 2020 Christoph Oelckers
This file is part of Enhanced Duke Nukem 3D version 1.5 - Atomic Edition
Duke Nukem 3D is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Original Source: 1996 - Todd Replogle
Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
EDuke enhancements integrated: 04/13/2003 - Matt Saettler
Note: EDuke source was in transition. Changes are in-progress in the
source as it is released.
*/
//-------------------------------------------------------------------------
#include "ns.h"
#include "duke3d.h"
#include "c_cvars.h"
#include "mapinfo.h"
#include "cheathandler.h"
#include "c_dispatch.h"
EXTERN_CVAR(Int, developer)
EXTERN_CVAR(Bool, sv_cheats)
BEGIN_DUKE_NS
const char *GameInterface::CheckCheatMode()
{
if (sv_cheats && (ud.player_skill == 4 || (isRR() && ud.player_skill > 3) || (isRRRA() && ps[myconnectindex].nocheat)))
{
return quoteMgr.GetQuote(QUOTE_CHEATS_DISABLED);
}
return nullptr;
}
static 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);
}
}
static const char* cheatUnlock()
{
if (VOLUMEONE) return nullptr;
for (int i = numsectors - 1; i >= 0; i--) //Unlock
{
int j = sector[i].lotag;
if (j == -1 || j == 32767) continue;
if ((j & 0x7fff) > 2)
{
if (j & (0xffff - 16384))
sector[i].lotag &= (0xffff - 16384);
operatesectors(i, ps[myconnectindex].i);
}
}
fi.operateforcefields(ps[myconnectindex].i, -1);
return quoteMgr.GetQuote(QUOTE_CHEAT_UNLOCK);
}
static const char *cheatKfc(int player)
{
for (int i = 0; i < 7; i++)
{
int spr = fi.spawn(ps[player].i, TILE_HEN);
sprite[spr].pal = 1;
sprite[spr].xrepeat = sprite[spr].xrepeat << 2;
sprite[spr].yrepeat = sprite[spr].yrepeat << 2;
}
return quoteMgr.GetQuote(QUOTE_CHEAT_KFC);
}
static const char * cheatMonsters()
{
static char textbuf[64];
if (++actor_tog == 3) actor_tog = 0;
static const char* s[] = { "OPTVAL_ON", "OPTVAL_OFF", "TXT_ON2" };
mysnprintf(textbuf, 64, "%s: %s", GStrings("NETMNU_MONSTERS"), GStrings(s[actor_tog]));
return textbuf;
}
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);
case CHT_NOCLIP:
ud.clipping = 1 - ud.clipping;
return quoteMgr.GetQuote(ud.clipping ? QUOTE_CHEAT_NOCLIP : QUOTE_CHEAT_NOCLIP);
case CHT_UNLOCK:
return cheatUnlock();
case CHT_CASHMAN:
ud.cashman = 1 - ud.cashman;
return nullptr;
case CHT_HYPER:
ps[player].steroids_amount = 399;
return quoteMgr.GetQuote(QUOTE_CHEAT_STEROIDS);
case CHT_KILL:
quickkill(&ps[player]);
return quoteMgr.GetQuote(QUOTE_CHEAT_KILL);
case CHT_MONSTERS:
return cheatMonsters();
case CHT_BIKE:
OnMotorcycle(&ps[player], 0);
ps[player].ammo_amount[MOTORCYCLE_WEAPON] = max_ammo_amount[MOTORCYCLE_WEAPON];
return quoteMgr.GetQuote(QUOTE_ON_BIKE);
case CHT_BOAT:
OnBoat(&ps[player], 0);
ps[player].ammo_amount[BOAT_WEAPON] = max_ammo_amount[BOAT_WEAPON];
return quoteMgr.GetQuote(QUOTE_ON_BOAT);
case CHT_TONY:
enemysizecheat = 2;
return nullptr;
case CHT_VAN:
enemysizecheat = 3;
return nullptr;
case CHT_RHETT:
ud.god = 0;
ps[player].gotweapon.Zero();
ps[player].curr_weapon = KNEE_WEAPON;
ps[player].nocheat = 1;
sprite[ps[player].i].extra = 1;
return quoteMgr.GetQuote(QUOTE_YERFUCKED);
case CHT_AARON:
ps[player].DrugMode = !ps[player].DrugMode;
return nullptr;
case CHT_NOCHEAT:
ps[player].nocheat = 1;
return quoteMgr.GetQuote(QUOTE_NOCHEATS);
case CHT_DRINK:
ps[player].drink_amt = ps[player].drink_amt ? 0 : 90;
return quoteMgr.GetQuote(ps[player].drink_amt ? QUOTE_INSTADRUNK : QUOTE_INSTASOBER);
case CHT_SEASICK:
ps[player].sea_sick_stat = !ps[player].sea_sick_stat;
return quoteMgr.GetQuote(ps[player].sea_sick_stat ? QUOTE_BOATMODEON : QUOTE_BOATMODEOFF);
case CHT_KFC:
return cheatKfc(player);
default:
return nullptr;
}
}
bool cheatWeapons(cheatseq_t *s)
{
int weaponLimit = (VOLUMEONE) ? SHRINKER_WEAPON : MAX_WEAPONS;
for (int weapon = PISTOL_WEAPON; weapon < weaponLimit; weapon++ )
{
addammo( weapon, &ps[myconnectindex], max_ammo_amount[weapon] );
ps[myconnectindex].gotweapon.Set(weapon);
}
if (isRRRA())
ps[myconnectindex].ammo_amount[SLINGBLADE_WEAPON] = 1;
if (s) FTA(119,&ps[myconnectindex]);
return true;
}
bool cheatInventory(cheatseq_t *s)
{
auto invGet = [](int defvalue, int evtype, int16_t &dest)
{
SetGameVarID(g_iReturnVarID, defvalue, -1, myconnectindex);
OnEvent(evtype, -1, myconnectindex, -1);
if (GetGameVarID(g_iReturnVarID, -1, myconnectindex) >= 0)
{
dest = GetGameVarID(g_iReturnVarID, -1, myconnectindex);
}
};
invGet(400, EVENT_CHEATGETSTEROIDS, ps[myconnectindex].steroids_amount);
if (!isRR()) invGet(1200, EVENT_CHEATGETHEAT, ps[myconnectindex].heat_amount);
invGet(isRR() ? 2000 : 200, EVENT_CHEATGETBOOT, ps[myconnectindex].boot_amount);
invGet(100, EVENT_CHEATGETSHIELD, ps[myconnectindex].shield_amount);
invGet(6400, EVENT_CHEATGETSCUBA, ps[myconnectindex].scuba_amount);
invGet(2400, EVENT_CHEATGETHOLODUKE, ps[myconnectindex].holoduke_amount);
invGet(isRR() ? 600 : 1600, EVENT_CHEATGETJETPACK, ps[myconnectindex].jetpack_amount);
invGet(max_player_health, EVENT_CHEATGETFIRSTAID, ps[myconnectindex].firstaid_amount);
if (s) FTA(120,&ps[myconnectindex]);
return true;
}
bool cheatKeys(cheatseq_t *s)
{
ps[myconnectindex].got_access = 7;
if (isRR()) for (int ikey = 0; ikey < 5; ikey++)
ps[myconnectindex].keys[ikey] = 1;
if (s) FTA(121,&ps[myconnectindex]);
return true;
}
static bool cheatDebug(cheatseq_t *)
{
// Let's do something useful with this.
if (developer == 0) developer = 3;
else developer = 0;
return true;
}
static bool cheatAllen(cheatseq_t *)
{
FTA(79,&ps[myconnectindex]);
return true;
}
bool cheatStuff(cheatseq_t *)
{
cheatWeapons(nullptr);
cheatInventory(nullptr);
if (!isNamWW2GI()) cheatKeys(nullptr);
FTA(5,&ps[myconnectindex]);
return true;
}
static bool cheatLevel(cheatseq_t *s)
{
// Fixme: This should be broadcast as a net event once things are up again.
lastlevel = 0;
int volnume,levnume;
volnume = s->Args[0] - '0' - 1;
levnume = (s->Args[1] - '0')*10+(s->Args[2]-'0') - 1;
// Instead of hard coded range checks on volume and level, let's just check if the level is defined.
auto map = FindMapByLevelNum(levelnum(volnume, levnume));
if (map)
{
ud.nextLevel = map;
FX_StopAllSounds();
FX_SetReverb(0);
ps[myconnectindex].gm |= MODE_RESTART;
}
return true;
}
bool cheatItems(cheatseq_t *)
{
cheatInventory(nullptr);
if (!isNamWW2GI()) cheatKeys(nullptr);
FTA(5,&ps[myconnectindex]);
return true;
}
static bool cheatSkill(cheatseq_t *s)
{
lastlevel = 0;
ud.m_player_skill = ud.player_skill = s->Args[0] - '1';
ps[myconnectindex].gm |= MODE_RESTART;
FX_StopAllSounds();
FX_SetReverb(0);
return true;
}
// The remaining cheats are client side only.
static bool cheatBeta(cheatseq_t *)
{
FTA(105,&ps[myconnectindex]);
return true;
}
static bool cheatTodd(cheatseq_t *)
{
FTA(99,&ps[myconnectindex]);
return true;
}
static bool cheatMap(cheatseq_t *)
{
gFullMap = !gFullMap;
FTA(gFullMap? 111 : 1, &ps[myconnectindex]);
return true;
}
// RRRA only cheats
static bool cheatGary(cheatseq_t *)
{
S_PlayRRMusic(10);
return true;
}
static cheatseq_t dukecheats[] = {
{ "dncornholio", nullptr, SendGenericCheat, 0, CHT_GOD },
{ "dnstuff", "give all", },
{ "dnscotty###", nullptr, cheatLevel }, // -> levelwarp
{ "dncoords", "stat coord", nullptr, 1 },
{ "dnview", "third_person_view",nullptr, 1 },
{ "dntime", "stat fps", nullptr, 1 },
{ "dnunlock", nullptr, SendGenericCheat, 0, CHT_UNLOCK },
{ "dncashman", nullptr, SendGenericCheat, 0, CHT_CASHMAN },
{ "dnitems", "give items", },
{ "dnrate", "toggle vid_fps", nullptr, 1 },
{ "dnskill#", nullptr, cheatSkill }, // restartmap <skill>
{ "dnbeta", nullptr, cheatBeta },
{ "dnhyper", nullptr, SendGenericCheat, 0, CHT_HYPER },
{ "dnmonsters", nullptr, SendGenericCheat, 0, CHT_MONSTERS },
{ "dntodd", nullptr, cheatTodd },
{ "dnshowmap", nullptr, cheatMap },
{ "dnkroz", nullptr, SendGenericCheat, 0, CHT_GOD },
{ "dnallen", nullptr, cheatAllen },
{ "dnclip", nullptr, SendGenericCheat, 0, CHT_NOCLIP },
{ "dnweapons", "give weapons" },
{ "dninventory", "give inventory" },
{ "dnkeys", "give keys" },
{ "dndebug", nullptr, cheatDebug, 1 },
{ "dncgs", nullptr, SendGenericCheat, 0, CHT_KILL },
};
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.
{ "gi2god", nullptr, SendGenericCheat, 0, CHT_GOD },
{ "gi2blood", "give all", },
{ "gi2level###", nullptr, cheatLevel },
{ "gi2coords", "stat coord", nullptr, 1 },
{ "gi2view", "third_person_view",nullptr, 1 },
{ "gi2time", "stat fps", nullptr, 1 },
{ "gi2rate", "toggle vid_fps", nullptr, 1 },
{ "gi2skill", nullptr, cheatSkill },
{ "gi2enemies", nullptr, SendGenericCheat, 0, CHT_MONSTERS },
{ "gi2matt", nullptr, cheatTodd },
{ "gi2showmap", nullptr, cheatMap },
{ "gi2ryan", nullptr, SendGenericCheat, 0, CHT_GOD },
{ "gi2clip", nullptr, SendGenericCheat, 0, CHT_NOCLIP },
{ "gi2weapons", "give weapons" },
{ "gi2inventory", "give inventory" },
{ "gi2debug", nullptr, cheatDebug, 1 },
{ "gi2cgs", nullptr, SendGenericCheat, 0, CHT_KILL },
};
static cheatseq_t namcheats[] = {
{ "nvacaleb", nullptr, SendGenericCheat, 0, CHT_GOD },
{ "nvablood", "give all", },
{ "nvalevel###", nullptr, cheatLevel },
{ "nvacoords", "stat coord", nullptr, 1 },
{ "nvaview", "third_person_view",nullptr, 1 },
{ "nvatime", "stat fps", nullptr, 1 },
{ "nvarate", "toggle vid_fps", nullptr, 1 },
{ "nvaskill", nullptr, cheatSkill },
{ "nvahyper", nullptr, SendGenericCheat, 0, CHT_HYPER },
{ "nvaenemies", nullptr, SendGenericCheat, 0, CHT_MONSTERS },
{ "nvamatt", nullptr, cheatTodd },
{ "nvashowmap", nullptr, cheatMap },
{ "nvagod", nullptr, SendGenericCheat, 0, CHT_GOD },
{ "nvaclip", nullptr, SendGenericCheat, 0, CHT_NOCLIP },
{ "nvaweapons", "give weapons" },
{ "nvainventory","give inventory" },
{ "nvadebug", nullptr, cheatDebug, 1 },
{ "nvacgs", nullptr, SendGenericCheat, 0, CHT_KILL },
};
static cheatseq_t rrcheats[] = {
{ "rdhounddog", "god" },
{ "rdall", "give all", },
{ "rdmeadow###", nullptr, cheatLevel },
{ "rdyerat", "stat coord", nullptr, 1 },
{ "rdview", "third_person_view",nullptr, 1 },
{ "rdtime", "stat fps", nullptr, 1 },
{ "rdunlock", nullptr, SendGenericCheat, 0, CHT_UNLOCK },
{ "rdcluck", nullptr, SendGenericCheat, 0, CHT_CASHMAN },
{ "rditems", "give items", },
{ "rdrate", "toggle vid_fps", nullptr, 1 },
{ "rdskill#", nullptr, cheatSkill },
{ "rdteachers", nullptr, cheatBeta },
{ "rdmoonshine", nullptr, SendGenericCheat, 0, CHT_HYPER },
{ "rdcritters", nullptr, SendGenericCheat, 0, CHT_MONSTERS },
{ "rdrafael", nullptr, cheatTodd },
{ "rdshowmap", nullptr, cheatMap },
{ "rdelvis", "god" },
{ "rdclip", "noclip" },
{ "rdguns", "give weapons" },
{ "rdinventory", "give inventory" },
{ "rdkeys", "give keys" },
{ "rddebug", nullptr, cheatDebug, 1 },
{ "rdcgs", nullptr, SendGenericCheat, 0, CHT_KILL },
// RRRA only!
{ "rdjoseph", nullptr, SendGenericCheat, 0, CHT_BIKE },
{ "rdmrbill", nullptr, SendGenericCheat, 0, CHT_KILL },
{ "rdtony", nullptr, SendGenericCheat, 0, CHT_TONY },
{ "rdgary", nullptr, cheatGary },
{ "rdrhett", nullptr, SendGenericCheat, 0, CHT_RHETT },
{ "rdaaron", nullptr, SendGenericCheat, 0, CHT_AARON },
{ "rdnocheat", nullptr, SendGenericCheat, 0, CHT_NOCHEAT },
{ "rdwoleslagle",nullptr, SendGenericCheat, 0, CHT_DRINK },
{ "rdmikael", "give all", },
{ "rdgreg", nullptr, SendGenericCheat, 0, CHT_SEASICK },
//"rdnoah", nullptr, // no-op
{ "rdarijit", nullptr, SendGenericCheat, 0, CHT_BOAT },
{ "rddonut", nullptr, SendGenericCheat, 0, CHT_BOAT },
{ "rdkfc", nullptr, SendGenericCheat, 0, CHT_KFC },
{ "rdvan", nullptr, SendGenericCheat, 0, CHT_VAN },
};
void InitCheats()
{
if (isRRRA()) SetCheats(rrcheats, countof(rrcheats));
else if (isRR()) SetCheats(rrcheats, 23);
else if (isWW2GI()) SetCheats(ww2cheats, countof(ww2cheats));
else if (isNam()) SetCheats(namcheats, countof(namcheats));
else SetCheats(dukecheats, countof(dukecheats));
}
END_DUKE_NS