]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/game.cpp
Sapier's fix for the RESEND RELIABLE problem (#4170)
[dragonfireclient.git] / src / game.cpp
index cae468d4cc72ecfbc3b67bddc33d99ab6113a049..def202fe558711cb6c19fa273dca64ca4038ad20 100644 (file)
@@ -55,6 +55,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "tool.h"
 #include "util/directiontables.h"
 #include "util/pointedthing.h"
+#include "irrlicht_changes/static_text.h"
 #include "version.h"
 #include "minimap.h"
 #include "mapblock_mesh.h"
@@ -176,19 +177,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);
 
@@ -286,6 +274,49 @@ inline bool isPointableNode(const MapNode &n,
               (liquids_pointable && features.isLiquid());
 }
 
+static inline void getNeighborConnectingFace(v3s16 p, INodeDefManager *nodedef,
+               ClientMap *map, MapNode n, u8 bitmask, u8 *neighbors)
+{
+       MapNode n2 = map->getNodeNoEx(p);
+       if (nodedef->nodeboxConnects(n, n2, bitmask))
+               *neighbors |= bitmask;
+}
+
+static inline u8 getNeighbors(v3s16 p, INodeDefManager *nodedef, ClientMap *map, MapNode n)
+{
+       u8 neighbors = 0;
+       const ContentFeatures &f = nodedef->get(n);
+       // locate possible neighboring nodes to connect to
+       if (f.drawtype == NDT_NODEBOX && f.node_box.type == NODEBOX_CONNECTED) {
+               v3s16 p2 = p;
+
+               p2.Y++;
+               getNeighborConnectingFace(p2, nodedef, map, n, 1, &neighbors);
+
+               p2 = p;
+               p2.Y--;
+               getNeighborConnectingFace(p2, nodedef, map, n, 2, &neighbors);
+
+               p2 = p;
+               p2.Z--;
+               getNeighborConnectingFace(p2, nodedef, map, n, 4, &neighbors);
+
+               p2 = p;
+               p2.X--;
+               getNeighborConnectingFace(p2, nodedef, map, n, 8, &neighbors);
+
+               p2 = p;
+               p2.Z++;
+               getNeighborConnectingFace(p2, nodedef, map, n, 16, &neighbors);
+
+               p2 = p;
+               p2.X++;
+               getNeighborConnectingFace(p2, nodedef, map, n, 32, &neighbors);
+       }
+
+       return neighbors;
+}
+
 /*
        Find what the player is pointing at
 */
@@ -299,12 +330,14 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
 
        std::vector<aabb3f> *selectionboxes = hud->getSelectionBoxes();
        selectionboxes->clear();
+       static const bool show_entity_selectionbox = g_settings->getBool("show_entity_selectionbox");
+
        selected_object = NULL;
 
        INodeDefManager *nodedef = client->getNodeDefManager();
        ClientMap &map = client->getEnv().getClientMap();
 
