]> git.lizzy.rs Git - minetest.git/blobdiff - src/game.cpp
Make sure none of the irrlicht member objects of GenericCAO are deleted prior deletio...
[minetest.git] / src / game.cpp
index 1ad06acb19f7102141dd7bb4edb06b80b40abc27..3acc93828817f1bc7629abb37abb80ee08b1e13a 100644 (file)
@@ -31,8 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "guiPasswordChange.h"
 #include "guiVolumeChange.h"
 #include "guiFormSpecMenu.h"
-#include "guiTextInputMenu.h"
-#include "guiDeathScreen.h"
 #include "tool.h"
 #include "guiChatConsole.h"
 #include "config.h"
@@ -69,6 +67,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <list>
 #include "util/directiontables.h"
 #include "util/pointedthing.h"
+#include "drawscene.h"
+#include "content_cao.h"
 
 /*
        Text input system
@@ -123,13 +123,16 @@ struct TextDestPlayerInventory : public TextDest
 struct LocalFormspecHandler : public TextDest
 {
        LocalFormspecHandler();
-       LocalFormspecHandler(std::string formname) {
+       LocalFormspecHandler(std::string formname) :
+               m_client(0)
+       {
                m_formname = formname;
        }
 
-       LocalFormspecHandler(std::string formname,Client *client) {
+       LocalFormspecHandler(std::string formname, Client *client) :
+               m_client(client)
+       {
                m_formname = formname;
-               m_client = client;
        }
 
        void gotText(std::wstring message) {
@@ -168,20 +171,37 @@ 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())) {
                                if (fields.find("f_text") != fields.end()) {
-                                       if (m_client != 0) {
-                                               m_client->typeChatMessage(narrow_to_wide(fields["f_text"]));
-                                       }
-                                       else {
-                                               errorstream << "LocalFormspecHandler::gotText received chat message but m_client is NULL" << std::endl;
-                                       }
+                                       m_client->typeChatMessage(narrow_to_wide(fields["f_text"]));
                                }
                                return;
                        }
                }
 
+               if (m_formname == "MT_DEATH_SCREEN") {
+                       assert(m_client != 0);
+                       if ((fields.find("btn_respawn") != fields.end())) {
+                               m_client->sendRespawn();
+                               return;
+                       }
+
+                       if (fields.find("quit") != fields.end()) {
+                               m_client->sendRespawn();
+                               return;
+                       }
+               }
+
+               // don't show error message for unhandled cursor keys
+               if ( (fields.find("key_up") != fields.end()) ||
+                       (fields.find("key_down") != fields.end()) ||
+                       (fields.find("key_left") != fields.end()) ||
+                       (fields.find("key_right") != fields.end())) {
+                       return;
+               }
+
                errorstream << "LocalFormspecHandler::gotText unhandled >" << m_formname << "< event" << std::endl;
                int i = 0;
                for (std::map<std::string,std::string>::iterator iter = fields.begin();
@@ -194,26 +214,6 @@ struct LocalFormspecHandler : public TextDest
        Client *m_client;
 };
 
-/* Respawn menu callback */
-
-class MainRespawnInitiator: public IRespawnInitiator
-{
-public:
-       MainRespawnInitiator(bool *active, Client *client):
-               m_active(active), m_client(client)
-       {
-               *m_active = true;
-       }
-       void respawn()
-       {
-               *m_active = false;
-               m_client->sendRespawn();
-       }
-private:
-       bool *m_active;
-       Client *m_client;
-};
-
 /* Form update callback */
 
 class NodeMetadataFormSource: public IFormSource
@@ -318,7 +318,7 @@ PointedThing getPointedThing(Client *client, v3f player_position,
 
        // 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<<")"
@@ -331,7 +331,7 @@ PointedThing getPointedThing(Client *client, v3f player_position,
        s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
        s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
        s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
-       
+
        // Prevent signed number overflow
        if(yend==32767)
                yend=32766;
@@ -419,59 +419,6 @@ PointedThing getPointedThing(Client *client, v3f player_position,
        return result;
 }
 
-/*
-       Draws a screen with a single text on it.
-       Text will be removed when the screen is drawn the next time.
-       Additionally, a progressbar can be drawn when percent is set between 0 and 100.
-*/
-/*gui::IGUIStaticText **/
-void draw_load_screen(const std::wstring &text, IrrlichtDevice* device,
-               gui::IGUIFont* font, float dtime=0 ,int percent=0, bool clouds=true)
-{
-       video::IVideoDriver* driver = device->getVideoDriver();
-       v2u32 screensize = driver->getScreenSize();
-       const wchar_t *loadingtext = text.c_str();
-       core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
-       core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
-       core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
-       core::rect<s32> textrect(center - textsize/2, center + textsize/2);
-
-       gui::IGUIStaticText *guitext = guienv->addStaticText(
-                       loadingtext, textrect, false, false);
-       guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
-
-       bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
-       if (cloud_menu_background)
-       {
-               g_menuclouds->step(dtime*3);
-               g_menuclouds->render();
-               driver->beginScene(true, true, video::SColor(255,140,186,250));
-               g_menucloudsmgr->drawAll();
-       }
-       else
-               driver->beginScene(true, true, video::SColor(255,0,0,0));
-       if (percent >= 0 && percent <= 100) // draw progress bar
-       {
-               core::vector2d<s32> barsize(256,32);
-               core::rect<s32> barrect(center-barsize/2, center+barsize/2);
-               driver->draw2DRectangle(video::SColor(255,255,255,255),barrect, NULL); // border
-               driver->draw2DRectangle(video::SColor(255,64,64,64), core::rect<s32> (
-                               barrect.UpperLeftCorner+1,
-                               barrect.LowerRightCorner-1), NULL); // black inside the bar
-               driver->draw2DRectangle(video::SColor(255,128,128,128), core::rect<s32> (
-                               barrect.UpperLeftCorner+1,
-                               core::vector2d<s32>(
-                                       barrect.LowerRightCorner.X-(barsize.X-1)+percent*(barsize.X-2)/100,
-                                       barrect.LowerRightCorner.Y-1)), NULL); // the actual progress
-       }
-       guienv->drawAll();
-       driver->endScene();
-       
-       guitext->remove();
-       
-       //return guitext;
-}
-
 /* Profiler display */
 
 void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
@@ -535,7 +482,7 @@ class ProfilerGraph
                while(m_log.size() > m_log_max_size)
                        m_log.erase(m_log.begin());
        }
-       
+
        void draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
                        gui::IGUIFont* font) const
        {
@@ -584,7 +531,7 @@ class ProfilerGraph
                s32 graphh = 50;
                s32 textx = x_left + m_log_max_size + 15;
                s32 textx2 = textx + 200 - 15;
-               
+
                // Draw background
                /*{
                        u32 num_graphs = m_meta.size();
@@ -593,7 +540,7 @@ class ProfilerGraph
                        video::SColor bgcolor(120,0,0,0);
                        driver->draw2DRectangle(bgcolor, rect, NULL);
                }*/
-               
+
                s32 meta_i = 0;
                for(std::map<std::string, Meta>::const_iterator i = m_meta.begin();
                                i != m_meta.end(); i++){
@@ -679,7 +626,7 @@ class NodeDugEvent: public MtEvent
 public:
        v3s16 p;
        MapNode n;
-       
+
        NodeDugEvent(v3s16 p, MapNode n):
                p(p),
                n(n)
@@ -852,7 +799,7 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
                u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
                float daynight_ratio_f = (float)daynight_ratio / 1000.0;
                services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
-               
+
                u32 animation_timer = porting::getTimeMs() % 100000;
                float animation_timer_f = (float)animation_timer / 100000.0;
                services->setPixelShaderConstant("animationTimer", &animation_timer_f, 1);
@@ -977,37 +924,71 @@ bool nodePlacementPrediction(Client &client,
        return false;
 }
 
-static void show_chat_menu(FormspecFormSource* current_formspec,
-               TextDest* current_textdest, IWritableTextureSource* tsrc,
-               IrrlichtDevice * device, Client* client, std::string text)
+static inline void create_formspec_menu(GUIFormSpecMenu** cur_formspec,
+               InventoryManager *invmgr, IGameDef *gamedef,
+               IWritableTextureSource* tsrc, IrrlichtDevice * device,
+               IFormSource* fs_src, TextDest* txt_dest
+               ) {
+
+       if (*cur_formspec == 0) {
+               *cur_formspec = new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr,
+                               invmgr, gamedef, tsrc, fs_src, txt_dest, cur_formspec );
+               (*cur_formspec)->doPause = false;
+               (*cur_formspec)->drop();
+       }
+       else {
+               (*cur_formspec)->setFormSource(fs_src);
+               (*cur_formspec)->setTextDest(txt_dest);
+       }
+}
+
+static void show_chat_menu(GUIFormSpecMenu** cur_formspec,
+               InventoryManager *invmgr, IGameDef *gamedef,
+               IWritableTextureSource* tsrc, IrrlichtDevice * device,
+               Client* client, std::string text)
 {
        std::string formspec =
                "size[11,5.5,true]"
                "field[3,2.35;6,0.5;f_text;;" + text + "]"
-               "button_exit[4,3;3,0.5;btn_send;"  + wide_to_narrow(wstrgettext("Proceed")) + "]"
+               "button_exit[4,3;3,0.5;btn_send;" + wide_to_narrow(wstrgettext("Proceed")) + "]"
                ;
 
        /* Create menu */
        /* Note: FormspecFormSource and LocalFormspecHandler
         * are deleted by guiFormSpecMenu                     */
-       current_formspec = new FormspecFormSource(formspec,&current_formspec);
-       current_textdest = new LocalFormspecHandler("MT_CHAT_MENU",client);
-       GUIFormSpecMenu *menu =
-                       new GUIFormSpecMenu(device, guiroot, -1,
-                                       &g_menumgr,
-                                       NULL, NULL, tsrc);
-       menu->doPause = false;
-       menu->setFormSource(current_formspec);
-       menu->setTextDest(current_textdest);
-       menu->drop();
+       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);
 }
 
