Skip to content

Instantly share code, notes, and snippets.

@JordanBell
Last active August 29, 2015 14:12
Show Gist options
  • Save JordanBell/52b2930b2cfb5bc6fe33 to your computer and use it in GitHub Desktop.
Save JordanBell/52b2930b2cfb5bc6fe33 to your computer and use it in GitHub Desktop.
A class, TestingConsole, which allows quick run-time function calls via SDL input, and an example implementation, CGConsole.
//
// CGConsole.cpp
// Testing-Console
//
// Created by Jordan Bell on 15/10/2014.
// Copyright (c) 2014 Jordan Bell. All rights reserved.
//
#include "CGConsole.h"
#include "Coin.h"
#include "Player.h"
#include "Game.h"
#include "Inventory.h"
#include "LaunchData.h"
#include "ParticleSnow.h"
#include "Camera.h"
#define DIVIDES(a, b) (a%b == 0)
/* Temporary calculation function for printing arbitrary calculations used in debugging.
Override the contents of this function for your own calculations when appropriate. */
void Calc(vector<int> args)
{
// Nothing
}
/* Launch all coins at the player */
void Pull(vector<int> args)
{
int suppression = args.empty() ? 1 : args.front();
printf("supp: %d\n ? %d\n\n", suppression, args.empty());
for (Throwable* t : g_throwables)
{
if (!t->IsAirborne()) {
t->LaunchTo(g_player->x, g_player->y, suppression);
}
}
}
/* Make a small explosion of simple particles */
void ParticleExplosion(vector<int> args)
{
if (args.front())
{
int s_x, s_y; // Start coords
s_x = screen->w/2 - TILE_SIZE/2;
s_y = screen->h/2 - TILE_SIZE/2+2*TILE_SIZE;
int e_x, e_y; // End coords
list<Particle*> particles;
int num = args.front();
for (int i = 0; i < num; i++)
{
// Dirt flies somewhere around behind the player
e_x = s_x + (rand() % (6*TILE_SIZE)) - 3*TILE_SIZE;
e_y = s_y + (rand() % (4*TILE_SIZE)) - 2*TILE_SIZE;
ParticleSimple* part = new ParticleSimple(s_x, s_y, e_x, e_y);
particles.push_back(part);
g_game->addGameObject(part);
}
for (Particle* p : particles)
p->Launch(1);
}
}
/* Make all coins bounce in place */
void BounceUp(vector<int> args)
{
for (Throwable* t : g_throwables)
if (!t->IsAirborne())
t->Bounce( rand()%15 + 5);
}
/* Make all coins bounce in place */
void SetBouncy(vector<int> args)
{
if (args.front())
{
for (Throwable* t : g_throwables)
if (!t->IsAirborne())
t->SetBouncy(args.front());
}
}
/* Enables Abilty: Pull. Press 1 to use. */
void TogglePull(vector<int> args)
{ KeyCode::ToggleBool1(); }
/* Home coins toward the player */
void HomeIn(vector<int> args)
{
int distance = args.size() > 0 ? args.at(0) : 400;
int speed = args.size() > 1 ? args.at(1) : 10;
list<Throwable*> closeThrowables = Throwable::ThrowablesAroundPlayer(distance);
for (Throwable* t : closeThrowables)
{
if (!t->IsAirborne()) {
t->SetHoming(distance, speed);
}
}
}
/* Forces Abilty: Smash. Specifies radius. */
void Smash(vector<int> args)
{ if (args.front()) g_player->Smash(args.front()); }
/* Forces Ability: Smash Wave */
void SmashWave(vector<int> args)
{ g_player->SmashWave(); }
/* Toggles coin magnetism */
void ToggleMagnetism(vector<int> args)
{ //g_player->SetMagnetic( !g_player->IsMagnetic() );
}
/* Turn off all sounds */
void Mute(vector<int> args)
{ g_game->Mute(); }
/* Turn on all sounds */
void Unmute(vector<int> args)
{ g_game->Unmute(); }
/* Add any number of coins to the wallet */
void AddCoins(vector<int> args)
{
if (args.front())
{
const int numCoins = args.front();
// Get the current room element
Element ele = g_camera->GetRoomFocus()->GetElement();
Inventory::GetCoinWallet(ele)->Add(numCoins);
}
}
/* Add a ludicrous number of coins to the wallet of the current room */
void AddCoins_Large(vector<int> args)
{ Inventory::GetCoinWallet(g_camera->GetRoomFocus()->GetElement())->Add(99999999); }
/* Doubles the player's coins in their room */
void DoubleCoins(vector<int> args)
{
int currentNumber = Inventory::GetCoinWallet(g_camera->GetRoomFocus()->GetElement())->GetAmount();
Inventory::GetCoinWallet(g_camera->GetRoomFocus()->GetElement())->Add(currentNumber * 2);
}
/* Dispense Coins */
void Dispense(vector<int> args)
{ if (args.front()) g_camera->GetRoomFocus()->GetDispenser()->ForceDispense(args.front()); }
/* Print Information about the Tier's Launch Info */
void Talk(vector<int> args)
{
g_player->Say("Hey.");
}
/* Jordan's debug preset */
void j(vector<int> args)
{
TogglePull(args);
//ToggleMagnetism(args);
//// Toggle Mute
//if (g_game->IsMuted())
// Unmute(args);
//else
// Mute(args);
/*g_machine->ForceDispense(1000);
Mute(args);*/
}
/* Set the rendering offset values */
void SetRenderOffset(vector<int> args)
{
s_renderingOffset_x = args.at(0);
s_renderingOffset_y = args.at(1);
}
/* Draw the player's hit box and AABB */
void ShowPlayerCollisionBoxes(vector<int> args)
{
g_player->ToggleDebug();
}
CGConsole::CGConsole(void)
{
// All recognised commands
m_commands.push_back(
Command("pull",
"Pulling all coins toward the player.",
"Launches all coins to the player.",
Pull)
);
m_commands.push_back(
Command("bounce",
"Bouncing.",
"Bounces all throwables up into the air.",
BounceUp)
);
m_commands.push_back(
Command("set_bounce",
"Bouncing set.",
"Pass an int boolean to set the bounciness of all throwables.",
SetBouncy)
);
m_commands.push_back(
Command("toggle_pull",
"Pull toggled. When enabled, press 1 to pull all coins toward the player.",
"Toggles the pull ability. Activate by pressing hotkey: 1",
TogglePull)
);
m_commands.push_back(
Command("mag",
"Magnetism Toggled",
"Toggles player magnetism, making it easier to collect coins.",
ToggleMagnetism)
);
m_commands.push_back(
Command("smash",
"Smash Activated.",
"Simulates the 'Smash' Ability.",
Smash)
);
m_commands.push_back(
Command("smash_wave",
"Wave Smash activated.",
"Simulates the 'Smash Wave' Ability.",
SmashWave)
);
m_commands.push_back(
Command("mute",
"Muted all sounds.",
"Mutes coin collection sound effects.",
Mute)
);
m_commands.push_back(
Command("unmute",
"Restored all sounds.",
"Restores all coin collection sound effects.",
Unmute)
);
m_commands.push_back(
Command("add_coins",
"Coins added.",
"Adds a specified number of coins to the player's wallet.",
AddCoins)
);
m_commands.push_back(
Command("max",
"Coins added. So many coins.",
"Adds 999999999 coins to the player's wallet.",
AddCoins_Large)
);
m_commands.push_back(
Command("double_coins",
"Coins have been doubled",
"Doubles the player's coins in their wallet.",
DoubleCoins)
);
m_commands.push_back(
Command("dispense",
"Dispensing...",
"Dispenses a specified number of coins directly into the game. May be unstable.",
Dispense)
);
m_commands.push_back(
Command("home",
"Homing in on player.",
"Sets all collectables' homing property to true.",
HomeIn)
);
m_commands.push_back(
Command("calc",
"Calculating: ",
"Performs a calculation. May change depending on the developer's choice of debug calculation.",
Calc)
);
m_commands.push_back(
Command("offset",
"Setting the offset ",
"Gives a manual value to the rendering offset values, x and y respectively.",
SetRenderOffset)
);
m_commands.push_back(
Command("j",
"Yes sir.",
"Jordan's preset of debug calls. Changes upon his mood. Originally [mag], [toggle_pull] and [mute].",
j)
);
m_commands.push_back(
Command("exp",
"Exploding particles",
"Adds a small, standard explosion of simple particles at (320,320).",
ParticleExplosion)
);
m_commands.push_back(
Command("talk",
"",
"Tests speech bubbles by making the player talk",
Talk)
);
m_commands.push_back(
Command("collision_debug",
"",
"Draws the player's hit box and AABB for collision debugging.",
ShowPlayerCollisionBoxes)
);
}
//
// CGConsole.h
// Testing-Console
//
// Created by Jordan Bell on 15/10/2014.
// Copyright (c) 2014 Jordan Bell. All rights reserved.
//
#pragma once
#include "testingconsole.h"
class CGConsole :
public TestingConsole
{
public:
CGConsole(void);
~CGConsole(void) {}
};
//
// TestingConsole.cpp
// Testing-Console
//
// Created by Jordan Bell on 15/10/2014.
// Copyright (c) 2014 Jordan Bell. All rights reserved.
//
#include "TestingConsole.h"
#include <cstdlib>
#include <iostream>
void TestingConsole::Open(void)
{
m_active = true;
printf("Console Active. Enter 'help' for a list of commands.");
SDL_EnableUNICODE( SDL_ENABLE );
}
void TestingConsole::Close(void)
{
m_active = false;
printf("\nConsole Inactive\n");
SDL_EnableUNICODE( SDL_DISABLE );
}
void TestingConsole::Toggle(void)
{
m_active ? Close() : Open();
if (m_active) NewLine();
}
void TestingConsole::KeyIn(SDL_keysym& keysym)
{
SDLKey key = keysym.sym;
if (key == SDLK_BACKSPACE) // Backspace
{
// Pop the last element of the string in the line
if (m_line.size() > 0) {
m_line.pop_back();
printf("\b \b"); // Backspace
}
}
else if (key == SDLK_RETURN) // Enter/Return
{
// Enter the code into the console
printf("\n");
Enter();
NewLine();
}
else if (key == SDLK_UP) // Traverse UP along the command memory
{
string commandStr = "";
if (!m_commandMemory.empty())
{
if (m_memoryIterator != m_commandMemory.begin()) {
m_memoryIterator--;
commandStr = *m_memoryIterator;
}
}
if (commandStr != "")
OverrideLine(commandStr);
}
else if (key == SDLK_DOWN) // Traverse DOWN along the command memory
{
string commandStr = "";
if (!m_commandMemory.empty())
{
if (m_memoryIterator != m_commandMemory.end())
{
m_memoryIterator++;
if (m_memoryIterator != m_commandMemory.end())
commandStr = *m_memoryIterator;
}
}
OverrideLine(commandStr);
}
else
{
// Otherwise, just input the character
char keyChar = keysym.unicode;
if (ValidationInput(keyChar))
printf("%c", keyChar);
}
}
void TestingConsole::OverrideLine(string _line)
{
// Replace the output on the command line with the new string
int strSize = m_line.size();
for (int i = 0; i < strSize; i++)
printf("\b \b");
// Set the new line
m_line = _line;
// Print it
printf("%s", m_line.c_str());
}
void TestingConsole::Enter(void)
{
// Add this line to the list of entered command strings
m_commandMemory.remove(m_line);
m_commandMemory.push_back(m_line);
m_memoryIterator = m_commandMemory.end();
// Separate the activation command from its arguments, if any
pair<string, string> codeArgumentsPair = SplitCommandCode(m_line);
string activationCode = codeArgumentsPair.first;
vector<int> arguments = ExtractArguments(codeArgumentsPair.second);
if (m_line == "help") {
CommandHelp();
return;
}
// Search through all of the commands for a match
for (Command possibleCommand : m_commands)
{
if (activationCode == possibleCommand.code)
{
try
{
// Execute the function
possibleCommand.func(arguments);
// Output the command's message, ie "Pull activated."
printf("%s", possibleCommand.message.c_str());
}
catch (exception e)
{
// If, for some reason, the called function does not operate correctly and throws an exception, fail and notify the user. Don't crash the game.
printf("Error. Called function threw an exception: %s", e.what());
}
catch (...)
{
// For everything else that isn't an exception, be more vague.
printf("Error caught. Called function and something went wrong.");
}
// Reset the m_line
m_line.clear();
// No point to continue searching
return;
}
}
// If no commands are recognised by now
printf("Command [%s] not recognised.", activationCode.c_str());
m_line.clear();
}
void TestingConsole::CommandHelp(void)
{
printf("Available commands:\n\n");
for (Command c : m_commands)
{
printf("[%s] = %s\n",
c.code.c_str(),
c.help.c_str());
}
NewLine();
}
pair<string, string> TestingConsole::SplitCommandCode(string line)
{
pair<string, string> codeArgumentsPair; // Return
string head = "";
string tail = line;
for (unsigned int i = 0; i < line.size(); i++)
{
char c = line.at(i);
tail.erase(0, 1);
if (c == ' ') {
// End of command code, beginning of arguments
codeArgumentsPair.first = head;
codeArgumentsPair.second = tail;
return codeArgumentsPair;
}
else
head.push_back(c);
}
codeArgumentsPair.first = line;
codeArgumentsPair.second = "";
return codeArgumentsPair;
}
vector<int> TestingConsole::ExtractArguments(string argumentsString)
{
vector<int> r_args;
string head = "";
string tail = argumentsString;
for (int i = 0; i < argumentsString.size(); i++)
{
char c = argumentsString.at(i);
tail.erase(0, 1);
if (c == ' ') {
r_args.push_back(atoi(head.c_str()));
head = "";
}
else
{
head.push_back(c);
}
}
// Add the last argument
if (head != "")
r_args.push_back(atoi(head.c_str()));
return r_args;
}
bool TestingConsole::ValidationInput(char keyChar)
{
// All valid character types
bool isMisc = ((keyChar == ' ') || (keyChar == '_'));
bool isNumber = ((keyChar >= '0') && (keyChar <= '9'));
bool isLowercase = ((keyChar >= 'a') && (keyChar <= 'z'));
bool isUppercase = ((keyChar >= 'A') && (keyChar <= 'Z'));
// Add the character if it is any of the above
if (isMisc || isNumber || isLowercase || isUppercase)
{
//Append the character
m_line += (char)keyChar;
}
return (isMisc || isNumber || isLowercase || isUppercase);
}
//
// TestingConsole.h
// Testing-Console
//
// Created by Jordan Bell on 15/10/2014.
// Copyright (c) 2014 Jordan Bell. All rights reserved.
//
#pragma once
#include <string>
#include <list>
#include <functional>
#include <type_traits>
#include <vector>
#include "SDL.h"
using namespace std;
class TestingConsole
{
public:
TestingConsole(void) : m_active(false), m_prompt("~: "), m_memoryIterator(m_commandMemory.begin()) {}
~TestingConsole(void) {}
// Activate or Deactivate the Testing Console for input
void Toggle(void);
// Return whether or not the Testing Console is currently active
bool IsActive(void) { return m_active; }
/* Enter the current m_line into the console, invoking any corresponding functions. */
void Enter(void);
// Enter a key into the Testing Console
void KeyIn(SDL_keysym& keysym);
protected:
/*
A struct containing information pertaining to the various commands that can be recognised by the console.
Object of this struct can be instantiated in subclasses of the Testing Console. Otherwise, no commands are recognised.
*/
struct Command
{
// Standard Constructor
Command(string _code, string _message, void (*_func)(vector<int>))
: code(_code), message(_message), help("No description."), func(_func) {}
// Constructor, with a help message defined for the Help menu
Command(string _code, string _message, string _help, void (*_func)(vector<int>))
: code(_code), message(_message), help(_help), func(_func) {}
string code; // The string that invokes a console response
string help; // The description displayed on the help menu
string message; // The response that is printed to acknowledge its activation
void (*func)(vector<int>); // The function to be called when the matching string is enterred.
};
// The list of commands recognised by the testing console
list<Command> m_commands;
private:
// The "prompt" displayed in the console before the user input
string m_prompt;
// The list of previously enterred commands, cycled through using the UP and DOWN keys
list<string> m_commandMemory;
// The iterator through the list of command memories
list<string>::iterator m_memoryIterator;
// The string currently enterred into the console
string m_line;
// Defines whether or not this console will accept input
bool m_active;
// Returns a pair of strings. The first being the argument's activation code, the second being its arguments
static pair<string, string> SplitCommandCode(string line);
// Returns a vector of arguments from a string of arguments, separated by spaces
static vector<int> ExtractArguments(string argumentsString);
// Open the console, enabling SDL unicode input and prompting the user
void Open(void);
// Close the console, notifying the user of its closing and disabling SDL unicode
void Close(void);
/*
* Add a character to the m_line, given that it is valid. Ignore, if not.
* Take a keysym object containing relevant information for validation
* Return a boolean indicating the validity of that key character
*/
bool ValidationInput(char keysym);
// Print the Help menu - all of the currently held commands, and their corresponding descriptions, if provided.
void CommandHelp(void);
// Add a new line, clearing the current m_line value and starting again
void NewLine(void) { m_line.clear(); printf("\n%s", m_prompt.c_str()); }
// Override m_line's value with a given string, and delete its output in the console
void OverrideLine(string _line);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment