Cheat codes

Started by
16 comments, last by rip-off 12 years, 6 months ago
Here are the header and cpp file for a cheat code class I've made along with a usage example. I've never done anything like this before so please let me know what you think.

CheatCode.h
[source lang="cpp"]
#pragma once
#ifndef CHEATCODE_H
#define CHEATCODE_H

#include "Global.h"
#include <SFML\Graphics.hpp>
#include <vector>

class CheatCode
{
private:
std::vector<sf::Key::Code> m_Code;
DWORD m_KeyCount;
DWORD m_TriggerCount;
DWORD m_MaxTrigger;
BOOL m_Triggered;

public:
CheatCode();
~CheatCode();

void Init(char *Code, DWORD TriggerCount = 1);
void RegisterKey(sf::Key::Code Key);
BOOL IsTriggered();
DWORD GetTriggerCount();
void Reset();
};

#endif
[/source]

CheatCode.cpp
[source lang="cpp"]
#include "CheatCode.h"

using namespace std;
using namespace sf;

CheatCode::CheatCode()
{
this->m_MaxTrigger = 0;
this->Reset();
}

CheatCode::~CheatCode()
{
this->m_Code.clear();
}

void CheatCode::Init(char *Code, DWORD TriggerCount)
{
DWORD size = strlen(Code);

for (int i = 0; i < size; i++)
{
char ch = tolower(Code);
this->m_Code.push_back((Key::Code)ch);
}

this->m_MaxTrigger = TriggerCount;
}

void CheatCode::RegisterKey(sf::Key::Code Key)
{
if (this->m_TriggerCount >= this->m_MaxTrigger)
return;

if (this->m_Code.at(this->m_KeyCount) == Key)
this->m_KeyCount++;
else
this->m_KeyCount = 0;

if (this->m_KeyCount >= this->m_Code.size())
{
this->m_TriggerCount++;
this->m_Triggered = TRUE;
this->m_KeyCount = 0;
}
}

BOOL CheatCode::IsTriggered()
{
return this->m_Triggered;
}

DWORD CheatCode::GetTriggerCount()
{
return this->m_TriggerCount;
}

void CheatCode::Reset()
{
this->m_KeyCount = 0;
this->m_TriggerCount = 0;
this->m_Triggered = FALSE;
}
[/source]

usage
[source lang="cpp"]
//initialize the cheat code
//this might go in a class constructor or init function
this->m_CheatTonk.init("tonksmash");

//this is an example game loop showing just an example of using this cheat class
while (this->m_App.IsOpened())
{
Event msg;
while (this->m_App.GetEvent(msg))
{
if (msg.Type == Event::Closed)
this->m_App.Close();

if (msg.Type == Event::KeyPressed)
{
this->m_CheatTonk.RegisterKey(msg.Key.Code);
}
}

if (this->m_CheatTonk.IsTriggered())
{
Sprite sprite(*this->m_ResMan.GetImage("RESOURCE1"));
this->m_App.Draw(sprite);
}

this->m_App.Display();
}
[/source]

Any suggestions or things I should change, things I'm doing wrong or even things I'm doing right? Thanks
-akusei
Advertisement
Not bad :-)

I would make a couple of suggestions:
  • Your game loop where you test the message type could use an else-if instead of two separate ifs
  • You could simplify things a bit by using std::string
  • No need to clear a vector (or any SC++L container, including strings) in your destructor. The container destructor will do it for you automatically
  • Your TriggerCount parameter to Init() should be named MaxTriggerCount to make it clear what it does
  • Any reason why you use a separate Init() instead of a constructor for the cheat code?


As a fun exercise, try writing another piece of code that lets you set up multiple cheat codes easily, without having to copy/paste a lot of code :-)

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


Not bad :-)

I would make a couple of suggestions:
  • Your game loop where you test the message type could use an else-if instead of two separate ifs
  • You could simplify things a bit by using std::string
  • No need to clear a vector (or any SC++L container, including strings) in your destructor. The container destructor will do it for you automatically
  • Your TriggerCount parameter to Init() should be named MaxTriggerCount to make it clear what it does
  • Any reason why you use a separate Init() instead of a constructor for the cheat code?


As a fun exercise, try writing another piece of code that lets you set up multiple cheat codes easily, without having to copy/paste a lot of code :-)


Great, thanks for the suggestions, I will make these changes. The reason I went with a separate init function and a default constructor with no parameters is because I wanted to keep the cheat codes as a private member variable of the main game class and I would have to make them all dynamically allocated and handle deleting them later because I can't initialize the class variable inside the header... for example:

I can't do this
[source lang="cpp"]
class test
{
private:
CheatCode m_code("codestring");
};
[/source]

