master
Maksim Gamarnik 2016-03-04 16:30:16 +02:00
commit 3505f8982f
17 changed files with 432 additions and 242 deletions

View File

@ -2337,7 +2337,7 @@ These functions return the leftover itemstack.
otherwise returns `nil`.
* The returned table contains the functions `fetch`, `fetch_async` and `fetch_async_get`
described below.
* Only works at init time.
* Only works at init time and must be called from the mod's main scope (not from a function).
* Function only exists if minetest server was built with cURL support.
* **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN
A LOCAL VARIABLE!**
@ -3698,11 +3698,12 @@ Definition tables
-- ^ Minimum and maximum `y` positions these decorations can be generated at.
-- ^ This parameter refers to the `y` position of the decoration base, so
-- the actual maximum height would be `height_max + size.Y`.
flags = "liquid_surface",
flags = "liquid_surface, force_placement",
-- ^ Flags for all decoration types.
-- ^ "liquid_surface": Instead of placement on the highest solid surface
-- ^ in a mapchunk column, placement is on the highest liquid surface.
-- ^ Placement is disabled if solid nodes are found above the liquid surface.
-- ^ "force_placement": Nodes other than "air" and "ignore" are replaced by the decoration.
----- Simple-type parameters
decoration = "default:grass",
@ -3746,7 +3747,7 @@ Definition tables
},
-- ^ See 'Schematic specifier' for details.
replacements = {["oldname"] = "convert_to", ...},
flags = "place_center_x, place_center_y, place_center_z, force_placement",
flags = "place_center_x, place_center_y, place_center_z",
-- ^ Flags for schematic decorations. See 'Schematic attributes'.
rotation = "90" -- rotate schematic 90 degrees on placement
-- ^ Rotation can be "0", "90", "180", "270", or "random".

View File

@ -316,7 +316,7 @@ if map format version >= 23:
u8[key_len] key
u32 val_len
u8[val_len] value
serialized inventory
serialized inventory
- Node timers
if map format version == 23:

View File

