mirror of
https://github.com/ZDoom/Raze.git
synced 2024-12-03 01:22:19 +00:00
1b958a7f9f
Unfortunately this means that the keybinding menus in all games except Blood are shot to shit right now because of how they passed the data on to its destination. These menus are not fixable, this will have to wait until the replacement is up.
937 lines
26 KiB
C++
937 lines
26 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
Copyright (C) 2019 Nuke.YKT
|
|
|
|
This file is part of NBlood.
|
|
|
|
NBlood is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License version 2
|
|
as published by the Free Software Foundation.
|
|
|
|
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.
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
#include "ns.h" // Must come before everything else!
|
|
|
|
#include "build.h"
|
|
#include "mmulti.h"
|
|
#include "compat.h"
|
|
#include "keyboard.h"
|
|
#include "control.h"
|
|
#include "gamecontrol.h"
|
|
#include "common_game.h"
|
|
#include "blood.h"
|
|
#include "config.h"
|
|
#include "demo.h"
|
|
#include "eventq.h"
|
|
#include "globals.h"
|
|
#include "levels.h"
|
|
#include "loadsave.h"
|
|
#include "menu.h"
|
|
#include "messages.h"
|
|
#include "network.h"
|
|
#include "player.h"
|
|
#include "view.h"
|
|
|
|
BEGIN_BLD_NS
|
|
|
|
CPlayerMsg gPlayerMsg;
|
|
CCheatMgr gCheatMgr;
|
|
|
|
void sub_5A928(void)
|
|
{
|
|
for (int i = 0; i < NUMGAMEFUNCTIONS-1; i++)
|
|
inputState.ClearButton(i);
|
|
}
|
|
|
|
void sub_5A944(int key)
|
|
{
|
|
auto binding = Bindings.GetBind(key);
|
|
#pragma message("todo: reset the bound button here")
|
|
}
|
|
|
|
void SetGodMode(bool god)
|
|
{
|
|
playerSetGodMode(gMe, god);
|
|
if (gMe->godMode)
|
|
viewSetMessage("You are immortal.");
|
|
else
|
|
viewSetMessage("You are mortal.");
|
|
}
|
|
|
|
void SetClipMode(bool noclip)
|
|
{
|
|
gNoClip = noclip;
|
|
if (gNoClip)
|
|
viewSetMessage("Unclipped movement.");
|
|
else
|
|
viewSetMessage("Normal movement.");
|
|
}
|
|
|
|
void packStuff(PLAYER *pPlayer)
|
|
{
|
|
for (int i = 0; i < 5; i++)
|
|
packAddItem(pPlayer, i);
|
|
}
|
|
|
|
void packClear(PLAYER *pPlayer)
|
|
{
|
|
pPlayer->packItemId = 0;
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
pPlayer->packSlots[i].isActive = 0;
|
|
pPlayer->packSlots[i].curAmount = 0;
|
|
}
|
|
}
|
|
|
|
void SetAmmo(bool stat)
|
|
{
|
|
if (stat)
|
|
{
|
|
for (int i = 0; i < 12; i++)
|
|
gMe->ammoCount[i] = gAmmoInfo[i].max;
|
|
viewSetMessage("You have full ammo.");
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < 12; i++)
|
|
gMe->ammoCount[i] = 0;
|
|
viewSetMessage("You have no ammo.");
|
|
}
|
|
}
|
|
|
|
void SetWeapons(bool stat)
|
|
{
|
|
for (int i = 0; i < 14; i++)
|
|
{
|
|
gMe->hasWeapon[i] = stat;
|
|
}
|
|
SetAmmo(stat);
|
|
if (stat)
|
|
viewSetMessage("You have all weapons.");
|
|
else
|
|
{
|
|
if (!VanillaMode())
|
|
{
|
|
// Keep the pitchfork to avoid freeze
|
|
gMe->hasWeapon[1] = 1;
|
|
gMe->curWeapon = 0;
|
|
gMe->nextWeapon = 1;
|
|
}
|
|
viewSetMessage("You have no weapons.");
|
|
}
|
|
}
|
|
|
|
void SetToys(bool stat)
|
|
{
|
|
if (stat)
|
|
{
|
|
packStuff(gMe);
|
|
viewSetMessage("Your inventory is full.");
|
|
}
|
|
else
|
|
{
|
|
packClear(gMe);
|
|
viewSetMessage("Your inventory is empty.");
|
|
}
|
|
}
|
|
|
|
void SetArmor(bool stat)
|
|
{
|
|
int nAmount;
|
|
if (stat)
|
|
{
|
|
viewSetMessage("You have full armor.");
|
|
nAmount = 3200;
|
|
}
|
|
else
|
|
{
|
|
viewSetMessage("You have no armor.");
|
|
nAmount = 0;
|
|
}
|
|
for (int i = 0; i < 3; i++)
|
|
gMe->armor[i] = nAmount;
|
|
}
|
|
|
|
void SetKeys(bool stat)
|
|
{
|
|
for (int i = 1; i <= 6; i++)
|
|
gMe->hasKey[i] = stat;
|
|
if (stat)
|
|
viewSetMessage("You have all keys.");
|
|
else
|
|
viewSetMessage("You have no keys.");
|
|
}
|
|
|
|
void SetInfiniteAmmo(bool stat)
|
|
{
|
|
gInfiniteAmmo = stat;
|
|
if (gInfiniteAmmo)
|
|
viewSetMessage("You have infinite ammo.");
|
|
else
|
|
viewSetMessage("You have limited ammo.");
|
|
}
|
|
|
|
void SetMap(bool stat)
|
|
{
|
|
gFullMap = stat;
|
|
if (gFullMap)
|
|
viewSetMessage("You have the map.");
|
|
else
|
|
viewSetMessage("You have no map.");
|
|
}
|
|
|
|
void SetWooMode(bool stat)
|
|
{
|
|
if (stat)
|
|
{
|
|
if (!powerupCheck(gMe, kPwUpTwoGuns))
|
|
powerupActivate(gMe, kPwUpTwoGuns);
|
|
}
|
|
else
|
|
{
|
|
if (powerupCheck(gMe, kPwUpTwoGuns))
|
|
{
|
|
if (!VanillaMode())
|
|
gMe->pwUpTime[kPwUpTwoGuns] = 0;
|
|
powerupDeactivate(gMe, kPwUpTwoGuns);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ToggleWooMode(void)
|
|
{
|
|
SetWooMode(!(powerupCheck(gMe, kPwUpTwoGuns) != 0));
|
|
}
|
|
|
|
void ToggleBoots(void)
|
|
{
|
|
if (powerupCheck(gMe, kPwUpJumpBoots))
|
|
{
|
|
viewSetMessage("You have no Jumping Boots.");
|
|
if (!VanillaMode())
|
|
{
|
|
gMe->pwUpTime[kPwUpJumpBoots] = 0;
|
|
gMe->packSlots[4].curAmount = 0;
|
|
}
|
|
powerupDeactivate(gMe, kPwUpJumpBoots);
|
|
}
|
|
else
|
|
{
|
|
viewSetMessage("You have the Jumping Boots.");
|
|
if (!VanillaMode())
|
|
gMe->pwUpTime[kPwUpJumpBoots] = gPowerUpInfo[kPwUpJumpBoots].bonusTime;
|
|
powerupActivate(gMe, kPwUpJumpBoots);
|
|
}
|
|
}
|
|
|
|
void ToggleInvisibility(void)
|
|
{
|
|
if (powerupCheck(gMe, kPwUpShadowCloak))
|
|
{
|
|
viewSetMessage("You are visible.");
|
|
if (!VanillaMode())
|
|
gMe->pwUpTime[kPwUpShadowCloak] = 0;
|
|
powerupDeactivate(gMe, kPwUpShadowCloak);
|
|
}
|
|
else
|
|
{
|
|
viewSetMessage("You are invisible.");
|
|
powerupActivate(gMe, kPwUpShadowCloak);
|
|
}
|
|
}
|
|
|
|
void ToggleInvulnerability(void)
|
|
{
|
|
if (powerupCheck(gMe, kPwUpDeathMask))
|
|
{
|
|
viewSetMessage("You are vulnerable.");
|
|
if (!VanillaMode())
|
|
gMe->pwUpTime[kPwUpDeathMask] = 0;
|
|
powerupDeactivate(gMe, kPwUpDeathMask);
|
|
}
|
|
else
|
|
{
|
|
viewSetMessage("You are invulnerable.");
|
|
powerupActivate(gMe, kPwUpDeathMask);
|
|
}
|
|
}
|
|
|
|
void ToggleDelirium(void)
|
|
{
|
|
if (powerupCheck(gMe, kPwUpDeliriumShroom))
|
|
{
|
|
viewSetMessage("You are not delirious.");
|
|
if (!VanillaMode())
|
|
gMe->pwUpTime[kPwUpDeliriumShroom] = 0;
|
|
powerupDeactivate(gMe, kPwUpDeliriumShroom);
|
|
}
|
|
else
|
|
{
|
|
viewSetMessage("You are delirious.");
|
|
powerupActivate(gMe, kPwUpDeliriumShroom);
|
|
}
|
|
}
|
|
|
|
void LevelWarp(int nEpisode, int nLevel)
|
|
{
|
|
levelSetupOptions(nEpisode, nLevel);
|
|
StartLevel(&gGameOptions);
|
|
viewResizeView(gViewSize);
|
|
}
|
|
|
|
void LevelWarpAndRecord(int nEpisode, int nLevel)
|
|
{
|
|
char buffer[BMAX_PATH];
|
|
levelSetupOptions(nEpisode, nLevel);
|
|
gGameStarted = false;
|
|
strcpy(buffer, levelGetFilename(nEpisode, nLevel));
|
|
ChangeExtension(buffer, ".DEM");
|
|
gDemo.Create(buffer);
|
|
StartLevel(&gGameOptions);
|
|
viewResizeView(gViewSize);
|
|
}
|
|
|
|
CGameMessageMgr::CGameMessageMgr()
|
|
{
|
|
if (!VanillaMode())
|
|
Clear();
|
|
x = 1;
|
|
y = 0;
|
|
at9 = 0;
|
|
atd = 0;
|
|
nFont = 0;
|
|
fontHeight = 8;
|
|
maxNumberOfMessagesToDisplay = 4;
|
|
visibilityDurationInSecs = 5;
|
|
messageFlags = 15;
|
|
numberOfDisplayedMessages = 0;
|
|
nextMessagesIndex = messagesIndex = 0;
|
|
}
|
|
|
|
void CGameMessageMgr::SetState(char state)
|
|
{
|
|
if (this->state && !state)
|
|
{
|
|
this->state = 0;
|
|
Clear();
|
|
}
|
|
else if (!this->state && state)
|
|
this->state = 1;
|
|
}
|
|
|
|
void CGameMessageMgr::Add(const char *pText, char a2, const int pal, const MESSAGE_PRIORITY priority)
|
|
{
|
|
if (a2 && messageFlags)
|
|
{
|
|
messageStruct *pMessage = &messages[nextMessagesIndex];
|
|
strncpy(pMessage->text, pText, kMaxMessageTextLength-1);
|
|
pMessage->text[kMaxMessageTextLength-1] = 0;
|
|
pMessage->lastTickWhenVisible = gFrameClock + visibilityDurationInSecs*kTicRate;
|
|
pMessage->pal = pal;
|
|
pMessage->priority = priority;
|
|
pMessage->deleted = false;
|
|
nextMessagesIndex = (nextMessagesIndex+1)%kMessageLogSize;
|
|
if (VanillaMode())
|
|
{
|
|
numberOfDisplayedMessages++;
|
|
if (numberOfDisplayedMessages > maxNumberOfMessagesToDisplay)
|
|
{
|
|
messagesIndex = (messagesIndex+1)%kMessageLogSize;
|
|
atd = 0;
|
|
numberOfDisplayedMessages = maxNumberOfMessagesToDisplay;
|
|
at9 = fontHeight;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGameMessageMgr::Display(void)
|
|
{
|
|
if (VanillaMode())
|
|
{
|
|
if (numberOfDisplayedMessages && this->state && gInputMode != kInputMessage)
|
|
{
|
|
int initialNrOfDisplayedMsgs = numberOfDisplayedMessages;
|
|
int initialMessagesIndex = messagesIndex;
|
|
int shade = ClipHigh(initialNrOfDisplayedMsgs*8, 48);
|
|
int x = gViewMode == 3 ? gViewX0S : 0;
|
|
int y = (gViewMode == 3 ? this->y : 0) + (int)at9;
|
|
for (int i = 0; i < initialNrOfDisplayedMsgs; i++)
|
|
{
|
|
messageStruct* pMessage = &messages[(initialMessagesIndex+i)%kMessageLogSize];
|
|
if (pMessage->lastTickWhenVisible < gFrameClock)
|
|
{
|
|
messagesIndex = (messagesIndex+1)%kMessageLogSize;
|
|
numberOfDisplayedMessages--;
|
|
continue;
|
|
}
|
|
viewDrawText(nFont, pMessage->text, x, y, shade, pMessage->pal, 0, false, 256);
|
|
if (gViewMode == 3)
|
|
{
|
|
int height;
|
|
gMenuTextMgr.GetFontInfo(nFont, pMessage->text, &height, NULL);
|
|
if (x+height > gViewX1S)
|
|
viewUpdatePages();
|
|
}
|
|
y += fontHeight;
|
|
shade = ClipLow(shade-64/initialNrOfDisplayedMsgs, -128);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this->state && gInputMode != kInputMessage)
|
|
{
|
|
messageStruct* currentMessages[kMessageLogSize];
|
|
int currentMessagesCount = 0;
|
|
for (int i = 0; i < kMessageLogSize; i++)
|
|
{
|
|
messageStruct* pMessage = &messages[i];
|
|
if (gFrameClock < pMessage->lastTickWhenVisible && !pMessage->deleted)
|
|
{
|
|
currentMessages[currentMessagesCount++] = pMessage;
|
|
}
|
|
}
|
|
|
|
SortMessagesByPriority(currentMessages, currentMessagesCount);
|
|
|
|
messageStruct* messagesToDisplay[kMessageLogSize];
|
|
int messagesToDisplayCount = 0;
|
|
for (int i = 0; i < currentMessagesCount && messagesToDisplayCount < maxNumberOfMessagesToDisplay; i++)
|
|
{
|
|
messagesToDisplay[messagesToDisplayCount++] = currentMessages[i];
|
|
}
|
|
|
|
SortMessagesByTime(messagesToDisplay, messagesToDisplayCount);
|
|
|
|
int shade = ClipHigh(messagesToDisplayCount*8, 48);
|
|
int x = gViewMode == 3 ? gViewX0S : 0;
|
|
int y = (gViewMode == 3 ? this->y : 0) + (int)at9;
|
|
for (int i = 0; i < messagesToDisplayCount; i++)
|
|
{
|
|
messageStruct* pMessage = messagesToDisplay[i];
|
|
viewDrawText(nFont, pMessage->text, x, y, shade, pMessage->pal, 0, false, 256);
|
|
if (gViewMode == 3)
|
|
{
|
|
int height;
|
|
gMenuTextMgr.GetFontInfo(nFont, pMessage->text, &height, NULL);
|
|
if (x+height > gViewX1S)
|
|
viewUpdatePages();
|
|
}
|
|
y += fontHeight;
|
|
shade = ClipLow(shade-64/messagesToDisplayCount, -128);
|
|
}
|
|
}
|
|
}
|
|
if (at9 != 0)
|
|
{
|
|
at9 = fontHeight*at9/kTicRate;
|
|
atd += gFrameTicks;
|
|
}
|
|
}
|
|
|
|
void CGameMessageMgr::Clear(void)
|
|
{
|
|
if (VanillaMode())
|
|
{
|
|
messagesIndex = nextMessagesIndex = numberOfDisplayedMessages = 0;
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < kMessageLogSize; i++)
|
|
{
|
|
messageStruct* pMessage = &messages[i];
|
|
pMessage->deleted = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGameMessageMgr::SetMaxMessages(int nMessages)
|
|
{
|
|
maxNumberOfMessagesToDisplay = ClipRange(nMessages, 1, 16);
|
|
}
|
|
|
|
void CGameMessageMgr::SetFont(int nFont)
|
|
{
|
|
this->nFont = nFont;
|
|
fontHeight = gFont[nFont].ySize;
|
|
}
|
|
|
|
void CGameMessageMgr::SetCoordinates(int x, int y)
|
|
{
|
|
this->x = ClipRange(x, 0, gViewX1S);
|
|
this->y = ClipRange(y, 0, gViewY1S);
|
|
}
|
|
|
|
void CGameMessageMgr::SetMessageTime(int nTime)
|
|
{
|
|
visibilityDurationInSecs = ClipRange(nTime, 1, 8);
|
|
}
|
|
|
|
void CGameMessageMgr::SetMessageFlags(unsigned int nFlags)
|
|
{
|
|
messageFlags = nFlags&0xf;
|
|
}
|
|
|
|
void CGameMessageMgr::SortMessagesByPriority(messageStruct** messages, int count) {
|
|
for (int i = 1; i < count; i++)
|
|
{
|
|
for (int j = 0; j < count - i; j++)
|
|
{
|
|
if (messages[j]->priority != messages[j + 1]->priority ? messages[j]->priority < messages[j + 1]->priority : messages[j]->lastTickWhenVisible < messages[j + 1]->lastTickWhenVisible)
|
|
{
|
|
messageStruct* temp = messages[j];
|
|
messages[j] = messages[j + 1];
|
|
messages[j + 1] = temp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGameMessageMgr::SortMessagesByTime(messageStruct** messages, int count) {
|
|
for (int i = 1; i < count; i++)
|
|
{
|
|
for (int j = 0; j < count - i; j++)
|
|
{
|
|
if (messages[j]->lastTickWhenVisible > messages[j + 1]->lastTickWhenVisible)
|
|
{
|
|
messageStruct* temp = messages[j];
|
|
messages[j] = messages[j + 1];
|
|
messages[j + 1] = temp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPlayerMsg::Clear(void)
|
|
{
|
|
text[0] = 0;
|
|
at0 = 0;
|
|
}
|
|
|
|
void CPlayerMsg::Term(void)
|
|
{
|
|
Clear();
|
|
gInputMode = kInputGame;
|
|
}
|
|
|
|
void CPlayerMsg::Draw(void)
|
|
{
|
|
char buffer[44];
|
|
strcpy(buffer, text);
|
|
if ((int)totalclock & 16)
|
|
strcat(buffer, "_");
|
|
int x = gViewMode == 3 ? gViewX0S : 0;
|
|
int y = gViewMode == 3 ? gViewY0S : 0;
|
|
if (gViewSize >= 1)
|
|
y += tilesiz[2229].y*((gNetPlayers+3)/4);
|
|
viewDrawText(0, buffer, x+1,y+1, -128, 0, 0, false, 256);
|
|
viewUpdatePages();
|
|
}
|
|
|
|
bool CPlayerMsg::AddChar(char ch)
|
|
{
|
|
if (at0 < 40)
|
|
{
|
|
text[at0++] = ch;
|
|
text[at0] = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CPlayerMsg::DelChar(void)
|
|
{
|
|
if (at0 > 0)
|
|
text[--at0] = 0;
|
|
}
|
|
|
|
void CPlayerMsg::Set(const char * pzString)
|
|
{
|
|
strncpy(text, pzString, 40);
|
|
at0 = ClipHigh(strlen(pzString), 40);
|
|
text[at0] = 0;
|
|
}
|
|
|
|
void CPlayerMsg::Send(void)
|
|
{
|
|
if (VanillaMode() || !IsWhitespaceOnly(text))
|
|
{
|
|
netBroadcastMessage(myconnectindex, text);
|
|
if (!VanillaMode())
|
|
{
|
|
char *myName = gProfile[myconnectindex].name;
|
|
char szTemp[128];
|
|
sprintf(szTemp, "%s: %s", myName, text);
|
|
viewSetMessage(szTemp, 10); // 10: dark blue
|
|
}
|
|
else
|
|
viewSetMessage(text);
|
|
}
|
|
|
|
Term();
|
|
keyFlushScans();
|
|
}
|
|
|
|
void CPlayerMsg::ProcessKeys(void)
|
|
{
|
|
int key = keyGetScan();
|
|
int ch;
|
|
if (key != 0)
|
|
{
|
|
bool ctrl = (inputState.CtrlPressed());
|
|
bool shift = (inputState.ShiftPressed());
|
|
switch (key)
|
|
{
|
|
case sc_Escape:
|
|
Term();
|
|
break;
|
|
case sc_F1:
|
|
case sc_F2:
|
|
case sc_F3:
|
|
case sc_F4:
|
|
case sc_F5:
|
|
case sc_F6:
|
|
case sc_F7:
|
|
case sc_F8:
|
|
case sc_F9:
|
|
case sc_F10:
|
|
inputState.ClearButton(gamefunc_See_Chase_View);
|
|
Set(*CombatMacros[key-sc_F1]);
|
|
Send();
|
|
inputState.ClearKeyStatus(key);
|
|
break;
|
|
case sc_BackSpace:
|
|
if (ctrl)
|
|
Clear();
|
|
else
|
|
DelChar();
|
|
break;
|
|
case sc_Enter:
|
|
case sc_kpad_Enter:
|
|
if (gCheatMgr.Check(text))
|
|
Term();
|
|
else
|
|
Send();
|
|
break;
|
|
default:
|
|
if (key < 128)
|
|
{
|
|
ch = shift ? g_keyAsciiTableShift[key] : g_keyAsciiTable[key];
|
|
if (ch)
|
|
AddChar(ch);
|
|
}
|
|
break;
|
|
}
|
|
sub_5A944(key);
|
|
}
|
|
}
|
|
|
|
bool CPlayerMsg::IsWhitespaceOnly(const char * const pzString)
|
|
{
|
|
const char *p = pzString;
|
|
while (*p != 0)
|
|
if (*p++ > 32)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
CCheatMgr::CHEATINFO CCheatMgr::s_CheatInfo[] = {
|
|
{"NQLGB", kCheatMpkfa, 0 }, // MPKFA (Invincibility)
|
|
{"DBQJONZBTT", kCheatCapInMyAss, 0 }, // CAPINMYASS (Disable invincibility )
|
|
{"OPDBQJONZBTT", kCheatNoCapInMyAss, 0 }, // NOCAPINMYASS (Invincibility)
|
|
{"J!XBOOB!CF!MJLF!LFWJO", kCheatNoCapInMyAss, 0 }, // I WANNA BE LIKE KEVIN (Invincibility)
|
|
{"JEBIP", kCheatIdaho, 0 }, // IDAHO (All weapons and full ammo)
|
|
{"NPOUBOB", kCheatMontana, 0 }, // MONTANA (All weapons, full ammo and all items)
|
|
{"HSJTXPME", kCheatGriswold, 0 }, // GRISWOLD (Full armor (same effect as getting super armor))
|
|
{"FENBSL", 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".)
|
|
{"UFRVJMB", kCheatTequila, 0 }, // TEQUILA (Guns akimbo power-up)
|
|
{"CVO[", kCheatBunz, 0 }, // BUNZ (All weapons, full ammo, and guns akimbo power-up)
|
|
{"GVOLZ!TIPFT", kCheatFunkyShoes, 0 }, // FUNKY SHOES (Gives jump boots item and activates it)
|
|
{"HBUFLFFQFS", kCheatGateKeeper, 0 }, // GATEKEEPER (Sets the you cheated flag to true, at the end of the level you will see that you have cheated)
|
|
{"LFZNBTUFS", kCheatKeyMaster, 0 }, // KEYMASTER (All keys)
|
|
{"KPKP", kCheatJoJo, 0 }, // JOJO (Drunk mode (same effect as getting bitten by red spider))
|
|
{"TBUDIFM", kCheatSatchel, 0 }, // SATCHEL (Full inventory)
|
|
{"TQPSL", kCheatSpork, 0 }, // SPORK (200% health (same effect as getting life seed))
|
|
{"POFSJOH", kCheatOneRing, 0 }, // ONERING (Cloak of invisibility power-up)
|
|
{"NBSJP", kCheatMario, 1 }, // MARIO (Warp to level E M, e.g.: MARIO 1 3 will take you to Phantom Express)
|
|
{"DBMHPO", kCheatCalgon, 1 }, // CALGON (Jumps to next level or can be used like MARIO with parameters)
|
|
{"LFWPSLJBO", 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".)
|
|
{"NDHFF", kCheatMcGee, 0 }, // MCGEE (Sets you on fire. Displays the message "YOU'RE FIRED".)
|
|
{"LSVFHFS", kCheatKrueger, 0 }, // KRUEGER (200% health, but sets you on fire. Displays the message "FLAME RETARDANT".)
|
|
{"DIFFTFIFBE", kCheatCheeseHead, 0 }, // CHEESEHEAD (100% diving suit)
|
|
{"DPVTUFBV", kCheatCousteau, 0 }, // COUSTEAU (200% health and diving suit)
|
|
{"WPPSIFFT", kCheatVoorhees, 0 }, // VOORHEES (Death mask power-up)
|
|
{"MBSB!DSPGU", 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.)
|
|
{"IPOHLPOH", kCheatHongKong, 0 }, // HONGKONG (All weapons and infinite ammo)
|
|
{"GSBOLFOTUFJO", kCheatFrankenstein, 0 }, // FRANKENSTEIN (100% med-kit)
|
|
{"TUFSOP", kCheatSterno, 0 }, // STERNO (Temporary blindness (same effect as getting bitten by green spider))
|
|
{"DMBSJDF", kCheatClarice, 0 }, // CLARICE (Gives 100% body armor, 100% fire armor, 100% spirit armor)
|
|
{"GPSL!ZPV", kCheatForkYou, 0 }, // FORK YOU (Drunk mode, 1HP, no armor, no weapons, no ammo, no items, no keys, no map, guns akimbo power-up)
|
|
{"MJFCFSNBO", kCheatLieberMan, 0 }, // LIEBERMAN (Sets the you cheated flag to true, at the end of the level you will see that you have cheated)
|
|
{"FWB!HBMMJ", kCheatEvaGalli, 0 }, // EVA GALLI (Disable/enable clipping (grant the ability to walk through walls))
|
|
{"SBUF", kCheatRate, 0 }, // RATE (Display frame rate (doesn't count as a cheat))
|
|
{"HPPOJFT", kCheatGoonies, 0 }, // GOONIES (Enable full map. Displays the message "YOU HAVE THE MAP".)
|
|
{"TQJFMCFSH", 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.)
|
|
};
|
|
|
|
bool CCheatMgr::m_bPlayerCheated = false;
|
|
|
|
bool CCheatMgr::Check(char *pzString)
|
|
{
|
|
char buffer[80];
|
|
strcpy(buffer, pzString);
|
|
Bstrupr(buffer);
|
|
for (size_t i = 0; i < strlen(pzString); i++)
|
|
buffer[i]++;
|
|
for (int i = 0; i < 36; i++)
|
|
{
|
|
int nCheatLen = strlen(s_CheatInfo[i].pzString);
|
|
if (s_CheatInfo[i].flags & 1)
|
|
{
|
|
if (!strncmp(buffer, s_CheatInfo[i].pzString, nCheatLen))
|
|
{
|
|
Process(s_CheatInfo[i].id, buffer+nCheatLen);
|
|
return true;
|
|
}
|
|
}
|
|
if (!strcmp(buffer, s_CheatInfo[i].pzString))
|
|
{
|
|
Process(s_CheatInfo[i].id, NULL);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int parseArgs(char *pzArgs, int *nArg1, int *nArg2)
|
|
{
|
|
if (!nArg1 || !nArg2)
|
|
return -1;
|
|
int nLength = strlen(pzArgs);
|
|
for (int i = 0; i < nLength; i++)
|
|
pzArgs[i]--;
|
|
int stat = sscanf(pzArgs, " %d %d", nArg1, nArg2);
|
|
if (stat == 2 && (*nArg1 == 0 || *nArg2 == 0))
|
|
return -1;
|
|
*nArg1 = ClipRange(*nArg1-1, 0, gEpisodeCount-1);
|
|
*nArg2 = ClipRange(*nArg2-1, 0, gEpisodeInfo[*nArg1].nLevels-1);
|
|
return stat;
|
|
}
|
|
|
|
void CCheatMgr::Process(CCheatMgr::CHEATCODE nCheatCode, char* pzArgs)
|
|
{
|
|
dassert(nCheatCode > kCheatNone && nCheatCode < kCheatMax);
|
|
|
|
if (gDemo.at0) return;
|
|
if (nCheatCode == kCheatRate)
|
|
{
|
|
r_showfps = !r_showfps;
|
|
return;
|
|
}
|
|
if (gGameOptions.nGameType != 0)
|
|
return;
|
|
int nEpisode, nLevel;
|
|
switch (nCheatCode)
|
|
{
|
|
case kCheatSpielberg:
|
|
if (parseArgs(pzArgs, &nEpisode, &nLevel) == 2)
|
|
LevelWarpAndRecord(nEpisode, nLevel);
|
|
break;
|
|
case kCheat1:
|
|
SetAmmo(true);
|
|
break;
|
|
case kCheatGriswold:
|
|
SetArmor(true);
|
|
break;
|
|
case kCheatSatchel:
|
|
SetToys(true);
|
|
break;
|
|
case kCheatEvaGalli:
|
|
SetClipMode(!gNoClip);
|
|
break;
|
|
case kCheatMpkfa:
|
|
SetGodMode(!gMe->godMode);
|
|
break;
|
|
case kCheatCapInMyAss:
|
|
SetGodMode(false);
|
|
break;
|
|
case kCheatNoCapInMyAss:
|
|
SetGodMode(true);
|
|
break;
|
|
case kCheatIdaho:
|
|
SetWeapons(true);
|
|
break;
|
|
case kCheatKevorkian:
|
|
actDamageSprite(gMe->nSprite, gMe->pSprite, DAMAGE_TYPE_2, 8000);
|
|
viewSetMessage("Kevorkian approves.");
|
|
break;
|
|
case kCheatMcGee:
|
|
{
|
|
if (!gMe->pXSprite->burnTime)
|
|
evPost(gMe->nSprite, 3, 0, kCallbackFXFlameLick);
|
|
actBurnSprite(actSpriteIdToOwnerId(gMe->nSprite), gMe->pXSprite, 2400);
|
|
viewSetMessage("You're fired!");
|
|
break;
|
|
}
|
|
case kCheatEdmark:
|
|
actDamageSprite(gMe->nSprite, gMe->pSprite, DAMAGE_TYPE_3, 8000);
|
|
viewSetMessage("Ahhh...those were the days.");
|
|
break;
|
|
case kCheatKrueger:
|
|
{
|
|
actHealDude(gMe->pXSprite, 200, 200);
|
|
gMe->armor[1] = VanillaMode() ? 200 : 3200;
|
|
if (!gMe->pXSprite->burnTime)
|
|
evPost(gMe->nSprite, 3, 0, kCallbackFXFlameLick);
|
|
actBurnSprite(actSpriteIdToOwnerId(gMe->nSprite), gMe->pXSprite, 2400);
|
|
viewSetMessage("Flame retardant!");
|
|
break;
|
|
}
|
|
case kCheatSterno:
|
|
gMe->blindEffect = 250;
|
|
break;
|
|
case kCheat14: // quakeEffect (causing a little flickerEffect), not used by any cheat code (dead code)
|
|
gMe->flickerEffect = 360;
|
|
break;
|
|
case kCheatSpork:
|
|
actHealDude(gMe->pXSprite, 200, 200);
|
|
break;
|
|
case kCheatGoonies:
|
|
SetMap(!gFullMap);
|
|
break;
|
|
case kCheatClarice:
|
|
if (!VanillaMode())
|
|
{
|
|
viewSetMessage("You have half armor.");
|
|
for (int i = 0; i < 3; i++)
|
|
gMe->armor[i] = 1600;
|
|
}
|
|
break;
|
|
case kCheatFrankenstein:
|
|
gMe->packSlots[0].curAmount = 100;
|
|
break;
|
|
case kCheatCheeseHead:
|
|
gMe->packSlots[1].curAmount = 100;
|
|
if (!VanillaMode())
|
|
gMe->pwUpTime[kPwUpDivingSuit] = gPowerUpInfo[kPwUpDivingSuit].bonusTime;
|
|
break;
|
|
case kCheatTequila:
|
|
ToggleWooMode();
|
|
break;
|
|
case kCheatFunkyShoes:
|
|
ToggleBoots();
|
|
break;
|
|
case kCheatKeyMaster:
|
|
SetKeys(true);
|
|
break;
|
|
case kCheatOneRing:
|
|
ToggleInvisibility();
|
|
break;
|
|
case kCheatVoorhees:
|
|
ToggleInvulnerability();
|
|
break;
|
|
case kCheatJoJo:
|
|
ToggleDelirium();
|
|
break;
|
|
case kCheatRate: // show FPS, handled before (dead code), leave here for safety
|
|
return;
|
|
case kCheatMario:
|
|
if (parseArgs(pzArgs, &nEpisode, &nLevel) == 2)
|
|
LevelWarp(nEpisode, nLevel);
|
|
break;
|
|
case kCheatCalgon:
|
|
if (parseArgs(pzArgs, &nEpisode, &nLevel) == 2)
|
|
LevelWarp(nEpisode, nLevel);
|
|
else
|
|
if (!VanillaMode())
|
|
levelEndLevel(0);
|
|
break;
|
|
case kCheatLaraCroft:
|
|
SetInfiniteAmmo(!gInfiniteAmmo);
|
|
SetWeapons(gInfiniteAmmo);
|
|
break;
|
|
case kCheatHongKong:
|
|
SetWeapons(true);
|
|
SetInfiniteAmmo(true);
|
|
break;
|
|
case kCheatMontana:
|
|
SetWeapons(true);
|
|
SetToys(true);
|
|
break;
|
|
case kCheatBunz:
|
|
SetWeapons(true);
|
|
SetWooMode(true);
|
|
break;
|
|
case kCheatCousteau:
|
|
actHealDude(gMe->pXSprite,200,200);
|
|
gMe->packSlots[1].curAmount = 100;
|
|
if (!VanillaMode())
|
|
gMe->pwUpTime[kPwUpDivingSuit] = gPowerUpInfo[kPwUpDivingSuit].bonusTime;
|
|
break;
|
|
case kCheatForkYou:
|
|
SetInfiniteAmmo(false);
|
|
SetMap(false);
|
|
SetWeapons(false);
|
|
SetAmmo(false);
|
|
SetArmor(false);
|
|
SetToys(false);
|
|
SetKeys(false);
|
|
SetWooMode(true);
|
|
powerupActivate(gMe, kPwUpDeliriumShroom);
|
|
gMe->pXSprite->health = 16;
|
|
gMe->hasWeapon[1] = 1;
|
|
gMe->curWeapon = 0;
|
|
gMe->nextWeapon = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
m_bPlayerCheated = true;
|
|
}
|
|
|
|
void CCheatMgr::sub_5BCF4(void)
|
|
{
|
|
m_bPlayerCheated = 0;
|
|
playerSetGodMode(gMe, 0);
|
|
gNoClip = 0;
|
|
packClear(gMe);
|
|
gInfiniteAmmo = 0;
|
|
gFullMap = 0;
|
|
}
|
|
|
|
class MessagesLoadSave : public LoadSave
|
|
{
|
|
public:
|
|
virtual void Load();
|
|
virtual void Save();
|
|
};
|
|
|
|
void MessagesLoadSave::Load()
|
|
{
|
|
Read(&CCheatMgr::m_bPlayerCheated, sizeof(CCheatMgr::m_bPlayerCheated));
|
|
}
|
|
|
|
void MessagesLoadSave::Save()
|
|
{
|
|
Write(&CCheatMgr::m_bPlayerCheated, sizeof(CCheatMgr::m_bPlayerCheated));
|
|
}
|
|
|
|
static MessagesLoadSave *myLoadSave;
|
|
|
|
void MessagesLoadSaveConstruct(void)
|
|
{
|
|
myLoadSave = new MessagesLoadSave();
|
|
}
|
|
|
|
END_BLD_NS
|