2015-05-19 21:54:34 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 1997, 2005 - 3D Realms Entertainment
|
|
|
|
|
|
|
|
This file is part of Shadow Warrior version 1.2
|
|
|
|
|
|
|
|
Shadow Warrior 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
Original Source: 1997 - Frank Maddin and Jim Norwood
|
|
|
|
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
2019-11-17 17:02:17 +00:00
|
|
|
|
2019-10-09 16:09:05 +00:00
|
|
|
#include "ns.h"
|
|
|
|
|
2015-05-19 21:54:34 +00:00
|
|
|
#include "build.h"
|
|
|
|
|
|
|
|
#include "names2.h"
|
|
|
|
#include "panel.h"
|
|
|
|
#include "game.h"
|
|
|
|
#include "mytypes.h"
|
2020-08-05 22:18:45 +00:00
|
|
|
#include "misc.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2019-10-25 22:32:49 +00:00
|
|
|
#include "gamecontrol.h"
|
2019-12-09 20:19:05 +00:00
|
|
|
#include "gstrings.h"
|
2020-08-12 20:24:51 +00:00
|
|
|
#include "cheathandler.h"
|
2020-09-02 22:29:17 +00:00
|
|
|
#include "d_protocol.h"
|
|
|
|
#include "cheats.h"
|
2020-09-03 15:39:41 +00:00
|
|
|
#include "gamestate.h"
|
2020-09-06 18:49:43 +00:00
|
|
|
#include "automap.h"
|
2015-05-19 21:54:34 +00:00
|
|
|
//#include "inv.h"
|
|
|
|
|
2019-10-09 16:09:05 +00:00
|
|
|
BEGIN_SW_NS
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-09-09 17:52:52 +00:00
|
|
|
SWBOOL CheatInputMode = false;
|
|
|
|
SWBOOL EveryCheat = false;
|
2020-03-01 15:33:06 +00:00
|
|
|
SWBOOL mapcheat = false;
|
2020-08-12 20:24:51 +00:00
|
|
|
extern SWBOOL FAF_DebugView;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2019-11-17 17:02:17 +00:00
|
|
|
const char *CheatKeyType;
|
|
|
|
void KeysCheat(PLAYERp pp, const char *cheat_string);
|
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
static PLAYERp checkCheat(cheatseq_t* c)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-09-04 19:15:15 +00:00
|
|
|
if (::CheckCheatmode(true, true)) return nullptr;
|
2020-08-12 20:24:51 +00:00
|
|
|
return &Player[screenpeek];
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2020-09-02 22:29:17 +00:00
|
|
|
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");
|
|
|
|
|
2020-09-02 22:41:32 +00:00
|
|
|
case CHT_NOCLIP:
|
|
|
|
Player[player].Flags ^= PF_CLIP_CHEAT;
|
|
|
|
return GStrings(Player[player].Flags & PF_CLIP_CHEAT ? "CLIPPING: OFF" : "CLIPPING: ON");
|
|
|
|
|
2020-09-02 22:29:17 +00:00
|
|
|
default:
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
bool RestartCheat(cheatseq_t* c)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-08-12 20:24:51 +00:00
|
|
|
if (!checkCheat(c)) return false;
|
2020-09-04 19:15:15 +00:00
|
|
|
DeferedStartGame(currentLevel, -1);
|
2020-09-04 19:17:24 +00:00
|
|
|
return true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
bool RoomCheat(cheatseq_t* c)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-09-09 18:28:05 +00:00
|
|
|
FAF_DebugView = !FAF_DebugView;
|
2020-08-12 20:24:51 +00:00
|
|
|
return true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
bool NextCheat(cheatseq_t* c)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-08-12 20:24:51 +00:00
|
|
|
if (!checkCheat(c)) return false;
|
2020-08-16 12:39:18 +00:00
|
|
|
if (!currentLevel) return true;
|
2020-09-04 19:15:15 +00:00
|
|
|
auto map = FindMapByLevelNum(currentLevel->levelNumber + 1);
|
|
|
|
if (map) DeferedStartGame(map, -1);
|
2020-08-12 20:24:51 +00:00
|
|
|
return true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
bool PrevCheat(cheatseq_t* c)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-08-12 20:24:51 +00:00
|
|
|
if (!checkCheat(c)) return false;
|
2020-08-16 12:39:18 +00:00
|
|
|
if (!currentLevel) return true;
|
2020-09-04 19:15:15 +00:00
|
|
|
auto map = FindMapByLevelNum(currentLevel->levelNumber - 1);
|
|
|
|
if (map) DeferedStartGame(map, -1);
|
2020-08-12 20:24:51 +00:00
|
|
|
return true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
bool MapCheat(cheatseq_t* c)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-08-12 20:24:51 +00:00
|
|
|
PLAYERp pp;
|
|
|
|
if (!(pp=checkCheat(c))) return false;
|
2020-09-06 18:49:43 +00:00
|
|
|
gFullMap = !gFullMap;
|
2019-12-31 21:05:23 +00:00
|
|
|
// Need to do this differently. The code here was completely broken.
|
2020-09-06 18:49:43 +00:00
|
|
|
PutStringInfo(pp, GStrings(gFullMap ? "TXTS_AMON" : "TXTS_AMOFF"));
|
2020-08-12 20:24:51 +00:00
|
|
|
return true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
bool WarpCheat(cheatseq_t* c)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-08-12 20:24:51 +00:00
|
|
|
PLAYERp pp;
|
|
|
|
if (!(pp = checkCheat(c))) return false;
|
2015-05-19 21:54:34 +00:00
|
|
|
int level_num;
|
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
level_num = atol((char*)c->Args);
|
2020-08-16 12:39:18 +00:00
|
|
|
auto maprec = FindMapByLevelNum(level_num);
|
|
|
|
if (!maprec) return false;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
if (!pp) return true;
|
2020-08-16 12:39:18 +00:00
|
|
|
if (SW_SHAREWARE)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
if (level_num > 4 || level_num < 1)
|
2020-08-12 20:24:51 +00:00
|
|
|
return false;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
2020-02-13 23:37:15 +00:00
|
|
|
if (TEST(pp->Flags, PF_DEAD))
|
2020-08-12 20:24:51 +00:00
|
|
|
return true;
|
2020-02-13 23:37:15 +00:00
|
|
|
|
2020-09-04 19:15:15 +00:00
|
|
|
DeferedStartGame(maprec, -1);
|
2020-08-12 20:24:51 +00:00
|
|
|
return true;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
bool EveryCheatToggle(cheatseq_t* c)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-09-09 18:28:05 +00:00
|
|
|
EveryCheat = !EveryCheat;
|
2020-09-03 15:39:41 +00:00
|
|
|
C_DoCommand("god");
|
|
|
|
C_DoCommand("give weapons");
|
|
|
|
C_DoCommand("give items");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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[] = {
|
|
|
|
{"lwgod", "god" },
|
|
|
|
{"lwchan", "god" },
|
|
|
|
{"lwgimme", "give all" },
|
|
|
|
{"lwmedic", "give health" },
|
|
|
|
{"lwkeys", "give keys" },
|
|
|
|
{"lwammo", "give ammo" },
|
|
|
|
{"lwarmor", "give armor" },
|
|
|
|
{"lwitems", "give items" },
|
|
|
|
{"lwguns", "give weapons" },
|
|
|
|
{"lwtrek##", nullptr, WarpCheat, 0},
|
|
|
|
{"lwgreed", nullptr, EveryCheatToggle, 0},
|
|
|
|
{"lwghost", "noclip" },
|
|
|
|
{"lwstart", nullptr, RestartCheat, 0},
|
|
|
|
{"lwloc", "stat coord", nullptr, true},
|
|
|
|
{"lwmap", nullptr, MapCheat, 0},
|
|
|
|
{"lwroom", nullptr, RoomCheat, true}, // Room above room debug
|
|
|
|
};
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
static void WeaponCheat(int player)
|
|
|
|
{
|
|
|
|
auto p = &Player[player];
|
|
|
|
auto u = User[p->PlayerSprite];
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
if (!TEST(p->Flags, PF_TWO_UZI))
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-09-03 15:39:41 +00:00
|
|
|
SET(p->Flags, PF_TWO_UZI);
|
|
|
|
SET(p->Flags, PF_PICKED_UP_AN_UZI);
|
|
|
|
}
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
// ALL WEAPONS
|
|
|
|
if (!SW_SHAREWARE) p->WpnFlags = 0xFFFFFFFF;
|
|
|
|
else p->WpnFlags = 0x0000207F; // Disallows high weapon cheat in shareware
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
for (int i = 0; i < SIZ(p->WpnAmmo); i++)
|
|
|
|
{
|
|
|
|
p->WpnAmmo[i] = DamageData[i].max_ammo;
|
|
|
|
}
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
p->WpnShotgunAuto = 50;
|
|
|
|
p->WpnRocketHeat = 5;
|
|
|
|
p->WpnRocketNuke = 1;
|
|
|
|
|
|
|
|
PlayerUpdateWeapon(p, u->WeaponNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ItemCheat(int player)
|
|
|
|
{
|
|
|
|
auto p = &Player[player];
|
|
|
|
PutStringInfo(p, GStrings("GIVING EVERYTHING!"));
|
2020-09-09 17:52:52 +00:00
|
|
|
memset(p->HasKey, true, sizeof(p->HasKey));
|
2020-09-03 15:39:41 +00:00
|
|
|
|
|
|
|
p->WpnShotgunAuto = 50;
|
|
|
|
p->WpnRocketHeat = 5;
|
|
|
|
p->WpnRocketNuke = 1;
|
|
|
|
p->Armor = 100;
|
|
|
|
|
|
|
|
for (int inv = 0; inv < MAX_INVENTORY; inv++)
|
|
|
|
{
|
|
|
|
p->InventoryPercent[inv] = 100;
|
|
|
|
p->InventoryAmount[inv] = InventoryData[inv].MaxInv;
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
PlayerUpdateInventory(p, p->InventoryNum);
|
|
|
|
|
|
|
|
for (int i = 0; i < numsectors; i++)
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
|
|
|
if (SectUser[i] && SectUser[i]->stag == SECT_LOCK_DOOR)
|
|
|
|
SectUser[i]->number = 0; // unlock all doors of this type
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
|
|
|
|
static void cmd_Give(int player, uint8_t** stream, bool skip)
|
2020-01-23 17:55:37 +00:00
|
|
|
{
|
2020-09-03 15:39:41 +00:00
|
|
|
int type = ReadByte(stream);
|
|
|
|
if (skip) return;
|
|
|
|
|
|
|
|
if (numplayers != 1 || gamestate != GS_LEVEL || (Player[player].Flags & PF_DEAD))
|
|
|
|
{
|
|
|
|
Printf("give: Cannot give while dead or not in a single-player game.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case GIVE_ALL:
|
|
|
|
ItemCheat(player);
|
|
|
|
WeaponCheat(player);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GIVE_HEALTH:
|
|
|
|
if (User[Player[player].PlayerSprite]->Health < Player[player].MaxHealth)
|
|
|
|
{
|
|
|
|
User[Player[player].PlayerSprite]->Health += 25;
|
|
|
|
PutStringInfo(&Player[player], GStrings("TXTS_ADDEDHEALTH"));
|
|
|
|
}
|
|
|
|
break;
|
2020-01-23 17:55:37 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
case GIVE_WEAPONS:
|
|
|
|
WeaponCheat(player);
|
|
|
|
break;
|
2020-01-23 17:55:37 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
case GIVE_AMMO:
|
2020-01-23 17:55:37 +00:00
|
|
|
{
|
2020-09-03 15:39:41 +00:00
|
|
|
auto p = &Player[player];
|
|
|
|
auto u = User[p->PlayerSprite];
|
2020-01-23 17:55:37 +00:00
|
|
|
|
|
|
|
p->WpnShotgunAuto = 50;
|
|
|
|
p->WpnRocketHeat = 5;
|
|
|
|
p->WpnRocketNuke = 1;
|
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
for (int i = 0; i < SIZ(p->WpnAmmo); i++)
|
2020-01-23 17:55:37 +00:00
|
|
|
{
|
2020-09-03 15:39:41 +00:00
|
|
|
p->WpnAmmo[i] = DamageData[i].max_ammo;
|
2020-01-23 17:55:37 +00:00
|
|
|
}
|
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
PlayerUpdateWeapon(p, u->WeaponNum);
|
|
|
|
break;
|
2020-01-23 17:55:37 +00:00
|
|
|
}
|
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
case GIVE_ARMOR:
|
|
|
|
if (User[Player[player].PlayerSprite]->Health < Player[player].MaxHealth)
|
|
|
|
{
|
|
|
|
Player[player].Armor = 100;
|
|
|
|
PutStringInfo(&Player[player], GStrings("TXTB_FULLARM"));
|
|
|
|
}
|
|
|
|
break;
|
2020-01-23 17:55:37 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
case GIVE_KEYS:
|
2020-09-09 17:52:52 +00:00
|
|
|
memset(Player[player].HasKey, true, sizeof(Player[player].HasKey));
|
2020-09-03 15:39:41 +00:00
|
|
|
PutStringInfo(&Player[player], GStrings("TXTS_GIVEKEY"));
|
|
|
|
break;
|
2019-11-17 17:02:17 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
case GIVE_INVENTORY:
|
2019-11-17 17:02:17 +00:00
|
|
|
{
|
2020-09-03 15:39:41 +00:00
|
|
|
auto p = &Player[player];
|
|
|
|
PutStringInfo(p, GStrings("GOT ALL INVENTORY"));
|
2019-11-17 17:02:17 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
p->WpnShotgunAuto = 50;
|
|
|
|
p->WpnRocketHeat = 5;
|
|
|
|
p->WpnRocketNuke = 1;
|
|
|
|
p->Armor = 100;
|
2019-11-17 17:02:17 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
for (int inv = 0; inv < MAX_INVENTORY; inv++)
|
2019-11-17 17:02:17 +00:00
|
|
|
{
|
2020-09-03 15:39:41 +00:00
|
|
|
p->InventoryPercent[inv] = 100;
|
|
|
|
p->InventoryAmount[inv] = InventoryData[inv].MaxInv;
|
2019-11-17 17:02:17 +00:00
|
|
|
}
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
PlayerUpdateInventory(p, p->InventoryNum);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
2020-09-03 15:39:41 +00:00
|
|
|
break;
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-09-03 15:39:41 +00:00
|
|
|
case GIVE_ITEMS:
|
|
|
|
ItemCheat(player);
|
|
|
|
break;
|
|
|
|
}
|
2020-08-12 20:24:51 +00:00
|
|
|
}
|
2015-05-19 21:54:34 +00:00
|
|
|
|
2020-08-12 20:24:51 +00:00
|
|
|
void InitCheats()
|
2015-05-19 21:54:34 +00:00
|
|
|
{
|
2020-08-12 20:24:51 +00:00
|
|
|
SetCheats(swcheats, countof(swcheats));
|
2020-09-03 15:39:41 +00:00
|
|
|
Net_SetCommandHandler(DEM_GIVE, cmd_Give);
|
2015-05-19 21:54:34 +00:00
|
|
|
}
|
2020-08-12 20:24:51 +00:00
|
|
|
|
2019-10-09 16:09:05 +00:00
|
|
|
END_SW_NS
|