-/******************************************************************************/
-static void show_pause_menu(FormspecFormSource* current_formspec,
-               TextDest* current_textdest, IWritableTextureSource* tsrc,
-               IrrlichtDevice * device, bool singleplayermode)
+static void show_deathscreen(GUIFormSpecMenu** cur_formspec,
+               InventoryManager *invmgr, IGameDef *gamedef,
+               IWritableTextureSource* tsrc, IrrlichtDevice * device, Client* client)
 {
+       std::string formspec =
+               std::string("") +
+               "size[11,5.5,true]"
+               "bgcolor[#320000b4;true]"
+               "label[4.85,1.35;You died.]"
+               "button_exit[4,3;3,0.5;btn_respawn;" + gettext("Respawn") + "]"
+               ;
 
+       /* Create menu */
+       /* Note: FormspecFormSource and LocalFormspecHandler
+        * are deleted by guiFormSpecMenu                     */
+       FormspecFormSource* fs_src = new FormspecFormSource(formspec);
+       LocalFormspecHandler* txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
+
+       create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device,  fs_src, txt_dst);
+}
+
+/******************************************************************************/
+static void show_pause_menu(GUIFormSpecMenu** cur_formspec,
+               InventoryManager *invmgr, IGameDef *gamedef,
+               IWritableTextureSource* tsrc, IrrlichtDevice * device,
+               bool singleplayermode)
+{
        std::string control_text = wide_to_narrow(wstrgettext("Default Controls:\n"
                        "- WASD: move\n"
                        "- Space: jump/climb\n"
@@ -1033,7 +1014,7 @@ static void show_pause_menu(FormspecFormSource* current_formspec,
                                        << wide_to_narrow(wstrgettext("Change Password")) << "]";
                }
 
-       os              << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
+       os              << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
                                        << wide_to_narrow(wstrgettext("Sound Volume")) << "]";
        os              << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;"
                                        << wide_to_narrow(wstrgettext("Exit to Menu")) << "]";
@@ -1048,14 +1029,14 @@ static void show_pause_menu(FormspecFormSource* current_formspec,
        /* Create menu */
        /* Note: FormspecFormSource and LocalFormspecHandler  *
         * are deleted by guiFormSpecMenu                     */
-       current_formspec = new FormspecFormSource(os.str(),&current_formspec);
-       current_textdest = new LocalFormspecHandler("MT_PAUSE_MENU");
-       GUIFormSpecMenu *menu =
-               new GUIFormSpecMenu(device, guiroot, -1, &g_menumgr, NULL, NULL, tsrc);
-       menu->doPause = true;
-       menu->setFormSource(current_formspec);
-       menu->setTextDest(current_textdest);
-       menu->drop();
+       FormspecFormSource* fs_src = new FormspecFormSource(os.str());
+       LocalFormspecHandler* txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
+
+       create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device,  fs_src, txt_dst);
+
+       if (singleplayermode) {
+               (*cur_formspec)->doPause = true;
+       }
 }
 
 /******************************************************************************/
@@ -1067,39 +1048,35 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        const SubgameSpec &gamespec /* Used for local game */,
        bool simple_singleplayer_mode)
 {
-       FormspecFormSource* current_formspec = 0;
-       TextDest* current_textdest = 0;
+       GUIFormSpecMenu* current_formspec = 0;
        video::IVideoDriver* driver = device->getVideoDriver();
        scene::ISceneManager* smgr = device->getSceneManager();
-       
+
        // Calculate text height using the font
        u32 text_height = font->getDimension(L"Random test string").Height;
 
-       v2u32 last_screensize(0,0);
-       v2u32 screensize = driver->getScreenSize();
-       
        /*
                Draw "Loading" screen
        */
 
        {
                wchar_t* text = wgettext("Loading...");
-               draw_load_screen(text, device, font,0,0);
+               draw_load_screen(text, device, guienv, font, 0, 0);
                delete[] text;
        }
-       
+
        // Create texture source
        IWritableTextureSource *tsrc = createTextureSource(device);
-       
+
        // Create shader source
        IWritableShaderSource *shsrc = createShaderSource(device);
-       
+
        // These will be filled by data received from the server
        // Create item definition manager
        IWritableItemDefManager *itemdef = createItemDefManager();
        // Create node definition manager
        IWritableNodeDefManager *nodedef = createNodeDefManager();
-       
+
        // Sound fetcher (useful when testing)
        GameOnDemandSoundFetcher soundfetcher;
 
@@ -1131,7 +1108,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        // Sound maker
        SoundMaker soundmaker(sound, nodedef);
        soundmaker.registerReceiver(&eventmgr);
-       
+
        // Add chat log output for errors to be shown in chat
        LogOutputBuffer chat_log_error_buf(LMT_ERROR);
 
@@ -1144,7 +1121,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
 
        if(address == ""){
                wchar_t* text = wgettext("Creating server....");
-               draw_load_screen(text, device, font,0,25);
+               draw_load_screen(text, device, guienv, font, 0, 25);
                delete[] text;
                infostream<<"Creating server"<<std::endl;
 
@@ -1180,23 +1157,23 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        }
 
        do{ // Client scope (breakable do-while(0))
-       
+
        /*
                Create client
        */
 
        {
                wchar_t* text = wgettext("Creating client...");
-               draw_load_screen(text, device, font,0,50);
+               draw_load_screen(text, device, guienv, font, 0, 50);
                delete[] text;
        }
        infostream<<"Creating client"<<std::endl;
-       
+
        MapDrawControl draw_control;
-       
+
        {
                wchar_t* text = wgettext("Resolving address...");
-               draw_load_screen(text, device, font,0,75);
+               draw_load_screen(text, device, guienv, font, 0, 75);
                delete[] text;
        }
        Address connect_address(0,0,0,0, port);
@@ -1227,26 +1204,26 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                // Break out of client scope
                break;
        }
-       
+
        /*
                Create client
        */
        Client client(device, playername.c_str(), password, draw_control,
                tsrc, shsrc, itemdef, nodedef, sound, &eventmgr,
                connect_address.isIPv6());
-       
+
        // Client acts as our GameDef
        IGameDef *gamedef = &client;
 
        /*
                Attempt to connect to the server
        */
-       
+
        infostream<<"Connecting to server at ";
        connect_address.print(&infostream);
        infostream<<std::endl;
        client.connect(connect_address);
-       
+
        /*
                Wait for server to accept connection
        */
@@ -1273,7 +1250,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        client.step(dtime);
                        if(server != NULL)
                                server->step(dtime);
-                       
+
                        // End condition
                        if(client.getState() == LC_Init){
                                could_connect = true;
@@ -1291,14 +1268,14 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                infostream<<"Connect aborted [Escape]"<<std::endl;
                                break;
                        }
-                       
+
                        // Display status
                        {
                                wchar_t* text = wgettext("Connecting to server...");
-                               draw_load_screen(text, device, font, dtime, 100);
+                               draw_load_screen(text, device, guienv, font, dtime, 100);
                                delete[] text;
                        }
-                       
+
                        // On some computers framerate doesn't seem to be
                        // automatically limited
                        if (cloud_menu_background) {
@@ -1328,7 +1305,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        }
        catch(con::PeerNotFoundException &e)
        {}
-       
+
        /*
                Handle failure to connect
        */
@@ -1340,7 +1317,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                // Break out of client scope
                break;
        }
-       
+
        /*
                Wait until content has been received
        */
@@ -1367,7 +1344,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        client.step(dtime);
                        if(server != NULL)
                                server->step(dtime);
-                       
+
                        // End condition
                        if(client.mediaReceived() &&
                                        client.itemdefReceived() &&
@@ -1392,31 +1369,46 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                infostream<<"Connect aborted [Escape]"<<std::endl;
                                break;
                        }
-                       
+
                        // Display status
                        int progress=0;
                        if (!client.itemdefReceived())
                        {
                                wchar_t* text = wgettext("Item definitions...");
                                progress = 0;
-                               draw_load_screen(text, device, font, dtime, progress);
+                               draw_load_screen(text, device, guienv, font, dtime, progress);
                                delete[] text;
                        }
                        else if (!client.nodedefReceived())
                        {
                                wchar_t* text = wgettext("Node definitions...");
                                progress = 25;
-                               draw_load_screen(text, device, font, dtime, progress);
+                               draw_load_screen(text, device, guienv, font, dtime, progress);
                                delete[] text;
                        }
                        else
                        {
-                               wchar_t* text = wgettext("Media...");
+
+                               std::stringstream message;
+                               message.precision(3);
+                               message << gettext("Media...");
+
+                               if ( ( USE_CURL == 0) ||
+                                               (!g_settings->getBool("enable_remote_media_server"))) {
+                                       float cur = client.getCurRate();
+                                       std::string cur_unit = gettext(" KB/s");
+
+                                       if (cur > 900) {
+                                               cur /= 1024.0;
+                                               cur_unit = gettext(" MB/s");
+                                       }
+                                       message << " ( " << cur << cur_unit << " )";
+                               }
                                progress = 50+client.mediaReceiveProgress()*50+0.5;
-                               draw_load_screen(text, device, font, dtime, progress);
-                               delete[] text;
+                               draw_load_screen(narrow_to_wide(message.str().c_str()), device,
+                                               guienv, font, dtime, progress);
                        }
-                       
+
                        // On some computers framerate doesn't seem to be
                        // automatically limited
                        if (cloud_menu_background) {
@@ -1470,12 +1462,10 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        f32 camera_yaw = 0; // "right/left"
        f32 camera_pitch = 0; // "up/down"
 
-       int current_camera_mode = CAMERA_MODE_FIRST; // start in first-person view
-
        /*
                Clouds
        */
-       
+
        Clouds *clouds = NULL;
        if(g_settings->getBool("enable_clouds"))
        {
@@ -1487,10 +1477,10 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        */
 
        Sky *sky = NULL;
-       sky = new Sky(smgr->getRootSceneNode(), smgr, -1, client.getEnv().getLocalPlayer());
+       sky = new Sky(smgr->getRootSceneNode(), smgr, -1);
 
        scene::ISceneNode* skybox = NULL;
-       
+
        /*
                A copy of the local inventory
        */
@@ -1513,12 +1503,12 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        // First line of debug text
        gui::IGUIStaticText *guitext = guienv->addStaticText(
                        L"Minetest",
-                       core::rect<s32>(5, 5, 795, 5+text_height),
+                       core::rect<s32>(0, 0, 0, 0),
                        false, false);
        // Second line of debug text
        gui::IGUIStaticText *guitext2 = guienv->addStaticText(
                        L"",
-                       core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),
+                       core::rect<s32>(0, 0, 0, 0),
                        false, false);
        // At the middle of the screen
        // Object infos are shown in this
@@ -1526,17 +1516,17 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        L"",
                        core::rect<s32>(0,0,400,text_height*5+5) + v2s32(100,200),
                        false, true);
-       
+
        // Status text (displays info when showing and hiding GUI stuff, etc.)
        gui::IGUIStaticText *guitext_status = guienv->addStaticText(
                        L"<Status>",
                        core::rect<s32>(0,0,0,0),
                        false, false);
        guitext_status->setVisible(false);
-       
+
        std::wstring statustext;
        float statustext_time = 0;
-       
+
        // Chat text
        gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
                        L"",
@@ -1547,7 +1537,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        chat_backend.clearRecentChat();
        // Chat backend and console
        GUIChatConsole *gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(), -1, &chat_backend, &client);
