mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-16 17:32:13 +00:00
541 lines
13 KiB
C++
541 lines
13 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"
|
|
|
|
EXTERN_CVAR(Int, developer)
|
|
|
|
BEGIN_DUKE_NS
|
|
|
|
bool GameInterface::CheatAllowed(bool printmsg)
|
|
{
|
|
if (ud.player_skill == 4 || (isRR() && ud.player_skill > 3) || (isRRRA() && ps[myconnectindex].nocheat))
|
|
{
|
|
if (printmsg) FTA(22, &ps[myconnectindex]);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
bool cheatClip(cheatseq_t *)
|
|
{
|
|
ud.clipping = 1-ud.clipping;
|
|
FTA(112+ud.clipping,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatAllen(cheatseq_t *)
|
|
{
|
|
FTA(79,&ps[myconnectindex]);
|
|
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 *)
|
|
{
|
|
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.
|
|
g_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.
|
|
if (mapList[volnume*MAXLEVELS + levnume].fileName.IsNotEmpty())
|
|
{
|
|
FX_StopAllSounds();
|
|
FX_SetReverb(0);
|
|
ud.m_volume_number = ud.volume_number = volnume;
|
|
ud.m_level_number = ud.level_number = levnume;
|
|
ps[myconnectindex].gm |= MODE_RESTART;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool cheatCoord(cheatseq_t *)
|
|
{
|
|
C_DoCommand("stat coord");
|
|
return true;
|
|
}
|
|
|
|
static bool cheatTime(cheatseq_t *)
|
|
{
|
|
C_DoCommand("stat fps");
|
|
return true;
|
|
}
|
|
|
|
static bool cheatRate(cheatseq_t *)
|
|
{
|
|
C_DoCommand("toggle vid_fps");
|
|
return true;
|
|
}
|
|
|
|
static bool cheatItems(cheatseq_t *)
|
|
{
|
|
cheatInventory(nullptr);
|
|
if (!isNamWW2GI()) cheatKeys(nullptr);
|
|
FTA(5,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
|
|
static bool cheatView(cheatseq_t *)
|
|
{
|
|
if (ps[myconnectindex].OnMotorcycle == 0 && ps[myconnectindex].OnBoat == 0)
|
|
{
|
|
if( ps[myconnectindex].over_shoulder_on )
|
|
ps[myconnectindex].over_shoulder_on = 0;
|
|
else
|
|
{
|
|
ps[myconnectindex].over_shoulder_on = 1;
|
|
cameradist = 0;
|
|
cameraclock = (int)totalclock;
|
|
}
|
|
//FTA(22,&ps[myconnectindex]); this message makes no sense.
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool cheatUnlock(cheatseq_t *)
|
|
{
|
|
if (VOLUMEONE) return false;
|
|
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);
|
|
FTA(100,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatCashman(cheatseq_t *)
|
|
{
|
|
ud.cashman = 1-ud.cashman;
|
|
return true;
|
|
}
|
|
|
|
static bool cheatSkill(cheatseq_t *s)
|
|
{
|
|
g_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;
|
|
}
|
|
|
|
static bool cheatBeta(cheatseq_t *)
|
|
{
|
|
FTA(105,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatTodd(cheatseq_t *)
|
|
{
|
|
FTA(99,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatHyper(cheatseq_t *)
|
|
{
|
|
ps[myconnectindex].steroids_amount = 399;
|
|
FTA(37,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatMonsters(cheatseq_t *)
|
|
{
|
|
if(actor_tog == 3) actor_tog = 0;
|
|
actor_tog++;
|
|
static const char *s [] = { "OPTVAL_ON", "OPTVAL_OFF", "$TXT_ON2" };
|
|
Printf(PRINT_NOTIFY, "%s: %s", GStrings("NETMNU_MONSTERS"), s[actor_tog]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatMap(cheatseq_t *)
|
|
{
|
|
gFullMap = !gFullMap;
|
|
FTA(gFullMap? 111 : 1, &ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatKill(cheatseq_t *)
|
|
{
|
|
quickkill(&ps[myconnectindex]);
|
|
FTA(127,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
// RRRA only cheats
|
|
|
|
static bool cheatMotorcycle(cheatseq_t *)
|
|
{
|
|
OnMotorcycle(&ps[myconnectindex],0);
|
|
ps[myconnectindex].ammo_amount[MOTORCYCLE_WEAPON] = max_ammo_amount[MOTORCYCLE_WEAPON];
|
|
FTA(126,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatBoat(cheatseq_t *)
|
|
{
|
|
OnBoat(&ps[myconnectindex],0);
|
|
ps[myconnectindex].ammo_amount[BOAT_WEAPON] = max_ammo_amount[BOAT_WEAPON];
|
|
FTA(136,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatTony(cheatseq_t *)
|
|
{
|
|
enemysizecheat = 2;
|
|
return true;
|
|
}
|
|
|
|
static bool cheatVan(cheatseq_t *)
|
|
{
|
|
enemysizecheat = 3;
|
|
return true;
|
|
}
|
|
|
|
static bool cheatGary(cheatseq_t *)
|
|
{
|
|
S_PlayRRMusic(10);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatRhett(cheatseq_t *)
|
|
{
|
|
ud.god = 0;
|
|
ps[myconnectindex].gotweapon.Zero();
|
|
ps[myconnectindex].curr_weapon = KNEE_WEAPON;
|
|
ps[myconnectindex].nocheat = 1;
|
|
sprite[ps[myconnectindex].i].extra = 1;
|
|
FTA(128,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatAaron(cheatseq_t *)
|
|
{
|
|
if (ps[myconnectindex].DrugMode)
|
|
ps[myconnectindex].DrugMode = 0;
|
|
else
|
|
ps[myconnectindex].DrugMode = 5;
|
|
return true;
|
|
}
|
|
|
|
static bool cheatNocheat(cheatseq_t *)
|
|
{
|
|
ps[myconnectindex].nocheat = 1;
|
|
FTA(130,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static bool cheatDrink(cheatseq_t *)
|
|
{
|
|
if (ps[myconnectindex].drink_amt)
|
|
{
|
|
ps[myconnectindex].drink_amt = 0;
|
|
FTA(132,&ps[myconnectindex]);
|
|
}
|
|
else
|
|
{
|
|
ps[myconnectindex].drink_amt = 90;
|
|
FTA(131,&ps[myconnectindex]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool cheatSeasick(cheatseq_t *)
|
|
{
|
|
if (ps[myconnectindex].sea_sick_stat)
|
|
{
|
|
ps[myconnectindex].sea_sick_stat = 0;
|
|
FTA(129,&ps[myconnectindex]);
|
|
}
|
|
else
|
|
{
|
|
ps[myconnectindex].sea_sick_stat = 1;
|
|
FTA(137, &ps[myconnectindex]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool cheatKfc(cheatseq_t *)
|
|
{
|
|
for (int i = 0; i < 7; i++)
|
|
{
|
|
int spr = fi.spawn(ps[screenpeek].i,TILE_HEN);
|
|
sprite[spr].pal = 1;
|
|
sprite[spr].xrepeat = sprite[spr].xrepeat<<2;
|
|
sprite[spr].yrepeat = sprite[spr].yrepeat<<2;
|
|
}
|
|
FTA(139,&ps[myconnectindex]);
|
|
return true;
|
|
}
|
|
|
|
static cheatseq_t dukecheats[] = {
|
|
{ "dncornholio", cheatGod },
|
|
{ "dnstuff", cheatStuff },
|
|
{ "dnscotty###", cheatLevel },
|
|
{ "dncoords", cheatCoord, 1 },
|
|
{ "dnview", cheatView, 1 },
|
|
{ "dntime", cheatTime, 1 },
|
|
{ "dnunlock", cheatUnlock },
|
|
{ "dncashman", cheatCashman },
|
|
{ "dnitems", cheatItems },
|
|
{ "dnrate", cheatRate, 1 },
|
|
{ "dnskill#", cheatSkill },
|
|
{ "dnbeta", cheatBeta },
|
|
{ "dnhyper", cheatHyper },
|
|
{ "dnmonsters", cheatMonsters },
|
|
{ "dntodd", cheatTodd },
|
|
{ "dnshowmap", cheatMap },
|
|
{ "dnkroz", cheatGod },
|
|
{ "dnallen", cheatAllen },
|
|
{ "dnclip", cheatClip },
|
|
{ "dnweapons", cheatWeapons },
|
|
{ "dninventory", cheatInventory },
|
|
{ "dnkeys", cheatKeys },
|
|
{ "dndebug", cheatDebug, 1 },
|
|
{ "dncgs", cheatKill },
|
|
};
|
|
|
|
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", cheatGod },
|
|
{ "gi2blood", cheatStuff },
|
|
{ "gi2level###", cheatLevel },
|
|
{ "gi2coords", cheatCoord, 1 },
|
|
{ "gi2view", cheatView, 1 },
|
|
{ "gi2time", cheatTime, 1 },
|
|
{ "gi2rate", cheatRate, 1 },
|
|
{ "gi2skill", cheatSkill },
|
|
{ "gi2enemies", cheatMonsters },
|
|
{ "gi2matt", cheatTodd },
|
|
{ "gi2showmap", cheatMap },
|
|
{ "gi2ryan", cheatGod },
|
|
{ "gi2clip", cheatClip },
|
|
{ "gi2weapons", cheatWeapons },
|
|
{ "gi2inventory", cheatInventory },
|
|
{ "gi2debug", cheatDebug, 1 },
|
|
{ "gi2cgs", cheatKill },
|
|
};
|
|
|
|
static cheatseq_t namcheats[] = {
|
|
{ "nvacaleb", cheatGod },
|
|
{ "nvablood", cheatStuff },
|
|
{ "nvalevel###", cheatLevel },
|
|
{ "nvacoords", cheatCoord, 1 },
|
|
{ "nvaview", cheatView, 1 },
|
|
{ "nvatime", cheatTime, 1 },
|
|
{ "nvarate", cheatRate, 1 },
|
|
{ "nvaskill", cheatSkill },
|
|
{ "nvahyper", cheatHyper },
|
|
{ "nvaenemies", cheatMonsters },
|
|
{ "nvamatt", cheatTodd },
|
|
{ "nvashowmap", cheatMap },
|
|
{ "nvagod", cheatGod },
|
|
{ "nvaclip", cheatClip },
|
|
{ "nvaweapons", cheatWeapons },
|
|
{ "nvainventory", cheatInventory },
|
|
{ "nvadebug", cheatDebug, 1 },
|
|
{ "nvacgs", cheatKill },
|
|
};
|
|
|
|
static cheatseq_t rrcheats[] = {
|
|
{ "rdhounddog", cheatGod },
|
|
{ "rdall", cheatStuff },
|
|
{ "rdmeadow###", cheatLevel },
|
|
{ "rdyerat", cheatCoord, 1 },
|
|
{ "rdview", cheatView, 1 },
|
|
{ "rdtime", cheatTime, 1 },
|
|
{ "rdunlock", cheatUnlock },
|
|
{ "rdcluck", cheatCashman },
|
|
{ "rditems", cheatItems },
|
|
{ "rdrate", cheatRate, 1 },
|
|
{ "rdskill#", cheatSkill },
|
|
{ "rdteachers", cheatBeta },
|
|
{ "rdmoonshine", cheatHyper },
|
|
{ "rdcritters", cheatMonsters },
|
|
{ "rdrafael", cheatTodd },
|
|
{ "rdshowmap", cheatMap },
|
|
{ "rdelvis", cheatGod },
|
|
{ "rdclip", cheatClip },
|
|
{ "rdguns", cheatWeapons },
|
|
{ "rdinventory", cheatInventory },
|
|
{ "rdkeys", cheatKeys },
|
|
{ "rddebug", cheatDebug, 1 },
|
|
{ "rdcgs", cheatKill }, // 23 for RR
|
|
// RRRA only!
|
|
{ "rdjoseph", cheatMotorcycle },
|
|
{ "rdmrbill", cheatKill },
|
|
{ "rdtony", cheatTony },
|
|
{ "rdgary", cheatGary },
|
|
{ "rdrhett", cheatRhett },
|
|
{ "rdaaron", cheatAaron },
|
|
{ "rdnocheat", cheatNocheat },
|
|
{ "rdwoleslagle", cheatDrink },
|
|
{ "rdmikael", cheatStuff },
|
|
{ "rdgreg", cheatSeasick },
|
|
//"rdnoah", // no-op
|
|
{ "rdarijit", cheatBoat },
|
|
{ "rddonut", cheatBoat },
|
|
{ "rdkfc", cheatKfc },
|
|
{ "rdvan", cheatVan },
|
|
};
|
|
|
|
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
|