summaryrefslogtreecommitdiff
path: root/engine/cheatcodes.cpp
blob: 12fa378f30311478c622ec6a1c8394be91e6eafd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//===========================================================================//

#include "cheatcodes.h"
#include "cmd.h"
#include "KeyValues.h"
#include "filesystem.h"
#include "tier2/tier2.h"
#include "inputsystem/iinputsystem.h"
#include "host.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"


//=========================================================
// Cheat Codes
//=========================================================
#define CHEAT_NAME_MAX_LEN		32
#define CHEAT_CODE_MAX_LEN		10
#define CHEAT_COMMAND_MAX_LEN	128
static ButtonCode_t s_pKeyLog[CHEAT_CODE_MAX_LEN];
static int s_nKeyLogIndex = 0;


struct CheatCodeData_t
{
	char			szName[ CHEAT_NAME_MAX_LEN ];

	bool			bDevOnly;

	int				iCodeLength;
	ButtonCode_t	pButtonCodes[ CHEAT_CODE_MAX_LEN ];

	char			szCommand[ CHEAT_COMMAND_MAX_LEN ];
};


static CUtlVector<CheatCodeData_t> s_CheatCodeCommands;


void ClearCheatCommands( void )
{
	s_CheatCodeCommands.RemoveAll();
}

void ReadCheatCommandsFromFile( char *pchFileName )
{
	KeyValues *pCheatCodeKeys = new KeyValues( "cheat_codes" );
	pCheatCodeKeys->LoadFromFile( g_pFullFileSystem, pchFileName, NULL );

	KeyValues *pKey = NULL;
	for ( pKey = pCheatCodeKeys->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() )
	{
		int iCheat = s_CheatCodeCommands.AddToTail();
		CheatCodeData_t *pNewCheatCode = &(s_CheatCodeCommands[ iCheat ]);

		Q_strncpy( pNewCheatCode->szName, pKey->GetName(), CHEAT_NAME_MAX_LEN );	// Get the name
		pNewCheatCode->bDevOnly = ( pKey->GetInt( "dev", 0 ) != 0 );				// Get developer only flag
		pNewCheatCode->iCodeLength = 0;												// Start at zero code elements
		Q_strncpy( pNewCheatCode->szCommand, pKey->GetString( "command", "echo \"Cheat code has no command!\"" ), CHEAT_COMMAND_MAX_LEN );

		KeyValues *pSubKey = NULL;
		for ( pSubKey = pKey->GetFirstSubKey(); pSubKey; pSubKey = pSubKey->GetNextKey() )
		{
			const char *pchType = pSubKey->GetName();
			if ( Q_strcmp( pchType, "code" ) == 0 )
			{
				AssertMsg( ( pNewCheatCode->iCodeLength < CHEAT_NAME_MAX_LEN ), "Cheat code elements exceeded max!" );

				pNewCheatCode->pButtonCodes[ pNewCheatCode->iCodeLength ] = g_pInputSystem->StringToButtonCode( pSubKey->GetString() );
				++pNewCheatCode->iCodeLength;
			}
		}

		if ( pNewCheatCode->iCodeLength < CHEAT_NAME_MAX_LEN )
		{
			// If it's activation is a subsequence of another cheat, the longer cheat can't be activated!
			DevWarning( "Cheat code \"%s\" has less than %i code elements!", pKey->GetName(), CHEAT_NAME_MAX_LEN );
		}
	}
}

//---------------------------------------------------------
//---------------------------------------------------------
void ResetKeyLogging()
{
	s_nKeyLogIndex = 0;
}

//---------------------------------------------------------
//---------------------------------------------------------
void LogKeyPress( ButtonCode_t code )
{
	if ( s_nKeyLogIndex < CHEAT_CODE_MAX_LEN )
	{
		// Log isn't full, so add it in the next spot
		s_pKeyLog[ s_nKeyLogIndex ] = code;
		++s_nKeyLogIndex;
		return;
	}

	// Log is full so shift all data to the previous bucket
	int i;
	for ( i = 0; i < CHEAT_CODE_MAX_LEN - 1; ++i )
	{
		s_pKeyLog[ i ] = s_pKeyLog[ i + 1 ];
	}

	// Log into the last bucket
	s_pKeyLog[ i ] = code;
}

//---------------------------------------------------------
//---------------------------------------------------------
void CheckCheatCodes()
{
	// Loop through all cheat codes
	int iNumCheatCodes = s_CheatCodeCommands.Count();
	for ( int iCheatCode = 0; iCheatCode < iNumCheatCodes; ++iCheatCode )
	{
		CheatCodeData_t *pCheatCode = &(s_CheatCodeCommands[ iCheatCode ]);

		if ( pCheatCode->bDevOnly && !developer.GetBool() )
			continue;	// This cheat is only allowed in developer mode

		int iLogIndex = s_nKeyLogIndex - pCheatCode->iCodeLength;	// Check code against the back chunk of the log

		if ( iLogIndex < 0 )
			continue;	// There's less codes in the log than we need

		int iCode = 0;

		while ( iCode < pCheatCode->iCodeLength && pCheatCode->pButtonCodes[ iCode ] == s_pKeyLog[ iLogIndex ] )
		{
			++iCode;
			++iLogIndex;
		}
		
		if ( iCode == pCheatCode->iCodeLength )
		{
			// Every part of the code was correct
			DevMsg( "Cheat code \"%s\" activated!", pCheatCode->szName );

			Cbuf_AddText( "sv_cheats 1\n" );
			Cbuf_AddText( pCheatCode->szCommand );
			Cbuf_AddText( "\n" );

			ResetKeyLogging();
			return;
		}
	}
}