-       
+
        // Profiler text (size is updated when text is updated)
        gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
                        L"<Profiler>",
@@ -1556,17 +1546,16 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        guitext_profiler->setBackgroundColor(video::SColor(120,0,0,0));
        guitext_profiler->setVisible(false);
        guitext_profiler->setWordWrap(true);
-       
+
        /*
                Some statistics are collected in these
        */
        u32 drawtime = 0;
        u32 beginscenetime = 0;
-       u32 scenetime = 0;
        u32 endscenetime = 0;
-       
+
        float recent_turn_speed = 0.0;
-       
+
        ProfilerGraph graph;
        // Initially clear the profiler
        Profiler::GraphValues dummyvalues;
@@ -1593,7 +1582,6 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
 
        bool invert_mouse = g_settings->getBool("invert_mouse");
 
-       bool respawn_menu_active = false;
        bool update_wielded_item_trigger = true;
 
        bool show_hud = true;
@@ -1635,15 +1623,13 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        LocalPlayer* player = client.getEnv().getLocalPlayer();
        player->hurt_tilt_timer = 0;
        player->hurt_tilt_strength = 0;
-       
+
        /*
                HUD object
        */
        Hud hud(driver, smgr, guienv, font, text_height,
                        gamedef, player, &local_inventory);
 
-       bool use_weather = g_settings->getBool("weather");
-
        core::stringw str = L"Minetest [";
        str += driver->getName();
        str += "]";