-       f32 mindistance = BS * 1001;
+       f32 min_distance = BS * 1001;
 
        // First try to find a pointed at active object
        if (look_for_object) {
@@ -312,7 +345,8 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
                                  camera_position, shootline);
 
                if (selected_object != NULL) {
-                       if (selected_object->doShowSelectionBox()) {
+                       if (show_entity_selectionbox &&
+                                       selected_object->doShowSelectionBox()) {
                                aabb3f *selection_box = selected_object->getSelectionBox();
                                // Box should exist because object was
                                // returned in the first place
@@ -324,7 +358,7 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
                                hud->setSelectionPos(pos, camera_offset);
                        }
 
-                       mindistance = (selected_object->getPosition() - camera_position).getLength();
+                       min_distance = (selected_object->getPosition() - camera_position).getLength();
 
                        result.type = POINTEDTHING_OBJECT;
                        result.object_id = selected_object->getId();
@@ -333,14 +367,13 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
 
        // That didn't work, try to find a pointed at node
 
-
        v3s16 pos_i = floatToInt(player_position, BS);
 
        /*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
                        <<std::endl;*/
 
        s16 a = d;
-       s16 ystart = pos_i.Y + 0 - (camera_direction.Y < 0 ? a : 1);
+       s16 ystart = pos_i.Y - (camera_direction.Y < 0 ? a : 1);
        s16 zstart = pos_i.Z - (camera_direction.Z < 0 ? a : 1);
        s16 xstart = pos_i.X - (camera_direction.X < 0 ? a : 1);
        s16 yend = pos_i.Y + 1 + (camera_direction.Y > 0 ? a : 1);
@@ -357,24 +390,28 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
        if (xend == 32767)
                xend = 32766;
 
-       for (s16 y = ystart; y <= yend; y++)
-               for (s16 z = zstart; z <= zend; z++)
+       v3s16 pointed_pos(0, 0, 0);
+
+       for (s16 y = ystart; y <= yend; y++) {
+               for (s16 z = zstart; z <= zend; z++) {
                        for (s16 x = xstart; x <= xend; x++) {
                                MapNode n;
                                bool is_valid_position;
+                               v3s16 p(x, y, z);
 
-                               n = map.getNodeNoEx(v3s16(x, y, z), &is_valid_position);
-                               if (!is_valid_position)
+                               n = map.getNodeNoEx(p, &is_valid_position);
+                               if (!is_valid_position) {
                                        continue;
-
-                               if (!isPointableNode(n, client, liquids_pointable))
+                               }
+                               if (!isPointableNode(n, client, liquids_pointable)) {
                                        continue;
+                               }
 
-                               std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
+                               std::vector<aabb3f> boxes;
+                               n.getSelectionBoxes(nodedef, &boxes, getNeighbors(p, nodedef, &map, n));
 
                                v3s16 np(x, y, z);
                                v3f npf = intToFloat(np, BS);
-
                                for (std::vector<aabb3f>::const_iterator
                                                i = boxes.begin();
                                                i != boxes.end(); ++i) {
@@ -382,62 +419,81 @@ PointedThing getPointedThing(Client *client, Hud *hud, const v3f &player_positio
                                        box.MinEdge += npf;
                                        box.MaxEdge += npf;
 
-                                       for (u16 j = 0; j < 6; j++) {
-                                               v3s16 facedir = g_6dirs[j];
-                                               aabb3f facebox = box;
-
-                                               f32 d = 0.001 * BS;
-
-                                               if (facedir.X > 0)
-                                                       facebox.MinEdge.X = facebox.MaxEdge.X - d;
-                                               else if (facedir.X < 0)
-                                                       facebox.MaxEdge.X = facebox.MinEdge.X + d;
-                                               else if (facedir.Y > 0)
-                                                       facebox.MinEdge.Y = facebox.MaxEdge.Y - d;
-                                               else if (facedir.Y < 0)
-                                                       facebox.MaxEdge.Y = facebox.MinEdge.Y + d;
-                                               else if (facedir.Z > 0)
-                                                       facebox.MinEdge.Z = facebox.MaxEdge.Z - d;
-                                               else if (facedir.Z < 0)
-                                                       facebox.MaxEdge.Z = facebox.MinEdge.Z + d;
-
-                                               v3f centerpoint = facebox.getCenter();
-                                               f32 distance = (centerpoint - camera_position).getLength();
-
-                                               if (distance >= mindistance)
-                                                       continue;
-
-                                               if (!facebox.intersectsWithLine(shootline))
-                                                       continue;
-
-                                               v3s16 np_above = np + facedir;
-
-                                               result.type = POINTEDTHING_NODE;
-                                               result.node_undersurface = np;
-                                               result.node_abovesurface = np_above;
-                                               mindistance = distance;
-
-                                               selectionboxes->clear();
-                                               for (std::vector<aabb3f>::const_iterator
-                                                               i2 = boxes.begin();
-                                                               i2 != boxes.end(); ++i2) {
-                                                       aabb3f box = *i2;
-                                                       box.MinEdge += v3f(-d, -d, -d);
-                                                       box.MaxEdge += v3f(d, d, d);
-                                                       selectionboxes->push_back(box);
-                                               }
-                                               hud->setSelectionPos(npf, camera_offset);
+                                       v3f centerpoint = box.getCenter();
+                                       f32 distance = (centerpoint - camera_position).getLength();
+                                       if (distance >= min_distance) {
+                                               continue;
+                                       }
+                                       if (!box.intersectsWithLine(shootline)) {
+                                               continue;
                                        }
+                                       result.type = POINTEDTHING_NODE;
+                                       min_distance = distance;
+                                       pointed_pos = np;
+                               }
+                       }
+               }
+       }
+
+       if (result.type == POINTEDTHING_NODE) {
+               f32 d = 0.001 * BS;
+               MapNode n = map.getNodeNoEx(pointed_pos);
+               v3f npf = intToFloat(pointed_pos, BS);
+               std::vector<aabb3f> boxes;
+               n.getSelectionBoxes(nodedef, &boxes, getNeighbors(pointed_pos, nodedef, &map, n));
+               f32 face_min_distance = 1000 * BS;
+               for (std::vector<aabb3f>::const_iterator
+                               i = boxes.begin();
+                               i != boxes.end(); ++i) {
+                       aabb3f box = *i;
+                       box.MinEdge += npf;
+                       box.MaxEdge += npf;
+                       for (u16 j = 0; j < 6; j++) {
+                               v3s16 facedir = g_6dirs[j];
+                               aabb3f facebox = box;
+                               if (facedir.X > 0) {
+                                       facebox.MinEdge.X = facebox.MaxEdge.X - d;
+                               } else if (facedir.X < 0) {
+                                       facebox.MaxEdge.X = facebox.MinEdge.X + d;
+                               } else if (facedir.Y > 0) {
+                                       facebox.MinEdge.Y = facebox.MaxEdge.Y - d;
+                               } else if (facedir.Y < 0) {
+                                       facebox.MaxEdge.Y = facebox.MinEdge.Y + d;
+                               } else if (facedir.Z > 0) {
+                                       facebox.MinEdge.Z = facebox.MaxEdge.Z - d;
+                               } else if (facedir.Z < 0) {
+                                       facebox.MaxEdge.Z = facebox.MinEdge.Z + d;
                                }
-                       } // for coords
+                               v3f centerpoint = facebox.getCenter();
+                               f32 distance = (centerpoint - camera_position).getLength();
+                               if (distance >= face_min_distance)
+                                       continue;
+                               if (!facebox.intersectsWithLine(shootline))
+                                       continue;
+                               result.node_abovesurface = pointed_pos + facedir;
+                               face_min_distance = distance;
+                       }
+               }
+               selectionboxes->clear();
+               for (std::vector<aabb3f>::const_iterator
+                               i = boxes.begin();
+                               i != boxes.end(); ++i) {
+                       aabb3f box = *i;
+                       box.MinEdge += v3f(-d, -d, -d);
+                       box.MaxEdge += v3f(d, d, d);
+                       selectionboxes->push_back(box);
+               }
+               hud->setSelectionPos(intToFloat(pointed_pos, BS), camera_offset);
+               result.node_undersurface = pointed_pos;
+       }
 
        // Update selection mesh light level and vertex colors
        if (selectionboxes->size() > 0) {
                v3f pf = hud->getSelectionPos();
-               v3s16 p = floatToInt(pf, BS);  
+               v3s16 p = floatToInt(pf, BS);
 
                // Get selection mesh light level
-               MapNode n = map.getNodeNoEx(p); 
+               MapNode n = map.getNodeNoEx(p);
                u16 node_light = getInteriorLight(n, -1, nodedef);
                u16 light_level = node_light;
 
@@ -482,7 +538,7 @@ void update_profiler_gui(gui::IGUIStaticText *guitext_profiler, FontEngine *fe,
                std::ostringstream os(std::ios_base::binary);
                g_profiler->printPage(os, show_profiler, show_profiler_max);
                std::wstring text = utf8_to_wide(os.str());
-               guitext_profiler->setText(text.c_str());
+               setStaticText(guitext_profiler, text.c_str());
                guitext_profiler->setVisible(true);
 
                s32 w = fe->getTextWidth(text.c_str());
@@ -907,15 +963,18 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
                services->setPixelShaderConstant("yawVec", (irr::f32 *)&minimap_yaw_vec, 3);
 
                // Uniform sampler layers
-               int layer0 = 0;
-               int layer1 = 1;
-               int layer2 = 2;
                // before 1.8 there isn't a "integer interface", only float
 #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
+               f32 layer0 = 0;
+               f32 layer1 = 1;
+               f32 layer2 = 2;
                services->setPixelShaderConstant("baseTexture" , (irr::f32 *)&layer0, 1);
                services->setPixelShaderConstant("normalTexture" , (irr::f32 *)&layer1, 1);
                services->setPixelShaderConstant("textureFlags" , (irr::f32 *)&layer2, 1);
 #else
+               s32 layer0 = 0;
+               s32 layer1 = 1;
+               s32 layer2 = 2;
                services->setPixelShaderConstant("baseTexture" , (irr::s32 *)&layer0, 1);
                services->setPixelShaderConstant("normalTexture" , (irr::s32 *)&layer1, 1);
                services->setPixelShaderConstant("textureFlags" , (irr::s32 *)&layer2, 1);
@@ -1076,27 +1135,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)
@@ -1203,7 +1241,11 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
 
        // Get new messages from error log buffer
        while (!chat_log_error_buf.empty()) {
-               chat_backend.addMessage(L"", utf8_to_wide(chat_log_error_buf.get()));
+               std::wstring error_message = utf8_to_wide(chat_log_error_buf.get());
+               if (!g_settings->getBool("disable_escape_sequences")) {
+                       error_message = L"\x1b(c@red)" + error_message + L"\x1b(c@white)";
+               }
+               chat_backend.addMessage(L"", error_message);
        }
 
        // Get new messages from client
@@ -1218,10 +1260,10 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
 
        // Display all messages in a static text element
        unsigned int recent_chat_count = chat_backend.getRecentBuffer().getLineCount();
-       std::wstring recent_chat       = chat_backend.getRecentChat();
+       EnrichedString recent_chat     = chat_backend.getRecentChat();
        unsigned int line_height       = g_fontengine->getLineHeight();
 
-       guitext_chat->setText(recent_chat.c_str());
+       setStaticText(guitext_chat, recent_chat);
 
        // Update gui element size and position
        s32 chat_y = 5 + line_height;
@@ -1230,7 +1272,7 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
                chat_y += line_height;
 
        // first pass to calculate height of text to be set
-       s32 width = std::min(g_fontengine->getTextWidth(recent_chat) + 10,
+       s32 width = std::min(g_fontengine->getTextWidth(recent_chat.c_str()) + 10,
                             porting::getWindowSize().X - 20);
        core::rect<s32> rect(10, chat_y, width, chat_y + porting::getWindowSize().Y);
        guitext_chat->setRelativePosition(rect);
@@ -1260,7 +1302,11 @@ static void updateChat(Client &client, f32 dtime, bool show_debug,
  */
 struct KeyCache {
 
-       KeyCache() { populate(); }
+       KeyCache()
+       {
+               handler = NULL;
+               populate();
+       }
 
        enum {
                // Player movement
@@ -1312,6 +1358,7 @@ struct KeyCache {
        void populate();
 
        KeyPress key[KEYMAP_INTERNAL_ENUM_COUNT];
+       InputHandler *handler;
 };
 
 void KeyCache::populate()
@@ -1362,6 +1409,19 @@ void KeyCache::populate()
        key[KEYMAP_ID_QUICKTUNE_DEC]  = getKeySetting("keymap_quicktune_dec");
 
        key[KEYMAP_ID_DEBUG_STACKS]   = getKeySetting("keymap_print_debug_stacks");
+
+       if (handler) {
+               // First clear all keys, then re-add the ones we listen for
+               handler->dontListenForKeys();
+               for (size_t i = 0; i < KEYMAP_INTERNAL_ENUM_COUNT; i++) {
+                       handler->listenForKey(key[i]);
+               }
+               handler->listenForKey(EscapeKey);
+               handler->listenForKey(CancelKey);
+               for (size_t i = 0; i < 10; i++) {
+                       handler->listenForKey(NumberKey[i]);
+               }
+       }
 }
 
 
@@ -1527,7 +1587,7 @@ class Game {
 
        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);
@@ -1587,6 +1647,10 @@ class Game {
        static void settingChangedCallback(const std::string &setting_name, void *data);
        void readSettings();
 
+#ifdef __ANDROID__
+       void handleAndroidChatInput();
+#endif
+
 private:
        InputHandler *input;
 
@@ -1673,8 +1737,8 @@ class Game {
 
 #ifdef __ANDROID__
        bool m_cache_hold_aux1;
+       bool m_android_chat_open;
 #endif
-
 };
 
 Game::Game() :
@@ -1788,6 +1852,9 @@ bool Game::startup(bool *kill,
        this->chat_backend        = chat_backend;
        this->simple_singleplayer_mode = simple_singleplayer_mode;
 
+       keycache.handler = input;
+       keycache.populate();
+
        driver              = device->getVideoDriver();
        smgr                = device->getSceneManager();
 
@@ -2084,6 +2151,7 @@ bool Game::createClient(const std::string &playername,
        camera = new Camera(smgr, *draw_control, gamedef);
        if (!camera || !camera->successfullyCreated(*error_message))
                return false;
+       client->setCamera(camera);
 
        /* Clouds
         */
@@ -2151,43 +2219,45 @@ bool Game::createClient(const std::string &playername,
 bool Game::initGui()
 {
        // First line of debug text
-       guitext = guienv->addStaticText(
+       guitext = addStaticText(guienv,
                        utf8_to_wide(PROJECT_NAME_C).c_str(),
                        core::rect<s32>(0, 0, 0, 0),
                        false, false, guiroot);
 
        // Second line of debug text
-       guitext2 = guienv->addStaticText(
+       guitext2 = addStaticText(guienv,
                        L"",
                        core::rect<s32>(0, 0, 0, 0),
                        false, false, guiroot);
 
        // At the middle of the screen
        // Object infos are shown in this
-       guitext_info = guienv->addStaticText(
+       guitext_info = addStaticText(guienv,
                        L"",
                        core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5) + v2s32(100, 200),
                        false, true, guiroot);
 
        // Status text (displays info when showing and hiding GUI stuff, etc.)
-       guitext_status = guienv->addStaticText(
+       guitext_status = addStaticText(guienv,
                        L"<Status>",
                        core::rect<s32>(0, 0, 0, 0),
                        false, false, guiroot);
        guitext_status->setVisible(false);
 
        // Chat text
-       guitext_chat = guienv->addStaticText(
+       guitext_chat = addStaticText(
+                       guienv,
                        L"",
                        core::rect<s32>(0, 0, 0, 0),
                        //false, false); // Disable word wrap as of now
                        false, true, guiroot);
+
        // Remove stale "recent" chat messages from previous connections
        chat_backend->clearRecentChat();
 
        // 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;
@@ -2195,7 +2265,7 @@ bool Game::initGui()
        }
 
        // Profiler text (size is updated when text is updated)
-       guitext_profiler = guienv->addStaticText(
+       guitext_profiler = addStaticText(guienv,
                        L"<Profiler>",
                        core::rect<s32>(0, 0, 0, 0),
                        false, false, guiroot);
@@ -2622,10 +2692,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"
@@ -2661,16 +2731,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])) {
@@ -2705,15 +2775,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;
@@ -2813,14 +2883,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)
@@ -3035,10 +3122,10 @@ void Game::toggleProfiler(float *statustext_time, u32 *profiler_current_page,
 
 void Game::increaseViewRange(float *statustext_time)
 {
-       s16 range = g_settings->getS16("viewing_range_nodes_min");
+       s16 range = g_settings->getS16("viewing_range");
        s16 range_new = range + 10;
-       g_settings->set("viewing_range_nodes_min", itos(range_new));
-       statustext = utf8_to_wide("Minimum viewing range changed to "
+       g_settings->set("viewing_range", itos(range_new));
+       statustext = utf8_to_wide("Viewing range changed to "
                        + itos(range_new));
        *statustext_time = 0;
 }
@@ -3046,14 +3133,14 @@ void Game::increaseViewRange(float *statustext_time)
 
 void Game::decreaseViewRange(float *statustext_time)
 {
-       s16 range = g_settings->getS16("viewing_range_nodes_min");
+       s16 range = g_settings->getS16("viewing_range");
        s16 range_new = range - 10;
 
-       if (range_new < 0)
-               range_new = range;
+       if (range_new < 20)
+               range_new = 20;
 
-       g_settings->set("viewing_range_nodes_min", itos(range_new));
-       statustext = utf8_to_wide("Minimum viewing range changed to "
+       g_settings->set("viewing_range", itos(range_new));
+       statustext = utf8_to_wide("Viewing range changed to "
                        + itos(range_new));
        *statustext_time = 0;
 }
@@ -3672,7 +3759,7 @@ void Game::handlePointingAtNode(GameRunData *runData,
        NodeMetadata *meta = map.getNodeMetadata(nodepos);
 
        if (meta) {
-               infotext = utf8_to_wide(meta->getString("infotext"));
+               infotext = unescape_enriched(utf8_to_wide(meta->getString("infotext")));
        } else {
                MapNode n = map.getNodeNoEx(nodepos);
 
@@ -3748,13 +3835,15 @@ void Game::handlePointingAtObject(GameRunData *runData,
                const v3f &player_position,
                bool show_debug)
 {
-       infotext = utf8_to_wide(runData->selected_object->infoText());
+       infotext = unescape_enriched(
+               utf8_to_wide(runData->selected_object->infoText()));
 
        if (show_debug) {
                if (infotext != L"") {
                        infotext += L"\n";
                }
-               infotext += utf8_to_wide(runData->selected_object->debugInfoText());
+               infotext += unescape_enriched(utf8_to_wide(
+                       runData->selected_object->debugInfoText()));
        }
 
        if (input->getLeftState()) {
@@ -3931,12 +4020,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats,
        if (draw_control->range_all) {
                runData->fog_range = 100000 * BS;
        } else {
-               runData->fog_range = draw_control->wanted_range * BS
-                               + 0.0 * MAP_BLOCKSIZE * BS;
-               runData->fog_range = MYMIN(
-                               runData->fog_range,
-                               (draw_control->farthest_drawn + 20) * BS);
-               runData->fog_range *= 0.9;
+               runData->fog_range = 0.9 * draw_control->wanted_range * BS;
        }
 
        /*
@@ -4219,12 +4303,12 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
                   << ", v_range = " << draw_control->wanted_range
                   << std::setprecision(3)
                   << ", RTT = " << client->getRTT();
-               guitext->setText(utf8_to_wide(os.str()).c_str());
+               setStaticText(guitext, utf8_to_wide(os.str()).c_str());
                guitext->setVisible(true);
        } else if (flags.show_hud || flags.show_chat) {
                std::ostringstream os(std::ios_base::binary);
                os << PROJECT_NAME_C " " << g_version_hash;
-               guitext->setText(utf8_to_wide(os.str()).c_str());
+               setStaticText(guitext, utf8_to_wide(os.str()).c_str());
                guitext->setVisible(true);
        } else {
                guitext->setVisible(false);
@@ -4261,7 +4345,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
                        }
                }
 
-               guitext2->setText(utf8_to_wide(os.str()).c_str());
+               setStaticText(guitext2, utf8_to_wide(os.str()).c_str());
                guitext2->setVisible(true);
 
                core::rect<s32> rect(
@@ -4273,7 +4357,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
                guitext2->setVisible(false);
        }
 
-       guitext_info->setText(infotext.c_str());
+       setStaticText(guitext_info, infotext.c_str());
        guitext_info->setVisible(flags.show_hud && g_menumgr.menuCount() == 0);
 
        float statustext_time_max = 1.5;
@@ -4287,7 +4371,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
                }
        }
 
-       guitext_status->setText(statustext.c_str());
+       setStaticText(guitext_status, statustext.c_str());
        guitext_status->setVisible(!statustext.empty());
 
        if (!statustext.empty()) {