@ -390,6 +390,7 @@ ChatPrompt::ChatPrompt(std::wstring prompt, u32 history_limit):
m_cols(0),
m_view(0),
m_cursor(0),
m_cursor_len(0),
m_nick_completion_start(0),
m_nick_completion_end(0)
{
@ -417,20 +418,13 @@ void ChatPrompt::input(const std::wstring &str)
m_nick_completion_end = 0;
}
std::wstring ChatPrompt::submit()
void ChatPrompt::addToHistory(std::wstring line)
{
std::wstring line = m_line;
m_line.clear();
if (!line.empty())
m_history.push_back(line);
if (m_history.size() > m_history_limit)
m_history.erase(m_history.begin());
m_history_index = m_history.size();
m_view = 0;
m_cursor = 0;
m_nick_completion_start = 0;
m_nick_completion_end = 0;
return line;
}
void ChatPrompt::clear()
@ -442,13 +436,15 @@ void ChatPrompt::clear()
m_nick_completion_end = 0;
}
void ChatPrompt::replace(std::wstring line)
std::wstring ChatPrompt::replace(std::wstring line)
{
std::wstring old_line = m_line;
m_line = line;
m_view = m_cursor = line.size();
clampView();
m_nick_completion_start = 0;
m_nick_completion_end = 0;
return old_line;
}
void ChatPrompt::historyPrev()
@ -590,14 +586,12 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
s32 length = m_line.size();
s32 increment = (dir == CURSOROP_DIR_RIGHT) ? 1 : -1;
if (scope == CURSOROP_SCOPE_CHARACTER)
{
switch (scope) {
case CURSOROP_SCOPE_CHARACTER:
new_cursor += increment;
}
else if (scope == CURSOROP_SCOPE_WORD)
{
if (increment > 0)
{
break;
case CURSOROP_SCOPE_WORD:
if (dir == CURSOROP_DIR_RIGHT) {
// skip one word to the right
while (new_cursor < length && isspace(m_line[new_cursor]))
new_cursor++;
@ -605,39 +599,47 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
new_cursor++;
while (new_cursor < length && isspace(m_line[new_cursor]))
new_cursor++;
}
else
{
} else {
// skip one word to the left
while (new_cursor >= 1 && isspace(m_line[new_cursor - 1]))
new_cursor--;
while (new_cursor >= 1 && !isspace(m_line[new_cursor - 1]))
new_cursor--;
}
}
else if (scope == CURSOROP_SCOPE_LINE)
{
break;
case CURSOROP_SCOPE_LINE:
new_cursor += increment * length;
break;
case CURSOROP_SCOPE_SELECTION:
break;
}
new_cursor = MYMAX(MYMIN(new_cursor, length), 0);
if (op == CURSOROP_MOVE)
{
switch (op) {
case CURSOROP_MOVE:
m_cursor = new_cursor;
}
else if (op == CURSOROP_DELETE)
{
if (new_cursor < old_cursor)
{
m_line.erase(new_cursor, old_cursor - new_cursor);
m_cursor = new_cursor;
m_cursor_len = 0;
break;
case CURSOROP_DELETE:
if (m_cursor_len > 0) { // Delete selected text first
m_line.erase(m_cursor, m_cursor_len);
} else {
m_cursor = MYMIN(new_cursor, old_cursor);
m_line.erase(m_cursor, abs(new_cursor - old_cursor));
}
else if (new_cursor > old_cursor)
{
m_line.erase(old_cursor, new_cursor - old_cursor);
m_cursor = old_cursor;
m_cursor_len = 0;
break;
case CURSOROP_SELECT:
if (scope == CURSOROP_SCOPE_LINE) {
m_cursor = 0;
m_cursor_len = length;
} else {
m_cursor = MYMIN(new_cursor, old_cursor);
m_cursor_len += abs(new_cursor - old_cursor);
m_cursor_len = MYMIN(m_cursor_len, length - m_cursor);
}
break;
}
clampView();

View File

@ -146,14 +146,21 @@ public:
void input(wchar_t ch);
void input(const std::wstring &str);
// Submit, clear and return current line
std::wstring submit();
// Add a string to the history
void addToHistory(std::wstring line);
// Get current line
std::wstring getLine() const { return m_line; }
// Get section of line that is currently selected
std::wstring getSelection() const
{ return m_line.substr(m_cursor, m_cursor_len); }
// Clear the current line
void clear();
// Replace the current line with the given text
void replace(std::wstring line);
std::wstring replace(std::wstring line);
// Select previous command from history
void historyPrev();
@ -169,10 +176,13 @@ public:
std::wstring getVisiblePortion() const;
// Get cursor position (relative to visible portion). -1 if invalid
s32 getVisibleCursorPosition() const;
// Get length of cursor selection
s32 getCursorLength() const { return m_cursor_len; }
// Cursor operations
enum CursorOp {
CURSOROP_MOVE,
CURSOROP_SELECT,
CURSOROP_DELETE
};
@ -186,7 +196,8 @@ public:
enum CursorOpScope {
CURSOROP_SCOPE_CHARACTER,
CURSOROP_SCOPE_WORD,
CURSOROP_SCOPE_LINE
CURSOROP_SCOPE_LINE,
CURSOROP_SCOPE_SELECTION
};
// Cursor operation
@ -224,6 +235,8 @@ private:
s32 m_view;
// Cursor (index into m_line)
s32 m_cursor;
// Cursor length (length of selected portion of line)
s32 m_cursor_len;
// Last nick completion start (index into m_line)
s32 m_nick_completion_start;

View File

@ -248,9 +248,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
bool any_position_valid = false;
// The order is important here, must be y first
for(s16 y = max_y; y >= min_y; y--)
for(s16 x = min_x; x <= max_x; x++)
for(s16 y = min_y; y <= max_y; y++)
for(s16 z = min_z; z <= max_z; z++)
{
v3s16 p(x,y,z);
@ -404,17 +403,15 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
Go through every nodebox, find nearest collision
*/
for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
// Ignore if already stepped up this nodebox.
if(is_step_up[boxindex])
continue;
// Find nearest collision of the two boxes (raytracing-like)
f32 dtime_tmp;
int collided = axisAlignedCollision(
cboxes[boxindex], movingbox, *speed_f, d, &dtime_tmp);
// Ignore if already stepped up this nodebox.
if (is_step_up[boxindex]) {
pos_f->Y += (cboxes[boxindex].MaxEdge.Y - movingbox.MinEdge.Y);
continue;
}
if (collided == -1 || dtime_tmp >= nearest_dtime)
continue;
@ -464,12 +461,10 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
is_collision = false;
CollisionInfo info;
if (is_object[nearest_boxindex]) {
if (is_object[nearest_boxindex])
info.type = COLLISION_OBJECT;
result.standing_on_object = true;
} else {
else
info.type = COLLISION_NODE;
}
info.node_p = node_positions[nearest_boxindex];
info.bouncy = bouncy;
@ -487,13 +482,12 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
speed_f->X = 0;
result.collides = true;
result.collides_xz = true;
} else if(nearest_collided == 1) { // Y
if (fabs(speed_f->Y) > BS * 3) {
}
else if(nearest_collided == 1) { // Y
if (fabs(speed_f->Y) > BS * 3)
speed_f->Y *= bounce;
} else {
else
speed_f->Y = 0;
result.touching_ground = true;
}
result.collides = true;
} else if(nearest_collided == 2) { // Z
if (fabs(speed_f->Z) > BS * 3)
@ -514,5 +508,43 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
}
}
/*
Final touches: Check if standing on ground, step up stairs.
*/
aabb3f box = box_0;
box.MinEdge += *pos_f;
box.MaxEdge += *pos_f;
for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
const aabb3f& cbox = cboxes[boxindex];
/*
See if the object is touching ground.
Object touches ground if object's minimum Y is near node's
maximum Y and object's X-Z-area overlaps with the node's
X-Z-area.
Use 0.15*BS so that it is easier to get on a node.
*/
if (cbox.MaxEdge.X - d > box.MinEdge.X && cbox.MinEdge.X + d < box.MaxEdge.X &&
cbox.MaxEdge.Z - d > box.MinEdge.Z &&
cbox.MinEdge.Z + d < box.MaxEdge.Z) {
if (is_step_up[boxindex]) {
pos_f->Y += (cbox.MaxEdge.Y - box.MinEdge.Y);
box = box_0;
box.MinEdge += *pos_f;
box.MaxEdge += *pos_f;
}
if (fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.15 * BS) {
result.touching_ground = true;
if (is_object[boxindex])
result.standing_on_object = true;
if (is_unloaded[boxindex])
result.standing_on_unloaded = true;
}
}
}
return result;
}

View File

@ -176,19 +176,6 @@ struct LocalFormspecHandler : public TextDest {
}
}
if (m_formname == "MT_CHAT_MENU") {
assert(m_client != 0);
if ((fields.find("btn_send") != fields.end()) ||
(fields.find("quit") != fields.end())) {
StringMap::const_iterator it = fields.find("f_text");
if (it != fields.end())
m_client->typeChatMessage(utf8_to_wide(it->second));
return;
}
}
if (m_formname == "MT_DEATH_SCREEN") {
assert(m_client != 0);
@ -1097,27 +1084,6 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec,
#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
#endif
static void show_chat_menu(GUIFormSpecMenu **cur_formspec,
InventoryManager *invmgr, IGameDef *gamedef,
IWritableTextureSource *tsrc, IrrlichtDevice *device,
Client *client, std::string text)
{
std::string formspec =
FORMSPEC_VERSION_STRING
SIZE_TAG
"field[3,2.35;6,0.5;f_text;;" + text + "]"
"button_exit[4,3;3,0.5;btn_send;" + strgettext("Proceed") + "]"
;
/* Create menu */
/* Note: FormspecFormSource and LocalFormspecHandler
* are deleted by guiFormSpecMenu */
FormspecFormSource *fs_src = new FormspecFormSource(formspec);
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_CHAT_MENU", client);
create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, fs_src, txt_dst, NULL);
}
static void show_deathscreen(GUIFormSpecMenu **cur_formspec,
InventoryManager *invmgr, IGameDef *gamedef,
IWritableTextureSource *tsrc, IrrlichtDevice *device, Client *client)
@ -1518,7 +1484,7 @@ protected:
void dropSelectedItem();
void openInventory();
void openConsole();
void openConsole(float height, const wchar_t *line=NULL);
void toggleFreeMove(float *statustext_time);
void toggleFreeMoveAlt(float *statustext_time, float *jump_timer);
void toggleFast(float *statustext_time);
@ -1578,6 +1544,10 @@ protected:
static void settingChangedCallback(const std::string &setting_name, void *data);
void readSettings();
#ifdef __ANDROID__
void handleAndroidChatInput();
#endif
private:
InputHandler *input;
@ -1664,8 +1634,8 @@ private:
#ifdef __ANDROID__
bool m_cache_hold_aux1;
bool m_android_chat_open;
#endif
};
Game::Game() :
@ -2179,7 +2149,7 @@ bool Game::initGui()
// Chat backend and console
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client);
-1, chat_backend, client, &g_menumgr);
if (!gui_chat_console) {
*error_message = "Could not allocate memory for chat console";
errorstream << *error_message << std::endl;
@ -2617,10 +2587,10 @@ void Game::processUserInput(VolatileRunFlags *flags,
input->step(dtime);
#ifdef __ANDROID__
if (current_formspec != 0)
if (current_formspec != NULL)
current_formspec->getAndroidUIInput();
else
handleAndroidChatInput();
#endif
// Increase timer for double tap of "keymap_jump"
@ -2656,16 +2626,16 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_INVENTORY])) {
openInventory();
} else if (input->wasKeyDown(EscapeKey) || input->wasKeyDown(CancelKey)) {
show_pause_menu(&current_formspec, client, gamedef, texture_src, device,
simple_singleplayer_mode);
if (!gui_chat_console->isOpenInhibited()) {
show_pause_menu(&current_formspec, client, gamedef,
texture_src, device, simple_singleplayer_mode);
}
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CHAT])) {
show_chat_menu(&current_formspec, client, gamedef, texture_src, device,
client, "");
openConsole(0.2, L"");
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CMD])) {
show_chat_menu(&current_formspec, client, gamedef, texture_src, device,
client, "/");
openConsole(0.2, L"/");
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_CONSOLE])) {
openConsole();
openConsole(1);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_FREEMOVE])) {
toggleFreeMove(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_JUMP])) {
@ -2700,15 +2670,15 @@ void Game::processKeyboardInput(VolatileRunFlags *flags,
decreaseViewRange(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_RANGESELECT])) {
toggleFullViewRange(statustext_time);
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_NEXT]))
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_NEXT])) {
quicktune->next();
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV]))
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_PREV])) {
quicktune->prev();
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_INC]))
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_INC])) {
quicktune->inc();
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC]))
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_QUICKTUNE_DEC])) {
quicktune->dec();
else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DEBUG_STACKS])) {
} else if (input->wasKeyDown(keycache.key[KeyCache::KEYMAP_ID_DEBUG_STACKS])) {
// Print debug stacks
dstream << "-----------------------------------------"
<< std::endl;
@ -2808,14 +2778,31 @@ void Game::openInventory()
}
void Game::openConsole()
void Game::openConsole(float height, const wchar_t *line)
{
if (!gui_chat_console->isOpenInhibited()) {
// Open up to over half of the screen
gui_chat_console->openConsole(0.6);
guienv->setFocus(gui_chat_console);
#ifdef __ANDROID__
porting::showInputDialog(gettext("ok"), "", "", 2);
m_android_chat_open = true;
#else
if (gui_chat_console->isOpenInhibited())
return;
gui_chat_console->openConsole(height);
if (line) {
gui_chat_console->setCloseOnEnter(true);
gui_chat_console->replaceAndAddToHistory(line);
}
#endif
}
#ifdef __ANDROID__
void Game::handleAndroidChatInput()
{
if (m_android_chat_open && porting::getInputDialogState() == 0) {
std::string text = porting::getInputDialogValue();
client->typeChatMessage(utf8_to_wide(text));
}
}
#endif
void Game::toggleFreeMove(float *statustext_time)

View File

@ -46,15 +46,18 @@ GUIChatConsole::GUIChatConsole(
gui::IGUIElement* parent,
s32 id,
ChatBackend* backend,
Client* client
Client* client,
IMenuManager* menumgr
):
IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
core::rect<s32>(0,0,100,100)),
m_chat_backend(backend),
m_client(client),
m_menumgr(menumgr),
m_screensize(v2u32(0,0)),
m_animate_time_old(0),
m_open(false),
m_close_on_enter(false),
m_height(0),
m_desired_height(0),
m_desired_height_fraction(0.0),
@ -119,6 +122,8 @@ void GUIChatConsole::openConsole(f32 height)
m_desired_height_fraction = height;
m_desired_height = height * m_screensize.Y;
reformatConsole();
Environment->setFocus(this);
m_menumgr->createdMenu(this);
}
bool GUIChatConsole::isOpen() const
@ -134,11 +139,13 @@ bool GUIChatConsole::isOpenInhibited() const
void GUIChatConsole::closeConsole()
{
m_open = false;
Environment->removeFocus(this);
m_menumgr->deletingMenu(this);
}
void GUIChatConsole::closeConsoleAtOnce()
{
m_open = false;
closeConsole();
m_height = 0;
recalculateConsolePosition();
}
@ -148,6 +155,14 @@ f32 GUIChatConsole::getDesiredHeight() const
return m_desired_height_fraction;
}
void GUIChatConsole::replaceAndAddToHistory(std::wstring line)
{
ChatPrompt& prompt = m_chat_backend->getPrompt();
prompt.addToHistory(prompt.getLine());
prompt.replace(line);
}
void GUIChatConsole::setCursor(
bool visible, bool blinking, f32 blink_speed, f32 relative_height)
{
@ -362,13 +377,15 @@ void GUIChatConsole::drawPrompt()
s32 cursor_pos = prompt.getVisibleCursorPosition();
if (cursor_pos >= 0)
{
s32 cursor_len = prompt.getCursorLength();
video::IVideoDriver* driver = Environment->getVideoDriver();
s32 x = (1 + cursor_pos) * m_fontsize.X;
core::rect<s32> destrect(
x,
y + (1.0-m_cursor_height) * m_fontsize.Y,
x + m_fontsize.X,
y + m_fontsize.Y);
y + m_fontsize.Y * (1.0 - m_cursor_height),
x + m_fontsize.X * MYMAX(cursor_len, 1),
y + m_fontsize.Y * (cursor_len ? m_cursor_height+1 : 1)
);
video::SColor cursor_color(255,255,255,255);
driver->draw2DRectangle(
cursor_color,
@ -381,23 +398,27 @@ void GUIChatConsole::drawPrompt()
bool GUIChatConsole::OnEvent(const SEvent& event)
{
ChatPrompt &prompt = m_chat_backend->getPrompt();
if(event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
{
// Key input
if(KeyPress(event.KeyInput) == getKeySetting("keymap_console"))
{
closeConsole();
Environment->removeFocus(this);
// inhibit open so the_game doesn't reopen immediately
m_open_inhibited = 50;
m_close_on_enter = false;
return true;
}
else if(event.KeyInput.Key == KEY_ESCAPE)
{
closeConsoleAtOnce();
Environment->removeFocus(this);
// the_game will open the pause menu
m_close_on_enter = false;
// inhibit open so the_game doesn't reopen immediately
m_open_inhibited = 1; // so the ESCAPE button doesn't open the "pause menu"
return true;
}
else if(event.KeyInput.Key == KEY_PRIOR)
@ -412,57 +433,50 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
}
else if(event.KeyInput.Key == KEY_RETURN)
{
std::wstring text = m_chat_backend->getPrompt().submit();
prompt.addToHistory(prompt.getLine());
std::wstring text = prompt.replace(L"");
m_client->typeChatMessage(text);
if (m_close_on_enter) {
closeConsoleAtOnce();
m_close_on_enter = false;
}
return true;
}
else if(event.KeyInput.Key == KEY_UP)
{
// Up pressed
// Move back in history
m_chat_backend->getPrompt().historyPrev();
prompt.historyPrev();
return true;
}
else if(event.KeyInput.Key == KEY_DOWN)
{
// Down pressed
// Move forward in history
m_chat_backend->getPrompt().historyNext();
prompt.historyNext();
return true;
}
else if(event.KeyInput.Key == KEY_LEFT)
else if(event.KeyInput.Key == KEY_LEFT || event.KeyInput.Key == KEY_RIGHT)
{
// Left or Ctrl-Left pressed
// move character / word to the left
ChatPrompt::CursorOpScope scope =
event.KeyInput.Control ?
// Left/right pressed
// Move/select character/word to the left depending on control and shift keys
ChatPrompt::CursorOp op = event.KeyInput.Shift ?
ChatPrompt::CURSOROP_SELECT :
ChatPrompt::CURSOROP_MOVE;
ChatPrompt::CursorOpDir dir = event.KeyInput.Key == KEY_LEFT ?
ChatPrompt::CURSOROP_DIR_LEFT :
ChatPrompt::CURSOROP_DIR_RIGHT;
ChatPrompt::CursorOpScope scope = event.KeyInput.Control ?
ChatPrompt::CURSOROP_SCOPE_WORD :
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
m_chat_backend->getPrompt().cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_LEFT,
scope);
return true;
}
else if(event.KeyInput.Key == KEY_RIGHT)
{
// Right or Ctrl-Right pressed
// move character / word to the right
ChatPrompt::CursorOpScope scope =
event.KeyInput.Control ?
ChatPrompt::CURSOROP_SCOPE_WORD :
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
m_chat_backend->getPrompt().cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_RIGHT,
scope);
prompt.cursorOperation(op, dir, scope);
return true;
}
else if(event.KeyInput.Key == KEY_HOME)
{
// Home pressed
// move to beginning of line
m_chat_backend->getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_LEFT,
ChatPrompt::CURSOROP_SCOPE_LINE);
@ -472,7 +486,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
{
// End pressed
// move to end of line
m_chat_backend->getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_RIGHT,
ChatPrompt::CURSOROP_SCOPE_LINE);
@ -486,7 +500,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
event.KeyInput.Control ?
ChatPrompt::CURSOROP_SCOPE_WORD :
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
m_chat_backend->getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_LEFT,
scope);
@ -500,30 +514,72 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
event.KeyInput.Control ?
ChatPrompt::CURSOROP_SCOPE_WORD :
ChatPrompt::CURSOROP_SCOPE_CHARACTER;
m_chat_backend->getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_RIGHT,
scope);
return true;
}
else if(event.KeyInput.Key == KEY_KEY_A && event.KeyInput.Control)
{
// Ctrl-A pressed
// Select all text
prompt.cursorOperation(
ChatPrompt::CURSOROP_SELECT,
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
ChatPrompt::CURSOROP_SCOPE_LINE);
return true;
}
else if(event.KeyInput.Key == KEY_KEY_C && event.KeyInput.Control)
{
// Ctrl-C pressed
// Copy text to clipboard
if (prompt.getCursorLength() <= 0)
return true;
std::wstring wselected = prompt.getSelection();
std::string selected(wselected.begin(), wselected.end());
Environment->getOSOperator()->copyToClipboard(selected.c_str());
return true;
}
else if(event.KeyInput.Key == KEY_KEY_V && event.KeyInput.Control)
{
// Ctrl-V pressed
// paste text from clipboard
if (prompt.getCursorLength() > 0) {
// Delete selected section of text
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
ChatPrompt::CURSOROP_SCOPE_SELECTION);
}
IOSOperator *os_operator = Environment->getOSOperator();
const c8 *text = os_operator->getTextFromClipboard();
if (text)
{
std::wstring wtext = narrow_to_wide(text);
m_chat_backend->getPrompt().input(wtext);
}
if (!text)
return true;
std::basic_string<unsigned char> str((const unsigned char*)text);
prompt.input(std::wstring(str.begin(), str.end()));
return true;
}
else if(event.KeyInput.Key == KEY_KEY_X && event.KeyInput.Control)
{
// Ctrl-X pressed
// Cut text to clipboard
if (prompt.getCursorLength() <= 0)
return true;
std::wstring wselected = prompt.getSelection();
std::string selected(wselected.begin(), wselected.end());
Environment->getOSOperator()->copyToClipboard(selected.c_str());
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_LEFT, // Ignored
ChatPrompt::CURSOROP_SCOPE_SELECTION);
return true;
}
else if(event.KeyInput.Key == KEY_KEY_U && event.KeyInput.Control)
{
// Ctrl-U pressed
// kill line to left end
m_chat_backend->getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_LEFT,
ChatPrompt::CURSOROP_SCOPE_LINE);
@ -533,7 +589,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
{
// Ctrl-K pressed
// kill line to right end
m_chat_backend->getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_RIGHT,
ChatPrompt::CURSOROP_SCOPE_LINE);
@ -545,7 +601,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
// Nick completion
std::list<std::string> names = m_client->getConnectedPlayerNames();
bool backwards = event.KeyInput.Shift;
m_chat_backend->getPrompt().nickCompletion(names, backwards);
prompt.nickCompletion(names, backwards);
return true;
}
else if(event.KeyInput.Char != 0 && !event.KeyInput.Control)
@ -553,9 +609,9 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
#if (defined(linux) || defined(__linux))
wchar_t wc = L'_';
mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
m_chat_backend->getPrompt().input(wc);
prompt.input(wc);
#else
m_chat_backend->getPrompt().input(event.KeyInput.Char);
prompt.input(event.KeyInput.Char);
#endif
return true;
}

