Skip to content

Commit

Permalink
Add a simple script console
Browse files Browse the repository at this point in the history
  • Loading branch information
dscharrer committed Dec 18, 2016
1 parent a10af51 commit a921794
Show file tree
Hide file tree
Showing 4 changed files with 371 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -900,6 +900,7 @@ set(GRAPHICS_OPENGL_SOURCES

set(GUI_SOURCES
src/gui/CinematicBorder.cpp
src/gui/Console.cpp
src/gui/Credits.cpp
src/gui/Cursor.cpp
src/gui/DebugHud.cpp
Expand Down
5 changes: 5 additions & 0 deletions src/core/ArxGame.cpp
Expand Up @@ -108,6 +108,7 @@ ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
#include "graphics/particle/Spark.h"
#include "graphics/texture/TextureStage.h"

#include "gui/Console.h"
#include "gui/Cursor.h"
#include "gui/DebugHud.h"
#include "gui/Hud.h"
Expand Down Expand Up @@ -1748,6 +1749,8 @@ void ArxGame::updateInput() {
drawDebugCycleViews();
}

g_console.update();

#ifdef ARX_DEBUG
if(GInput->isKeyPressedNowPressed(Keyboard::Key_Pause)) {
if(!arxtime.is_paused()) {
Expand Down Expand Up @@ -2258,6 +2261,8 @@ void ArxGame::render() {
}
}

g_console.draw();

if(ARXmenu.currentmode == AMCM_OFF) {
ARX_SCRIPT_AllowInterScriptExec();
ARX_SCRIPT_EventStackExecute();
Expand Down
262 changes: 262 additions & 0 deletions src/gui/Console.cpp
@@ -0,0 +1,262 @@
/*
* Copyright 2016 Arx Libertatis Team (see the AUTHORS file)
*
* This file is part of Arx Libertatis.
*
* Arx Libertatis is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Arx Libertatis 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 Arx Libertatis. If not, see <http://www.gnu.org/licenses/>.
*/

#include "gui/Console.h"

#include <algorithm>

#include "core/Config.h"
#include "core/Core.h"
#include "core/GameTime.h"
#include "game/Entity.h"
#include "game/EntityManager.h"
#include "graphics/Draw.h"
#include "graphics/DrawLine.h"
#include "graphics/font/Font.h"
#include "gui/Interface.h"
#include "gui/Text.h"
#include "input/Input.h"
#include "math/Rectangle.h"
#include "script/ScriptEvent.h"
#include "util/Unicode.h"

// TODO Share some of this with the save name entry field

void ConsoleBuffer::append(const std::string & text) {

std::string::const_iterator i = text.begin();
std::string::const_iterator end = text.end();

while(i != end) {

// Remember newline but don't apply until there is content
if(m_pos < m_width + 1 && *i == '\n') {
// Delay newline
m_pos = m_width + 1;
++i;
}

if(i == end) {
break;
}

// Apply delayed newline
if(m_pos >= m_width) {
m_newline = false;
m_line = (m_line + 1) % m_lines.size();
m_lines[m_line].clear();
m_pos = 0;
}

// Find the next line break
std::string::const_iterator line_end = i;
size_t length = 0;
while(line_end != end && *line_end != '\n'
&& length < m_width - m_pos) {
line_end = util::UTF8::next(line_end, end);
++length;
}

m_lines[m_line].append(i, line_end);
m_pos += length;
i = line_end;

}

}

bool ScriptConsole::keyPressed(Keyboard::Key key, KeyModifiers mod) {

switch(key) {

case Keyboard::Key_Escape: {
close();
return true;
}

case Keyboard::Key_Enter: {
execute();
clear();
return true;
}

case Keyboard::Key_LeftCtrl:
case Keyboard::Key_RightCtrl: {
// We use control as a modifier, disable other uses while the console is open
return true;
}

default: break;
}

if(mod.control) {
switch(key) {

case Keyboard::Key_J: {
execute();
clear();
return true;
}

case Keyboard::Key_O: {
execute();
moveEnd();
return true;
}

default: break;
}
}

return BasicTextInput::keyPressed(key, mod);
}

void ScriptConsole::open() {
if(!m_enabled) {
config.input.allowConsole = true;
m_enabled = true;
}
}

void ScriptConsole::close() {
if(m_enabled) {
GInput->stopTextInput();
m_enabled = false;
}
}

void ScriptConsole::execute() {

m_buffer.append("> " + text() + "\n");

Entity * entity = entities.player();

std::string script = command() + "\naccept\n";
EERIE_SCRIPT es;
es.size = script.size();
es.data = const_cast<char *>(script.c_str());
es.master = entity ? &entity->script : NULL;
// TODO Some script commands (timers, etc.) store references to the script

long pos = 0;
ScriptEvent::send(&es, SM_EXECUTELINE, std::string(), entity, std::string(), pos);
}

void ScriptConsole::update() {

if(!m_enabled) {
if(config.input.allowConsole && GInput->actionNowPressed(CONTROLS_CUST_CONSOLE)) {
open();
} else {
return;
}
}

s32 lineHeight = hFontDebug->getLineHeight();
Rect box = g_size;
box.top += lineHeight * s32(m_buffer.lines());
box.bottom = box.top + lineHeight;
box.left += hFontDebug->getTextSize("> ").advance();
GInput->startTextInput(box, this);

{
static const PlatformDuration BlinkDuration = PlatformDurationMs(600);
m_blinkTime += g_platformTime.lastFrameDuration();
if(m_blinkTime > (BlinkDuration + BlinkDuration))
m_blinkTime = PlatformDuration_ZERO;
m_blink = m_blinkTime > BlinkDuration;
}

}

void ScriptConsole::draw() {

if(!m_enabled) {
return;
}

UseRenderState state(render2D());

Color background = Color::black;
background.a = 150;
Color line = Color::gray(0.8f);
Color selection = Color::yellow;
selection.a = 40;

Rectf box = Rectf(g_size);
box.bottom = box.top + (m_buffer.lines() + 1) * hFontDebug->getLineHeight() + 4;
EERIEDrawBitmap(box, 0.f, NULL, background);

Vec2i pos = Vec2i_ZERO;
for(size_t i = 0; i < m_buffer.lines(); i++) {
hFontDebug->draw(pos, m_buffer.line(i), Color::white);
pos.y += hFontDebug->getLineHeight();
}

pos.y += 1;

drawLine(Vec2f(0, pos.y), Vec2f(g_size.width(), pos.y), 0.f, line);

pos.y += 2;

pos.x += hFontDebug->draw(pos, "> ", Color::green).advance();

std::string displayText = text();
if(!editText().empty()) {
displayText = displayText.substr(0, cursorPos()) + editText() + displayText.substr(cursorPos());
}
size_t displayCursorPos = cursorPos() + editCursorPos();

std::string::const_iterator begin = displayText.begin();
std::string::const_iterator end = displayText.end();

// Highlight edit area
if(!editText().empty()) {
int left = hFontDebug->getTextSize(begin, begin + cursorPos()).advance();
int right = hFontDebug->getTextSize(begin, begin + cursorPos() + editText().size()).advance();
int height = hFontDebug->getLineHeight();
Rectf box = Rectf(pos + Vec2i(left, 0), right - left, height);
EERIEDrawBitmap(box, 0.f, NULL, selection);
}

// Draw text
s32 x = hFontDebug->draw(pos.x, pos.y, begin, end, Color::white).next();

// Draw cursor
if(m_blink) {
int cursor = x;
if(cursorPos() != displayText.size()) {
cursor = pos.x + hFontDebug->getTextSize(begin, begin + displayCursorPos).next();
}
drawLine(Vec2f(cursor, pos.y), Vec2f(cursor, pos.y + hFontDebug->getLineHeight()), 0.f, line);
if(editCursorLength() > 0) {
int end = pos.x + hFontDebug->getTextSize(begin, begin + displayCursorPos + editCursorLength()).next();
drawLine(Vec2f(end, pos.y), Vec2f(end, pos.y + hFontDebug->getLineHeight()), 0.f, line);
}
}

pos.y += hFontDebug->getLineHeight();

pos.y += 1;

drawLine(Vec2f(0, pos.y), Vec2f(g_size.width(), pos.y), 0.f, line);

}

ScriptConsole g_console;

0 comments on commit a921794

Please sign in to comment.