@@ -1657,6 +1643,8 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                if(device->run() == false || kill == true)
                        break;
 
+               v2u32 screensize = driver->getScreenSize();
+
                // Time of frame without fps limit
                float busytime;
                u32 busytime_u32;
@@ -1669,7 +1657,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                busytime_u32 = 0;
                        busytime = busytime_u32 / 1000.0;
                }
-               
+
                g_profiler->graphAdd("mainloop_other", busytime - (float)drawtime/1000.0f);
 
                // Necessary for device->getTimer()->getTime()
@@ -1684,7 +1672,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        g_settings->getFloat("pause_fps_max") :
                                        g_settings->getFloat("fps_max");
                        u32 frametime_min = 1000./fps_max;
-                       
+
                        if(busytime_u32 < frametime_min)
                        {
                                u32 sleeptime = frametime_min - busytime_u32;
@@ -1700,7 +1688,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        Time difference calculation
                */
                f32 dtime; // in seconds
-               
+
                u32 time = device->getTimer()->getTime();
                if(time > lasttime)
                        dtime = (time - lasttime) / 1000.0;
@@ -1717,7 +1705,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                if(object_hit_delay_timer >= 0)
                        object_hit_delay_timer -= dtime;
                time_from_last_punch += dtime;
-               
+
                g_profiler->add("Elapsed time", dtime);
                g_profiler->avg("FPS", 1./dtime);
 
@@ -1746,7 +1734,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                jitter1_max = 0.0;
                        }
                }
-               
+
                /*
                        Busytime average and jitter calculation
                */
@@ -1754,7 +1742,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                static f32 busytime_avg1 = 0.0;
                busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;
                f32 busytime_jitter1 = busytime - busytime_avg1;
-               
+
                static f32 busytime_jitter1_max_sample = 0.0;
                static f32 busytime_jitter1_min_sample = 0.0;
                {
@@ -1778,7 +1766,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                /*
                        Handle miscellaneous stuff
                */
-               
+
                if(client.accessDenied())
                {
                        error_message = L"Access denied. Reason: "
@@ -1821,17 +1809,8 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                /*
                        Random calculations
                */
-               last_screensize = screensize;
-               screensize = driver->getScreenSize();
-               v2s32 displaycenter(screensize.X/2,screensize.Y/2);
-               //bool screensize_changed = screensize != last_screensize;
-
-                       
-               // Update HUD values
-               hud.screensize    = screensize;
-               hud.displaycenter = displaycenter;
                hud.resizeHotbar();
-               
+
                // Hilight boxes collected during the loop and displayed
                std::vector<aabb3f> hilightboxes;
 
@@ -1863,7 +1842,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                /*
                        Direct handling of user input
                */
-               
+
                // Reset input if window not active or some menu is active
                if(device->isWindowActive() == false
                                || noMenuActive() == false
@@ -1900,35 +1879,30 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                {
                        infostream<<"the_game: "
                                        <<"Launching inventory"<<std::endl;
-                       
-                       GUIFormSpecMenu *menu =
-                               new GUIFormSpecMenu(device, guiroot, -1,
-                                       &g_menumgr,
-                                       &client, gamedef, tsrc);
+
+                       PlayerInventoryFormSource* fs_src = new PlayerInventoryFormSource(&client);
+                       TextDest* txt_dst = new TextDestPlayerInventory(&client);
+
+                       create_formspec_menu(&current_formspec, &client, gamedef, tsrc, device, fs_src, txt_dst);
 
                        InventoryLocation inventoryloc;
                        inventoryloc.setCurrentPlayer();
-
-                       PlayerInventoryFormSource *src = new PlayerInventoryFormSource(&client);
-                       assert(src);
-                       menu->doPause = false;
-                       menu->setFormSpec(src->getForm(), inventoryloc);
-                       menu->setFormSource(src);
-                       menu->setTextDest(new TextDestPlayerInventory(&client));
-                       menu->drop();
+                       current_formspec->setFormSpec(fs_src->getForm(), inventoryloc);
                }
                else if(input->wasKeyDown(EscapeKey))
                {
-                       show_pause_menu(current_formspec, current_textdest, tsrc, device,
+                       show_pause_menu(&current_formspec, &client, gamedef, tsrc, device,
                                        simple_singleplayer_mode);
                }
                else if(input->wasKeyDown(getKeySetting("keymap_chat")))
                {
-                       show_chat_menu(current_formspec, current_textdest, tsrc, device, &client,"");
+                       show_chat_menu(&current_formspec, &client, gamedef, tsrc, device,
+                                       &client,"");
                }
                else if(input->wasKeyDown(getKeySetting("keymap_cmd")))
                {
-                       show_chat_menu(current_formspec, current_textdest, tsrc, device, &client,"/");
+                       show_chat_menu(&current_formspec, &client, gamedef, tsrc, device,
+                                       &client,"/");
                }
                else if(input->wasKeyDown(getKeySetting("keymap_console")))
                {
@@ -2138,7 +2112,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        + itos(range_new));
                        statustext_time = 0;
                }
-               
+
                // Reset jump_timer
                if(!input->isKeyDown(getKeySetting("keymap_jump")) && reset_jump_timer)
                {
@@ -2185,7 +2159,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        new_playeritem = max_item;
                        }
                }
-               
+
                // Item selection
                for(u16 i=0; i<10; i++)
                {
@@ -2235,7 +2209,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        Mouse and camera control
                        NOTE: Do this before client.setPlayerControl() to not cause a camera lag of one frame
                */
-               
+
                float turn_amount = 0;
                if((device->isWindowActive() && noMenuActive()) || random_input)
                {
@@ -2251,12 +2225,13 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                first_loop_after_window_activation = false;
                        }
                        else{
-                               s32 dx = input->getMousePos().X - displaycenter.X;
-                               s32 dy = input->getMousePos().Y - displaycenter.Y;
-                               if(invert_mouse || player->camera_mode == CAMERA_MODE_THIRD_FRONT)
+                               s32 dx = input->getMousePos().X - (driver->getScreenSize().Width/2);
+                               s32 dy = input->getMousePos().Y - (driver->getScreenSize().Height/2);
+                               if(invert_mouse || camera.getCameraMode() == CAMERA_MODE_THIRD_FRONT) {
                                        dy = -dy;
+                               }
                                //infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
-                               
+
                                /*const float keyspeed = 500;
                                if(input->isKeyDown(irr::KEY_UP))
                                        dy -= dtime * keyspeed;
@@ -2266,17 +2241,18 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        dx -= dtime * keyspeed;
                                if(input->isKeyDown(irr::KEY_RIGHT))
                                        dx += dtime * keyspeed;*/
-                               
+
                                float d = g_settings->getFloat("mouse_sensitivity");
                                d = rangelim(d, 0.01, 100.0);
                                camera_yaw -= dx*d;
                                camera_pitch += dy*d;
                                if(camera_pitch < -89.5) camera_pitch = -89.5;
                                if(camera_pitch > 89.5) camera_pitch = 89.5;
-                               
+
                                turn_amount = v2f(dx, dy).getLength() * d;
                        }
-                       input->setMousePos(displaycenter.X, displaycenter.Y);
+                       input->setMousePos((driver->getScreenSize().Width/2),
+                                       (driver->getScreenSize().Height/2));
                }
                else{
                        // Mac OSX gets upset if this is set every frame
@@ -2356,16 +2332,13 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
 
                {
                        // Read client events
-                       for(;;)
-                       {
+                       for(;;) {
                                ClientEvent event = client.getClientEvent();
-                               if(event.type == CE_NONE)
-                               {
+                               if(event.type == CE_NONE) {
                                        break;
                                }
                                else if(event.type == CE_PLAYER_DAMAGE &&
-                                               client.getHP() != 0)
-                               {
+                                               client.getHP() != 0) {
                                        //u16 damage = event.player_damage.amount;
                                        //infostream<<"Player damage: "<<damage<<std::endl;
 
@@ -2379,74 +2352,37 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        MtEvent *e = new SimpleTriggerEvent("PlayerDamage");
                                        gamedef->event()->put(e);
                                }
-                               else if(event.type == CE_PLAYER_FORCE_MOVE)
-                               {
+                               else if(event.type == CE_PLAYER_FORCE_MOVE) {
                                        camera_yaw = event.player_force_move.yaw;
                                        camera_pitch = event.player_force_move.pitch;
                                }
-                               else if(event.type == CE_DEATHSCREEN)
-                               {
-                                       if(respawn_menu_active)
-                                               continue;
+                               else if(event.type == CE_DEATHSCREEN) {
+                                       show_deathscreen(&current_formspec, &client, gamedef, tsrc,
+                                                       device, &client);
 
-                                       /*bool set_camera_point_target =
-                                                       event.deathscreen.set_camera_point_target;
-                                       v3f camera_point_target;
-                                       camera_point_target.X = event.deathscreen.camera_point_target_x;
-                                       camera_point_target.Y = event.deathscreen.camera_point_target_y;
-                                       camera_point_target.Z = event.deathscreen.camera_point_target_z;*/
-                                       MainRespawnInitiator *respawner =
-                                                       new MainRespawnInitiator(
-                                                                       &respawn_menu_active, &client);
-                                       GUIDeathScreen *menu =
-                                                       new GUIDeathScreen(guienv, guiroot, -1,
-                                                               &g_menumgr, respawner);
-                                       menu->drop();
-                                       
                                        chat_backend.addMessage(L"", L"You died.");
 
                                        /* Handle visualization */
-
                                        damage_flash = 0;
 
                                        LocalPlayer* player = client.getEnv().getLocalPlayer();
                                        player->hurt_tilt_timer = 0;
                                        player->hurt_tilt_strength = 0;
 
-                                       /*LocalPlayer* player = client.getLocalPlayer();
-                                       player->setPosition(player->getPosition() + v3f(0,-BS,0));
-                                       camera.update(player, busytime, screensize);*/
                                }
-                               else if (event.type == CE_SHOW_FORMSPEC)
-                               {
-                                       if (current_formspec == 0)
-                                       {
-                                               /* Create menu */
-                                               /* Note: FormspecFormSource and TextDestPlayerInventory
-                                                * are deleted by guiFormSpecMenu                     */
-                                               current_formspec = new FormspecFormSource(*(event.show_formspec.formspec),&current_formspec);
-                                               current_textdest = new TextDestPlayerInventory(&client,*(event.show_formspec.formname));
-                                               GUIFormSpecMenu *menu =
-                                                               new GUIFormSpecMenu(device, guiroot, -1,
-                                                                               &g_menumgr,
-                                                                               &client, gamedef, tsrc);
-                                               menu->doPause = false;
-                                               menu->setFormSource(current_formspec);
-                                               menu->setTextDest(current_textdest);
-                                               menu->drop();
-                                       }
-                                       else
-                                       {
-                                               assert(current_textdest != 0);
-                                               /* update menu */
-                                               current_textdest->setFormName(*(event.show_formspec.formname));
-                                               current_formspec->setForm(*(event.show_formspec.formspec));
-                                       }
+                               else if (event.type == CE_SHOW_FORMSPEC) {
+                                       FormspecFormSource* fs_src =
+                                                       new FormspecFormSource(*(event.show_formspec.formspec));
+                                       TextDestPlayerInventory* txt_dst =
+                                                       new TextDestPlayerInventory(&client,*(event.show_formspec.formname));
+
+                                       create_formspec_menu(&current_formspec, &client, gamedef,
+                                                       tsrc, device, fs_src, txt_dst);
+
                                        delete(event.show_formspec.formspec);
                                        delete(event.show_formspec.formname);
                                }
-                               else if(event.type == CE_SPAWN_PARTICLE)
-                               {
+                               else if(event.type == CE_SPAWN_PARTICLE) {
                                        LocalPlayer* player = client.getEnv().getLocalPlayer();
                                        video::ITexture *texture =
                                                gamedef->tsrc()->getTexture(*(event.spawn_particle.texture));
@@ -2463,8 +2399,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                                 v2f(0.0, 0.0),
                                                 v2f(1.0, 1.0));
                                }
-                               else if(event.type == CE_ADD_PARTICLESPAWNER)
-                               {
+                               else if(event.type == CE_ADD_PARTICLESPAWNER) {
                                        LocalPlayer* player = client.getEnv().getLocalPlayer();
                                        video::ITexture *texture =
                                                gamedef->tsrc()->getTexture(*(event.add_particlespawner.texture));
@@ -2487,15 +2422,15 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                                 texture,
                                                 event.add_particlespawner.id);
                                }
-                               else if(event.type == CE_DELETE_PARTICLESPAWNER)
-                               {
+                               else if(event.type == CE_DELETE_PARTICLESPAWNER) {
                                        delete_particlespawner (event.delete_particlespawner.id);
                                }
-                               else if (event.type == CE_HUDADD)
-                               {
+                               else if (event.type == CE_HUDADD) {
                                        u32 id = event.hudadd.id;
-                                       size_t nhudelem = player->hud.size();
-                                       if (id > nhudelem || (id < nhudelem && player->hud[id])) {
+
+                                       HudElement *e = player->getHud(id);
+
+                                       if (e != NULL) {
                                                delete event.hudadd.pos;
                                                delete event.hudadd.name;
                                                delete event.hudadd.scale;
@@ -2503,10 +2438,11 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                                delete event.hudadd.align;
                                                delete event.hudadd.offset;
                                                delete event.hudadd.world_pos;
+                                               delete event.hudadd.size;
                                                continue;
                                        }
-                                       
-                                       HudElement *e = new HudElement;
+
+                                       e = new HudElement;
                                        e->type   = (HudElementType)event.hudadd.type;
                                        e->pos    = *event.hudadd.pos;
                                        e->name   = *event.hudadd.name;
@@ -2518,11 +2454,11 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        e->align  = *event.hudadd.align;
                                        e->offset = *event.hudadd.offset;
                                        e->world_pos = *event.hudadd.world_pos;
-                                       
-                                       if (id == nhudelem)
-                                               player->hud.push_back(e);
-                                       else
-                                               player->hud[id] = e;
+                                       e->size = *event.hudadd.size;
+
+                                       u32 new_id = player->addHud(e);
+                                       //if this isn't true our huds aren't consistent
+                                       assert(new_id == id);
 
                                        delete event.hudadd.pos;
                                        delete event.hudadd.name;
@@ -2531,26 +2467,26 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        delete event.hudadd.align;
                                        delete event.hudadd.offset;
                                        delete event.hudadd.world_pos;
+                                       delete event.hudadd.size;
                                }
-                               else if (event.type == CE_HUDRM)
-                               {
-                                       u32 id = event.hudrm.id;
-                                       if (id < player->hud.size() && player->hud[id]) {
-                                               delete player->hud[id];
-                                               player->hud[id] = NULL;
-                                       }
+                               else if (event.type == CE_HUDRM) {
+                                       HudElement* e = player->removeHud(event.hudrm.id);
+
+                                       if (e != NULL)
+                                               delete (e);
                                }
-                               else if (event.type == CE_HUDCHANGE)
-                               {
+                               else if (event.type == CE_HUDCHANGE) {
                                        u32 id = event.hudchange.id;
-                                       if (id >= player->hud.size() || !player->hud[id]) {
+                                       HudElement* e = player->getHud(id);
+                                       if (e == NULL)
+                                       {
                                                delete event.hudchange.v3fdata;
                                                delete event.hudchange.v2fdata;
                                                delete event.hudchange.sdata;
+                                               delete event.hudchange.v2s32data;
                                                continue;
                                        }
-                                               
-                                       HudElement* e = player->hud[id];
+
                                        switch (event.hudchange.stat) {
                                                case HUD_STAT_POS:
                                                        e->pos = *event.hudchange.v2fdata;
@@ -2582,25 +2518,28 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                                case HUD_STAT_WORLD_POS:
                                                        e->world_pos = *event.hudchange.v3fdata;
                                                        break;
+                                               case HUD_STAT_SIZE:
+                                                       e->size = *event.hudchange.v2s32data;
+                                                       break;
                                        }
-                                       
+
                                        delete event.hudchange.v3fdata;
                                        delete event.hudchange.v2fdata;
                                        delete event.hudchange.sdata;
+                                       delete event.hudchange.v2s32data;
                                }
-                               else if (event.type == CE_SET_SKY)
-                               {
+                               else if (event.type == CE_SET_SKY) {
                                        sky->setVisible(false);
                                        if(skybox){
-                                               skybox->drop();
+                                               skybox->remove();
                                                skybox = NULL;
                                        }
                                        // Handle according to type
-                                       if(*event.set_sky.type == "regular"){
+                                       if(*event.set_sky.type == "regular") {
                                                sky->setVisible(true);
                                        }
                                        else if(*event.set_sky.type == "skybox" &&
-                                                       event.set_sky.params->size() == 6){
+                                                       event.set_sky.params->size() == 6) {
                                                sky->setFallbackBgColor(*event.set_sky.bgcolor);
                                                skybox = smgr->addSkyBoxSceneNode(
                                                                tsrc->getTexture((*event.set_sky.params)[0]),
@@ -2622,15 +2561,14 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        delete event.set_sky.type;
                                        delete event.set_sky.params;
                                }
-                               else if (event.type == CE_OVERRIDE_DAY_NIGHT_RATIO)
-                               {
+                               else if (event.type == CE_OVERRIDE_DAY_NIGHT_RATIO) {
                                        bool enable = event.override_day_night_ratio.do_override;
                                        u32 value = event.override_day_night_ratio.ratio_f * 1000;
                                        client.getEnv().setDayNightRatioOverride(enable, value);
                                }
                        }
                }
-               
+
                //TimeTaker //timer2("//timer2");
 
                /*
@@ -2642,16 +2580,14 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                ItemStack playeritem;
                {
                        InventoryList *mlist = local_inventory.getList("main");
-                       if(mlist != NULL)
-                       {
+                       if((mlist != NULL) && (client.getPlayerItem() < mlist->getSize()))
                                playeritem = mlist->getItem(client.getPlayerItem());
-                       }
                }
                const ItemDefinition &playeritem_def =
                                playeritem.getDefinition(itemdef);
                ToolCapabilities playeritem_toolcap =
                                playeritem.getToolCapabilities(itemdef);
-               
+
                /*
                        Update camera
                */
@@ -2663,30 +2599,30 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                float tool_reload_ratio = time_from_last_punch / full_punch_interval;
 
                if(input->wasKeyDown(getKeySetting("keymap_camera_mode"))) {
+                       camera.toggleCameraMode();
+                       GenericCAO* playercao = player->getCAO();
 
-                       if (current_camera_mode == CAMERA_MODE_FIRST)
-                               current_camera_mode = CAMERA_MODE_THIRD;
-                       else if (current_camera_mode == CAMERA_MODE_THIRD)
-                               current_camera_mode = CAMERA_MODE_THIRD_FRONT;
-                       else
-                               current_camera_mode = CAMERA_MODE_FIRST;
-
+                       assert( playercao != NULL );
+                       if (camera.getCameraMode() > CAMERA_MODE_FIRST) {
+                               playercao->setVisible(true);
+                       }
+                       else {
+                               playercao->setVisible(false);
+                       }
                }
-               player->camera_mode = current_camera_mode;
                tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
-               camera.update(player, dtime, busytime, screensize, tool_reload_ratio,
-                               current_camera_mode, client.getEnv());
+               camera.update(player, dtime, busytime, tool_reload_ratio,
+                               client.getEnv());
                camera.step(dtime);
 
                v3f player_position = player->getPosition();
-               v3s16 pos_i = floatToInt(player_position, BS);
                v3f camera_position = camera.getPosition();
                v3f camera_direction = camera.getDirection();
                f32 camera_fov = camera.getFovMax();
                v3s16 camera_offset = camera.getOffset();
 
                bool camera_offset_changed = (camera_offset != old_camera_offset);
-               
+
                if(!disable_camera_update){
                        client.getEnv().getClientMap().updateCamera(camera_position,
                                camera_direction, camera_fov, camera_offset);
@@ -2697,7 +2633,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        clouds->updateCameraOffset(camera_offset);
                        }
                }
-               
+
                // Update sound listener
                sound->updateListener(camera.getCameraNode()->getPosition()+intToFloat(camera_offset, BS),
                                v3f(0,0,0), // velocity
@@ -2710,7 +2646,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                */
                {
                        soundmaker.step(dtime);
-                       
+
                        ClientMap &map = client.getEnv().getClientMap();
                        MapNode n = map.getNodeNoEx(player->getStandingNodePos());
                        soundmaker.m_player_step_sound = nodedef->get(n).sound_footstep;
@@ -2719,9 +2655,9 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                /*
                        Calculate what block is the crosshair pointing to
                */
-               
+
                //u32 t1 = device->getTimer()->getRealTime();
-               
+
                f32 d = playeritem_def.range; // max. distance
                f32 d_hand = itemdef->get("").range;
                if(d < 0 && d_hand >= 0)
@@ -2732,7 +2668,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                camera_position + camera_direction * BS * (d+1));
 
                // prevent player pointing anything in front-view
-               if (current_camera_mode == CAMERA_MODE_THIRD_FRONT)
+               if (camera.getCameraMode() == CAMERA_MODE_THIRD_FRONT)
                        shootline = core::line3d<f32>(0,0,0,0,0,0);
 
                ClientActiveObject *selected_object = NULL;
@@ -2815,7 +2751,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        /*
                                Check information text of node
                        */
-                       
+
                        ClientMap &map = client.getEnv().getClientMap();
                        NodeMetadata *meta = map.getNodeMetadata(nodepos);
                        if(meta){
@@ -2827,11 +2763,11 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        infotext += narrow_to_wide(nodedef->get(n).name);
                                }
                        }
-                       
+
                        /*
                                Handle digging
                        */
-                       
+
                        if(nodig_delay_timer <= 0.0 && input->getLeftState()
                                        && client.checkPrivilege("interact"))
                        {
@@ -2843,7 +2779,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        ldown_for_dig = true;
                                }
                                MapNode n = client.getEnv().getClientMap().getNode(nodepos);
-                               
+
                                // NOTE: Similar piece of code exists on the server side for
                                // cheat detection.
                                // Get digging parameters
@@ -2944,7 +2880,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        float mindelay = 0.15;
                                        if(nodig_delay_timer < mindelay)
                                                nodig_delay_timer = mindelay;
-                                       
+
                                        // Send event to trigger sound
                                        MtEvent *e = new NodeDugEvent(nodepos, wasnode);
                                        gamedef->event()->put(e);
@@ -2967,47 +2903,23 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        {
                                repeat_rightclick_timer = 0;
                                infostream<<"Ground right-clicked"<<std::endl;
-                               
-                               // Sign special case, at least until formspec is properly implemented.
-                               // Deprecated?
-                               if(meta && meta->getString("formspec") == "hack:sign_text_input"
-                                               && !random_input
-                                               && !input->isKeyDown(getKeySetting("keymap_sneak")))
-                               {
-                                       infostream<<"Launching metadata text input"<<std::endl;
-                                       
-                                       // Get a new text for it
-
-                                       TextDest *dest = new TextDestNodeMetadata(nodepos, &client);
 
-                                       std::wstring wtext = narrow_to_wide(meta->getString("text"));
-
-                                       (new GUITextInputMenu(guienv, guiroot, -1,
-                                                       &g_menumgr, dest,
-                                                       wtext))->drop();
-                               }
-                               // If metadata provides an inventory view, activate it
-                               else if(meta && meta->getString("formspec") != "" && !random_input
+                               if(meta && meta->getString("formspec") != "" && !random_input
                                                && !input->isKeyDown(getKeySetting("keymap_sneak")))
                                {
                                        infostream<<"Launching custom inventory view"<<std::endl;
 
                                        InventoryLocation inventoryloc;
                                        inventoryloc.setNodeMeta(nodepos);
-                                       
-                                       /* Create menu */
-
-                                       GUIFormSpecMenu *menu =
-                                               new GUIFormSpecMenu(device, guiroot, -1,
-                                                       &g_menumgr,
-                                                       &client, gamedef, tsrc);
-                                       menu->doPause = false;
-                                       menu->setFormSpec(meta->getString("formspec"),
-                                                       inventoryloc);
-                                       menu->setFormSource(new NodeMetadataFormSource(
-                                                       &client.getEnv().getClientMap(), nodepos));
-                                       menu->setTextDest(new TextDestNodeMetadata(nodepos, &client));
-                                       menu->drop();
+
+                                       NodeMetadataFormSource* fs_src = new NodeMetadataFormSource(
+                                                       &client.getEnv().getClientMap(), nodepos);
+                                       TextDest* txt_dst = new TextDestNodeMetadata(nodepos, &client);
+
+                                       create_formspec_menu(&current_formspec, &client, gamedef,
+                                                       tsrc, device, fs_src, txt_dst);
+
+                                       current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
                                }
                                // Otherwise report right click to server
                                else
@@ -3066,7 +2978,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        // Report direct punch
                                        v3f objpos = selected_object->getPosition();
                                        v3f dir = (objpos - player_position).normalize();
-                                       
+
                                        bool disable_send = selected_object->directReportPunch(
                                                        dir, &playeritem, time_from_last_punch);
                                        time_from_last_punch = 0;
@@ -3087,7 +2999,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                }
 
                pointed_old = pointed;
-               
+
                if(left_punch || input->getLeftClicked())
                {
                        camera.setDigging(0); // left click animation
@@ -3098,7 +3010,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
 
                input->resetLeftReleased();
                input->resetRightReleased();
-               
+
                /*
                        Calculate stuff for drawing
                */
@@ -3106,13 +3018,11 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                /*
                        Fog range
                */
-       
+
                if(draw_control.range_all)
                        fog_range = 100000*BS;
                else {
                        fog_range = draw_control.wanted_range*BS + 0.0*MAP_BLOCKSIZE*BS;
-                       if(use_weather)
-                               fog_range *= (1.5 - 1.4*(float)client.getEnv().getClientMap().getHumidity(pos_i)/100);
                        fog_range = MYMIN(fog_range, (draw_control.farthest_drawn+20)*BS);
                        fog_range *= 0.9;
                }
@@ -3135,7 +3045,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                        daynight_ratio, (int)(old_brightness*255.5), &sunlight_seen)
                                        / 255.0;
                }
-               
+
                time_of_day = client.getEnv().getTimeOfDayF();
                float maxsm = 0.05;
                if(fabs(time_of_day - time_of_day_smooth) > maxsm &&
@@ -3149,10 +3059,11 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                else
                        time_of_day_smooth = time_of_day_smooth * (1.0-todsm)
                                        + time_of_day * todsm;
-                       
+
                sky->update(time_of_day_smooth, time_brightness, direct_brightness,
-                               sunlight_seen);
-               
+                               sunlight_seen,camera.getCameraMode(), player->getYaw(),
+                               player->getPitch());
+
                video::SColor bgcolor = sky->getBgColor();
                video::SColor skycolor = sky->getSkyColor();
 
@@ -3169,18 +3080,18 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                clouds->setVisible(false);
                        }
                }
-               
+
                /*
                        Update particles
                */
 
                allparticles_step(dtime);
                allparticlespawners_step(dtime, client.getEnv());
-               
+
                /*
                        Fog
                */
-               
+
                if(g_settings->getBool("enable_fog") && !force_fog_off)
                {
                        driver->setFog(
@@ -3211,7 +3122,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                */
 
                //TimeTaker guiupdatetimer("Gui updating");
-               
+
                if(show_debug)
                {
                        static float drawtime_avg = 0;
@@ -3253,7 +3164,18 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                {
                        guitext->setVisible(false);
                }
-               
+
+               if (guitext->isVisible())
+               {
+                       core::rect<s32> rect(
+                               5,
+                               5,
+                               screensize.X,
+                               5 + text_height
+                       );
+                       guitext->setRelativePosition(rect);
+               }
+
                if(show_debug)
                {
                        std::ostringstream os(std::ios_base::binary);
@@ -3262,18 +3184,24 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                <<", "<<(player_position.Y/BS)
                                <<", "<<(player_position.Z/BS)
                                <<") (yaw="<<(wrapDegrees_0_360(camera_yaw))
-                               <<") (t="<<client.getEnv().getClientMap().getHeat(pos_i)
-                               <<"C, h="<<client.getEnv().getClientMap().getHumidity(pos_i)
-                               <<"%) (seed = "<<((u64)client.getMapSeed())
+                               <<") (seed = "<<((u64)client.getMapSeed())
                                <<")";
                        guitext2->setText(narrow_to_wide(os.str()).c_str());
                        guitext2->setVisible(true);
+
+                       core::rect<s32> rect(
+                               5,
+                               5 + text_height,
+                               screensize.X,
+                               5 + (text_height * 2)
+                       );
+                       guitext2->setRelativePosition(rect);
                }
                else
                {
                        guitext2->setVisible(false);
                }
-               
+
                {
                        guitext_info->setText(infotext.c_str());
                        guitext_info->setVisible(show_hud && g_menumgr.menuCount() == 0);
@@ -3299,7 +3227,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                core::rect<s32> rect(
                                                10,
                                                status_y - guitext_status->getTextHeight(),
-                                               screensize.X - 10,
+                                               10 + guitext_status->getTextWidth(),
                                                status_y
                                );
                                guitext_status->setRelativePosition(rect);
@@ -3319,7 +3247,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                guitext_status->enableOverrideColor(true);
                        }
                }
-               
+
                /*
                        Get chat messages from client
                */
@@ -3364,7 +3292,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                /*
                        Inventory
                */
-               
+
                if(client.getPlayerItem() != new_playeritem)
                {
                        client.selectPlayerItem(new_playeritem);
@@ -3373,7 +3301,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                {
                        //infostream<<"Updating local inventory"<<std::endl;
                        client.getLocalInventory(local_inventory);
-                       
+
                        update_wielded_item_trigger = true;
                }
                if(update_wielded_item_trigger)
@@ -3382,7 +3310,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        // Update wielded tool
                        InventoryList *mlist = local_inventory.getList("main");
                        ItemStack item;
-                       if(mlist != NULL)
+                       if((mlist != NULL) && (client.getPlayerItem() < mlist->getSize()))
                                item = mlist->getItem(client.getPlayerItem());
                        camera.wield(item, client.getPlayerItem());
                }
@@ -3403,142 +3331,16 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                /*
                        Drawing begins
                */
-
                TimeTaker tt_draw("mainloop: draw");
-               
                {
                        TimeTaker timer("beginScene");
-                       //driver->beginScene(false, true, bgcolor);
-                       //driver->beginScene(true, true, bgcolor);
                        driver->beginScene(true, true, skycolor);
                        beginscenetime = timer.stop(true);
                }
-               
-               //timer3.stop();
-       
-               //infostream<<"smgr->drawAll()"<<std::endl;
-               {
-                       TimeTaker timer("smgr");
-                       smgr->drawAll();
-                       
-                       if(g_settings->getBool("anaglyph"))
-                       {
-                               irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
-                               irr::core::vector3df oldTarget   = camera.getCameraNode()->getTarget();
-
-                               irr::core::matrix4 startMatrix   = camera.getCameraNode()->getAbsoluteTransformation();
-
-                               irr::core::vector3df focusPoint  = (camera.getCameraNode()->getTarget() -
-                                                                                camera.getCameraNode()->getAbsolutePosition()).setLength(1) +
-                                                                                camera.getCameraNode()->getAbsolutePosition() ;
-
-                               //Left eye...
-                               irr::core::vector3df leftEye;
-                               irr::core::matrix4   leftMove;
-
-                               leftMove.setTranslation( irr::core::vector3df(-g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
-                               leftEye=(startMatrix*leftMove).getTranslation();
-
-                               //clear the depth buffer, and color
-                               driver->beginScene( true, true, irr::video::SColor(0,200,200,255) );
-
-                               driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_RED;
-                               driver->getOverrideMaterial().EnableFlags  = irr::video::EMF_COLOR_MASK;
-                               driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
-                                                                                                                        irr::scene::ESNRP_SOLID +
-                                                                                                                        irr::scene::ESNRP_TRANSPARENT +
-                                                                                                                        irr::scene::ESNRP_TRANSPARENT_EFFECT +
-                                                                                                                        irr::scene::ESNRP_SHADOW;
-
-                               camera.getCameraNode()->setPosition( leftEye );
-                               camera.getCameraNode()->setTarget( focusPoint );
-
-                               smgr->drawAll(); // 'smgr->drawAll();' may go here
-
-                               driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
-
-                               if (show_hud)
-                                       hud.drawSelectionBoxes(hilightboxes);
-
-
-                               //Right eye...
-                               irr::core::vector3df rightEye;
-                               irr::core::matrix4   rightMove;
-
-                               rightMove.setTranslation( irr::core::vector3df(g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
-                               rightEye=(startMatrix*rightMove).getTranslation();
-
-                               //clear the depth buffer
-                               driver->clearZBuffer();
-
-                               driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_GREEN + irr::video::ECP_BLUE;
-                               driver->getOverrideMaterial().EnableFlags  = irr::video::EMF_COLOR_MASK;
-                               driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
-                                                                                                                        irr::scene::ESNRP_SOLID +
-                                                                                                                        irr::scene::ESNRP_TRANSPARENT +
-                                                                                                                        irr::scene::ESNRP_TRANSPARENT_EFFECT +
-                                                                                                                        irr::scene::ESNRP_SHADOW;
-
-                               camera.getCameraNode()->setPosition( rightEye );
-                               camera.getCameraNode()->setTarget( focusPoint );
-
-                               smgr->drawAll(); // 'smgr->drawAll();' may go here
-
-                               driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
-
-                               if (show_hud)
-                                       hud.drawSelectionBoxes(hilightboxes);
-
-
-                               //driver->endScene();
-
-                               driver->getOverrideMaterial().Material.ColorMask=irr::video::ECP_ALL;
-                               driver->getOverrideMaterial().EnableFlags=0;
-                               driver->getOverrideMaterial().EnablePasses=0;
-
-                               camera.getCameraNode()->setPosition( oldPosition );
-                               camera.getCameraNode()->setTarget( oldTarget );
-                       }
-
-                       scenetime = timer.stop(true);
-               }
-               
-               {
-               //TimeTaker timer9("auxiliary drawings");
-               // 0ms
-               
-               //timer9.stop();
-               //TimeTaker //timer10("//timer10");
-               
-               video::SMaterial m;
-               //m.Thickness = 10;
-               m.Thickness = 3;
-               m.Lighting = false;
-               driver->setMaterial(m);
-
-               driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
-               if((!g_settings->getBool("anaglyph")) && (show_hud))
-               {
-                       hud.drawSelectionBoxes(hilightboxes);
-               }
 
-               /*
-                       Wielded tool
-               */
-               if(show_hud &&
-                       (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) &&
-                       current_camera_mode < CAMERA_MODE_THIRD)
-               {
-                       // Warning: This clears the Z buffer.
-                       camera.drawWieldedTool();
-               }
 
-               /*
-                       Post effects
-               */
-               {
-                       client.getEnv().getClientMap().renderPostFx();
-               }
+               draw_scene(driver, smgr, camera, client, player, hud, guienv,
+                               hilightboxes, screensize, skycolor, show_hud);
 
                /*
                        Profiler graph
@@ -3548,27 +3350,6 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        graph.draw(10, screensize.Y - 10, driver, font);
                }
 
-               /*
-                       Draw crosshair
-               */
-               if (show_hud)
-                       hud.drawCrosshair();
-                       
-               } // timer
-
-               //timer10.stop();
-               //TimeTaker //timer11("//timer11");
-
-
-               /*
-                       Draw hotbar
-               */
-               if (show_hud)
-               {
-                       hud.drawHotbar(v2s32(displaycenter.X, screensize.Y),
-                                       client.getHP(), client.getPlayerItem(), client.getBreath());
-               }
-
                /*
                        Damage flash
                */
@@ -3578,7 +3359,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                        driver->draw2DRectangle(color,
                                        core::rect<s32>(0,0,screensize.X,screensize.Y),
                                        NULL);
-                       
+
                        damage_flash -= 100.0*dtime;
                }
 
@@ -3592,18 +3373,6 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                                player->hurt_tilt_strength = 0;
                }
 
-               /*
-                       Draw lua hud items
-               */
-               if (show_hud)
-                       hud.drawLuaElements();
-
-               /*
-                       Draw gui
-               */
-               // 0-1ms
-               guienv->drawAll();
-
                /*
                        End scene
                */
@@ -3638,20 +3407,21 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        if (sky)
                sky->drop();
        clear_particles();
-       
+
+       /* cleanup menus */
+       while (g_menumgr.menuCount() > 0)
+       {
+               g_menumgr.m_stack.front()->setVisible(false);
+               g_menumgr.deletingMenu(g_menumgr.m_stack.front());
+       }
        /*
                Draw a "shutting down" screen, which will be shown while the map
                generator and other stuff quits
        */
        {
-               /*gui::IGUIStaticText *gui_shuttingdowntext = */
                wchar_t* text = wgettext("Shutting down stuff...");
-               draw_load_screen(text, device, font, 0, -1, false);
+               draw_load_screen(text, device, guienv, font, 0, -1, false);
                delete[] text;
-               /*driver->beginScene(true, true, video::SColor(255,0,0,0));
-               guienv->drawAll();
-               driver->endScene();
-               gui_shuttingdowntext->remove();*/
        }
 
        chat_backend.addMessage(L"", L"# Disconnected.");
@@ -3687,7 +3457,7 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
        }
 
 
-       
+
        if(!sound_is_dummy)
                delete sound;
 
@@ -3715,5 +3485,3 @@ void the_game(bool &kill, bool random_input, InputHandler *input,
                << driver-> getMaterialRendererCount ()
                << " (note: irrlicht doesn't support removing renderers)"<< std::endl;
 }
-
-