View File

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define GUICHATCONSOLE_HEADER
#include "irrlichttypes_extrabloated.h"
#include "modalMenu.h"
#include "chat.h"
#include "config.h"
@ -33,7 +34,8 @@ public:
gui::IGUIElement* parent,
s32 id,
ChatBackend* backend,
Client* client);
Client* client,
IMenuManager* menumgr);
virtual ~GUIChatConsole();
// Open the console (height = desired fraction of screen size)
@ -51,11 +53,16 @@ public:
void closeConsole();
// Close the console immediately, without animation.
void closeConsoleAtOnce();
// Set whether to close the console after the user presses enter.
void setCloseOnEnter(bool close) { m_close_on_enter = close; }
// Return the desired height (fraction of screen size)
// Zero if the console is closed or getting closed
f32 getDesiredHeight() const;
// Replace actual line when adding the actual to the history (if there is any)
void replaceAndAddToHistory(std::wstring line);
// Change how the cursor looks
void setCursor(
bool visible,
@ -81,11 +88,9 @@ private:
void drawPrompt();
private:
// pointer to the chat backend
ChatBackend* m_chat_backend;
// pointer to the client
Client* m_client;
IMenuManager* m_menumgr;
// current screen size
v2u32 m_screensize;
@ -95,6 +100,8 @@ private:
// should the console be opened or closed?
bool m_open;
// should it close after you press enter?
bool m_close_on_enter;
// current console height [pixels]
s32 m_height;
// desired height [pixels]

View File

@ -47,9 +47,9 @@ extern gui::IGUIStaticText *guiroot;
class MainMenuManager : public IMenuManager
{
public:
virtual void createdMenu(GUIModalMenu *menu)
virtual void createdMenu(gui::IGUIElement *menu)
{
for(std::list<GUIModalMenu*>::iterator
for(std::list<gui::IGUIElement*>::iterator
i = m_stack.begin();
i != m_stack.end(); ++i)
{
@ -61,13 +61,13 @@ public:
m_stack.push_back(menu);
}
virtual void deletingMenu(GUIModalMenu *menu)
virtual void deletingMenu(gui::IGUIElement *menu)
{
// Remove all entries if there are duplicates
bool removed_entry;
do{
removed_entry = false;
for(std::list<GUIModalMenu*>::iterator
for(std::list<gui::IGUIElement*>::iterator
i = m_stack.begin();
i != m_stack.end(); ++i)
{
@ -91,10 +91,10 @@ public:
// Returns true to prevent further processing
virtual bool preprocessEvent(const SEvent& event)
{
if(!m_stack.empty())
return m_stack.back()->preprocessEvent(event);
else
if (m_stack.empty())
return false;
GUIModalMenu *mm = dynamic_cast<GUIModalMenu*>(m_stack.back());
return mm && mm->preprocessEvent(event);
}
u32 menuCount()
@ -104,16 +104,17 @@ public:
bool pausesGame()
{
for(std::list<GUIModalMenu*>::iterator
for(std::list<gui::IGUIElement*>::iterator
i = m_stack.begin(); i != m_stack.end(); ++i)
{
if((*i)->pausesGame())
GUIModalMenu *mm = dynamic_cast<GUIModalMenu*>(*i);
if (mm && mm->pausesGame())
return true;
}
return false;
}
std::list<GUIModalMenu*> m_stack;
std::list<gui::IGUIElement*> m_stack;
};
extern MainMenuManager g_menumgr;

View File

@ -399,8 +399,21 @@ void MapgenValleys::calculateNoise()
//mapgen_profiler->avg("noisemaps", tcn.stop() / 1000.f);
float heat_offset = 0.f;
float humidity_scale = 1.f;
// Altitude chill tends to reduce the average heat.
if (use_altitude_chill)
heat_offset = 5.f;
// River humidity tends to increase the humidity range.
if (humid_rivers) {
humidity_scale = 0.8f;
}
for (s32 index = 0; index < csize.X * csize.Z; index++) {
noise_heat->result[index] += noise_heat_blend->result[index];
noise_heat->result[index] += noise_heat_blend->result[index] + heat_offset;
noise_humidity->result[index] *= humidity_scale;
noise_humidity->result[index] += noise_humidity_blend->result[index];
}
@ -481,9 +494,10 @@ float MapgenValleys::terrainLevelFromNoise(TerrainNoise *tn)
}
// base - depth : height of the bottom of the river
// water_level - 6 : don't make rivers below 6 nodes under the surface
// water_level - 3 : don't make rivers below 3 nodes under the surface
// We use three because that's as low as the swamp biomes go.
// There is no logical equivalent to this using rangelim.
mount = MYMIN(MYMAX(base - depth, (float) (water_level - 6)), mount);
mount = MYMIN(MYMAX(base - depth, (float)(water_level - 3)), mount);
// Slope has no influence on rivers.
*tn->slope = 0.f;
@ -503,7 +517,7 @@ float MapgenValleys::adjustedTerrainLevelFromNoise(TerrainNoise *tn)
for (s16 y = y_start; y <= y_start + 1000; y++) {
float fill = NoisePerlin3D(&noise_inter_valley_fill->np, tn->x, y, tn->z, seed);
if (fill * *tn->slope <= y - mount) {
if (fill * *tn->slope < y - mount) {
mount = MYMAX(y - 1, mount);
break;
}
@ -522,7 +536,7 @@ int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
s16 level_at_point = terrainLevelAtPoint(p.X, p.Y);
if (level_at_point <= water_level ||
level_at_point > water_level + 16)
level_at_point > water_level + 32)
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
else
return level_at_point;
@ -552,6 +566,15 @@ float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z)
int MapgenValleys::generateTerrain()
{
// Raising this reduces the rate of evaporation.
static const float evaporation = 300.f;
// from the lua
static const float humidity_dropoff = 4.f;
// constant to convert altitude chill (compatible with lua) to heat
static const float alt_to_heat = 20.f;
// humidity reduction by altitude
static const float alt_to_humid = 10.f;
MapNode n_air(CONTENT_AIR);
MapNode n_river_water(c_river_water_source);
MapNode n_sand(c_sand);
@ -564,42 +587,56 @@ int MapgenValleys::generateTerrain()
for (s16 z = node_min.Z; z <= node_max.Z; z++)
for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
s16 river_y = floor(noise_rivers->result[index_2d]);
s16 surface_y = floor(noise_terrain_height->result[index_2d]);
float river_y = noise_rivers->result[index_2d];
float surface_y = noise_terrain_height->result[index_2d];
float slope = noise_inter_valley_slope->result[index_2d];
float t_heat = noise_heat->result[index_2d];
heightmap[index_2d] = surface_y;
heightmap[index_2d] = -MAX_MAP_GENERATION_LIMIT;
if (surface_y > surface_max_y)
surface_max_y = surface_y;
surface_max_y = ceil(surface_y);
if (humid_rivers) {
// Derive heat from (base) altitude. This will be most correct
// at rivers, since other surface heights may vary below.
if (use_altitude_chill && (surface_y > 0.f || river_y > 0.f))
t_heat -= alt_to_heat * MYMAX(surface_y, river_y) / altitude_chill;
// If humidity is low or heat is high, lower the water table.
float delta = noise_humidity->result[index_2d] - 50.f;
if (delta < 0.f) {
float t_evap = (t_heat - 32.f) / evaporation;
river_y += delta * MYMAX(t_evap, 0.08f);
}
}
u32 index_3d = (z - node_min.Z) * zstride + (x - node_min.X);
u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
// Mapgens concern themselves with stone and water.
for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
float fill = 0.f;
fill = noise_inter_valley_fill->result[index_3d];
if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
bool river = (river_y > surface_y);
float fill = noise_inter_valley_fill->result[index_3d];
float surface_delta = (float)y - surface_y;
bool river = y + 1 < river_y;
if (river && y == surface_y) {
if (fabs(surface_delta) <= 0.5f && y > water_level && river) {
// river bottom
vm->m_data[index_data] = n_sand;
} else if (river && y <= surface_y) {
} else if (slope * fill > surface_delta) {
// ground
vm->m_data[index_data] = n_stone;
} else if (river && y < river_y) {
// river
vm->m_data[index_data] = n_river_water;
} else if ((!river) && myround(fill * slope) >= y - surface_y) {
// ground
vm->m_data[index_data] = n_stone;
heightmap[index_2d] = surface_max_y = y;
if (y > heightmap[index_2d])
heightmap[index_2d] = y;
if (y > surface_max_y)
surface_max_y = y;
} else if (y <= water_level) {
// sea
vm->m_data[index_data] = n_water;
} else if (river) {
// river
vm->m_data[index_data] = n_river_water;
} else {
vm->m_data[index_data] = n_air;
}
@ -609,18 +646,51 @@ int MapgenValleys::generateTerrain()
index_3d += ystride;
}
// Although the original valleys adjusts humidity by distance
// from seawater, this causes problems with the default biomes.
// Adjust only by freshwater proximity.
const float humidity_offset = 0.8f; // derived by testing
if (humid_rivers)
noise_humidity->result[index_2d] *= (1 + pow(0.5f, MYMAX((surface_max_y
- noise_rivers->result[index_2d]) / 3.f, 0.f))) * humidity_offset;
// This happens if we're generating a chunk that doesn't
// contain the terrain surface, in which case, we need
// to set heightmap to a value outside of the chunk,
// to avoid confusing lua mods that use heightmap.
if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT) {
s16 surface_y_int = myround(surface_y);
if (surface_y_int > node_max.Y + 1 || surface_y_int < node_min.Y - 1) {
// If surface_y is outside the chunk, it's good enough.
heightmap[index_2d] = surface_y_int;
} else {
// If the ground is outside of this chunk, but surface_y
// is within the chunk, give a value outside.
heightmap[index_2d] = node_min.Y - 2;
}
}
// Assign the heat adjusted by altitude.
if (use_altitude_chill && surface_max_y > 0)
noise_heat->result[index_2d] *=
pow(0.5f, (surface_max_y - altitude_chill / 3.f) / altitude_chill);
if (humid_rivers) {
// Use base ground (water table) in a riverbed, to
// avoid an unnatural rise in humidity.
float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
float humid = noise_humidity->result[index_2d];
float water_depth = (t_alt - river_y) / humidity_dropoff;
humid *= 1.f + pow(0.5f, MYMAX(water_depth, 1.f));
// Reduce humidity with altitude (ignoring riverbeds).
// This is similar to the lua version's seawater adjustment,
// but doesn't increase the base humidity, which causes
// problems with the default biomes.
if (t_alt > 0.f)
humid -= alt_to_humid * t_alt / altitude_chill;
noise_humidity->result[index_2d] = humid;
}
// Assign the heat adjusted by any changed altitudes.
// The altitude will change about half the time.
if (use_altitude_chill) {
// ground height ignoring riverbeds
float t_alt = MYMAX(noise_rivers->result[index_2d], (float)heightmap[index_2d]);
if (humid_rivers && heightmap[index_2d] == (s16)myround(surface_y))
// The altitude hasn't changed. Use the first result.
noise_heat->result[index_2d] = t_heat;
else if (t_alt > 0.f)
noise_heat->result[index_2d] -= alt_to_heat * t_alt / altitude_chill;
}
}
return surface_max_y;
@ -645,7 +715,7 @@ MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
// generated mapchunk or if not, a node of overgenerated base terrain.
content_t c_above = vm->m_data[vi + em.X].getContent();
bool air_above = c_above == CONTENT_AIR;
bool water_above = (c_above == c_water_source);
bool water_above = (c_above == c_water_source || c_above == c_river_water_source);
// If there is air or water above enable top/filler placement, otherwise force
// nplaced to stone level by setting a number exceeding any possible filler depth.
@ -714,7 +784,7 @@ MgStoneType MapgenValleys::generateBiomes(float *heat_map, float *humidity_map)
water_above = true;
} else if (c == c_river_water_source) {
vm->m_data[vi] = MapNode(biome->c_river_water);
nplaced = U16_MAX; // Sand was already placed under rivers.
nplaced = depth_top; // Enable filler placement for next surface
air_above = false;
water_above = true;
} else if (c == CONTENT_AIR) {

View File

@ -304,13 +304,16 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p)
s16 height = (deco_height_max > 0) ?
pr->range(deco_height, deco_height_max) : deco_height;
bool force_placement = (flags & DECO_FORCE_PLACEMENT);
v3s16 em = vm->m_area.getExtent();
u32 vi = vm->m_area.index(p);
for (int i = 0; i < height; i++) {
vm->m_area.add_y(em, vi, 1);
content_t c = vm->m_data[vi].getContent();
if (c != CONTENT_AIR && c != CONTENT_IGNORE)
if (c != CONTENT_AIR && c != CONTENT_IGNORE &&
!force_placement)
break;
vm->m_data[vi] = MapNode(c_place);

View File

@ -31,8 +31,8 @@ class IMenuManager
{
public:
// A GUIModalMenu calls these when this class is passed as a parameter
virtual void createdMenu(GUIModalMenu *menu) = 0;
virtual void deletingMenu(GUIModalMenu *menu) = 0;
virtual void createdMenu(gui::IGUIElement *menu) = 0;
virtual void deletingMenu(gui::IGUIElement *menu) = 0;
};
/*

View File

@ -853,7 +853,7 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
assert(f->liquid_type == LIQUID_SOURCE);
if (opaque_water)
f->alpha = 255;
f->solidness = 0;
f->solidness = 1;
is_liquid = true;
break;
case NDT_FLOWINGLIQUID:

View File

@ -116,7 +116,6 @@ void ScriptApiSecurity::initializeSecurity()
"upvaluejoin",
"sethook",
"debug",
"getupvalue",
"setlocal",
};
static const char *package_whitelist[] = {

View File

@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_http.h"
#include "httpfetch.h"
#include "settings.h"
#include "debug.h"
#include "log.h"
#include <algorithm>
@ -130,11 +131,27 @@ int ModApiHttp::l_request_http_api(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
// We have to make sure that this function is being called directly by
// a mod, otherwise a malicious mod could override this function and
// steal its return value.
lua_Debug info;
// Make sure there's only one item below this function on the stack...
if (lua_getstack(L, 2, &info)) {
return 0;
}
FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
// ...and that that item is the main file scope.
if (strcmp(info.what, "main") != 0) {
return 0;
}
// Mod must be listed in secure.http_mods or secure.trusted_mods
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
if (!lua_isstring(L, -1)) {
lua_pushnil(L);
return 1;
return 0;
}
const char *mod_name = lua_tostring(L, -1);

View File

@ -75,9 +75,10 @@ int ModApiUtil::l_get_us_time(lua_State *L)
}
#define CHECK_SECURE_SETTING(L, name) \
if (name.compare(0, 7, "secure.") == 0) {\
lua_pushliteral(L, "Attempt to set secure setting.");\
lua_error(L);\
if (ScriptApiSecurity::isSecure(L) && \
name.compare(0, 7, "secure.") == 0) { \
lua_pushliteral(L, "Attempt to set secure setting."); \
lua_error(L); \
}
// setting_set(name, value)

View File

@ -146,6 +146,7 @@ void TerminalChatConsole::typeChatMessage(const std::wstring &msg)
void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
{
ChatPrompt &prompt = m_chat_backend.getPrompt();
// Helpful if you want to collect key codes that aren't documented
/*if (ch != ERR) {
m_chat_backend.addMessage(L"",
@ -177,20 +178,20 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case KEY_ENTER:
case '\r':
case '\n': {
std::wstring text = m_chat_backend.getPrompt().submit();
typeChatMessage(text);
prompt.addToHistory(prompt.getLine());
typeChatMessage(prompt.replace(L""));
break;
}
case KEY_UP:
m_chat_backend.getPrompt().historyPrev();
prompt.historyPrev();
break;
case KEY_DOWN:
m_chat_backend.getPrompt().historyNext();
prompt.historyNext();
break;
case KEY_LEFT:
// Left pressed
// move character to the left
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_LEFT,
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
@ -198,7 +199,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case 545:
// Ctrl-Left pressed
// move word to the left
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_LEFT,
ChatPrompt::CURSOROP_SCOPE_WORD);
@ -206,7 +207,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case KEY_RIGHT:
// Right pressed
// move character to the right
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_RIGHT,
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
@ -214,7 +215,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case 560:
// Ctrl-Right pressed
// move word to the right
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_RIGHT,
ChatPrompt::CURSOROP_SCOPE_WORD);
@ -222,7 +223,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case KEY_HOME:
// Home pressed
// move to beginning of line
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_LEFT,
ChatPrompt::CURSOROP_SCOPE_LINE);
@ -230,7 +231,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case KEY_END:
// End pressed
// move to end of line
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_MOVE,
ChatPrompt::CURSOROP_DIR_RIGHT,
ChatPrompt::CURSOROP_SCOPE_LINE);
@ -240,7 +241,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case 127:
// Backspace pressed
// delete character to the left
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_LEFT,
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
@ -248,7 +249,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case KEY_DC:
// Delete pressed
// delete character to the right
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_RIGHT,
ChatPrompt::CURSOROP_SCOPE_CHARACTER);
@ -256,7 +257,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case 519:
// Ctrl-Delete pressed
// delete word to the right
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_RIGHT,
ChatPrompt::CURSOROP_SCOPE_WORD);
@ -264,7 +265,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case 21:
// Ctrl-U pressed
// kill line to left end
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_LEFT,
ChatPrompt::CURSOROP_SCOPE_LINE);
@ -272,7 +273,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case 11:
// Ctrl-K pressed
// kill line to right end
m_chat_backend.getPrompt().cursorOperation(
prompt.cursorOperation(
ChatPrompt::CURSOROP_DELETE,
ChatPrompt::CURSOROP_DIR_RIGHT,
ChatPrompt::CURSOROP_SCOPE_LINE);
@ -280,7 +281,7 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
case KEY_TAB:
// Tab pressed
// Nick completion
m_chat_backend.getPrompt().nickCompletion(m_nicks, false);
prompt.nickCompletion(m_nicks, false);
break;
default:
// Add character to the prompt,
@ -296,11 +297,11 @@ void TerminalChatConsole::handleInput(int ch, bool &complete_redraw_needed)
m_pending_utf8_bytes = "";
// hopefully only one char in the wstring...
for (size_t i = 0; i < w.size(); i++) {
m_chat_backend.getPrompt().input(w.c_str()[i]);
prompt.input(w.c_str()[i]);
}
}
} else if (IS_ASCII_PRINTABLE_CHAR(ch)) {
m_chat_backend.getPrompt().input(ch);
prompt.input(ch);
} else {
// Silently ignore characters we don't handle