I could do this, but want to avoid having to allocate with new were possible
[source lang="cpp"]
class test
{
private:
CheatCode *m_code;
};

test::test()
{
this->m_code = new CheatCode("codestring");
}

test::~test()
{
delete this->m_code;
}
[/source]

Or am I completely missing something or possibly not understanding it correctly?Is it just better practice to use the constructor for initialization and not have an init function?
-akusei

Great, thanks for the suggestions, I will make these changes. The reason I went with a separate init function and a default constructor with no parameters is because I wanted to keep the cheat codes as a private member variable of the main game class and I would have to make them all dynamically allocated and handle deleting them later because I can't initialize the class variable inside the header... for example:

I can't do this
[source lang="cpp"]
class test
{
private:
CheatCode m_code("codestring");
};
[/source]

I could do this, but want to avoid having to allocate with new were possible
[source lang="cpp"]
class test
{
private:
CheatCode *m_code;
};

test::test()
{
this->m_code = new CheatCode("codestring");
}

test::~test()
{
delete this->m_code;
}
[/source]

Or am I completely missing something or possibly not understanding it correctly?Is it just better practice to use the constructor for initialization and not have an init function?


Initializer lists can help with this:

[source lang="cpp"]
// H
class Test {
private:
CheatCode code;
};

// CPP
Test::Test() :
code("cheatcode") {
}
[/source]

You can call constructors of private members (on stack or on heap) in the initializer list of the constructor of the class.

Initializer lists can help with this:

[source lang="cpp"]
// H
class Test {
private:
CheatCode code;
};

// CPP
Test::Test() :
code("cheatcode") {
}
[/source]

You can call constructors of private members (on stack or on heap) in the initializer list of the constructor of the class.


Thanks, that works great. Although it seems a little clumsy i guess you could say; it could just be me and my limited knowledge of how things are meant to be done (read: best practices). Is this the "proper" way to do it or would allocating a new instance of the CheatCode class and likewise destroying it in the destructor be more acceptable?
-akusei

Thanks, that works great. Although it seems a little clumsy i guess you could say; it could just be me and my limited knowledge of how things are meant to be done (read: best practices). Is this the "proper" way to do it or would allocating a new instance of the CheatCode class and likewise destroying it in the destructor be more acceptable?


This is the "proper" way and it is not clumsy at all. When a member of an object is initialized on the stack it is destroyed (the destructor is called) after the destructor of the class that contains it is called. If you are allocating a new object in the constructor and deleting it in the destructor then most likely it should just be on the stack (like in the example I posted).


I would suggest reading some material on C++ object lifecycles and initialization lists. It is also helpful to write up some tests with constructors/destructors that print to the console to get a good idea on the ordering of constructors/destructors. This is also important for inheritance; if you aren't careful you will find that your destructors are not even begin called.

Hope that helps.
That all helps a bunch, thanks!
-akusei
What is actually clumsy is having "this->" all over the place.
I recommend doing a search and replace to change "this->" to "" i.e. an empty string.

Initialisation lists are definitely the correct way to go in C++.

Note that because you do not need to manually clear a vector in a destructor (that's the vector's responsibility), you should actually remove the destructor entirely rather then leaving it empty.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

What is actually clumsy is having "this->" all over the place.
I recommend doing a search and replace to change "this->" to "" i.e. an empty string.

Initialisation lists are definitely the correct way to go in C++.

Note that because you do not need to manually clear a vector in a destructor (that's the vector's responsibility), you should actually remove the destructor entirely rather then leaving it empty.


Could you explain to me why the "this->" is clumsy and not just a personal preference like having a curly bracket on the same line as the if statement instead of on the line below? Also, please explain the reasoning behind leaving the destructor out all together if it's empty. I'm not trying to sound rude or anything; I feel I need to say this because no matter how I wrote those questions it came across as being a jerk, but in all honesty I'm just curious and would like to know.

edit:
There are a couple reasons why I use "this->"

1. It's a habit that formed a long time ago to trigger intellisense in visual studio for things in the class' scope, which allows for very quick and easy glances into what I've created as variables/objects in the class scope without having to re-read the header file over again after I've taken a month broke from the project.

2. It helps me to, at a glance, see what scope that variable or object is at (along with the m_ designation). anything with a this-> is not the local function or block scope.So anything with a this-> I know is class scope and anything without I know is local to that code block.
-akusei

There are a couple reasons why I use "this->"


Using this-> along with m_ just seems redundant. It would seem much easier to read - especially if asking for peer review or collaborating - to choose one or the other. Personally I find m_ preferable to this-> but I know people who feel the opposite way. If you're thoroughly attached to the intellisense thing then perhaps eliminating m_ would be preferable?

This topic is closed to new replies.

Advertisement