Verified Commit 4143647c authored by RobLoach's avatar RobLoach
Browse files

Add an in-game console

Fixes #183
parent 144e1a9e
......@@ -2,3 +2,5 @@
*.so
*.state*
node_modules
*.srm.*
*.srm1.*
......@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## 0.16.2 - Unreleased
### Added
- `love.system.getOS()` now returns actual operating system name
- `love.console` an in-game console toggled with the tilde key
## 0.16.1 - 2018-03-12
### Added
......
......@@ -58,6 +58,7 @@ bool ChaiLove::load(const std::string& file) {
sound.load();
}
console.load();
graphics.load();
image.load();
keyboard.load();
......@@ -132,6 +133,9 @@ void ChaiLove::draw() {
test.draw();
#endif
// Render the in-game console.
console.draw();
// Flip the buffer.
if (SDL_Flip(screen) == -1) {
std::string out("[ChaiLove] Failed to swap the buffers: ");
......
......@@ -92,6 +92,7 @@
#include "love/window.h"
#include "love/math.h"
#include "love/event.h"
#include "love/console.h"
#ifdef __HAVE_TESTS__
#include "../test/native/NativeTest.h"
......@@ -107,6 +108,7 @@ class ChaiLove {
static retro_input_poll_t input_poll_cb;
love::config config;
love::console console;
love::keyboard keyboard;
love::script* script;
love::filesystem filesystem;
......
#include "console.h"
#include "../ChaiLove.h"
#include "Types/Graphics/Font.h"
#include <iostream>
#include <string>
#include <vector>
using love::Types::Graphics::Font;
namespace love {
bool console::load() {
// Use ` for the toggling key.
m_togglescancode = 96;
m_enabled = false;
}
void console::keypressed(std::string key, int scancode) {
// Test scancode and key input.
std::cout << "Key: " << key << std::endl << "Cod: " << scancode << std::endl << m_togglescancode;
// Toggle the console.
if (scancode == m_togglescancode) {
toggle();
return;
}
// Act on the key press only if the console is enabled.
if (!isEnabled()) {
return;
}
ChaiLove* app = ChaiLove::getInstance();
bool shiftDown = app->keyboard.isDown("shift") || app->keyboard.isDown("lshift") || app->keyboard.isDown("rshift");
if (key.size() == 1) {
if (scancode >= 97 && scancode <= 122) {
if (shiftDown) {
m_input += (char)(scancode - 32);
} else {
m_input += key;
}
} else if (scancode == 43) {
// Nothing.
} else if (scancode == 61) {
if (!shiftDown) {
m_input += "=";
} else {
m_input += "+";
}
} else if (scancode == 45) {
// Nothing.
} else if (scancode == 95) {
if (!shiftDown) {
m_input += "-";
} else {
m_input += "_";
}
} else if (scancode == 33 || scancode == 64 || scancode == 35 || scancode == 36 || scancode == 38 || scancode == 42) {
// Nothing.
} else if (scancode >= 48 && scancode <= 57) {
if (!shiftDown) {
m_input += key;
} else {
switch (scancode) {
case 48:
m_input += ")";
break;
case 49:
m_input += "!";
break;
case 50:
m_input += "@";
break;
case 51:
m_input += "#";
break;
case 52:
m_input += "$";
break;
case 53:
m_input += "%";
break;
case 54:
m_input += "^";
break;
case 55:
m_input += "&";
break;
case 56:
m_input += "*";
break;
case 57:
m_input += "(";
break;
}
}
} else if (scancode == 39) {
// Nothing
} else if (scancode == 34) {
if (shiftDown) {
m_input += '"';
} else {
m_input += '\'';
}
} else if (scancode == 47) {
// Nothing.
} else if (scancode == 63) {
if (shiftDown) {
m_input += '?';
} else {
m_input += '/';
}
} else if (scancode == 46) {
// Nothing.
} else if (scancode == 62) {
if (shiftDown) {
m_input += '>';
} else {
m_input += '.';
}
} else if (scancode == 58) {
// Nothing.
} else if (scancode == 59) {
if (shiftDown) {
m_input += ':';
} else {
m_input += ';';
}
} else if (scancode == 91) {
if (shiftDown) {
m_input += "{";
} else {
m_input += "[";
}
} else if (scancode == 93) {
if (shiftDown) {
m_input += "}";
} else {
m_input += "]";
}
} else {
m_input += key;
}
} else if (key == "space") {
m_input += " ";
} else if (key == "backspace") {
if (m_input.size() > 0) {
m_input.pop_back();
}
} else if (key == "return") {
execute(m_input);
m_input = "";
}
}
void console::draw() {
if (!m_enabled) {
return;
}
ChaiLove* app = ChaiLove::getInstance();
int bottom = app->graphics.getHeight() - app->graphics.getHeight() / 3;
// Retrieve the detault font.
Font* font = app->graphics.setFont().getFont();
app->graphics.setColor(0, 0, 0, 200);
app->graphics.rectangle("fill", 0, 0, app->graphics.getWidth(), bottom);
app->graphics.setColor(255, 255, 255);
app->graphics.print("> " + m_input, 0, bottom - font->getHeight());
// Display the log, starting 2 lines up from the bottom.
int numEntry = 2;
for (std::vector<std::string>::reverse_iterator i = m_log.rbegin(); i != m_log.rend(); ++i) {
app->graphics.print(*i, 0, bottom - font->getHeight() * numEntry++);
}
}
void console::execute(const std::string& entry) {
m_log.push_back(entry);
ChaiLove* app = ChaiLove::getInstance();
try {
std::string out = app->script->evalString(entry, "__EVAL__");
if (!out.empty()) {
m_log.push_back(out);
}
}
catch (const chaiscript::exception::eval_error &e) {
m_log.push_back(e.what());
} catch (const std::exception &e) {
m_log.push_back(e.what());
}
}
bool console::isEnabled() {
return m_enabled;
}
bool console::toggle() {
return setEnabled(!isEnabled());
}
bool console::setEnabled(bool enabled) {
return m_enabled = enabled;
}
} // namespace love
#ifndef SRC_LOVE_CONSOLE_H_
#define SRC_LOVE_CONSOLE_H_
#include <string>
#include <vector>
namespace love {
/**
* @brief In-game console for ChaiLove.
*
* Enable the console by pressing the tilde key on your keyboard. It will
* execute ChaiScript. For example, open the console with \`, and type
* `love.system.getOS()`.
*/
class console {
public:
std::vector<std::string> m_log;
std::string m_input = std::string("");
bool m_enabled = false;
int m_togglescancode;
bool load();
void keypressed(std::string key, int scancode);
void draw();
/**
* @brief Checks to see if the console is enabled.
*/
bool isEnabled();
/**
* @brief Enable or disable the console.
*/
bool setEnabled(bool enabled);
/**
* @brief Toggles the console on or off.
*
* @return True if the console is toggle on, false otherwise.
*/
bool toggle();
void execute(const std::string& entry);
};
} // namespace love
#endif // SRC_LOVE_CONSOLE_H_
......@@ -191,10 +191,15 @@ graphics& graphics::setColor(int red, int green, int blue, int alpha) {
a = alpha;
return *this;
}
graphics& graphics::setColor(int red, int green, int blue) {
return setColor(red, green, blue, 255);
}
Color graphics::getColor() {
return Color(r, g, b, a);
}
Color graphics::getBackgroundColor() {
Color c;
c.r = backR;
......
......@@ -157,6 +157,11 @@ class graphics {
*/
graphics& setColor(int red, int green, int blue);
/**
* @brief Gets the current color.
*/
Color getColor();
/**
* @brief Retrieves the active background color.
*
......
......@@ -60,6 +60,9 @@ bool joystick::isDown(int index, const std::string& button) {
}
void joystick::update() {
if (ChaiLove::getInstance()->console.isEnabled()) {
return;
}
// SDL_JoystickUpdate();
int i, u;
int16_t state;
......
......@@ -215,13 +215,22 @@ bool keyboard::update() {
void keyboard::eventKeyPressed(int scancode) {
std::string key = getKeyFromScancode(scancode);
ChaiLove* app = ChaiLove::getInstance();
app->script->keypressed(key, scancode);
// Trigger the keypress in the in-game console and the game.
app->console.keypressed(key, scancode);
if (!app->console.isEnabled()) {
app->script->keypressed(key, scancode);
}
}
void keyboard::eventKeyReleased(int scancode) {
std::string key = getKeyFromScancode(scancode);
ChaiLove* app = ChaiLove::getInstance();
app->script->keyreleased(key, scancode);
// Only trigger the event in the game if the console is not being used.
if (!app->console.isEnabled()) {
app->script->keyreleased(key, scancode);
}
}
} // namespace love
......@@ -47,15 +47,24 @@ bool script::loadModule(const std::string& moduleName) {
return false;
}
// Replace possible problematic tabs, and evaluate the script.
contents = replaceString(contents, "\t", " ");
chai.eval(contents, Exception_Handler(), filename);
eval(contents, filename);
return true;
#endif
return false;
}
chaiscript::Boxed_Value script::eval(const std::string& code, const std::string& filename) {
// Replace possible problematic tabs, and evaluate the script.
std::string contents = replaceString(code, "\t", " ");
return chai.eval(contents, Exception_Handler(), filename);
}
std::string script::evalString(const std::string& code, const std::string& filename) {
// Replace possible problematic tabs, and evaluate the script.
std::string contents = replaceString(code, "\t", " ");
return chai.eval<std::string>(contents, Exception_Handler(), filename);
}
script::script(const std::string& file) {
#ifdef __HAVE_CHAISCRIPT__
ChaiLove* app = ChaiLove::getInstance();
......@@ -76,6 +85,7 @@ script::script(const std::string& file) {
ChaiLove* app = ChaiLove::getInstance();
love["audio"] = var(std::ref(app->audio));
love["config"] = var(std::ref(app->config));
love["console"] = var(std::ref(app->console));
love["event"] = var(std::ref(app->event));
love["filesystem"] = var(std::ref(app->filesystem));
love["font"] = var(std::ref(app->font));
......@@ -162,6 +172,11 @@ script::script(const std::string& file) {
chai.add(fun(&config::modules), "modules");
chai.add(fun(&config::options), "options");
// Console
chai.add(fun(&console::isEnabled), "isEnabled");
chai.add(fun(&console::setEnabled), "setEnabled");
chai.add(fun(&console::toggle), "toggle");
// Joystick
chai.add(user_type<Joystick>(), "Joystick");
chai.add(fun<bool, Joystick, const std::string&>(&Joystick::isDown), "isDown");
......
......@@ -232,6 +232,9 @@ class script {
*/
bool loadstate(const std::string& data);
chaiscript::Boxed_Value eval(const std::string& code, const std::string& filename);
std::string evalString(const std::string& code, const std::string& filename);
#ifdef __HAVE_CHAISCRIPT__
chaiscript::ChaiScript chai;
std::function<void()> chaiload;
......
love.console.setEnabled(true)
assert_equal(love.console.isEnabled(), true, "love.console.setEnabled()")
love.console.toggle()
assert_equal(love.console.isEnabled(), false, "love.console.toggle()")
......@@ -6,6 +6,7 @@ def load() {
love.filesystem.load("assert")
love.filesystem.load("audio")
love.filesystem.load("console")
love.filesystem.load("filesystem")
love.filesystem.load("font")
love.filesystem.load("graphics")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment