diff --git a/builtin/serialize.lua b/builtin/serialize.lua
index ecb2438e864afaf1cc7a2dd08b3d95924c01ff67..61b923ce45a07dd85ab413b52ecbe6ba2ecd57de 100644
--- a/builtin/serialize.lua
+++ b/builtin/serialize.lua
@@ -197,7 +197,7 @@ local function unit_test()
 	unitTest("test 1b", unittest_input.cat.speed == unittest_output.cat.speed)
 	unitTest("test 1c", unittest_input.dog.sound == unittest_output.dog.sound)
 
-	unittest_input = {escapechars="\n\r\t\v\\\"\'\[\]", noneuropean="θשׁ٩∂"}
+	unittest_input = {escapechars="\n\r\t\v\\\"\'", noneuropean="θשׁ٩∂"}
 	unittest_output = minetest.deserialize(minetest.serialize(unittest_input))
 	unitTest("test 3a", unittest_input.escapechars == unittest_output.escapechars)
 	unitTest("test 3b", unittest_input.noneuropean == unittest_output.noneuropean)
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 285f3d205ee53299aace366e6063ce911b42b32a..44b2a0b632adf7bfdd8368a3848247aebe1854ae 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -401,6 +401,43 @@ Currently supported flags:  absheight
     Also produce this same ore between the height range of -height_max and -height_min.
     Useful for having ore in sky realms without having to duplicate ore entries.
 
+HUD element types
+-------------------
+The position field is used for all element types.
+To account for differing resolutions, the position coordinates are the percentage of the screen,
+ranging in value from 0 to 1.
+The name field is not yet used, but should contain a description of what the HUD element represents.
+Below are the specific uses for fields in each type; fields not listed for that type are ignored.
+
+Note: Future revisions to the HUD API may be incompatible; the HUD API is still in the experimental stages.
+
+- image
+    Displays an image on the HUD.
+	- scale: The scale of the image, with 1 being the original texture size.
+             Only the X coordinate scale is used.
+    - text: The name of the texture that is displayed.
+- text
+    Displays text on the HUD.
+    - scale: Defines the bounding rectangle of the text.
+             A value such as {x=100, y=100} should work.
+    - text: The text to be displayed in the HUD element.
+    - number: An integer containing the RGB value of the color used to draw the text.
+              Specify 0xFFFFFF for white text, 0xFF0000 for red, and so on.
+- statbar
+    Displays a horizontal bar made up of half-images.
+    - text: The name of the texture that is used.
+    - number: The number of half-textures that are displayed.
+              If odd, will end with a vertically center-split texture.
+- inventory
+    - text: The name of the inventory list to be displayed.
+    - number: Number of items in the inventory to be displayed.
+    - item: Position of item that is selected.
+    - direction: Direction in which the inventory list is drawn.
+                 0 draws from left to right,
+                 1 draws from right to left,
+                 2 draws from top to bottom, and
+                 3 draws from bottom to top.
+
 Representations of simple things
 --------------------------------
 Position/vector:
@@ -1002,10 +1039,23 @@ minetest.get_craft_recipe(output) -> input
 ^ input.items = for example { stack 1, stack 2, stack 3, stack 4,
                               stack 5, stack 6, stack 7, stack 8, stack 9 }
 ^ input.items = nil if no recipe found
-minetest.get_all_craft_recipes(output) -> table or nil
-^ returns table with all registered recipes for output item (node)
-^ returns nil if no recipe was found
-^ table entries have same format as minetest.get_craft_recipe
+minetest.get_all_craft_recipes(query item) -> table or nil
+^ returns indexed table with all registered recipes for query item (node)
+  or nil if no recipe was found
+  recipe entry table:
+  { 
+   method = 'normal' or 'cooking' or 'fuel'
+   width = 0-3, 0 means shapeless recipe
+   items = indexed [1-9] table with recipe items
+   output = string with item name and quantity
+  }
+  Example query for default:gold_ingot will return table:
+  {
+   1={type = "cooking", width = 3, output = "default:gold_ingot",
+    items = {1 = "default:gold_lump"}},
+   2={type = "normal", width = 1, output = "default:gold_ingot 9",
+    items = {1 = "default:goldblock"}}
+  }
 minetest.handle_node_drops(pos, drops, digger)
 ^ drops: list of itemstrings
 ^ Handles drops from nodes after digging: Default action is to put them into
@@ -1366,7 +1416,12 @@ Player-only: (no-op for other objects)
     modifies per-player walking speed, jump height, and gravity.
     Values default to 1 and act as offsets to the physics settings 
     in minetest.conf. nil will keep the current setting.
-    
+- hud_add(hud definition): add a HUD element described by HUD def, returns ID number on success
+- hud_remove(id): remove the HUD element of the specified id
+- hud_change(id, stat, value): change a value of a previously added HUD element
+  ^ element stat values: position, name, scale, text, number, item, dir
+- hud_get(id): gets the HUD element definition structure of the specified ID
+
 InvRef: Reference to an inventory
 methods:
 - is_empty(listname): return true if list is empty
@@ -1789,3 +1844,18 @@ Detached inventory callbacks
     ^ No return value
 }
 
+HUD Definition (hud_add, hud_get)
+{
+    type = "image",
+    ^ type of HUD element, can be either of "image", "text", "statbar", or "inventory"
+    position = {x=0.5, y=0.5},
+    ^ Left corner position of element
+    name = "<name>",
+    scale = {x=2, y=2},
+    text = "<text>",
+    number = 2,
+    item = 3,
+    ^ Selected item in inventory.  0 for no item selected.
+    dir = 0,
+    ^ Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top
+}
diff --git a/old/Makefile.bak b/old/Makefile.bak
deleted file mode 100644
index 8ba03f9bbf523166d5c678ed59d66c12e9532153..0000000000000000000000000000000000000000
--- a/old/Makefile.bak
+++ /dev/null
@@ -1,90 +0,0 @@
-# Makefile for Irrlicht Examples
-# It's usually sufficient to change just the target name and source file list
-# and be sure that CXX is set to a valid compiler
-SOURCE_FILES = porting.cpp guiMessageMenu.cpp materials.cpp guiTextInputMenu.cpp guiInventoryMenu.cpp irrlichtwrapper.cpp guiPauseMenu.cpp defaultsettings.cpp mapnode.cpp tile.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp
-
-DEBUG_TARGET = debugtest
-DEBUG_SOURCES = $(addprefix src/, $(SOURCE_FILES))
-DEBUG_BUILD_DIR = debugbuild
-DEBUG_OBJECTS = $(addprefix $(DEBUG_BUILD_DIR)/, $(SOURCE_FILES:.cpp=.o))
-
-FAST_TARGET = fasttest
-FAST_SOURCES = $(addprefix src/, $(SOURCE_FILES))
-FAST_BUILD_DIR = fastbuild
-FAST_OBJECTS = $(addprefix $(FAST_BUILD_DIR)/, $(SOURCE_FILES:.cpp=.o))
-
-SERVER_TARGET = server
-SERVER_SOURCE_FILES = porting.cpp materials.cpp defaultsettings.cpp mapnode.cpp voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp servermain.cpp test.cpp
-SERVER_SOURCES = $(addprefix src/, $(SERVER_SOURCE_FILES))
-SERVER_BUILD_DIR = serverbuild
-SERVER_OBJECTS = $(addprefix $(SERVER_BUILD_DIR)/, $(SERVER_SOURCE_FILES:.cpp=.o))
-
-IRRLICHTPATH = ../irrlicht/irrlicht-1.7.1
-JTHREADPATH = ../jthread/jthread-1.2.1
-
-
-all: fast
-
-ifeq ($(HOSTTYPE), x86_64)
-LIBSELECT=64
-endif
-
-debug: CXXFLAGS = -Wall -g -O1
-debug: CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src -DDEBUG -DRUN_IN_PLACE
-debug: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L$(IRRLICHTPATH)/lib/Linux -L$(JTHREADPATH)/src/.libs -lIrrlicht -lGL -lXxf86vm -lXext -lX11 -ljthread -lz
-
-fast: CXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686
-fast: CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src -DUNITTEST_DISABLE -DRUN_IN_PLACE
-fast: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L$(IRRLICHTPATH)/lib/Linux -L$(JTHREADPATH)/src/.libs -lIrrlicht -lGL -lXxf86vm -lXext -lX11 -ljthread -lz
-
-server: CXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686
-server: CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src -DSERVER -DUNITTEST_DISABLE -DRUN_IN_PLACE
-server: LDFLAGS = -L$(JTHREADPATH)/src/.libs -ljthread -lz -lpthread
-
-DEBUG_DESTPATH = bin/$(DEBUG_TARGET)
-FAST_DESTPATH = bin/$(FAST_TARGET)
-SERVER_DESTPATH = bin/$(SERVER_TARGET)
-
-# Build commands
-
-debug: $(DEBUG_BUILD_DIR) $(DEBUG_DESTPATH)
-fast: $(FAST_BUILD_DIR) $(FAST_DESTPATH)
-server: $(SERVER_BUILD_DIR) $(SERVER_DESTPATH)
-
-$(DEBUG_BUILD_DIR):
-	mkdir -p $(DEBUG_BUILD_DIR)
-$(FAST_BUILD_DIR):
-	mkdir -p $(FAST_BUILD_DIR)
-$(SERVER_BUILD_DIR):
-	mkdir -p $(SERVER_BUILD_DIR)
-
-$(DEBUG_DESTPATH): $(DEBUG_OBJECTS)
-	$(CXX) -o $@ $(DEBUG_OBJECTS) $(LDFLAGS)
-
-$(FAST_DESTPATH): $(FAST_OBJECTS)
-	$(CXX) -o $@ $(FAST_OBJECTS) $(LDFLAGS)
-
-$(SERVER_DESTPATH): $(SERVER_OBJECTS)
-	$(CXX) -o $@ $(SERVER_OBJECTS) $(LDFLAGS)
-
-$(DEBUG_BUILD_DIR)/%.o: src/%.cpp
-	$(CXX) -c -o $@ $< $(CPPFLAGS) $(CXXFLAGS)
-
-$(FAST_BUILD_DIR)/%.o: src/%.cpp
-	$(CXX) -c -o $@ $< $(CPPFLAGS) $(CXXFLAGS)
-
-$(SERVER_BUILD_DIR)/%.o: src/%.cpp
-	$(CXX) -c -o $@ $< $(CPPFLAGS) $(CXXFLAGS)
-
-clean: clean_debug clean_fast clean_server
-
-clean_debug:
-	@$(RM) $(DEBUG_OBJECTS) $(DEBUG_DESTPATH)
-
-clean_fast:
-	@$(RM) $(FAST_OBJECTS) $(FAST_DESTPATH)
-
-clean_server:
-	@$(RM) $(SERVER_OBJECTS) $(SERVER_DESTPATH)
-
-.PHONY: all all_win32 clean clean_debug clean_win32 clean_fast clean_server
diff --git a/po/du/minetest.po b/po/du/minetest.po
new file mode 100644
index 0000000000000000000000000000000000000000..b2024d8a500aa6bf64d60216639888769ed825c8
--- /dev/null
+++ b/po/du/minetest.po
@@ -0,0 +1,776 @@
+# SOME DESCRIPTIVE TITLE. DUTCH TRANSLATION
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: minetest\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-03-30 19:56+0100\n"
+"PO-Revision-Date: 2013-04-18 15:28+0100\n"
+"Last-Translator: LS-Steeef \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.5.5\n"
+"Language: dutch\n"
+
+#: src/guiConfigureWorld.cpp:125
+msgid ""
+"Warning: Some mods are not configured yet.\n"
+"They will be enabled by default when you save the configuration.  "
+msgstr ""
+"Let op: Nog niet alle mods zijn geconfigueerd. \n"
+"De mods zullen automatisch worden ingeschakeld als je de configuratie "
+"bewaard."
+
+#: src/guiConfigureWorld.cpp:144
+msgid ""
+"Warning: Some configured mods are missing.\n"
+"Their setting will be removed when you save the configuration.  "
+msgstr ""
+"LEt op: Sommige ingestelde mods zijn vermist.\n"
+"Hun instellingen worden verwijderd als je de configuratie opslaat."
+
+#: src/guiConfigureWorld.cpp:208
+msgid "enabled"
+msgstr "ingeschakeld"
+
+#: src/guiConfigureWorld.cpp:215
+msgid "Enable All"
+msgstr "Allen inschakelen"
+
+#: src/guiConfigureWorld.cpp:222
+msgid "Disable All"
+msgstr "Allen uitschakelen"
+
+#: src/guiConfigureWorld.cpp:228
+msgid "depends on:"
+msgstr "heeft nodig:"
+
+#: src/guiConfigureWorld.cpp:240
+msgid "is required by:"
+msgstr "is benodigd voor:"
+
+#: src/guiConfigureWorld.cpp:262 src/guiCreateWorld.cpp:165
+#: src/guiKeyChangeMenu.cpp:179 src/keycode.cpp:223
+msgid "Cancel"
+msgstr "Annuleer"
+
+#: src/guiConfigureWorld.cpp:268 src/guiKeyChangeMenu.cpp:173
+msgid "Save"
+msgstr "Bewaar"
+
+#: src/guiConfigureWorld.cpp:394
+msgid "Configuration saved.  "
+msgstr "Instellingen bewaard."
+
+#: src/guiConfigureWorld.cpp:402
+msgid "Warning: Configuration not consistent.  "
+msgstr "Waarschuwing: Instellingen niet consistent."
+
+#: src/guiConfirmMenu.cpp:120
+msgid "Yes"
+msgstr "Ja"
+
+#: src/guiConfirmMenu.cpp:126
+msgid "No"
+msgstr "Nee"
+
+#: src/guiCreateWorld.cpp:116
+msgid "World name"
+msgstr "Naam wereld"
+
+#: src/guiCreateWorld.cpp:135
+msgid "Game"
+msgstr "Spel"
+
+#: src/guiCreateWorld.cpp:159
+msgid "Create"
+msgstr "Maak aan"
+
+#: src/guiDeathScreen.cpp:96
+msgid "You died."
+msgstr "Je bent gestorven."
+
+#: src/guiDeathScreen.cpp:104
+msgid "Respawn"
+msgstr "Respawn"
+
+#: src/guiFormSpecMenu.cpp:582
+msgid "Left click: Move all items, Right click: Move single item"
+msgstr ""
+"Linkermuisknop: Verplaats alle items. Rechtermuisknop: Verplaats één item."
+
+#: src/guiFormSpecMenu.cpp:607 src/guiMessageMenu.cpp:109
+#: src/guiTextInputMenu.cpp:131
+msgid "Proceed"
+msgstr "Volgende"
+
+#: src/guiKeyChangeMenu.cpp:114
+msgid "Keybindings. (If this menu screws up, remove stuff from minetest.conf)"
+msgstr "Sneltoetsen."
+
+#: src/guiKeyChangeMenu.cpp:151
+msgid "\"Use\" = climb down"
+msgstr "\"Use\" = Omlaag klimmen"
+
+#: src/guiKeyChangeMenu.cpp:164
+msgid "Double tap \"jump\" to toggle fly"
+msgstr "Dubbelklik op \"jump\" om te vliegen"
+
+#: src/guiKeyChangeMenu.cpp:269
+msgid "Key already in use"
+msgstr "Toets is al in gebruik"
+
+#: src/guiKeyChangeMenu.cpp:347
+msgid "press key"
+msgstr "druk op"
+
+#: src/guiKeyChangeMenu.cpp:372
+msgid "Forward"
+msgstr "Vooruit"
+
+#: src/guiKeyChangeMenu.cpp:373
+msgid "Backward"
+msgstr "Achteruit"
+
+#: src/guiKeyChangeMenu.cpp:374 src/keycode.cpp:228
+msgid "Left"
+msgstr "Links"
+
+#: src/guiKeyChangeMenu.cpp:375 src/keycode.cpp:228
+msgid "Right"
+msgstr "Rechts"
+
+#: src/guiKeyChangeMenu.cpp:376
+msgid "Use"
+msgstr "Gebruikwn"
+
+#: src/guiKeyChangeMenu.cpp:377
+msgid "Jump"
+msgstr "Springen"
+
+#: src/guiKeyChangeMenu.cpp:378
+msgid "Sneak"
+msgstr "Kruipen"
+
+#: src/guiKeyChangeMenu.cpp:379
+msgid "Drop"
+msgstr "Weggooien"
+
+#: src/guiKeyChangeMenu.cpp:380
+msgid "Inventory"
+msgstr "Rugzak"
+
+#: src/guiKeyChangeMenu.cpp:381
+msgid "Chat"
+msgstr "Chat"
+
+#: src/guiKeyChangeMenu.cpp:382
+msgid "Command"
+msgstr "Opdracht"
+
+#: src/guiKeyChangeMenu.cpp:383
+msgid "Console"
+msgstr "Console"
+
+#: src/guiKeyChangeMenu.cpp:384
+msgid "Toggle fly"
+msgstr "Vliegen aan/uit"
+
+#: src/guiKeyChangeMenu.cpp:385
+msgid "Toggle fast"
+msgstr "Snel bewegen aan/uit"
+
+#: src/guiKeyChangeMenu.cpp:386
+msgid "Toggle noclip"
+msgstr "Noclip aan/uit"
+
+#: src/guiKeyChangeMenu.cpp:387
+msgid "Range select"
+msgstr "Range instellen"
+
+#: src/guiKeyChangeMenu.cpp:388
+msgid "Print stacks"
+msgstr "Print stacks"
+
+#: src/guiMainMenu.cpp:92
+msgid "Cannot create world: Name contains invalid characters"
+msgstr "Kan geen nieuwe wereld aanmaken: de naam bevat onjuiste tekens."
+
+#: src/guiMainMenu.cpp:101
+msgid "Cannot create world: A world by this name already exists"
+msgstr "Kan geen nieuwe wereld aanmaken: De naam bestaat al."
+
+#: src/guiMainMenu.cpp:283
+msgid "Singleplayer"
+msgstr "Singleplayer"
+
+#: src/guiMainMenu.cpp:284
+msgid "Multiplayer"
+msgstr "Multiplayer"
+
+#: src/guiMainMenu.cpp:285
+msgid "Advanced"
+msgstr "Geavanceerd"
+
+#: src/guiMainMenu.cpp:286
+msgid "Settings"
+msgstr "Instellingen"
+
+#: src/guiMainMenu.cpp:287
+msgid "Credits"
+msgstr "Credits"
+
+#: src/guiMainMenu.cpp:317
+msgid "Select World:"
+msgstr "Selecteer Wereld:"
+
+#: src/guiMainMenu.cpp:339 src/guiMainMenu.cpp:511 src/keycode.cpp:229
+msgid "Delete"
+msgstr "Verwijderen"
+
+#: src/guiMainMenu.cpp:346
+msgid "New"
+msgstr "Nieuw"
+
+#: src/guiMainMenu.cpp:354
+msgid "Configure"
+msgstr "Instellingen"
+
+#: src/guiMainMenu.cpp:369 src/keycode.cpp:248
+msgid "Play"
+msgstr "Speel!"
+
+#: src/guiMainMenu.cpp:380 src/guiMainMenu.cpp:619
+msgid "Creative Mode"
+msgstr "Creative Modus"
+
+#: src/guiMainMenu.cpp:386 src/guiMainMenu.cpp:625
+msgid "Enable Damage"
+msgstr "Schade inschakelen"
+
+#: src/guiMainMenu.cpp:406 src/guiMainMenu.cpp:541
+msgid "Name/Password"
+msgstr "Naam/Wachtwoord"
+
+#: src/guiMainMenu.cpp:442 src/guiMainMenu.cpp:459 src/guiMainMenu.cpp:1184
+msgid "Favorites:"
+msgstr "Favourieten:"
+
+#: src/guiMainMenu.cpp:450 src/guiMainMenu.cpp:1194
+msgid "Public Server List:"
+msgstr "Publieke Server lijst:"
+
+#: src/guiMainMenu.cpp:470 src/guiMainMenu.cpp:568
+msgid "Address/Port"
+msgstr "IP-Adres/Poort"
+
+#: src/guiMainMenu.cpp:497 src/guiMainMenu.cpp:1183
+msgid "Show Public"
+msgstr "Publieke server"
+
+#: src/guiMainMenu.cpp:501 src/guiMainMenu.cpp:1193
+msgid "Show Favorites"
+msgstr "Favourieten"
+
+#: src/guiMainMenu.cpp:521
+msgid "Connect"
+msgstr "Verbinden"
+
+#: src/guiMainMenu.cpp:591
+msgid "Leave address blank to start a local server."
+msgstr "Laat het adres leeg om een lokale server te starten."
+
+#: src/guiMainMenu.cpp:600
+msgid "Start Game / Connect"
+msgstr "Start het spel / Verbind"
+
+#: src/guiMainMenu.cpp:632
+msgid "Public"
+msgstr "Publiek"
+
+#: src/guiMainMenu.cpp:640 src/guiMainMenu.cpp:1113
+msgid "Delete world"
+msgstr "Verwijder wereld"
+
+#: src/guiMainMenu.cpp:647
+msgid "Create world"
+msgstr "Maak wereld aan"
+
+#: src/guiMainMenu.cpp:681
+msgid "Fancy trees"
+msgstr "Mooie bomen"
+
+#: src/guiMainMenu.cpp:687
+msgid "Smooth Lighting"
+msgstr "Mooie verlichting"
+
+#: src/guiMainMenu.cpp:693
+msgid "3D Clouds"
+msgstr "3D wolken"
+
+#: src/guiMainMenu.cpp:699
+msgid "Opaque water"
+msgstr "Doorzichtig water"
+
+#: src/guiMainMenu.cpp:709
+msgid "Mip-Mapping"
+msgstr "Mip-Mapping"
+
+#: src/guiMainMenu.cpp:716
+msgid "Anisotropic Filtering"
+msgstr "Bi-Linear Filtering"
+
+#: src/guiMainMenu.cpp:723
+msgid "Bi-Linear Filtering"
+msgstr "Bi-Linear Filtering"
+
+#: src/guiMainMenu.cpp:730
+msgid "Tri-Linear Filtering"
+msgstr "Tri-Linear Filtering"
+
+#: src/guiMainMenu.cpp:738
+msgid "Shaders"
+msgstr "Shaders"
+
+#: src/guiMainMenu.cpp:745
+msgid "Preload item visuals"
+msgstr "Preload item visuals"
+
+#: src/guiMainMenu.cpp:752
+msgid "Enable Particles"
+msgstr "Enable Particles"
+
+#: src/guiMainMenu.cpp:759
+msgid "Finite liquid"
+msgstr "Finite liquid"
+
+#: src/guiMainMenu.cpp:769
+msgid "Change keys"
+msgstr "Sneltoetsen veranderen"
+
+#: src/guiMainMenu.cpp:1084
+msgid "Address required."
+msgstr "IP-adres nodig."
+
+#: src/guiMainMenu.cpp:1102
+msgid "Cannot delete world: Nothing selected"
+msgstr "Kan niets verwijderen: Geen wereld geselecteerd."
+
+#: src/guiMainMenu.cpp:1117
+msgid "Files to be deleted"
+msgstr "Deze bestanden worden verwijderd"
+
+#: src/guiMainMenu.cpp:1133
+msgid "Cannot create world: No games found"
+msgstr "Kan geen wereld aanmaken: Geen games gevonden"
+
+#: src/guiMainMenu.cpp:1149
+msgid "Cannot configure world: Nothing selected"
+msgstr "Kan instellingen niet aanpassen: Niets geselecteerd"
+
+#: src/guiMainMenu.cpp:1256
+msgid "Failed to delete all world files"
+msgstr "Niet alle bestanden zijn verwijderd"
+
+#: src/guiPasswordChange.cpp:108
+msgid "Old Password"
+msgstr "Huidig wachtwoord"
+
+#: src/guiPasswordChange.cpp:125
+msgid "New Password"
+msgstr "Nieuw wachtwoord"
+
+#: src/guiPasswordChange.cpp:141
+msgid "Confirm Password"
+msgstr "Herhaal wachtwoord"
+
+#: src/guiPasswordChange.cpp:158
+msgid "Change"
+msgstr "Veranderen"
+
+#: src/guiPasswordChange.cpp:167
+msgid "Passwords do not match!"
+msgstr "Wachtwoorden zijn niet gelijk!"
+
+#: src/guiPauseMenu.cpp:123
+msgid "Continue"
+msgstr "Volgende"
+
+#: src/guiPauseMenu.cpp:132
+msgid "Change Password"
+msgstr "Verander wachtwoord"
+
+#: src/guiPauseMenu.cpp:140
+msgid "Sound Volume"
+msgstr "Volume"
+
+#: src/guiPauseMenu.cpp:147
+msgid "Exit to Menu"
+msgstr "Exit naar menu"
+
+#: src/guiPauseMenu.cpp:154
+msgid "Exit to OS"
+msgstr "Afsluiten"
+
+#: src/guiPauseMenu.cpp:161
+msgid ""
+"Default Controls:\n"
+"- WASD: Walk\n"
+"- Mouse left: dig/hit\n"
+"- Mouse right: place/use\n"
+"- Mouse wheel: select item\n"
+"- 0...9: select item\n"
+"- Shift: sneak\n"
+"- R: Toggle viewing all loaded chunks\n"
+"- I: Inventory menu\n"
+"- ESC: This menu\n"
+"- T: Chat\n"
+msgstr ""
+"Default Besturing:\n"
+"- WASD: Lopen\n"
+"- Linkermuisknop: Graaf/Sla\n"
+"- Rechtmuisknop: Plaats/Gebruik\n"
+"- Muiswiel: selecteer item\n"
+"- 0...9: selecteer item\n"
+"- Shift: kruipen\n"
+"- R: Toggle viewing all loaded chunks\n"
+"- I: Rugzak\n"
+"- ESC: Menu\n"
+"- T: Chat\n"
+
+#: src/guiVolumeChange.cpp:108
+msgid "Sound Volume: "
+msgstr "Volume:"
+
+#: src/guiVolumeChange.cpp:121
+msgid "Exit"
+msgstr "Exit"
+
+#: src/keycode.cpp:223
+msgid "Left Button"
+msgstr "Linkermuisknop"
+
+#: src/keycode.cpp:223
+msgid "Middle Button"
+msgstr "Muiswielknop"
+
+#: src/keycode.cpp:223
+msgid "Right Button"
+msgstr "Rechtmuisknop"
+
+#: src/keycode.cpp:223
+msgid "X Button 1"
+msgstr "X knop 1"
+
+#: src/keycode.cpp:224
+msgid "Back"
+msgstr "Terug"
+
+#: src/keycode.cpp:224
+msgid "Clear"
+msgstr "Wissen"
+
+#: src/keycode.cpp:224
+msgid "Return"
+msgstr "Return"
+
+#: src/keycode.cpp:224
+msgid "Tab"
+msgstr "Tab"
+
+#: src/keycode.cpp:224
+msgid "X Button 2"
+msgstr "X knop 2"
+
+#: src/keycode.cpp:225
+msgid "Capital"
+msgstr "Kapitaal"
+
+#: src/keycode.cpp:225
+msgid "Control"
+msgstr "Control"
+
+#: src/keycode.cpp:225
+msgid "Kana"
+msgstr "Kana"
+
+#: src/keycode.cpp:225
+msgid "Menu"
+msgstr "Menu"
+
+#: src/keycode.cpp:225
+msgid "Pause"
+msgstr "Pauze"
+
+#: src/keycode.cpp:225
+msgid "Shift"
+msgstr "Shift"
+
+#: src/keycode.cpp:226
+msgid "Convert"
+msgstr "Converteren"
+
+#: src/keycode.cpp:226
+msgid "Escape"
+msgstr "Escape"
+
+#: src/keycode.cpp:226
+msgid "Final"
+msgstr "Final"
+
+#: src/keycode.cpp:226
+msgid "Junja"
+msgstr "Junja"
+
+#: src/keycode.cpp:226
+msgid "Kanji"
+msgstr "Kanji"
+
+#: src/keycode.cpp:226
+msgid "Nonconvert"
+msgstr "Nonconvert"
+
+#: src/keycode.cpp:227
+msgid "Accept"
+msgstr "Accepteren"
+
+#: src/keycode.cpp:227
+msgid "End"
+msgstr "End"
+
+#: src/keycode.cpp:227
+msgid "Home"
+msgstr "Home"
+
+#: src/keycode.cpp:227
+msgid "Mode Change"
+msgstr "Modus veranderen"
+
+#: src/keycode.cpp:227
+msgid "Next"
+msgstr "Volgende"
+
+#: src/keycode.cpp:227
+msgid "Prior"
+msgstr "Eerste"
+
+#: src/keycode.cpp:227
+msgid "Space"
+msgstr "Spatie"
+
+#: src/keycode.cpp:228
+msgid "Down"
+msgstr "Omlaag"
+
+#: src/keycode.cpp:228
+msgid "Execute"
+msgstr "Uitvoeren"
+
+#: src/keycode.cpp:228
+msgid "Print"
+msgstr "Print"
+
+#: src/keycode.cpp:228
+msgid "Select"
+msgstr "Selecteren"
+
+#: src/keycode.cpp:228
+msgid "Up"
+msgstr "Omhoog"
+
+#: src/keycode.cpp:229
+msgid "Help"
+msgstr "Help"
+
+#: src/keycode.cpp:229
+msgid "Insert"
+msgstr "Insert"
+
+#: src/keycode.cpp:229
+msgid "Snapshot"
+msgstr "Screenshot"
+
+#: src/keycode.cpp:232
+msgid "Left Windows"
+msgstr "Linker Windowstoets"
+
+#: src/keycode.cpp:233
+msgid "Apps"
+msgstr "Apps"
+
+#: src/keycode.cpp:233
+msgid "Numpad 0"
+msgstr "Numpad 0"
+
+#: src/keycode.cpp:233
+msgid "Numpad 1"
+msgstr "Numpad 1"
+
+#: src/keycode.cpp:233
+msgid "Right Windows"
+msgstr "Rechter Windowstoets"
+
+#: src/keycode.cpp:233
+msgid "Sleep"
+msgstr "Slaapknop"
+
+#: src/keycode.cpp:234
+msgid "Numpad 2"
+msgstr "Numpad 2"
+
+#: src/keycode.cpp:234
+msgid "Numpad 3"
+msgstr "Numpad 3"
+
+#: src/keycode.cpp:234
+msgid "Numpad 4"
+msgstr "Numpad 4"
+
+#: src/keycode.cpp:234
+msgid "Numpad 5"
+msgstr "Numpad 5"
+
+#: src/keycode.cpp:234
+msgid "Numpad 6"
+msgstr "Numpad 6"
+
+#: src/keycode.cpp:234
+msgid "Numpad 7"
+msgstr "Numpad 7"
+
+#: src/keycode.cpp:235
+msgid "Numpad *"
+msgstr "Numpad *"
+
+#: src/keycode.cpp:235
+msgid "Numpad +"
+msgstr "Numpad +"
+
+#: src/keycode.cpp:235
+msgid "Numpad -"
+msgstr "Numpad -"
+
+#: src/keycode.cpp:235
+msgid "Numpad /"
+msgstr "Numpad /"
+
+#: src/keycode.cpp:235
+msgid "Numpad 8"
+msgstr "Numpad 8"
+
+#: src/keycode.cpp:235
+msgid "Numpad 9"
+msgstr "Numpad 9"
+
+#: src/keycode.cpp:239
+msgid "Num Lock"
+msgstr "Num Lock"
+
+#: src/keycode.cpp:239
+msgid "Scroll Lock"
+msgstr "Scroll Lock"
+
+#: src/keycode.cpp:240
+msgid "Left Shift"
+msgstr "Linker Shift"
+
+#: src/keycode.cpp:240
+msgid "Right Shift"
+msgstr "Rechter Shift"
+
+#: src/keycode.cpp:241
+msgid "Left Control"
+msgstr "Linker Ctrl"
+
+#: src/keycode.cpp:241
+msgid "Left Menu"
+msgstr "Linker Menu"
+
+#: src/keycode.cpp:241
+msgid "Right Control"
+msgstr "Rechter Ctrl"
+
+#: src/keycode.cpp:241
+msgid "Right Menu"
+msgstr "Rechter Menu"
+
+#: src/keycode.cpp:243
+msgid "Comma"
+msgstr "Komma"
+
+#: src/keycode.cpp:243
+msgid "Minus"
+msgstr "Min"
+
+#: src/keycode.cpp:243
+msgid "Period"
+msgstr "Punt"
+
+#: src/keycode.cpp:243
+msgid "Plus"
+msgstr "Plus"
+
+#: src/keycode.cpp:247
+msgid "Attn"
+msgstr "Attn"
+
+#: src/keycode.cpp:247
+msgid "CrSel"
+msgstr "CrSel"
+
+#: src/keycode.cpp:248
+msgid "Erase OEF"
+msgstr "Erase OEF"
+
+#: src/keycode.cpp:248
+msgid "ExSel"
+msgstr "ExSel"
+
+#: src/keycode.cpp:248
+msgid "OEM Clear"
+msgstr "OEM Clear"
+
+#: src/keycode.cpp:248
+msgid "PA1"
+msgstr "PA1"
+
+#: src/keycode.cpp:248
+msgid "Zoom"
+msgstr "Zoom"
+
+#: src/main.cpp:1506
+msgid "Main Menu"
+msgstr "Hoofdmenu"
+
+#: src/main.cpp:1830
+msgid "Failed to initialize world"
+msgstr "Laden van wereld is mislukt"
+
+#: src/main.cpp:1842
+msgid "No world selected and no address provided. Nothing to do."
+msgstr "Geen wereld en adres geselecteerd. Niks te doen."
+
+#: src/main.cpp:1850
+msgid "Could not find or load game \""
+msgstr "Kan niet de game laden of vinden."
+
+#: src/main.cpp:1864
+msgid "Invalid gamespec."
+msgstr "Onjuiste gamespec."
+
+#: src/main.cpp:1904
+msgid "Connection error (timed out?)"
+msgstr "Connection error (timed out?)"
+
+#: src/main.cpp:1915
+msgid ""
+"\n"
+"Check debug.txt for details."
+msgstr ""
+"\n"
+"Check debug.txt for details."
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9bef3289e06351f37ad77c3fd0b71e4f86c43120..7ddeeb02e425c85ef307e66326bf18db9e27505b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -180,10 +180,26 @@ if(USE_FREETYPE)
 	set(CGUITTFONT_LIBRARY cguittfont)
 endif(USE_FREETYPE)
 
-# Do not use system-wide installation of Lua, because it'll likely be a
-# different version and/or has different build options.
-set(LUA_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/lua/src")
-set(LUA_LIBRARY "lua")
+
+find_library(LUA_LIBRARY luajit
+		NAMES luajit-5.1)
+find_path(LUA_INCLUDE_DIR luajit.h
+	NAMES luajit.h
+	PATH_SUFFIXES luajit-2.0)
+message (STATUS "LuaJIT library: ${LUA_LIBRARY}")
+message (STATUS "LuaJIT headers: ${LUA_INCLUDE_DIR}")
+
+if(LUA_LIBRARY AND LUA_INCLUDE_DIR) 
+	message (STATUS "LuaJIT found.")
+else(LUA_LIBRARY AND LUA_INCLUDE_DIR)
+	message (STATUS "LuaJIT not found, using bundled Lua.")
+	set(LUA_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/lua/src")
+	set(LUA_LIBRARY "lua")
+	add_subdirectory(lua)
+endif(LUA_LIBRARY AND LUA_INCLUDE_DIR)
+
+mark_as_advanced(LUA_LIBRARY)
+mark_as_advanced(LUA_INCLUDE_DIR)
 
 configure_file(
 	"${PROJECT_SOURCE_DIR}/cmake_config.h.in"
@@ -311,6 +327,7 @@ set(minetest_SRCS
 	particles.cpp
 	clientobject.cpp
 	chat.cpp
+	hud.cpp
 	guiMainMenu.cpp
 	guiKeyChangeMenu.cpp
 	guiMessageMenu.cpp
@@ -601,11 +618,6 @@ if (BUILD_CLIENT AND USE_FREETYPE)
 	add_subdirectory(cguittfont)
 endif (BUILD_CLIENT AND USE_FREETYPE)
 
-if (LUA_FOUND)
-else (LUA_FOUND)
-	add_subdirectory(lua)
-endif (LUA_FOUND)
-
 if (JSON_FOUND)
 else (JSON_FOUND)
 	add_subdirectory(json)
diff --git a/src/camera.cpp b/src/camera.cpp
index 138b022c049208ec07a788e8daa7db15310e5f0d..211ecfd70e6e79f3367b0dbca63cd5107e2cb632 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -67,9 +67,11 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
 	m_view_bobbing_anim(0),
 	m_view_bobbing_state(0),
 	m_view_bobbing_speed(0),
+	m_view_bobbing_fall(0),
 
 	m_digging_anim(0),
-	m_digging_button(-1)
+	m_digging_button(-1),
+	m_dummymesh(createCubeMesh(v3f(1,1,1)))
 {
 	//dstream<<__FUNCTION_NAME<<std::endl;
 
@@ -84,13 +86,14 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control,
 	// all other 3D scene nodes and before the GUI.
 	m_wieldmgr = smgr->createNewSceneManager();
 	m_wieldmgr->addCameraSceneNode();
-	m_wieldnode = m_wieldmgr->addMeshSceneNode(createCubeMesh(v3f(1,1,1)), NULL);  // need a dummy mesh
+	m_wieldnode = m_wieldmgr->addMeshSceneNode(m_dummymesh, NULL);  // need a dummy mesh
 }
 
 Camera::~Camera()
 {
-	m_wieldnode->setMesh(NULL);
 	m_wieldmgr->drop();
+
+	delete m_dummymesh;
 }
 
 bool Camera::successfullyCreated(std::wstring& error_message)
@@ -132,6 +135,13 @@ inline f32 my_modf(f32 x)
 
 void Camera::step(f32 dtime)
 {
+	if(m_view_bobbing_fall > 0)
+	{
+		m_view_bobbing_fall -= 3 * dtime;
+		if(m_view_bobbing_fall <= 0)
+			m_view_bobbing_fall = -1; // Mark the effect as finished
+	}
+
 	if (m_view_bobbing_state != 0)
 	{
 		//f32 offset = dtime * m_view_bobbing_speed * 0.035;
@@ -235,11 +245,28 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize,
 	m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0));
 	m_playernode->updateAbsolutePosition();
 
-	//Get camera tilt timer (hurt animation)
+	// Get camera tilt timer (hurt animation)
 	float cameratilt = fabs(fabs(player->hurt_tilt_timer-0.75)-0.75);
 
+	// Fall bobbing animation
+	float fall_bobbing = 0;
+	if(player->camera_impact >= 1)
+	{
+		if(m_view_bobbing_fall == -1) // Effect took place and has finished
+			player->camera_impact = m_view_bobbing_fall = 0;
+		else if(m_view_bobbing_fall == 0) // Initialize effect
+			m_view_bobbing_fall = 1;
+
+		// Convert 0 -> 1 to 0 -> 1 -> 0
+		fall_bobbing = m_view_bobbing_fall < 0.5 ? m_view_bobbing_fall * 2 : -(m_view_bobbing_fall - 0.5) * 2 + 1;
+		// Smoothen and invert the above
+		fall_bobbing = sin(fall_bobbing * 0.5 * M_PI) * -1;
+		// Amplify according to the intensity of the impact
+		fall_bobbing *= (1 - rangelim(50 / player->camera_impact, 0, 1)) * 5;
+	}
+
 	// Set head node transformation
-	m_headnode->setPosition(player->getEyeOffset()+v3f(0,cameratilt*-player->hurt_tilt_strength,0));
+	m_headnode->setPosition(player->getEyeOffset()+v3f(0,cameratilt*-player->hurt_tilt_strength+fall_bobbing,0));
 	m_headnode->setRotation(v3f(player->getPitch(), 0, cameratilt*player->hurt_tilt_strength));
 	m_headnode->updateAbsolutePosition();
 
diff --git a/src/camera.h b/src/camera.h
index fc43d1176496d7ea6a3a4b0894fc68331228c0b0..0ed5c20d292096833afe890bdfb08f0fc4d302e1 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -166,6 +166,8 @@ class Camera
 	s32 m_view_bobbing_state;
 	// Speed of view bobbing animation
 	f32 m_view_bobbing_speed;
+	// Fall view bobbing
+	f32 m_view_bobbing_fall;
 
 	// Digging animation frame (0 <= m_digging_anim < 1)
 	f32 m_digging_anim;
@@ -173,6 +175,9 @@ class Camera
 	// If 0, left-click digging animation
 	// If 1, right-click digging animation
 	s32 m_digging_button;
+
+	//dummymesh for camera
+	irr::scene::IAnimatedMesh* m_dummymesh;
 };
 
 #endif
diff --git a/src/client.cpp b/src/client.cpp
index 1d5f8f472ee25f124161a07eb1a45833d67a6466..03a710599a4af4b3c035910013e21a96bbbf407c 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -363,6 +363,15 @@ Client::~Client()
 	for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
 			i != m_media_fetch_threads.end(); ++i)
 		delete *i;
+
+	// cleanup 3d model meshes on client shutdown
+	while (m_device->getSceneManager()->getMeshCache()->getMeshCount() != 0) {
+		scene::IAnimatedMesh * mesh =
+			m_device->getSceneManager()->getMeshCache()->getMeshByIndex(0);
+
+		if (mesh != NULL)
+			m_device->getSceneManager()->getMeshCache()->removeMesh(mesh);
+	}
 }
 
 void Client::connect(Address address)
@@ -976,16 +985,28 @@ bool Client::loadMedia(const std::string &data, const std::string &filename)
 	{
 		verbosestream<<"Client: Storing model into Irrlicht: "
 				<<"\""<<filename<<"\""<<std::endl;
+		scene::ISceneManager *smgr = m_device->getSceneManager();
+
+		//check if mesh was already cached
+		scene::IAnimatedMesh *mesh =
+			smgr->getMeshCache()->getMeshByName(filename.c_str());
+
+		if (mesh != NULL) {
+			errorstream << "Multiple models with name: " << filename.c_str() <<
+					" found replacing previous model!" << std::endl;
+
+			smgr->getMeshCache()->removeMesh(mesh);
+			mesh = 0;
+		}
 
 		io::IFileSystem *irrfs = m_device->getFileSystem();
 		io::IReadFile *rfile = irrfs->createMemoryReadFile(
 				*data_rw, data_rw.getSize(), filename.c_str());
 		assert(rfile);
 		
-		scene::ISceneManager *smgr = m_device->getSceneManager();
-		scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
+		mesh = smgr->getMesh(rfile);
 		smgr->getMeshCache()->addMesh(filename.c_str(), mesh);
-		
+		rfile->drop();
 		return true;
 	}
 
@@ -2019,6 +2040,74 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
 
 		m_client_event_queue.push_back(event);
 	}
+	else if(command == TOCLIENT_HUDADD)
+	{
+		std::string datastring((char *)&data[2], datasize - 2);
+		std::istringstream is(datastring, std::ios_base::binary);
+
+		u32 id           = readU32(is);
+		u8 type          = readU8(is);
+		v2f pos          = readV2F1000(is);
+		std::string name = deSerializeString(is);
+		v2f scale        = readV2F1000(is);
+		std::string text = deSerializeString(is);
+		u32 number       = readU32(is);
+		u32 item         = readU32(is);
+		u32 dir          = readU32(is);
+
+		ClientEvent event;
+		event.type = CE_HUDADD;
+		event.hudadd.id     = id;
+		event.hudadd.type   = type;
+		event.hudadd.pos    = new v2f(pos);
+		event.hudadd.name   = new std::string(name);
+		event.hudadd.scale  = new v2f(scale);
+		event.hudadd.text   = new std::string(text);
+		event.hudadd.number = number;
+		event.hudadd.item   = item;
+		event.hudadd.dir    = dir;
+		m_client_event_queue.push_back(event);
+	}
+	else if(command == TOCLIENT_HUDRM)
+	{
+		std::string datastring((char *)&data[2], datasize - 2);
+		std::istringstream is(datastring, std::ios_base::binary);
+
+		u32 id = readU32(is);
+
+		ClientEvent event;
+		event.type = CE_HUDRM;
+		event.hudrm.id = id;
+		m_client_event_queue.push_back(event);
+	}
+	else if(command == TOCLIENT_HUDCHANGE)
+	{	
+		std::string sdata;
+		v2f v2fdata;
+		u32 intdata = 0;
+		
+		std::string datastring((char *)&data[2], datasize - 2);
+		std::istringstream is(datastring, std::ios_base::binary);
+
+		u32 id  = readU32(is);
+		u8 stat = (HudElementStat)readU8(is);
+		
+		if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE)
+			v2fdata = readV2F1000(is);
+		else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
+			sdata = deSerializeString(is);
+		else
+			intdata = readU32(is);
+		
+		ClientEvent event;
+		event.type = CE_HUDCHANGE;
+		event.hudchange.id      = id;
+		event.hudchange.stat    = (HudElementStat)stat;
+		event.hudchange.v2fdata = new v2f(v2fdata);
+		event.hudchange.sdata   = new std::string(sdata);
+		event.hudchange.data    = intdata;
+		m_client_event_queue.push_back(event);
+	}
 	else
 	{
 		infostream<<"Client: Ignoring unknown command "
diff --git a/src/client.h b/src/client.h
index 16cdc237f4bd20e64b7f274090bed8f705132398..f59588680729f523b519aff24409e7ae1f530738 100644
--- a/src/client.h
+++ b/src/client.h
@@ -160,7 +160,10 @@ enum ClientEventType
 	CE_SHOW_FORMSPEC,
 	CE_SPAWN_PARTICLE,
 	CE_ADD_PARTICLESPAWNER,
-	CE_DELETE_PARTICLESPAWNER
+	CE_DELETE_PARTICLESPAWNER,
+	CE_HUDADD,
+	CE_HUDRM,
+	CE_HUDCHANGE
 };
 
 struct ClientEvent
@@ -183,8 +186,8 @@ struct ClientEvent
 			f32 camera_point_target_z;
 		} deathscreen;
 		struct{
-			std::string* formspec;
-			std::string* formname;
+			std::string *formspec;
+			std::string *formname;
 		} show_formspec;
 		struct{
 		} textures_updated;
@@ -217,6 +220,27 @@ struct ClientEvent
 		struct{
 			u32 id;
 		} delete_particlespawner;
+		struct{
+			u32 id;
+			u8 type;
+			v2f *pos;
+			std::string *name;
+			v2f *scale;
+			std::string *text;
+			u32 number;
+			u32 item;
+			u32 dir;
+		} hudadd;
+		struct{
+			u32 id;
+		} hudrm;
+		struct{
+			u32 id;
+			HudElementStat stat;
+			v2f *v2fdata;
+			std::string *sdata;
+			u32 data;
+		} hudchange;
 	};
 };
 
diff --git a/src/clientserver.h b/src/clientserver.h
index 8b1e0a7e48483a062571303043d97fbc04f2dd0b..6f7bb4402c109e4e18bd228a35be5e34593ca0bb 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -90,9 +90,13 @@ SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time, float time_speed);
 		sound_place added to ItemDefinition
 	PROTOCOL_VERSION 19:
 		GENERIC_CMD_SET_PHYSICS_OVERRIDE
+	PROTOCOL_VERSION 20:
+		TOCLIENT_HUD_ADD
+		TOCLIENT_HUD_RM
+		TOCLIENT_HUD_CHANGE
 */
 
-#define LATEST_PROTOCOL_VERSION 19
+#define LATEST_PROTOCOL_VERSION 20
 
 // Server's supported network protocol range
 #define SERVER_PROTOCOL_VERSION_MIN 13
@@ -433,6 +437,39 @@ enum ToClientCommand
 		u16 command
 		u32 id
 	*/
+
+	TOCLIENT_HUDADD = 0x49,
+	/*
+		u16 command
+		u32 id
+		u8 type
+		v2f1000 pos
+		u32 len
+		u8[len] name
+		v2f1000 scale
+		u32 len2
+		u8[len2] text
+		u32 number
+		u32 item
+		u32 dir
+	*/
+
+	TOCLIENT_HUDRM = 0x50,
+	/*
+		u16 command
+		u32 id
+	*/
+
+	TOCLIENT_HUDCHANGE = 0x51,
+	/*
+		u16 command
+		u32 id
+		u8 stat
+		[v2f1000 data |
+		 u32 len
+		 u8[len] data |
+		 u32 data]
+	*/
 };
 
 enum ToServerCommand
diff --git a/src/collision.cpp b/src/collision.cpp
index cd170196f4ef17e5b10666b0b3cbe9af79c28a6f..673966b6e89df679588db04949fa9cad7b04031b 100644
--- a/src/collision.cpp
+++ b/src/collision.cpp
@@ -192,7 +192,7 @@ bool wouldCollideWithCeiling(
 collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
 		f32 pos_max_d, const aabb3f &box_0,
 		f32 stepheight, f32 dtime,
-		v3f &pos_f, v3f &speed_f, v3f &accel_f)
+		v3f &pos_f, v3f &speed_f, v3f &accel_f,ActiveObject* self)
 {
 	Map *map = &env->getMap();
 	//TimeTaker tt("collisionMoveSimple");
@@ -300,7 +300,9 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
 			c_env->getActiveObjects(pos_f,distance * 1.5,clientobjects);
 			for (int i=0; i < clientobjects.size(); i++)
 			{
-				objects.push_back((ActiveObject*)clientobjects[i].obj);
+				if ((self == 0) || (self != clientobjects[i].obj)) {
+					objects.push_back((ActiveObject*)clientobjects[i].obj);
+				}
 			}
 		}
 		else
@@ -314,7 +316,9 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
 				for (std::set<u16>::iterator iter = s_objects.begin(); iter != s_objects.end(); iter++)
 				{
 					ServerActiveObject *current = s_env->getActiveObject(*iter);
-					objects.push_back((ActiveObject*)current);
+					if ((self == 0) || (self != current)) {
+						objects.push_back((ActiveObject*)current);
+					}
 				}
 			}
 		}
@@ -458,8 +462,9 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
 			if (is_object[nearest_boxindex]) {
 				info.type = COLLISION_OBJECT;
 			}
-			else
+			else {
 				info.type = COLLISION_NODE;
+			}
 			info.node_p = node_positions[nearest_boxindex];
 			info.bouncy = bouncy;
 			info.old_speed = speed_f;
diff --git a/src/collision.h b/src/collision.h
index 1178184567a3821f8a3d84397000fc8f908b0f85..77bf1f15d05ea32661197feb531af6233e50e836 100644
--- a/src/collision.h
+++ b/src/collision.h
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 class Map;
 class IGameDef;
 class Environment;
+class ActiveObject;
 
 enum CollisionType
 {
@@ -70,7 +71,7 @@ struct collisionMoveResult
 collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef,
 		f32 pos_max_d, const aabb3f &box_0,
 		f32 stepheight, f32 dtime,
-		v3f &pos_f, v3f &speed_f, v3f &accel_f);
+		v3f &pos_f, v3f &speed_f, v3f &accel_f,ActiveObject* self=0);
 
 #if 0
 // This doesn't seem to work and isn't used
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index 9738dc34c24eee94deeeec96b00ff112aae1dec8..f79d0d6f62c78d63467b4b75180d6687aae33809 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -1152,7 +1152,7 @@ class GenericCAO : public ClientActiveObject
 				v3f p_acceleration = m_acceleration;
 				moveresult = collisionMoveSimple(env,env->getGameDef(),
 						pos_max_d, box, stepheight, dtime,
-						p_pos, p_velocity, p_acceleration);
+						p_pos, p_velocity, p_acceleration,this);
 				// Apply results
 				m_position = p_pos;
 				m_velocity = p_velocity;
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index e6c8c725c25ff82cd74ef514301ea1917d43d201..3526ecbd2edffb64fa6fc2978c247a6f19ba8a4b 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -502,7 +502,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
 			v3f p_acceleration = m_acceleration;
 			moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
 					pos_max_d, box, stepheight, dtime,
-					p_pos, p_velocity, p_acceleration);
+					p_pos, p_velocity, p_acceleration,this);
 			// Apply results
 			m_base_position = p_pos;
 			m_velocity = p_velocity;
diff --git a/src/emerge.cpp b/src/emerge.cpp
index 499aaf291916d962818f1bccd50967e0d957d33b..049b3cc1276443b04910d3fc32e84f856c9cd661 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -96,9 +96,20 @@ EmergeManager::~EmergeManager() {
 		delete emergethread[i];
 		delete mapgen[i];
 	}
+	emergethread.clear();
+	mapgen.clear();
+
+	for (unsigned int i = 0; i < ores.size(); i++)
+		delete ores[i];
+	ores.clear();
 	
+	for (std::map<std::string, MapgenFactory *>::iterator iter = mglist.begin();
+			iter != mglist.end(); iter ++) {
+		delete iter->second;
+	}
+	mglist.clear();
+
 	delete biomedef;
-	delete params;
 }
 
 
diff --git a/src/game.cpp b/src/game.cpp
index 65feb50bf308921ed0c43eb00859cf9f74afdd56..a2d94ac0a0f07e57750d17bea756a236d751a736 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <IGUIStaticText.h>
 #include <IGUIFont.h>
 #include <IMaterialRendererServices.h>
+#include "IMeshCache.h"
 #include "client.h"
 #include "server.h"
 #include "guiPauseMenu.h"
@@ -58,6 +59,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "subgame.h"
 #include "quicktune_shortcutter.h"
 #include "clientmap.h"
+#include "hud.h"
 #include "sky.h"
 #include "sound.h"
 #if USE_SOUND
@@ -227,137 +229,6 @@ class FormspecFormSource: public IFormSource
 	std::string m_formspec;
 	FormspecFormSource** m_game_formspec;
 };
-/*
-	Hotbar draw routine
-*/
-void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
-		IGameDef *gamedef,
-		v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
-		Inventory *inventory, s32 halfheartcount, u16 playeritem)
-{
-	InventoryList *mainlist = inventory->getList("main");
-	if(mainlist == NULL)
-	{
-		errorstream<<"draw_hotbar(): mainlist == NULL"<<std::endl;
-		return;
-	}
-	
-	s32 padding = imgsize/12;
-	//s32 height = imgsize + padding*2;
-	s32 width = itemcount*(imgsize+padding*2);
-	
-	// Position of upper left corner of bar
-	v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);
-	
-	// Draw background color
-	/*core::rect<s32> barrect(0,0,width,height);
-	barrect += pos;
-	video::SColor bgcolor(255,128,128,128);
-	driver->draw2DRectangle(bgcolor, barrect, NULL);*/
-
-	core::rect<s32> imgrect(0,0,imgsize,imgsize);
-
-	for(s32 i=0; i<itemcount; i++)
-	{
-		const ItemStack &item = mainlist->getItem(i);
-		
-		core::rect<s32> rect = imgrect + pos
-				+ v2s32(padding+i*(imgsize+padding*2), padding);
-		
-		if(playeritem == i)
-		{
-			video::SColor c_outside(255,255,0,0);
-			//video::SColor c_outside(255,0,0,0);
-			//video::SColor c_inside(255,192,192,192);
-			s32 x1 = rect.UpperLeftCorner.X;
-			s32 y1 = rect.UpperLeftCorner.Y;
-			s32 x2 = rect.LowerRightCorner.X;
-			s32 y2 = rect.LowerRightCorner.Y;
-			// Black base borders
-			driver->draw2DRectangle(c_outside,
-					core::rect<s32>(
-						v2s32(x1 - padding, y1 - padding),
-						v2s32(x2 + padding, y1)
-					), NULL);
-			driver->draw2DRectangle(c_outside,
-					core::rect<s32>(
-						v2s32(x1 - padding, y2),
-						v2s32(x2 + padding, y2 + padding)
-					), NULL);
-			driver->draw2DRectangle(c_outside,
-					core::rect<s32>(
-						v2s32(x1 - padding, y1),
-						v2s32(x1, y2)
-					), NULL);
-			driver->draw2DRectangle(c_outside,
-					core::rect<s32>(
-						v2s32(x2, y1),
-						v2s32(x2 + padding, y2)
-					), NULL);
-			/*// Light inside borders
-			driver->draw2DRectangle(c_inside,
-					core::rect<s32>(
-						v2s32(x1 - padding/2, y1 - padding/2),
-						v2s32(x2 + padding/2, y1)
-					), NULL);
-			driver->draw2DRectangle(c_inside,
-					core::rect<s32>(
-						v2s32(x1 - padding/2, y2),
-						v2s32(x2 + padding/2, y2 + padding/2)
-					), NULL);
-			driver->draw2DRectangle(c_inside,
-					core::rect<s32>(
-						v2s32(x1 - padding/2, y1),
-						v2s32(x1, y2)
-					), NULL);
-			driver->draw2DRectangle(c_inside,
-					core::rect<s32>(
-						v2s32(x2, y1),
-						v2s32(x2 + padding/2, y2)
-					), NULL);
-			*/
-		}
-
-		video::SColor bgcolor2(128,0,0,0);
-		driver->draw2DRectangle(bgcolor2, rect, NULL);
-		drawItemStack(driver, font, item, rect, NULL, gamedef);
-	}
-	
-	/*
-		Draw hearts
-	*/
-	video::ITexture *heart_texture =
-		gamedef->getTextureSource()->getTextureRaw("heart.png");
-	if(heart_texture)
-	{
-		v2s32 p = pos + v2s32(0, -20);
-		for(s32 i=0; i<halfheartcount/2; i++)
-		{
-			const video::SColor color(255,255,255,255);
-			const video::SColor colors[] = {color,color,color,color};
-			core::rect<s32> rect(0,0,16,16);
-			rect += p;
-			driver->draw2DImage(heart_texture, rect,
-				core::rect<s32>(core::position2d<s32>(0,0),
-				core::dimension2di(heart_texture->getOriginalSize())),
-				NULL, colors, true);
-			p += v2s32(16,0);
-		}
-		if(halfheartcount % 2 == 1)
-		{
-			const video::SColor color(255,255,255,255);
-			const video::SColor colors[] = {color,color,color,color};
-			core::rect<s32> rect(0,0,16/2,16);
-			rect += p;
-			core::dimension2di srcd(heart_texture->getOriginalSize());
-			srcd.Width /= 2;
-			driver->draw2DImage(heart_texture, rect,
-				core::rect<s32>(core::position2d<s32>(0,0), srcd),
-				NULL, colors, true);
-			p += v2s32(16,0);
-		}
-	}
-}
 
 /*
 	Check if a node is pointable
@@ -943,14 +814,8 @@ void the_game(
 	// Calculate text height using the font
 	u32 text_height = font->getDimension(L"Random test string").Height;
 
-	v2u32 screensize(0,0);
 	v2u32 last_screensize(0,0);
-	screensize = driver->getScreenSize();
-
-	const s32 hotbar_itemcount = 8;
-	//const s32 hotbar_imagesize = 36;
-	//const s32 hotbar_imagesize = 64;
-	s32 hotbar_imagesize = 48;
+	v2u32 screensize = driver->getScreenSize();
 	
 	/*
 		Draw "Loading" screen
@@ -992,6 +857,9 @@ void the_game(
 		sound_is_dummy = true;
 	}
 
+	Server *server = NULL;
+
+	try{
 	// Event manager
 	EventManager eventmgr;
 
@@ -1007,9 +875,8 @@ void the_game(
 
 	/*
 		Create server.
-		SharedPtr will delete it when it goes out of scope.
 	*/
-	SharedPtr<Server> server;
+
 	if(address == ""){
 		draw_load_screen(L"Creating server...", driver, font);
 		infostream<<"Creating server"<<std::endl;
@@ -1018,7 +885,6 @@ void the_game(
 		server->start(port);
 	}
 
-	try{
 	do{ // Client scope (breakable do-while(0))
 	
 	/*
@@ -1373,6 +1239,12 @@ void the_game(
 	LocalPlayer* player = client.getEnv().getLocalPlayer();
 	player->hurt_tilt_timer = 0;
 	player->hurt_tilt_strength = 0;
+	
+	/*
+		HUD object
+	*/
+	Hud hud(driver, guienv, font, text_height,
+			gamedef, player, &local_inventory);
 
 	for(;;)
 	{
@@ -1546,13 +1418,11 @@ void the_game(
 		v2s32 displaycenter(screensize.X/2,screensize.Y/2);
 		//bool screensize_changed = screensize != last_screensize;
 
-		// Resize hotbar
-		if(screensize.Y <= 800)
-			hotbar_imagesize = 32;
-		else if(screensize.Y <= 1280)
-			hotbar_imagesize = 48;
-		else
-			hotbar_imagesize = 64;
+			
+		// Update HUD values
+		hud.screensize    = screensize;
+		hud.displaycenter = displaycenter;
+		hud.resizeHotbar();
 		
 		// Hilight boxes collected during the loop and displayed
 		std::vector<aabb3f> hilightboxes;
@@ -1916,7 +1786,7 @@ void the_game(
 		{
 			s32 wheel = input->getMouseWheel();
 			u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,
-					hotbar_itemcount-1);
+					hud.hotbar_itemcount-1);
 
 			if(wheel < 0)
 			{
@@ -1940,7 +1810,7 @@ void the_game(
 			const KeyPress *kp = NumberKey + (i + 1) % 10;
 			if(input->wasKeyDown(*kp))
 			{
-				if(i < PLAYER_INVENTORY_SIZE && i < hotbar_itemcount)
+				if(i < PLAYER_INVENTORY_SIZE && i < hud.hotbar_itemcount)
 				{
 					new_playeritem = i;
 
@@ -2227,6 +2097,83 @@ void the_game(
 				{
 					delete_particlespawner (event.delete_particlespawner.id);
 				}
+				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])) {
+						delete event.hudadd.pos;
+						delete event.hudadd.name;
+						delete event.hudadd.scale;
+						delete event.hudadd.text;
+						continue;
+					}
+					
+					HudElement *e = new HudElement;
+					e->type   = (HudElementType)event.hudadd.type;
+					e->pos    = *event.hudadd.pos;
+					e->name   = *event.hudadd.name;
+					e->scale  = *event.hudadd.scale;
+					e->text   = *event.hudadd.text;
+					e->number = event.hudadd.number;
+					e->item   = event.hudadd.item;
+					e->dir    = event.hudadd.dir;
+					
+					if (id == nhudelem)
+						player->hud.push_back(e);
+					else
+						player->hud[id] = e;
+
+					delete event.hudadd.pos;
+					delete event.hudadd.name;
+					delete event.hudadd.scale;
+					delete event.hudadd.text;
+				}
+				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_HUDCHANGE)
+				{
+					u32 id = event.hudchange.id;
+					if (id >= player->hud.size() || !player->hud[id]) {
+						delete event.hudchange.v2fdata;
+						delete event.hudchange.sdata;
+						continue;
+					}
+						
+					HudElement* e = player->hud[id];
+					switch (event.hudchange.stat) {
+						case HUD_STAT_POS:
+							e->pos = *event.hudchange.v2fdata;
+							break;
+						case HUD_STAT_NAME:
+							e->name = *event.hudchange.sdata;
+							break;
+						case HUD_STAT_SCALE:
+							e->scale = *event.hudchange.v2fdata;
+							break;
+						case HUD_STAT_TEXT:
+							e->text = *event.hudchange.sdata;
+							break;
+						case HUD_STAT_NUMBER:
+							e->number = event.hudchange.data;
+							break;
+						case HUD_STAT_ITEM:
+							e->item = event.hudchange.data;
+							break;
+						case HUD_STAT_DIR:
+							e->dir = event.hudchange.data;
+							break;
+					}
+					
+					delete event.hudchange.v2fdata;
+					delete event.hudchange.sdata;
+				}
 			}
 		}
 		
@@ -3003,7 +2950,6 @@ void the_game(
 		*/
 
 		TimeTaker tt_draw("mainloop: draw");
-
 		
 		{
 			TimeTaker timer("beginScene");
@@ -3107,26 +3053,8 @@ void the_game(
 
 		driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
 
-		if(show_hud)
-		{
-			v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
-			u32 selectionbox_color_r = rangelim(myround(selectionbox_color.X), 0, 255);
-			u32 selectionbox_color_g = rangelim(myround(selectionbox_color.Y), 0, 255);
-			u32 selectionbox_color_b = rangelim(myround(selectionbox_color.Z), 0, 255);
-
-			for(std::vector<aabb3f>::const_iterator
-					i = hilightboxes.begin();
- 					i != hilightboxes.end(); i++)
-	 		{
-				/*infostream<<"hilightbox min="
-						<<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
-						<<" max="
-						<<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
-						<<std::endl;*/
-				driver->draw3DBox(*i, video::SColor(255,selectionbox_color_r,selectionbox_color_g,selectionbox_color_b));
-			}
-		}
-
+		if (show_hud)
+			hud.drawSelectionBoxes(hilightboxes);
 		/*
 			Wielded tool
 		*/
@@ -3154,22 +3082,9 @@ void the_game(
 		/*
 			Draw crosshair
 		*/
-		if(show_hud)
-		{
-			v3f crosshair_color = g_settings->getV3F("crosshair_color");
-			u32 crosshair_color_r = rangelim(myround(crosshair_color.X), 0, 255);
-			u32 crosshair_color_g = rangelim(myround(crosshair_color.Y), 0, 255);
-			u32 crosshair_color_b = rangelim(myround(crosshair_color.Z), 0, 255);
-			u32 crosshair_alpha = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
-
-			driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
-					displaycenter + core::vector2d<s32>(10,0),
-					video::SColor(crosshair_alpha,crosshair_color_r,crosshair_color_g,crosshair_color_b));
-			driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
-					displaycenter + core::vector2d<s32>(0,10),
-					video::SColor(crosshair_alpha,crosshair_color_r,crosshair_color_g,crosshair_color_b));
-		}
-
+		if (show_hud)
+			hud.drawCrosshair();
+			
 		} // timer
 
 		//timer10.stop();
@@ -3179,11 +3094,9 @@ void the_game(
 		/*
 			Draw hotbar
 		*/
-		if(show_hud)
+		if (show_hud)
 		{
-			draw_hotbar(driver, font, gamedef,
-					v2s32(displaycenter.X, screensize.Y),
-					hotbar_imagesize, hotbar_itemcount, &local_inventory,
+			hud.drawHotbar(v2s32(displaycenter.X, screensize.Y),
 					client.getHP(), client.getPlayerItem());
 		}
 
@@ -3210,6 +3123,12 @@ void the_game(
 				player->hurt_tilt_strength = 0;
 		}
 
+		/*
+			Draw lua hud items
+		*/
+		if (show_hud)
+			hud.drawLuaElements();
+
 		/*
 			Draw gui
 		*/
@@ -3258,11 +3177,11 @@ void the_game(
 	/*
 		Drop stuff
 	*/
-	if(clouds)
+	if (clouds)
 		clouds->drop();
-	if(gui_chat_console)
+	if (gui_chat_console)
 		gui_chat_console->drop();
-	clear_particles ();
+	clear_particles();
 	
 	/*
 		Draw a "shutting down" screen, which will be shown while the map
@@ -3290,14 +3209,44 @@ void the_game(
 				L" running a different version of Minetest.";
 		errorstream<<wide_to_narrow(error_message)<<std::endl;
 	}
+	catch(ServerError &e)
+	{
+		error_message = narrow_to_wide(e.what());
+		errorstream<<wide_to_narrow(error_message)<<std::endl;
+	}
+	catch(ModError &e)
+	{
+		errorstream<<e.what()<<std::endl;
+		error_message = narrow_to_wide(e.what()) + wgettext("\nCheck debug.txt for details.");
+	}
+
+
 	
 	if(!sound_is_dummy)
 		delete sound;
 
+	//has to be deleted first to stop all server threads
+	delete server;
+
 	delete tsrc;
 	delete shsrc;
 	delete nodedef;
 	delete itemdef;
+
+	//extended resource accounting
+	infostream << "Irrlicht resources after cleanup:" << std::endl;
+	infostream << "\tRemaining meshes   : "
+		<< device->getSceneManager()->getMeshCache()->getMeshCount() << std::endl;
+	infostream << "\tRemaining textures : "
+		<< driver->getTextureCount() << std::endl;
+	for (unsigned int i = 0; i < driver->getTextureCount(); i++ ) {
+		irr::video::ITexture* texture = driver->getTextureByIndex(i);
+		infostream << "\t\t" << i << ":" << texture->getName().getPath().c_str()
+				<< std::endl;
+	}
+	infostream << "\tRemaining materials: "
+		<< driver-> getMaterialRendererCount ()
+		<< " (note: irrlicht doesn't support removing renderers)"<< std::endl;
 }
 
 
diff --git a/src/guiConfigureWorld.cpp b/src/guiConfigureWorld.cpp
index 080691222cf00b7dc181cfab29d2cb8552594966..b2debfbd2d5afcc6a3f57cc202324c0cdeceb62e 100644
--- a/src/guiConfigureWorld.cpp
+++ b/src/guiConfigureWorld.cpp
@@ -120,11 +120,12 @@ GUIConfigureWorld::GUIConfigureWorld(gui::IGUIEnvironment* env,
 	}
 	if(!m_new_mod_names.empty())
 	{
+		wchar_t* text = wgettext("Warning: Some mods are not configured yet.\n"
+				"They will be enabled by default when you save the configuration.  ");
 		GUIMessageMenu *menu = 
-			new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
-							   wgettext("Warning: Some mods are not configured yet.\n" 
-										"They will be enabled by default when you save the configuration.  ")); 
+			new GUIMessageMenu(Environment, Parent, -1, m_menumgr, text);
 		menu->drop();
+		delete[] text;
 	}
 	
 
@@ -139,10 +140,11 @@ GUIConfigureWorld::GUIConfigureWorld(gui::IGUIEnvironment* env,
 	}
 	if(!missing_mods.empty())
 	{
+		wchar_t* text = wgettext("Warning: Some configured mods are missing.\n"
+				"Their setting will be removed when you save the configuration.  ");
 		GUIMessageMenu *menu = 
-			new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
-							   wgettext("Warning: Some configured mods are missing.\n"
-										"Their setting will be removed when you save the configuration.  ")); 
+			new GUIMessageMenu(Environment, Parent, -1, m_menumgr, text);
+		delete[] text;
 		for(std::set<std::string>::iterator it = missing_mods.begin();
 			it != missing_mods.end(); ++it)
 			m_settings.remove("load_mod_"+(*it));
@@ -203,30 +205,36 @@ void GUIConfigureWorld::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 200, 20);
 		rect += v2s32(0, 25) + topleft;
+		wchar_t* text = wgettext("enabled");
 		m_enabled_checkbox = 
 			Environment->addCheckBox(false, rect, this, GUI_ID_ENABLED_CHECKBOX, 
-									 wgettext("enabled"));
+									 text);
+		delete[] text;
 		m_enabled_checkbox->setVisible(false);
 	}
 	{
 		core::rect<s32> rect(0, 0, 85, 30);
 		rect = rect + v2s32(0, 25) + topleft;
+		wchar_t* text = wgettext("Enable All");
 		m_enableall = Environment->addButton(rect, this, GUI_ID_ENABLEALL,
-											 wgettext("Enable All"));
+											 text);
+		delete[] text;
 		m_enableall->setVisible(false);
 	}
 	{
 		core::rect<s32> rect(0, 0, 85, 30);
 		rect = rect + v2s32(115, 25) + topleft;
-		m_disableall = Environment->addButton(rect, this, GUI_ID_DISABLEALL,
-											  wgettext("Disable All"));
+		wchar_t* text = wgettext("Disable All");
+		m_disableall = Environment->addButton(rect, this, GUI_ID_DISABLEALL, text );
+		delete[] text;
 		m_disableall->setVisible(false);
 	}
 	{
 		core::rect<s32> rect(0, 0, 200, 20);
 		rect += v2s32(0, 60) + topleft;
-		Environment->addStaticText(wgettext("depends on:"),
-			rect, false, false, this, -1);
+		wchar_t* text = wgettext("depends on:");
+		Environment->addStaticText(text, rect, false, false, this, -1);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 200, 85);
@@ -237,8 +245,9 @@ void GUIConfigureWorld::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 200, 20);
 		rect += v2s32(0, 175) + topleft;
-		Environment->addStaticText(wgettext("is required by:"),
-					rect, false, false, this, -1);
+		wchar_t* text = wgettext("is required by:");
+		Environment->addStaticText( text, rect, false, false, this, -1);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 200, 85);
@@ -258,14 +267,16 @@ void GUIConfigureWorld::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 120, 30);
 		rect = rect + v2s32(330, 270) - topleft;
-		Environment->addButton(rect, this, GUI_ID_CANCEL,
-			wgettext("Cancel"));
+		wchar_t* text = wgettext("Cancel");
+		Environment->addButton(rect, this, GUI_ID_CANCEL, text);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 120, 30);
 		rect = rect + v2s32(460, 270) - topleft;
-		Environment->addButton(rect, this, GUI_ID_SAVE,
-			wgettext("Save"));
+		wchar_t* text = wgettext("Save");
+		Environment->addButton(rect, this, GUI_ID_SAVE, text);
+		delete[] text;
 	}
 	changeCtype("C");
 
@@ -389,17 +400,21 @@ bool GUIConfigureWorld::OnEvent(const SEvent& event)
 				// bug in the text-size calculation. if the trailing
 				// spaces are removed from the message text, the
 				// message gets wrapped and parts of it are cut off:
+				wchar_t* text = wgettext("Configuration saved.  ");
 				GUIMessageMenu *menu = 
 					new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
-									   wgettext("Configuration saved.  "));
+									 text );
+				delete[] text;
 				menu->drop();
 
 				ModConfiguration modconf(m_wspec.path);
 				if(!modconf.isConsistent())
 				{
-					GUIMessageMenu *menu = 
+					wchar_t* text = wgettext("Warning: Configuration not consistent.  ");
+					GUIMessageMenu *menu =
 						new GUIMessageMenu(Environment, Parent, -1, m_menumgr, 
-										   wgettext("Warning: Configuration not consistent.  "));
+										 text );
+					delete[] text;
 					menu->drop();
 				}
 
diff --git a/src/guiConfirmMenu.cpp b/src/guiConfirmMenu.cpp
index 70e33c760158dc963daff10bbb3b3a3efe361f3e..86b2305060691a97f0894ddfb1aae15f510f8954 100644
--- a/src/guiConfirmMenu.cpp
+++ b/src/guiConfirmMenu.cpp
@@ -116,14 +116,18 @@ void GUIConfirmMenu::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, bw, 30);
 		rect = rect + v2s32(size.X/2-bw/2-(bw/2+5), size.Y/2-30/2+5 + msg_h/2);
+		wchar_t* text = wgettext("Yes");
 		Environment->addButton(rect, this, GUI_ID_YES,
-			wgettext("Yes"));
+				text);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, bw, 30);
 		rect = rect + v2s32(size.X/2-bw/2+(bw/2+5), size.Y/2-30/2+5 + msg_h/2);
+		wchar_t* text = wgettext("No");
 		Environment->addButton(rect, this, GUI_ID_NO,
-			wgettext("No"));
+			text);
+		delete[] text;
 	}
 	changeCtype("C");
 }
diff --git a/src/guiCreateWorld.cpp b/src/guiCreateWorld.cpp
index 8ac3fb17c0e8dc8df95045c6e057ed00abe7632f..09b18fb3c7e690708294c31cdeecd8f8522f5365 100644
--- a/src/guiCreateWorld.cpp
+++ b/src/guiCreateWorld.cpp
@@ -113,8 +113,9 @@ void GUICreateWorld::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 100, 20);
 		rect += v2s32(0, 5) + topleft;
-		Environment->addStaticText(wgettext("World name"),
-			rect, false, true, this, -1);
+		wchar_t* text = wgettext("World name");
+		Environment->addStaticText(text, rect, false, true, this, -1);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 300, 30);
@@ -132,8 +133,9 @@ void GUICreateWorld::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 100, 20);
 		rect += v2s32(0, 40+5) + topleft;
-		Environment->addStaticText(wgettext("Game"),
-			rect, false, true, this, -1);
+		wchar_t* text = wgettext("Game");
+		Environment->addStaticText(text, rect, false, true, this, -1);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 300, 80);
@@ -155,14 +157,18 @@ void GUICreateWorld::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 120, 30);
 		rect = rect + v2s32(170, 140) + topleft;
+		wchar_t* text = wgettext("Create");
 		Environment->addButton(rect, this, GUI_ID_CREATE,
-			wgettext("Create"));
+			text);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 120, 30);
 		rect = rect + v2s32(300, 140) + topleft;
+		wchar_t* text = wgettext("Cancel");
 		Environment->addButton(rect, this, GUI_ID_CANCEL,
-			wgettext("Cancel"));
+			text);
+		delete [] text;
 	}
 	changeCtype("C");
 }
diff --git a/src/guiDeathScreen.cpp b/src/guiDeathScreen.cpp
index ba329e3bef9326e065150af4b3706941a40d4a61..dfdce3f8db136ae10c6364c3d336b6f9eefd1a8a 100644
--- a/src/guiDeathScreen.cpp
+++ b/src/guiDeathScreen.cpp
@@ -93,15 +93,19 @@ void GUIDeathScreen::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 400, 50);
 		rect = rect + v2s32(size.X/2-400/2, size.Y/2-50/2-25);
-		Environment->addStaticText(wgettext("You died."), rect, false,
+		wchar_t* text = wgettext("You died.");
+		Environment->addStaticText(text, rect, false,
 				true, this, 256);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 140, 30);
 		rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+25);
+		wchar_t* text = wgettext("Respawn");
 		gui::IGUIElement *e = 
 		Environment->addButton(rect, this, 257,
-			wgettext("Respawn"));
+			text);
+		delete[] text;
 		Environment->setFocus(e);
 	}
 	changeCtype("C");
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp
index 1754422d08637eeee0f2e1126030a1b2d6742e98..6ada77698d2acd38f5a4dd3d43cab14a02bc3a60 100644
--- a/src/guiFormSpecMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -581,6 +581,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
 				size.Y-rect.getHeight()-5);
 		const wchar_t *text = wgettext("Left click: Move all items, Right click: Move single item");
 		Environment->addStaticText(text, rect, false, true, this, 256);
+		delete[] text;
 		changeCtype("C");
 	}
 	// If there's fields, add a Proceed button
@@ -604,7 +605,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
 
 			v2s32 size = DesiredRect.getSize();
 			rect = core::rect<s32>(size.X/2-70, pos.Y, (size.X/2-70)+140, pos.Y+30);
-			Environment->addButton(rect, this, 257, wgettext("Proceed"));
+			wchar_t* text = wgettext("Proceed");
+			Environment->addButton(rect, this, 257, text);
+			delete[] text;
 		}
 		changeCtype("C");
 	}
diff --git a/src/guiKeyChangeMenu.cpp b/src/guiKeyChangeMenu.cpp
index 4569f3d9dcf519cdb55e4ec0dfb363b1b724f7e5..c660ed870be829f835c6093a7141960f63733c7b 100644
--- a/src/guiKeyChangeMenu.cpp
+++ b/src/guiKeyChangeMenu.cpp
@@ -75,6 +75,13 @@ GUIModalMenu(env, parent, id, menumgr)
 GUIKeyChangeMenu::~GUIKeyChangeMenu()
 {
 	removeChildren();
+
+	for (std::vector<key_setting*>::iterator iter = key_settings.begin();
+			iter != key_settings.end(); iter ++) {
+		delete[] (*iter)->button_name;
+		delete (*iter);
+	}
+	key_settings.clear();
 }
 
 void GUIKeyChangeMenu::removeChildren()
@@ -111,8 +118,10 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
 		core::rect < s32 > rect(0, 0, 600, 40);
 		rect += topleft + v2s32(25, 3);
 		//gui::IGUIStaticText *t =
-		Environment->addStaticText(wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)"),
+		wchar_t* text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
+		Environment->addStaticText(text,
 								   rect, false, true, this, -1);
+		delete[] text;
 		//t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
 	}
 
@@ -132,7 +141,9 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect < s32 > rect(0, 0, 100, 30);
 			rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
-			k->button = Environment->addButton(rect, this, k->id, wgettext(k->key.name()));
+			wchar_t* text = wgettext(k->key.name());
+			k->button = Environment->addButton(rect, this, k->id, text );
+			delete[] text;
 		}
 		if(i + 1 == KMaxButtonPerColumns)
 			offset = v2s32(250, 60);
@@ -147,8 +158,10 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, option_w, 30);
 			rect += topleft + v2s32(option_x, option_y);
+			wchar_t* text = wgettext("\"Use\" = climb down");
 			Environment->addCheckBox(g_settings->getBool("aux1_descends"), rect, this,
-					GUI_ID_CB_AUX1_DESCENDS, wgettext("\"Use\" = climb down"));
+					GUI_ID_CB_AUX1_DESCENDS, text);
+			delete[] text;
 		}
 		offset += v2s32(0, 25);
 	}
@@ -160,8 +173,10 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, option_w, 30);
 			rect += topleft + v2s32(option_x, option_y);
+			wchar_t* text = wgettext("Double tap \"jump\" to toggle fly");
 			Environment->addCheckBox(g_settings->getBool("doubletap_jump"), rect, this,
-					GUI_ID_CB_DOUBLETAP_JUMP, wgettext("Double tap \"jump\" to toggle fly"));
+					GUI_ID_CB_DOUBLETAP_JUMP, text);
+			delete[] text;
 		}
 		offset += v2s32(0, 25);
 	}
@@ -169,14 +184,18 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
 	{
 		core::rect < s32 > rect(0, 0, 100, 30);
 		rect += topleft + v2s32(size.X - 100 - 20, size.Y - 40);
+		wchar_t* text =  wgettext("Save");
 		Environment->addButton(rect, this, GUI_ID_BACK_BUTTON,
-							   wgettext("Save"));
+							 text);
+		delete[] text;
 	}
 	{
 		core::rect < s32 > rect(0, 0, 100, 30);
 		rect += topleft + v2s32(size.X - 100 - 20 - 100 - 20, size.Y - 40);
+		wchar_t* text = wgettext("Cancel");
 		Environment->addButton(rect, this, GUI_ID_ABORT_BUTTON,
-							   wgettext("Cancel"));
+							 text );
+		delete[] text;
 	}
 	changeCtype("C");
 	
@@ -230,7 +249,9 @@ bool GUIKeyChangeMenu::resetMenu()
 			key_setting *k = key_settings.at(i);
 			if(k->id == activeKey)
 			{
-				k->button->setText(wgettext(k->key.name()));
+				wchar_t* text = wgettext(k->key.name());
+				k->button->setText(text);
+				delete[] text;
 				break;
 			}
 		}
@@ -266,8 +287,10 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
 		{
 			core::rect < s32 > rect(0, 0, 600, 40);
 			rect += v2s32(0, 0) + v2s32(25, 30);
-			this->key_used_text = Environment->addStaticText(wgettext("Key already in use"),
+			wchar_t* text = wgettext("Key already in use");
+			this->key_used_text = Environment->addStaticText(text,
 									rect, false, true, this, -1);
+			delete[] text;
 			//infostream << "Key already in use" << std::endl;
 		}
 
@@ -284,7 +307,9 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
 			}
 			assert(k);
 			k->key = kp;
-			k->button->setText(wgettext(k->key.name()));
+			wchar_t* text = wgettext(k->key.name());
+			k->button->setText(text);
+			delete[] text;
 
 			this->key_used.push_back(kp);
 
@@ -344,7 +369,9 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
 					resetMenu();
 					shift_down = false;
 					activeKey = event.GUIEvent.Caller->getID();
-					k->button->setText(wgettext("press key"));
+					wchar_t* text = wgettext("press key");
+					k->button->setText(text);
+					delete[] text;
 					this->key_used.erase(std::remove(this->key_used.begin(),
 							this->key_used.end(), k->key), this->key_used.end());
 					break;
@@ -357,11 +384,12 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
 	return Parent ? Parent->OnEvent(event) : false;
 }
 
-void GUIKeyChangeMenu::add_key(int id, std::string button_name, std::string setting_name)
+void GUIKeyChangeMenu::add_key(int id, wchar_t* button_name, std::string setting_name)
 {
 	key_setting *k = new key_setting;
 	k->id = id;
-	k->button_name = wgettext(button_name.c_str());
+
+	k->button_name = button_name;
 	k->setting_name = setting_name;
 	k->key = getKeySetting(k->setting_name.c_str());
 	key_settings.push_back(k);
@@ -369,21 +397,21 @@ void GUIKeyChangeMenu::add_key(int id, std::string button_name, std::string sett
 
 void GUIKeyChangeMenu::init_keys()
 {
-	this->add_key(GUI_ID_KEY_FORWARD_BUTTON, gettext("Forward"), "keymap_forward");
-	this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, gettext("Backward"), "keymap_backward");
-	this->add_key(GUI_ID_KEY_LEFT_BUTTON, gettext("Left"), "keymap_left");
-	this->add_key(GUI_ID_KEY_RIGHT_BUTTON, gettext("Right"), "keymap_right");
-	this->add_key(GUI_ID_KEY_USE_BUTTON, gettext("Use"), "keymap_special1");
-	this->add_key(GUI_ID_KEY_JUMP_BUTTON, gettext("Jump"), "keymap_jump");
-	this->add_key(GUI_ID_KEY_SNEAK_BUTTON, gettext("Sneak"), "keymap_sneak");
-	this->add_key(GUI_ID_KEY_DROP_BUTTON, gettext("Drop"), "keymap_drop");
-	this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, gettext("Inventory"), "keymap_inventory");
-	this->add_key(GUI_ID_KEY_CHAT_BUTTON, gettext("Chat"), "keymap_chat");
-	this->add_key(GUI_ID_KEY_CMD_BUTTON, gettext("Command"), "keymap_cmd");
-	this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, gettext("Console"), "keymap_console");
-	this->add_key(GUI_ID_KEY_FLY_BUTTON, gettext("Toggle fly"), "keymap_freemove");
-	this->add_key(GUI_ID_KEY_FAST_BUTTON, gettext("Toggle fast"), "keymap_fastmove");
-	this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, gettext("Toggle noclip"), "keymap_noclip");
-	this->add_key(GUI_ID_KEY_RANGE_BUTTON, gettext("Range select"), "keymap_rangeselect");
-	this->add_key(GUI_ID_KEY_DUMP_BUTTON, gettext("Print stacks"), "keymap_print_debug_stacks");
+	this->add_key(GUI_ID_KEY_FORWARD_BUTTON,   wgettext("Forward"),       "keymap_forward");
+	this->add_key(GUI_ID_KEY_BACKWARD_BUTTON,  wgettext("Backward"),      "keymap_backward");
+	this->add_key(GUI_ID_KEY_LEFT_BUTTON,      wgettext("Left"),          "keymap_left");
+	this->add_key(GUI_ID_KEY_RIGHT_BUTTON,     wgettext("Right"),         "keymap_right");
+	this->add_key(GUI_ID_KEY_USE_BUTTON,       wgettext("Use"),           "keymap_special1");
+	this->add_key(GUI_ID_KEY_JUMP_BUTTON,      wgettext("Jump"),          "keymap_jump");
+	this->add_key(GUI_ID_KEY_SNEAK_BUTTON,     wgettext("Sneak"),         "keymap_sneak");
+	this->add_key(GUI_ID_KEY_DROP_BUTTON,      wgettext("Drop"),          "keymap_drop");
+	this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"),     "keymap_inventory");
+	this->add_key(GUI_ID_KEY_CHAT_BUTTON,      wgettext("Chat"),          "keymap_chat");
+	this->add_key(GUI_ID_KEY_CMD_BUTTON,       wgettext("Command"),       "keymap_cmd");
+	this->add_key(GUI_ID_KEY_CONSOLE_BUTTON,   wgettext("Console"),       "keymap_console");
+	this->add_key(GUI_ID_KEY_FLY_BUTTON,       wgettext("Toggle fly"),    "keymap_freemove");
+	this->add_key(GUI_ID_KEY_FAST_BUTTON,      wgettext("Toggle fast"),   "keymap_fastmove");
+	this->add_key(GUI_ID_KEY_NOCLIP_BUTTON,    wgettext("Toggle noclip"), "keymap_noclip");
+	this->add_key(GUI_ID_KEY_RANGE_BUTTON,     wgettext("Range select"),  "keymap_rangeselect");
+	this->add_key(GUI_ID_KEY_DUMP_BUTTON,      wgettext("Print stacks"),  "keymap_print_debug_stacks");
 }
diff --git a/src/guiKeyChangeMenu.h b/src/guiKeyChangeMenu.h
index 2b498676b2691d16d35e48f5bde4375d9bedf48b..833514c1d98d2e8478d86afb6d614294bec4d49d 100644
--- a/src/guiKeyChangeMenu.h
+++ b/src/guiKeyChangeMenu.h
@@ -64,7 +64,7 @@ class GUIKeyChangeMenu: public GUIModalMenu
 
 	bool resetMenu();
 
-	void add_key(int id, std::string setting_name, std::string button_name);
+	void add_key(int id, wchar_t* button_name, std::string setting_name);
 
 	bool shift_down;
 	
diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp
index 1e30835776a55bcf354b7a55c258210c6ba1a190..431b40e6363d557ee3a0aa1500ca2a58105599ef 100644
--- a/src/guiMainMenu.cpp
+++ b/src/guiMainMenu.cpp
@@ -89,7 +89,9 @@ struct CreateWorldDestMainMenu : public CreateWorldDest
 		std::string name_narrow = wide_to_narrow(name);
 		if(!string_allowed_blacklist(name_narrow, WORLDNAME_BLACKLISTED_CHARS))
 		{
-			m_menu->displayMessageMenu(wgettext("Cannot create world: Name contains invalid characters"));
+			wchar_t* text = wgettext("Cannot create world: Name contains invalid characters");
+			m_menu->displayMessageMenu(text);
+			delete[] text;
 			return;
 		}
 		std::vector<WorldSpec> worlds = getAvailableWorlds();
@@ -98,7 +100,9 @@ struct CreateWorldDestMainMenu : public CreateWorldDest
 		{
 			if((*i).name == name_narrow)
 			{
-				m_menu->displayMessageMenu(wgettext("Cannot create world: A world by this name already exists"));
+				wchar_t* text = wgettext("Cannot create world: A world by this name already exists");
+				m_menu->displayMessageMenu(text);
+				delete[] text;
 				return;
 			}
 		}
@@ -280,12 +284,24 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		rect += m_topleft_client + v2s32(0, -30);
 		gui::IGUITabControl *e = Environment->addTabControl(
 				rect, this, true, true, GUI_ID_TAB_CONTROL);
-		e->addTab(wgettext("Singleplayer"));
-		e->addTab(wgettext("Multiplayer"));
-		e->addTab(wgettext("Advanced"));
-		e->addTab(wgettext("Settings"));
-		e->addTab(wgettext("Credits"));
+		wchar_t* text = wgettext("Singleplayer");
+		e->addTab(text);
+		delete[] text;
+		text = wgettext("Multiplayer");
+		e->addTab(text);
+		delete[] text;
+		text = wgettext("Advanced");
+		e->addTab(text);
+		delete[] text;
+		text = wgettext("Settings");
+		e->addTab(text);
+		delete[] text;
+		text = wgettext("Credits");
+		e->addTab(text);
+		delete[] text;
+
 		e->setActiveTab(m_data->selected_tab);
+
 	}
 	
 	if(m_data->selected_tab == TAB_SINGLEPLAYER)
@@ -313,9 +329,11 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, world_sel_w-4, 20);
 			rect += m_topleft_client + v2s32(world_sel_x+4, world_sel_y-20);
+			wchar_t* text = wgettext("Select World:");
 			/*gui::IGUIStaticText *e =*/ Environment->addStaticText(
-					wgettext("Select World:"), 
+					text,
 					rect, false, true, this, -1);
+			delete[] text;
 			/*e->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);*/
 		}
 		{
@@ -335,23 +353,29 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, world_button_w, 30);
 			rect += m_topleft_client + v2s32(world_sel_x, world_sel_y+world_sel_h+0);
+			wchar_t* text = wgettext("Delete");
 			Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
-				  wgettext("Delete"));
+				 text);
+			delete[] text;
 		}
 		// Create world button
 		{
 			core::rect<s32> rect(0, 0, world_button_w, 30);
 			rect += m_topleft_client + v2s32(world_sel_x+world_button_w+bs, world_sel_y+world_sel_h+0);
+			wchar_t* text = wgettext("New");
 			Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON,
-				  wgettext("New"));
+				 text);
+			delete[] text;
 		}
 		// Configure world button
 		{
 			core::rect<s32> rect(0, 0, world_button_w, 30);
 			rect += m_topleft_client + v2s32(world_sel_x+(world_button_w+bs)*2,
 					world_sel_y+world_sel_h+0);
+			wchar_t* text = wgettext("Configure");
 			Environment->addButton(rect, this, GUI_ID_CONFIGURE_WORLD_BUTTON,
-				  wgettext("Configure"));
+				text);
+			delete[] text;
 		}
 		// Start game button
 		{
@@ -365,8 +389,10 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 			core::rect<s32> rect(0, 0, bw, 30);
 			rect += m_topleft_client + v2s32(world_sel_x+world_sel_w-bw,
 					world_sel_y+world_sel_h+30+bs);
+			wchar_t* text = wgettext("Play");
 			Environment->addButton(rect, this,
-					GUI_ID_JOIN_GAME_BUTTON, wgettext("Play"));
+					GUI_ID_JOIN_GAME_BUTTON, text);
+			delete[] text;
 		}
 		// Options
 		s32 option_x = 50;
@@ -376,14 +402,18 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, option_w, 30);
 			rect += m_topleft_client + v2s32(option_x, option_y+20*0);
+			wchar_t* text = wgettext("Creative Mode");
 			Environment->addCheckBox(m_data->creative_mode, rect, this,
-					GUI_ID_CREATIVE_CB, wgettext("Creative Mode"));
+					GUI_ID_CREATIVE_CB, text);
+			delete[] text;
 		}
 		{
 			core::rect<s32> rect(0, 0, option_w, 30);
 			rect += m_topleft_client + v2s32(option_x, option_y+20*1);
+			wchar_t* text = wgettext("Enable Damage");
 			Environment->addCheckBox(m_data->enable_damage, rect, this,
-					GUI_ID_DAMAGE_CB, wgettext("Enable Damage"));
+					GUI_ID_DAMAGE_CB, text);
+			delete[] text;
 		}
 		changeCtype("C");
 	}
@@ -402,9 +432,11 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		// Nickname + password
 		{
 			core::rect<s32> rect(0, 0, 110, 20);
+			wchar_t* text = wgettext("Name/Password");
 			rect += m_topleft_client + v2s32(m_size_client.X-60-100, 10+6);
-			Environment->addStaticText(wgettext("Name/Password"), 
+			Environment->addStaticText(text,
 				rect, false, true, this, -1);
+			delete [] text;
 		}
 		changeCtype("C");
 		{
@@ -467,8 +499,10 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, 110, 20);
 			rect += m_topleft_client + v2s32(50, m_size_client.Y-50-15+6);
-			Environment->addStaticText(wgettext("Address/Port"),
+			wchar_t* text = wgettext("Address/Port");
+			Environment->addStaticText(text,
 				rect, false, true, this, -1);
+			delete [] text;
 		}
 		changeCtype("C");
 		{
@@ -493,13 +527,17 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 			core::rect<s32> rect(0, 0, 260, 30);
 			rect += m_topleft_client + v2s32(50,
 					180);
+			wchar_t* text = wgettext("Show Public");
 			gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_TOGGLE,
-				wgettext("Show Public"));
+				text);
+			delete[] text;
 			e->setIsPushButton(true);
 			if (m_data->selected_serverlist == SERVERLIST_PUBLIC)
 			{
-				e->setText(wgettext("Show Favorites"));
+				wchar_t* text = wgettext("Show Favorites");
+				e->setText(text);
 				e->setPressed();
+				delete[] text;
 			}
 		}
 		#endif
@@ -507,18 +545,23 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, 120, 30);
 			rect += m_topleft_client + v2s32(50+260+10, 180);
+			wchar_t* text = wgettext("Delete");
 			gui::IGUIButton *e = Environment->addButton(rect, this, GUI_ID_SERVERLIST_DELETE,
-				wgettext("Delete"));
+					text);
 			if (m_data->selected_serverlist == SERVERLIST_PUBLIC) // Hidden when on public list
 				e->setVisible(false);
+
+			delete [] text;
 		}
 		// Start game button
 		{
 			core::rect<s32> rect(0, 0, 120, 30);
 			rect += m_topleft_client + v2s32(m_size_client.X-130-30,
 					m_size_client.Y-25-15);
+			wchar_t* text = wgettext("Connect");
 			Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
-				wgettext("Connect"));
+				text);
+			delete[] text;
 		}
 		changeCtype("C");
 	}
@@ -538,8 +581,10 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, 110, 20);
 			rect += m_topleft_client + v2s32(35+30, 35+6);
-			Environment->addStaticText(wgettext("Name/Password"), 
+			wchar_t* text = wgettext("Name/Password");
+			Environment->addStaticText(text,
 				rect, false, true, this, -1);
+			delete [] text;
 		}
 		changeCtype("C");
 		{
@@ -565,8 +610,10 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, 110, 20);
 			rect += m_topleft_client + v2s32(35+30, 75+6);
-			Environment->addStaticText(wgettext("Address/Port"),
+			wchar_t* text = wgettext("Address/Port");
+			Environment->addStaticText(text,
 				rect, false, true, this, -1);
+			delete[] text;
 		}
 		changeCtype("C");
 		{
@@ -588,16 +635,20 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, 400, 20);
 			rect += m_topleft_client + v2s32(160+30, 75+35);
-			Environment->addStaticText(wgettext("Leave address blank to start a local server."),
+			wchar_t* text = wgettext("Leave address blank to start a local server.");
+			Environment->addStaticText(text,
 				rect, false, true, this, -1);
+			delete[] text;
 		}
 		// Start game button
 		{
 			core::rect<s32> rect(0, 0, 180, 30);
 			rect += m_topleft_client + v2s32(m_size_client.X-180-30,
 					m_size_client.Y-30-20);
+			wchar_t* text = wgettext("Start Game / Connect");
 			Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
-				wgettext("Start Game / Connect"));
+				text);
+			delete[] text;
 		}
 		/*
 			Server section
@@ -615,36 +666,46 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, 250, 30);
 			rect += m_topleft_server + v2s32(30+20+250+20, 20);
+			wchar_t* text = wgettext("Creative Mode");
 			Environment->addCheckBox(m_data->creative_mode, rect, this, GUI_ID_CREATIVE_CB,
-				wgettext("Creative Mode"));
+				text);
+			delete[] text;
 		}
 		{
 			core::rect<s32> rect(0, 0, 250, 30);
 			rect += m_topleft_server + v2s32(30+20+250+20, 40);
+			wchar_t* text = wgettext("Enable Damage");
 			Environment->addCheckBox(m_data->enable_damage, rect, this, GUI_ID_DAMAGE_CB,
-				wgettext("Enable Damage"));
+				text);
+			delete[] text;
 		}
 		#if USE_CURL
 		{
 			core::rect<s32> rect(0, 0, 250, 30);
 			rect += m_topleft_server + v2s32(30+20+250+20, 60);
+			wchar_t* text = wgettext("Public");
 			Environment->addCheckBox(m_data->enable_public, rect, this, GUI_ID_PUBLIC_CB,
-				wgettext("Public"));
+				text);
+			delete[] text;
 		}
 		#endif
 		// Delete world button
 		{
 			core::rect<s32> rect(0, 0, 130, 30);
 			rect += m_topleft_server + v2s32(30+20+250+20, 90);
+			wchar_t* text = wgettext("Delete world");
 			Environment->addButton(rect, this, GUI_ID_DELETE_WORLD_BUTTON,
-				  wgettext("Delete world"));
+				 text );
+			delete[] text;
 		}
 		// Create world button
 		{
 			core::rect<s32> rect(0, 0, 130, 30);
 			rect += m_topleft_server + v2s32(30+20+250+20+140, 90);
+			wchar_t* text = wgettext("Create world");
 			Environment->addButton(rect, this, GUI_ID_CREATE_WORLD_BUTTON,
-				  wgettext("Create world"));
+				 text );
+			delete[] text;
 		}
 		// World selection listbox
 		{
@@ -677,26 +738,34 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, option_w, 30);
 			rect += m_topleft_client + v2s32(option_x, option_y);
+			wchar_t* text = wgettext("Fancy trees");
 			Environment->addCheckBox(m_data->fancy_trees, rect, this,
-					GUI_ID_FANCYTREE_CB, wgettext("Fancy trees")); 
+					GUI_ID_FANCYTREE_CB, text);
+			delete[] text;
 		}
 		{
 			core::rect<s32> rect(0, 0, option_w, 30);
 			rect += m_topleft_client + v2s32(option_x, option_y+20);
+			wchar_t* text = wgettext("Smooth Lighting");
 			Environment->addCheckBox(m_data->smooth_lighting, rect, this,
-					GUI_ID_SMOOTH_LIGHTING_CB, wgettext("Smooth Lighting"));
+					GUI_ID_SMOOTH_LIGHTING_CB, text);
+			delete[] text;
 		}
 		{
 			core::rect<s32> rect(0, 0, option_w, 30);
 			rect += m_topleft_client + v2s32(option_x, option_y+20*2);
+			wchar_t* text = wgettext("3D Clouds");
 			Environment->addCheckBox(m_data->clouds_3d, rect, this,
-					GUI_ID_3D_CLOUDS_CB, wgettext("3D Clouds"));
+					GUI_ID_3D_CLOUDS_CB, text);
+			delete[] text;
 		}
 		{
 			core::rect<s32> rect(0, 0, option_w, 30);
 			rect += m_topleft_client + v2s32(option_x, option_y+20*3);
+			wchar_t* text = wgettext("Opaque water");
 			Environment->addCheckBox(m_data->opaque_water, rect, this,
-					GUI_ID_OPAQUE_WATER_CB, wgettext("Opaque water"));
+					GUI_ID_OPAQUE_WATER_CB, text);
+			delete[] text;
 		}
 
 
@@ -705,58 +774,74 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, option_w+20, 30);
 			rect += m_topleft_client + v2s32(option_x+175, option_y);
+			wchar_t* text = wgettext("Mip-Mapping");
 			Environment->addCheckBox(m_data->mip_map, rect, this,
-				       GUI_ID_MIPMAP_CB, wgettext("Mip-Mapping"));
+				       GUI_ID_MIPMAP_CB, text);
+			delete[] text;
 		}
 
 		{
 			core::rect<s32> rect(0, 0, option_w+20, 30);
 			rect += m_topleft_client + v2s32(option_x+175, option_y+20);
+			wchar_t* text = wgettext("Anisotropic Filtering");
 			Environment->addCheckBox(m_data->anisotropic_filter, rect, this,
-				       GUI_ID_ANISOTROPIC_CB, wgettext("Anisotropic Filtering"));
+				       GUI_ID_ANISOTROPIC_CB, text);
+			delete[] text;
 		}
 
 		{
 			core::rect<s32> rect(0, 0, option_w+20, 30);
 			rect += m_topleft_client + v2s32(option_x+175, option_y+20*2);
+			wchar_t* text = wgettext("Bi-Linear Filtering");
 			Environment->addCheckBox(m_data->bilinear_filter, rect, this,
-				       GUI_ID_BILINEAR_CB, wgettext("Bi-Linear Filtering"));
+				       GUI_ID_BILINEAR_CB, text);
+			delete[] text;
 		}
 
 		{
 			core::rect<s32> rect(0, 0, option_w+20, 30);
 			rect += m_topleft_client + v2s32(option_x+175, option_y+20*3);
+			wchar_t* text = wgettext("Tri-Linear Filtering");
 			Environment->addCheckBox(m_data->trilinear_filter, rect, this,
-				       GUI_ID_TRILINEAR_CB, wgettext("Tri-Linear Filtering"));
+				       GUI_ID_TRILINEAR_CB, text);
+			delete[] text;
 		}
 
 		// shader/on demand image loading/particles settings
 		{
 			core::rect<s32> rect(0, 0, option_w+20, 30);
 			rect += m_topleft_client + v2s32(option_x+175*2, option_y);
+			wchar_t* text = wgettext("Shaders");
 			Environment->addCheckBox(m_data->enable_shaders, rect, this,
-					GUI_ID_SHADERS_CB, wgettext("Shaders"));
+					GUI_ID_SHADERS_CB, text);
+			delete[] text;
 		}
 
 		{
 			core::rect<s32> rect(0, 0, option_w+20+20, 30);
 			rect += m_topleft_client + v2s32(option_x+175*2, option_y+20);
+			wchar_t* text = wgettext("Preload item visuals");
 			Environment->addCheckBox(m_data->preload_item_visuals, rect, this,
-					GUI_ID_PRELOAD_ITEM_VISUALS_CB, wgettext("Preload item visuals"));
+					GUI_ID_PRELOAD_ITEM_VISUALS_CB, text);
+			delete[] text;
 		}
 
 		{
 			core::rect<s32> rect(0, 0, option_w+20+20, 30);
 			rect += m_topleft_client + v2s32(option_x+175*2, option_y+20*2);
+			wchar_t* text = wgettext("Enable Particles");
 			Environment->addCheckBox(m_data->enable_particles, rect, this,
-					GUI_ID_ENABLE_PARTICLES_CB, wgettext("Enable Particles"));
+					GUI_ID_ENABLE_PARTICLES_CB, text);
+			delete[] text;
 		}
 
 		{
 			core::rect<s32> rect(0, 0, option_w+20+20, 30);
 			rect += m_topleft_client + v2s32(option_x+175*2, option_y+20*3);
+			wchar_t* text = wgettext("Finite liquid");
 			Environment->addCheckBox(m_data->liquid_finite, rect, this,
-					GUI_ID_LIQUID_FINITE_CB, wgettext("Finite liquid"));
+					GUI_ID_LIQUID_FINITE_CB, text);
+			delete[] text;
 		}
 
 		// Key change button
@@ -765,8 +850,10 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
 			/*rect += m_topleft_client + v2s32(m_size_client.X-120-30,
 					m_size_client.Y-30-20);*/
 			rect += m_topleft_client + v2s32(option_x, option_y+120);
+			wchar_t* text = wgettext("Change keys");
 			Environment->addButton(rect, this,
-					GUI_ID_CHANGE_KEYS_BUTTON, wgettext("Change keys"));
+					GUI_ID_CHANGE_KEYS_BUTTON, text);
+			delete[] text;
 		}
 		changeCtype("C");
 	}
@@ -1080,9 +1167,11 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 				readInput(&cur);
 				if (getTab() == TAB_MULTIPLAYER && cur.address == L"")
 				{
+					wchar_t* text = wgettext("Address required.");
 					(new GUIMessageMenu(env, parent, -1, menumgr,
-							wgettext("Address required."))
+							text)
 							)->drop();
+					delete[] text;
 					return true;
 				}
 				acceptInput();
@@ -1098,9 +1187,11 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 				MainMenuData cur;
 				readInput(&cur);
 				if(cur.selected_world == -1){
+					wchar_t* text = wgettext("Cannot delete world: Nothing selected");
 					(new GUIMessageMenu(env, parent, -1, menumgr,
-							wgettext("Cannot delete world: Nothing selected"))
+							text)
 							)->drop();
+					delete[] text;
 				} else {
 					WorldSpec spec = m_data->worlds[cur.selected_world];
 					// Get files and directories involved
@@ -1110,12 +1201,16 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 					// Launch confirmation dialog
 					ConfirmDestDeleteWorld *dest = new
 							ConfirmDestDeleteWorld(spec, this, paths);
-					std::wstring text = wgettext("Delete world");
+					wchar_t* text1 = wgettext("Delete world");
+					wchar_t* text2 = wgettext("Files to be deleted");
+					std::wstring text = text1;
 					text += L" \"";
 					text += narrow_to_wide(spec.name);
 					text += L"\"?\n\n";
-					text += wgettext("Files to be deleted");
+					text += text2;
 					text += L":\n";
+					delete[] text1;
+					delete[] text2;
 					for(u32 i=0; i<paths.size(); i++){
 						if(i == 3){ text += L"..."; break; }
 						text += narrow_to_wide(paths[i]) + L"\n";
@@ -1128,10 +1223,12 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 			case GUI_ID_CREATE_WORLD_BUTTON: {
 				std::vector<SubgameSpec> games = getAvailableGames();
 				if(games.size() == 0){
+					wchar_t* text = wgettext("Cannot create world: No games found");
 					GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
 							-1, menumgr,
-							wgettext("Cannot create world: No games found"));
+							text);
 					menu->drop();
+					delete[] text;
 				} else {
 					CreateWorldDest *dest = new CreateWorldDestMainMenu(this);
 					GUICreateWorld *menu = new GUICreateWorld(env, parent, -1,
@@ -1145,9 +1242,11 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 				readInput(&cur);
 				if(cur.selected_world == -1)
 				{
+					wchar_t* text = wgettext("Cannot configure world: Nothing selected");
 					(new GUIMessageMenu(env, parent, -1, menumgr,
-							wgettext("Cannot configure world: Nothing selected"))
+							text)
 							)->drop();
+					delete[] text;
 				} 
 				else 
 				{
@@ -1180,8 +1279,12 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 				if (m_data->selected_serverlist == SERVERLIST_PUBLIC) // switch to favorite list
 				{
 					m_data->servers = ServerList::getLocal();
-					togglebutton->setText(wgettext("Show Public"));
-					title->setText(wgettext("Favorites:"));
+					wchar_t* text1 = wgettext("Show Public");
+					wchar_t* text2 = wgettext("Favorites:");
+					togglebutton->setText(text1);
+					title->setText(text2);
+					delete[] text1;
+					delete[] text2;
 					deletebutton->setVisible(true);
 					updateGuiServerList();
 					serverlist->setSelected(0);
@@ -1190,8 +1293,12 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
 				else // switch to online list
 				{
 					m_data->servers = ServerList::getOnline();
-					togglebutton->setText(wgettext("Show Favorites"));
-					title->setText(wgettext("Public Server List:"));
+					wchar_t* text1 = wgettext("Show Favorites");
+					wchar_t* text2 = wgettext("Public Server List:");
+					togglebutton->setText(text1);
+					title->setText(text2);
+					delete[] text1;
+					delete[] text2;
 					deletebutton->setVisible(false);
 					updateGuiServerList();
 					serverlist->setSelected(0);
@@ -1261,8 +1368,10 @@ void GUIMainMenu::deleteWorld(const std::vector<std::string> &paths)
 	// Delete files
 	bool did = fs::DeletePaths(paths);
 	if(!did){
+		wchar_t* text = wgettext("Failed to delete all world files");
 		GUIMessageMenu *menu = new GUIMessageMenu(env, parent,
-				-1, menumgr, wgettext("Failed to delete all world files"));
+				-1, menumgr, text);
+		delete[] text;
 		menu->drop();
 	}
 	// Quit menu to refresh it
diff --git a/src/guiMessageMenu.cpp b/src/guiMessageMenu.cpp
index abb31cf2d5069214cd8a5f8956f30aa10ff1c76f..c6592e51cf4da5fbac9c9f83a86aa942463c29c7 100644
--- a/src/guiMessageMenu.cpp
+++ b/src/guiMessageMenu.cpp
@@ -104,10 +104,12 @@ void GUIMessageMenu::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, bw, 30);
 		rect = rect + v2s32(size.X/2-bw/2, size.Y/2-30/2+5 + msg_h/2);
+		wchar_t* text = wgettext("Proceed");
 		gui::IGUIElement *e = 
 		Environment->addButton(rect, this, 257,
-			wgettext("Proceed"));
+			text);
 		Environment->setFocus(e);
+		delete[] text;
 	}
 	changeCtype("C");
 }
diff --git a/src/guiPasswordChange.cpp b/src/guiPasswordChange.cpp
index e4b77b611193ccbe2429c9ce2bc1991f500f1201..a4d16444da63abf4332463902a4c8f06bd0990e4 100644
--- a/src/guiPasswordChange.cpp
+++ b/src/guiPasswordChange.cpp
@@ -105,8 +105,9 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 110, 20);
 		rect += topleft_client + v2s32(35, ypos+6);
-		Environment->addStaticText(wgettext("Old Password"),
-			rect, false, true, this, -1);
+		wchar_t* text = wgettext("Old Password");
+		Environment->addStaticText(text, rect, false, true, this, -1);
+		delete[] text;
 	}
 	changeCtype("C");
 	{
@@ -122,8 +123,9 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 110, 20);
 		rect += topleft_client + v2s32(35, ypos+6);
-		Environment->addStaticText(wgettext("New Password"),
-			rect, false, true, this, -1);
+		wchar_t* text = wgettext("New Password");
+		Environment->addStaticText(text, rect, false, true, this, -1);
+		delete[] text;
 	}
 	changeCtype("C");
 	{
@@ -138,8 +140,9 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 110, 20);
 		rect += topleft_client + v2s32(35, ypos+6);
-		Environment->addStaticText(wgettext("Confirm Password"),
-			rect, false, true, this, -1);
+		wchar_t* text = wgettext("Confirm Password");
+		Environment->addStaticText(text, rect, false, true, this, -1);
+		delete[] text;
 	}
 	changeCtype("C");
 	{
@@ -155,18 +158,22 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 140, 30);
 		rect = rect + v2s32(size.X/2-140/2, ypos);
-		Environment->addButton(rect, this, ID_change, wgettext("Change"));
+		wchar_t* text = wgettext("Change");
+		Environment->addButton(rect, this, ID_change, text);
+		delete[] text;
 	}
 
 	ypos += 50;
 	{
 		core::rect<s32> rect(0, 0, 300, 20);
 		rect += topleft_client + v2s32(35, ypos);
+		wchar_t* text = wgettext("Passwords do not match!");
 		IGUIElement *e = 
 		Environment->addStaticText(
-			wgettext("Passwords do not match!"),
+			text,
 			rect, false, true, this, ID_message);
 		e->setVisible(false);
+		delete[] text;
 	}
 	changeCtype("C");
 
diff --git a/src/guiPauseMenu.cpp b/src/guiPauseMenu.cpp
index dc95eef5ba7400a6fee12beb765cac584491edd5..b57b4a1d15bcd196f28d88725626eee689fe7824 100644
--- a/src/guiPauseMenu.cpp
+++ b/src/guiPauseMenu.cpp
@@ -119,8 +119,10 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 140, btn_height);
 		rect = rect + v2s32(size.X/2-140/2, btn_y);
+		wchar_t* text = wgettext("Continue");
 		Environment->addButton(rect, this, 256,
-			wgettext("Continue"));
+			text);
+		delete[] text;
 	}
 	btn_y += btn_height + btn_gap;
 	if(!m_simple_singleplayer_mode)
@@ -128,48 +130,58 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
 		{
 			core::rect<s32> rect(0, 0, 140, btn_height);
 			rect = rect + v2s32(size.X/2-140/2, btn_y);
+			wchar_t* text = wgettext("Change Password");
 			Environment->addButton(rect, this, 261,
-				wgettext("Change Password"));
+				text);
+			delete[] text;
 		}
 		btn_y += btn_height + btn_gap;
 	}
 	{
 		core::rect<s32> rect(0, 0, 140, btn_height);
 		rect = rect + v2s32(size.X/2-140/2, btn_y);
+		wchar_t* text = wgettext("Sound Volume");
 		Environment->addButton(rect, this, 262,
-			wgettext("Sound Volume"));
+			text);
+		delete[] text;
 	}
 	btn_y += btn_height + btn_gap;
 	{
 		core::rect<s32> rect(0, 0, 140, btn_height);
 		rect = rect + v2s32(size.X/2-140/2, btn_y);
+		wchar_t* text = wgettext("Exit to Menu");
 		Environment->addButton(rect, this, 260,
-			wgettext("Exit to Menu"));
+			text);
+		delete[] text;
 	}
 	btn_y += btn_height + btn_gap;
 	{
 		core::rect<s32> rect(0, 0, 140, btn_height);
 		rect = rect + v2s32(size.X/2-140/2, btn_y);
+		wchar_t* text = wgettext("Exit to OS");
 		Environment->addButton(rect, this, 257,
-			wgettext("Exit to OS"));
+			text);
+		delete[] text;
 	}
 
 	{
 		core::rect<s32> rect(0, 0, 180, 240);
 		rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2);
-		Environment->addStaticText(chartowchar_t(gettext(
-		"Default Controls:\n"
-		"- WASD: Walk\n"
-		"- Mouse left: dig/hit\n"
-		"- Mouse right: place/use\n"
-		"- Mouse wheel: select item\n"
-		"- 0...9: select item\n"
-		"- Shift: sneak\n"
-		"- R: Toggle viewing all loaded chunks\n"
-		"- I: Inventory menu\n"
-		"- ESC: This menu\n"
-		"- T: Chat\n"
-		)), rect, false, true, this, 258);
+		wchar_t* text = wgettext("Default Controls:\n"
+				"- WASD: Walk\n"
+				"- Mouse left: dig/hit\n"
+				"- Mouse right: place/use\n"
+				"- Mouse wheel: select item\n"
+				"- 0...9: select item\n"
+				"- Shift: sneak\n"
+				"- R: Toggle viewing all loaded chunks\n"
+				"- I: Inventory menu\n"
+				"- ESC: This menu\n"
+				"- T: Chat\n"
+				);
+		Environment->addStaticText(text, rect, false, true, this, 258);
+		delete[] text;
+
 	}
 	{
 		core::rect<s32> rect(0, 0, 180, 220);
diff --git a/src/guiTextInputMenu.cpp b/src/guiTextInputMenu.cpp
index f4e3bb5ba08aa9200073b0e3f028c1a3ab10602e..c15eeedc5fae607c4463351c985c377fdcd48237 100644
--- a/src/guiTextInputMenu.cpp
+++ b/src/guiTextInputMenu.cpp
@@ -127,8 +127,10 @@ void GUITextInputMenu::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 140, 30);
 		rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+25);
+		wchar_t* text = wgettext("Proceed");
 		Environment->addButton(rect, this, 257,
-			wgettext("Proceed"));
+			text);
+		delete[] text;
 	}
 	changeCtype("C");
 }
diff --git a/src/guiVolumeChange.cpp b/src/guiVolumeChange.cpp
index cfb89da1cf8c307759d9b958279068b8627504a7..4e92b82c25b3fc14d5b42fde2c4d97a1db5065f9 100644
--- a/src/guiVolumeChange.cpp
+++ b/src/guiVolumeChange.cpp
@@ -105,8 +105,10 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 120, 20);
 		rect = rect + v2s32(size.X/2-60, size.Y/2-35);
-		Environment->addStaticText(wgettext("Sound Volume: "), rect, false,
+		wchar_t* text = wgettext("Sound Volume: ");
+		Environment->addStaticText(text, rect, false,
 				true, this, ID_soundText1);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 30, 20);
@@ -117,8 +119,10 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
 	{
 		core::rect<s32> rect(0, 0, 80, 30);
 		rect = rect + v2s32(size.X/2-80/2, size.Y/2+55);
+		wchar_t* text = wgettext("Exit");
 		Environment->addButton(rect, this, ID_soundExitButton,
-			wgettext("Exit"));
+			text);
+		delete[] text;
 	}
 	{
 		core::rect<s32> rect(0, 0, 300, 20);
diff --git a/src/hud.cpp b/src/hud.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..349c55add317a2c4751ef8f9d8bf563af874fdf3
--- /dev/null
+++ b/src/hud.cpp
@@ -0,0 +1,291 @@
+/*
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2010-2013 blue42u, Jonathon Anderson <anderjon@umail.iu.edu>
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <IGUIStaticText.h>
+
+#include "guiFormSpecMenu.h"
+#include "main.h"
+#include "util/numeric.h"
+#include "log.h"
+#include "client.h"
+#include "hud.h"
+
+
+Hud::Hud(video::IVideoDriver *driver, gui::IGUIEnvironment* guienv,
+		gui::IGUIFont *font, u32 text_height, IGameDef *gamedef,
+		LocalPlayer *player, Inventory *inventory) {
+	this->driver      = driver;
+	this->guienv      = guienv;
+	this->font        = font;
+	this->text_height = text_height;
+	this->gamedef     = gamedef;
+	this->player      = player;
+	this->inventory   = inventory;
+	
+	screensize       = v2u32(0, 0);
+	displaycenter    = v2s32(0, 0);
+	hotbar_imagesize = 48;
+	hotbar_itemcount = 8;
+	
+	v3f crosshair_color = g_settings->getV3F("crosshair_color");
+	u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
+	u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
+	u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
+	u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
+	crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
+	
+	v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
+	u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
+	u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
+	u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
+	selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
+}
+
+
+//NOTE: selectitem = 0 -> no selected; selectitem 1-based
+void Hud::drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount,
+		InventoryList *mainlist, u16 selectitem, u16 direction)
+{
+	s32 padding = imgsize / 12;
+	s32 height  = imgsize + padding * 2;
+	s32 width   = itemcount * (imgsize + padding * 2);
+	if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
+		width  = imgsize + padding * 2;
+		height = itemcount * (imgsize + padding * 2);
+	}
+	s32 fullimglen = imgsize + padding * 2;
+
+	// Position of upper left corner of bar
+	v2s32 pos = upperleftpos;
+
+	// Draw background color
+	/*core::rect<s32> barrect(0,0,width,height);
+	barrect += pos;
+	video::SColor bgcolor(255,128,128,128);
+	driver->draw2DRectangle(bgcolor, barrect, NULL);*/
+
+	core::rect<s32> imgrect(0, 0, imgsize, imgsize);
+
+	for (s32 i = 0; i < itemcount; i++)
+	{
+		const ItemStack &item = mainlist->getItem(i);
+
+		v2s32 steppos;
+		switch (direction) {
+			case HUD_DIR_RIGHT_LEFT:
+				steppos = v2s32(-(padding + i * fullimglen), padding);
+				break;
+			case HUD_DIR_TOP_BOTTOM:
+				steppos = v2s32(padding, padding + i * fullimglen);
+				break;
+			case HUD_DIR_BOTTOM_TOP:
+				steppos = v2s32(padding, -(padding + i * fullimglen));
+				break;
+			default:
+				steppos = v2s32(padding + i * fullimglen, padding);	
+		}
+			
+		core::rect<s32> rect = imgrect + pos + steppos;
+
+		if (selectitem == i + 1)
+		{
+			video::SColor c_outside(255,255,0,0);
+			//video::SColor c_outside(255,0,0,0);
+			//video::SColor c_inside(255,192,192,192);
+			s32 x1 = rect.UpperLeftCorner.X;
+			s32 y1 = rect.UpperLeftCorner.Y;
+			s32 x2 = rect.LowerRightCorner.X;
+			s32 y2 = rect.LowerRightCorner.Y;
+			// Black base borders
+			driver->draw2DRectangle(c_outside,
+					core::rect<s32>(
+						v2s32(x1 - padding, y1 - padding),
+						v2s32(x2 + padding, y1)
+					), NULL);
+			driver->draw2DRectangle(c_outside,
+					core::rect<s32>(
+						v2s32(x1 - padding, y2),
+						v2s32(x2 + padding, y2 + padding)
+					), NULL);
+			driver->draw2DRectangle(c_outside,
+					core::rect<s32>(
+						v2s32(x1 - padding, y1),
+						v2s32(x1, y2)
+					), NULL);
+			driver->draw2DRectangle(c_outside,
+					core::rect<s32>(
+						v2s32(x2, y1),
+						v2s32(x2 + padding, y2)
+					), NULL);
+			/*// Light inside borders
+			driver->draw2DRectangle(c_inside,
+					core::rect<s32>(
+						v2s32(x1 - padding/2, y1 - padding/2),
+						v2s32(x2 + padding/2, y1)
+					), NULL);
+			driver->draw2DRectangle(c_inside,
+					core::rect<s32>(
+						v2s32(x1 - padding/2, y2),
+						v2s32(x2 + padding/2, y2 + padding/2)
+					), NULL);
+			driver->draw2DRectangle(c_inside,
+					core::rect<s32>(
+						v2s32(x1 - padding/2, y1),
+						v2s32(x1, y2)
+					), NULL);
+			driver->draw2DRectangle(c_inside,
+					core::rect<s32>(
+						v2s32(x2, y1),
+						v2s32(x2 + padding/2, y2)
+					), NULL);
+			*/
+		}
+
+		video::SColor bgcolor2(128, 0, 0, 0);
+		driver->draw2DRectangle(bgcolor2, rect, NULL);
+		drawItemStack(driver, font, item, rect, NULL, gamedef);
+	}
+}
+
+
+void Hud::drawLuaElements() {
+	for (size_t i = 0; i != player->hud.size(); i++) {
+		HudElement *e = player->hud[i];
+		if (!e)
+			continue;
+		
+		v2s32 pos(e->pos.X * screensize.X, e->pos.Y * screensize.Y);
+		switch (e->type) {
+			case HUD_ELEM_IMAGE: {
+				video::ITexture *texture =
+					gamedef->getTextureSource()->getTextureRaw(e->text);
+				if (!texture)
+					continue;
+
+				const video::SColor color(255, 255, 255, 255);
+				const video::SColor colors[] = {color, color, color, color};
+				core::dimension2di imgsize(texture->getOriginalSize());
+				core::rect<s32> rect(0, 0, imgsize.Width  * e->scale.X,
+									       imgsize.Height * e->scale.X);
+				rect += pos;
+				driver->draw2DImage(texture, rect,
+					core::rect<s32>(core::position2d<s32>(0,0), imgsize),
+					NULL, colors, true);
+				break; }
+			case HUD_ELEM_TEXT: {
+				video::SColor color(255, (e->number >> 16) & 0xFF,
+										 (e->number >> 8)  & 0xFF,
+										 (e->number >> 0)  & 0xFF);
+				core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
+				font->draw(narrow_to_wide(e->text).c_str(), size + pos, color);
+				break; }
+			case HUD_ELEM_STATBAR:
+				drawStatbar(pos, e->text, e->number);
+				break;
+			case HUD_ELEM_INVENTORY: {
+				InventoryList *inv = inventory->getList(e->text);
+				drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir);
+				break; }
+			default:
+				infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
+					"of hud element ID " << i << " due to unrecognized type" << std::endl;
+		}
+	}
+}
+
+
+void Hud::drawStatbar(v2s32 upperleftpos, std::string texture, s32 count) {
+	video::ITexture *stat_texture =
+		gamedef->getTextureSource()->getTextureRaw(texture);
+	if (!stat_texture)
+		return;
+
+	v2s32 p = upperleftpos;
+	for (s32 i = 0; i < count / 2; i++)
+	{
+		core::dimension2di srcd(stat_texture->getOriginalSize());
+		const video::SColor color(255, 255, 255, 255);
+		const video::SColor colors[] = {color, color, color, color};
+		core::rect<s32> rect(0, 0, srcd.Width, srcd.Height);
+		rect += p;
+		driver->draw2DImage(stat_texture, rect,
+			core::rect<s32>(core::position2d<s32>(0, 0), srcd),
+			NULL, colors, true);
+		p += v2s32(srcd.Width, 0);
+	}
+	
+	if (count % 2 == 1)
+	{
+		core::dimension2di srcd(stat_texture->getOriginalSize());
+		const video::SColor color(255, 255, 255, 255);
+		const video::SColor colors[] = {color, color, color, color};
+		core::rect<s32> rect(0, 0, srcd.Width / 2, srcd.Height);
+		rect += p;
+		srcd.Width /= 2;
+		driver->draw2DImage(stat_texture, rect,
+			core::rect<s32>(core::position2d<s32>(0, 0), srcd),
+			NULL, colors, true);
+		p += v2s32(srcd.Width * 2, 0);
+	}
+}
+
+
+void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem) {
+	InventoryList *mainlist = inventory->getList("main");
+	if (mainlist == NULL) {
+		errorstream << "draw_hotbar(): mainlist == NULL" << std::endl;
+		return;
+	}
+	
+	s32 padding = hotbar_imagesize / 12;
+	s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2);
+	v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 2);
+	
+	drawItem(pos, hotbar_imagesize, hotbar_itemcount, mainlist, playeritem + 1, 0);
+	drawStatbar(pos + v2s32(0, -20), "heart.png", halfheartcount);
+}
+
+
+void Hud::drawCrosshair() {
+	driver->draw2DLine(displaycenter - v2s32(10,0),
+			displaycenter + v2s32(10, 0), crosshair_argb);
+	driver->draw2DLine(displaycenter - v2s32(0,10),
+			displaycenter + v2s32(0, 10), crosshair_argb);
+}
+
+
+void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
+	for (std::vector<aabb3f>::const_iterator
+			i = hilightboxes.begin();
+			i != hilightboxes.end(); i++) {
+		driver->draw3DBox(*i, selectionbox_argb);
+	}
+}
+
+
+void Hud::resizeHotbar() {
+	if (screensize.Y <= 800)
+		hotbar_imagesize = 32;
+	else if (screensize.Y <= 1280)
+		hotbar_imagesize = 48;
+	else
+		hotbar_imagesize = 64;
+}
diff --git a/src/hud.h b/src/hud.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e00a94e3ead8eeab1033c7f66918eaf4f55c691
--- /dev/null
+++ b/src/hud.h
@@ -0,0 +1,116 @@
+/*
+Minetest
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef HUD_HEADER
+#define HUD_HEADER
+
+#include "irrlichttypes_extrabloated.h"
+
+#define HUD_DIR_LEFT_RIGHT 0
+#define HUD_DIR_RIGHT_LEFT 1
+#define HUD_DIR_TOP_BOTTOM 2
+#define HUD_DIR_BOTTOM_TOP 3
+
+class Player;
+
+enum HudElementType {
+	HUD_ELEM_IMAGE     = 0,
+	HUD_ELEM_TEXT      = 1,
+	HUD_ELEM_STATBAR   = 2,
+	HUD_ELEM_INVENTORY = 3
+};
+
+enum HudElementStat {
+	HUD_STAT_POS,
+	HUD_STAT_NAME,
+	HUD_STAT_SCALE,
+	HUD_STAT_TEXT,
+	HUD_STAT_NUMBER,
+	HUD_STAT_ITEM,
+	HUD_STAT_DIR
+};
+
+struct HudElement {
+	HudElementType type;
+	v2f pos;
+	std::string name;
+	v2f scale;
+	std::string text;
+	u32 number;
+	u32 item;
+	u32 dir;
+};
+
+
+inline u32 hud_get_free_id(Player *player) {
+	size_t size = player->hud.size();
+	for (size_t i = 0; i != size; i++) {
+		if (!player->hud[i])
+			return i;
+	}
+	return size;
+}
+
+#ifndef SERVER
+
+#include <deque>
+
+#include <IGUIFont.h>
+
+#include "gamedef.h"
+#include "inventory.h"
+#include "localplayer.h"
+
+class Hud {
+public:
+	video::IVideoDriver *driver;
+	gui::IGUIEnvironment *guienv;
+	gui::IGUIFont *font;
+	u32 text_height;
+	IGameDef *gamedef;
+	LocalPlayer *player;
+	Inventory *inventory;
+	
+	v2u32 screensize;
+	v2s32 displaycenter;
+	s32 hotbar_imagesize;
+	s32 hotbar_itemcount;
+	
+	video::SColor crosshair_argb;
+	video::SColor selectionbox_argb;
+	
+	Hud(video::IVideoDriver *driver, gui::IGUIEnvironment* guienv,
+		gui::IGUIFont *font, u32 text_height, IGameDef *gamedef,
+		LocalPlayer *player, Inventory *inventory);
+	
+	void drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount,
+		InventoryList *mainlist, u16 selectitem, u16 direction);
+	void drawLuaElements();
+	void drawStatbar(v2s32 upperleftpos, std::string texture, s32 count);
+	
+	void drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem);
+	void resizeHotbar();
+	
+	void drawCrosshair();
+	void drawSelectionBoxes(std::vector<aabb3f> &hilightboxes);
+};
+
+#endif
+
+#endif
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index 72ce0e6546dd990093e5b120bd5e0b622e5d3169..784919ae2deb371732118e6943511519c2be6c1d 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -226,8 +226,15 @@ class CItemDefManager: public IWritableItemDefManager
 public:
 	CItemDefManager()
 	{
+		for (std::map<std::string, ItemDefinition*>::iterator iter =
+				m_item_definitions.begin(); iter != m_item_definitions.end();
+				iter ++) {
+			delete iter->second;
+		}
+		m_item_definitions.clear();
 #ifndef SERVER
 		m_main_thread = get_current_thread_id();
+		m_driver = NULL;
 #endif
 	
 		clear();
@@ -241,7 +248,16 @@ class CItemDefManager: public IWritableItemDefManager
 		{
 			ClientCached *cc = *i;
 			cc->wield_mesh->drop();
+			delete cc;
+		}
+
+		if (m_driver != NULL) {
+			for (unsigned int i = 0; i < m_extruded_textures.size(); i++) {
+				m_driver->removeTexture(m_extruded_textures[i]);
+			}
+			m_extruded_textures.clear();
 		}
+		m_driver = NULL;
 #endif
 	}
 	virtual const ItemDefinition& get(const std::string &name_) const
@@ -290,6 +306,10 @@ class CItemDefManager: public IWritableItemDefManager
 		return m_item_definitions.find(name) != m_item_definitions.end();
 	}
 #ifndef SERVER
+private:
+	static video::IVideoDriver * m_driver;
+	static std::vector<video::ITexture*> m_extruded_textures;
+public:
 	ClientCached* createClientCachedDirect(const std::string &name,
 			IGameDef *gamedef) const
 	{
@@ -328,11 +348,7 @@ class CItemDefManager: public IWritableItemDefManager
 		}
 
 		// Create a wield mesh
-		if(cc->wield_mesh != NULL)
-		{
-			cc->wield_mesh->drop();
-			cc->wield_mesh = NULL;
-		}
+		assert(cc->wield_mesh == NULL);
 		if(def->type == ITEM_NODE && def->wield_image == "")
 		{
 			need_node_mesh = true;
@@ -432,20 +448,27 @@ class CItemDefManager: public IWritableItemDefManager
 						tsrc->getTextureRaw(f.tiledef[0].name);
 				}
 			}
+			else
+			{
+				if (m_driver == 0)
+					m_driver = driver;
+
+				m_extruded_textures.push_back(cc->inventory_texture);
+			}
 
 			/*
 				Use the node mesh as the wield mesh
 			*/
-			if(cc->wield_mesh == NULL)
-			{
-				// Scale to proper wield mesh proportions
-				scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
-						* def->wield_scale);
-				cc->wield_mesh = node_mesh;
-				cc->wield_mesh->grab();
-			}
 
-			// falling outside of here deletes node_mesh
+			// Scale to proper wield mesh proportions
+			scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0)
+					* def->wield_scale);
+
+			cc->wield_mesh = node_mesh;
+			cc->wield_mesh->grab();
+
+			//no way reference count can be smaller than 2 in this place!
+			assert(cc->wield_mesh->getReferenceCount() >= 2);
 		}
 
 		// Put in cache
@@ -658,3 +681,8 @@ IWritableItemDefManager* createItemDefManager()
 	return new CItemDefManager();
 }
 
+#ifndef SERVER
+//TODO very very very dirty hack!
+video::IVideoDriver * CItemDefManager::m_driver = 0;
+std::vector<video::ITexture*> CItemDefManager::m_extruded_textures;
+#endif
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 9c70c8b2f532a810a844a6db915208f12bbf32c9..6b7b0943cdc1a3ca6f7961a19fa061c14b8af021 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -329,6 +329,9 @@ void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d,
 	if(!touching_ground_was && touching_ground){
 		MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
 		m_gamedef->event()->put(e);
+
+		// Set camera impact value to be used for view bobbing
+		camera_impact = getSpeed().Y * -1;
 	}
 
 	{
diff --git a/src/localplayer.h b/src/localplayer.h
index 9ac2bc6828b3b3946287615516a0ca3e9c796db5..8c3041c04b4ac40172baa7ddf0dd204299eeb5cb 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -59,6 +59,8 @@ class LocalPlayer : public Player
 	float last_yaw;
 	unsigned int last_keyPressed;
 
+	float camera_impact;
+
 private:
 	// This is used for determining the sneaking range
 	v3s16 m_sneak_node;
diff --git a/src/main.cpp b/src/main.cpp
index 08af6a37d8bd59794924cb89c8b68690b1d5d52f..eef65cdb2ab77eee7b75630b01a3ff68d7576d13 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1501,7 +1501,9 @@ int main(int argc, char *argv[])
 	while(device->run() && kill == false)
 	{
 		// Set the window caption
-		device->setWindowCaption((std::wstring(L"Minetest [")+wgettext("Main Menu")+L"]").c_str());
+		wchar_t* text = wgettext("Main Menu");
+		device->setWindowCaption((std::wstring(L"Minetest [")+text+L"]").c_str());
+		delete[] text;
 
 		// This is used for catching disconnects
 		try
@@ -1902,16 +1904,6 @@ int main(int argc, char *argv[])
 			error_message = wgettext("Connection error (timed out?)");
 			errorstream<<wide_to_narrow(error_message)<<std::endl;
 		}
-		catch(ServerError &e)
-		{
-			error_message = narrow_to_wide(e.what());
-			errorstream<<wide_to_narrow(error_message)<<std::endl;
-		}
-		catch(ModError &e)
-		{
-			errorstream<<e.what()<<std::endl;
-			error_message = narrow_to_wide(e.what()) + wgettext("\nCheck debug.txt for details.");
-		}
 #ifdef NDEBUG
 		catch(std::exception &e)
 		{
diff --git a/src/map.cpp b/src/map.cpp
index a8201f3ee7cb0456c050e187e4df231837b8a9a6..c4884a45a12cdc3652ac2da5af01ca6f8943ad80 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -2494,6 +2494,8 @@ ServerMap::~ServerMap()
 		delete chunk;
 	}
 #endif
+
+	delete m_mgparams;
 }
 
 bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
diff --git a/src/mapgen.cpp b/src/mapgen.cpp
index 22488bc4cc4073f2f91b0e82bffd53e76c7bda91..0646a8826a0804279218d6dee92f7fb17332aa2e 100644
--- a/src/mapgen.cpp
+++ b/src/mapgen.cpp
@@ -94,7 +94,7 @@ void Ore::resolveNodeNames(INodeDefManager *ndef) {
 }
 
 
-void OreScatter::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
+void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
 	int in_range = 0;
 
 	in_range |= (nmin.Y <= height_max && nmax.Y >= height_min);
@@ -105,9 +105,6 @@ void OreScatter::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
 
 	resolveNodeNames(mg->ndef);
 	
-	MapNode n_ore(ore);
-	ManualMapVoxelManipulator *vm = mg->vm;
-	PseudoRandom pr(blockseed);
 	int ymin, ymax;
 	
 	if (in_range & ORE_RANGE_MIRROR) {
@@ -120,6 +117,17 @@ void OreScatter::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
 	if (clust_size >= ymax - ymin + 1)
 		return;
 	
+	nmin.Y = ymin;
+	nmax.Y = ymax;
+	generate(mg->vm, mg->seed, blockseed, nmin, nmax);
+}
+
+
+void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed,
+						u32 blockseed, v3s16 nmin, v3s16 nmax) {
+	PseudoRandom pr(blockseed);
+	MapNode n_ore(ore, 0, ore_param2);
+
 	int volume = (nmax.X - nmin.X + 1) *
 				 (nmax.Y - nmin.Y + 1) *
 				 (nmax.Z - nmin.Z + 1);
@@ -129,10 +137,10 @@ void OreScatter::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
 
 	for (int i = 0; i != nclusters; i++) {
 		int x0 = pr.range(nmin.X, nmax.X - csize + 1);
-		int y0 = pr.range(ymin,   ymax   - csize + 1);
+		int y0 = pr.range(nmin.Y, nmax.Y - csize + 1);
 		int z0 = pr.range(nmin.Z, nmax.Z - csize + 1);
 		
-		if (np && (NoisePerlin3D(np, x0, y0, z0, mg->seed) < nthresh))
+		if (np && (NoisePerlin3D(np, x0, y0, z0, seed) < nthresh))
 			continue;
 		
 		for (int z1 = 0; z1 != csize; z1++)
@@ -149,53 +157,25 @@ void OreScatter::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
 }
 
 
-void OreSheet::generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) {
-	int in_range = 0;
-
-	in_range |= (nmin.Y <= height_max && nmax.Y >= height_min);
-	if (flags & OREFLAG_ABSHEIGHT)
-		in_range |= (nmin.Y >= -height_max && nmax.Y <= -height_min) << 1;
-	if (!in_range)
-		return;
-		
-	resolveNodeNames(mg->ndef);
-
-	MapNode n_ore(ore);
-	ManualMapVoxelManipulator *vm = mg->vm;
+void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed,
+						u32 blockseed, v3s16 nmin, v3s16 nmax) {
 	PseudoRandom pr(blockseed + 4234);
-	int ymin, ymax;
-	
-	if (in_range & ORE_RANGE_MIRROR) {
-		ymin = MYMAX(nmin.Y, -height_max);
-		ymax = MYMIN(nmax.Y, -height_min);
-	} else {
-		ymin = MYMAX(nmin.Y, height_min);
-		ymax = MYMIN(nmax.Y, height_max);
-	}
-
-	if (clust_size >= ymax - ymin + 1)
-		return;
-		
-	int x0 = nmin.X;
-	int z0 = nmin.Z;
-	
-	int x1 = nmax.X;
-	int z1 = nmax.Z;
+	MapNode n_ore(ore, 0, ore_param2);
 	
 	int max_height = clust_size;
-	int y_start = pr.range(ymin, ymax - max_height);
+	int y_start = pr.range(nmin.Y, nmax.Y - max_height);
 	
 	if (!noise) {
 		int sx = nmax.X - nmin.X + 1;
 		int sz = nmax.Z - nmin.Z + 1;
 		noise = new Noise(np, 0, sx, sz);
 	}
-	noise->seed = mg->seed + y_start;
-	noise->perlinMap2D(x0, z0);
+	noise->seed = seed + y_start;
+	noise->perlinMap2D(nmin.X, nmin.Z);
 	
 	int index = 0;
-	for (int z = z0; z != z1; z++)
-	for (int x = x0; x != x1; x++) {
+	for (int z = nmin.Z; z <= nmax.Z; z++)
+	for (int x = nmin.X; x <= nmax.X; x++) {
 		float noiseval = noise->result[index++];
 		if (noiseval < nthresh)
 			continue;
diff --git a/src/mapgen.h b/src/mapgen.h
index e708f23b1e621fb68c262826c760f818c147f0f4..17136a13796c704de70ca44166752f51d923b0e5 100644
--- a/src/mapgen.h
+++ b/src/mapgen.h
@@ -120,7 +120,6 @@ class Ore {
 public:
 	std::string ore_name;
 	std::string wherein_name;
-
 	content_t ore;
 	content_t wherein;  // the node to be replaced
 	u32 clust_scarcity; // ore cluster has a 1-in-clust_scarcity chance of appearing at a node
@@ -128,6 +127,7 @@ class Ore {
 	s16 clust_size;     // how large (in nodes) a chunk of ore is
 	s16 height_min;
 	s16 height_max;
+	u8 ore_param2;		// to set node-specific attributes
 	u32 flags;          // attributes for this ore
 	float nthresh;      // threshhold for noise at which an ore is placed 
 	NoiseParams *np;    // noise for distribution of clusters (NULL for uniform scattering)
@@ -141,15 +141,19 @@ class Ore {
 	}
 	
 	void resolveNodeNames(INodeDefManager *ndef);
-	virtual void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) = 0;
+	void placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+	virtual void generate(ManualMapVoxelManipulator *vm, int seed,
+						u32 blockseed, v3s16 nmin, v3s16 nmax) = 0;
 };
 
 class OreScatter : public Ore {
-	 void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+	virtual void generate(ManualMapVoxelManipulator *vm, int seed,
+						u32 blockseed, v3s16 nmin, v3s16 nmax);
 };
 
 class OreSheet : public Ore {
-	void generate(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax);
+	virtual void generate(ManualMapVoxelManipulator *vm, int seed,
+						u32 blockseed, v3s16 nmin, v3s16 nmax);
 };
 
 Ore *createOre(OreType type);
diff --git a/src/mapgen_v6.cpp b/src/mapgen_v6.cpp
index 4a037bb8595454ecc9eb87eedb3260dcb4894cde..2e44d7b4af17b39031cfcb14b6d7774b2f494495 100644
--- a/src/mapgen_v6.cpp
+++ b/src/mapgen_v6.cpp
@@ -467,7 +467,7 @@ void MapgenV6::makeChunk(BlockMakeData *data) {
 	// Generate the registered ores
 	for (unsigned int i = 0; i != emerge->ores.size(); i++) {
 		Ore *ore = emerge->ores[i];
-		ore->generate(this, blockseed + i, node_min, node_max);
+		ore->placeOre(this, blockseed + i, node_min, node_max);
 	}
 
 	// Calculate lighting
diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp
index 6aecfe3109217a96a40f945c088a31fb34849611..8aad37f73cdad1bb1e8bd8834ab43943f7b6e307 100644
--- a/src/mapgen_v7.cpp
+++ b/src/mapgen_v7.cpp
@@ -180,7 +180,7 @@ void MapgenV7::makeChunk(BlockMakeData *data) {
 
 	for (size_t i = 0; i != emerge->ores.size(); i++) {
 		Ore *ore = emerge->ores[i];
-		ore->generate(this, blockseed + i, node_min, node_max);
+		ore->placeOre(this, blockseed + i, node_min, node_max);
 	}
 	
 	//printf("makeChunk: %dms\n", t.stop());
diff --git a/src/mesh.cpp b/src/mesh.cpp
index c2e6bcaa4dd6256194f2f193274b80fe92e6afd1..da0dbe44235d3b049d1a273c96d09865184a2100 100644
--- a/src/mesh.cpp
+++ b/src/mesh.cpp
@@ -246,6 +246,8 @@ static scene::IAnimatedMesh* extrudeARGB(u32 twidth, u32 theight, u8 *data)
 		}
 	}
 
+	delete[] solidity;
+
 	// Add to mesh
 	scene::SMesh *mesh = new scene::SMesh();
 	mesh->addMeshBuffer(buf);
diff --git a/src/pathfinder.cpp b/src/pathfinder.cpp
index c7621177ee951f5dde2f3450ab6415e3bd32a3f2..0d1cfe476cf2567cbe8045f8d7a6d6656ca40832 100644
--- a/src/pathfinder.cpp
+++ b/src/pathfinder.cpp
@@ -687,9 +687,8 @@ bool pathfinder::update_all_costs(	v3s16 ipos,
 
 				if ((g_pos2.totalcost < 0) ||
 						(g_pos2.totalcost > new_cost)) {
-					int old_cost = g_pos2.totalcost;
 					DEBUG_OUT(LVL "Pathfinder: updating path at: "<<
-							PPOS(ipos2) << " from: " << old_cost << " to "<<
+							PPOS(ipos2) << " from: " << g_pos2.totalcost << " to "<<
 							new_cost << std::endl);
 					if (update_all_costs(ipos2,invert(directions[i]),
 											new_cost,level)) {
@@ -847,9 +846,8 @@ bool pathfinder::update_cost_heuristic(	v3s16 ipos,
 
 				if ((g_pos2.totalcost < 0) ||
 						(g_pos2.totalcost > new_cost)) {
-					int old_cost = g_pos2.totalcost;
 					DEBUG_OUT(LVL "Pathfinder: updating path at: "<<
-							PPOS(ipos2) << " from: " << old_cost << " to "<<
+							PPOS(ipos2) << " from: " << g_pos2.totalcost << " to "<<
 							new_cost << " srcdir=" <<
 							PPOS(invert(direction))<< std::endl);
 					if (update_cost_heuristic(ipos2,invert(direction),
diff --git a/src/player.h b/src/player.h
index d95e535ffda63d91c5cf67cab8571d9c08f464f8..d0e50d2c36a494aea07259626b41e5103e78bfad 100644
--- a/src/player.h
+++ b/src/player.h
@@ -87,6 +87,7 @@ class Map;
 class IGameDef;
 struct CollisionInfo;
 class PlayerSAO;
+class HudElement;
 
 class Player
 {
@@ -242,6 +243,8 @@ class Player
 	}
 	
 	u32 keyPressed;
+	
+	std::vector<HudElement *> hud;
 
 protected:
 	IGameDef *m_gamedef;
@@ -253,6 +256,7 @@ class Player
 	v3f m_position;
 };
 
+
 /*
 	Player on the server
 */
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index 0227c6a193d3470f484ee66267940d9a0623b529..8d472e6b874ceb5571b9fc788547c53250cfb955 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -670,6 +670,7 @@ static int l_register_ore(lua_State *L)
 	}
 	
 	ore->ore_name       = getstringfield_default(L, index, "ore", "");
+	ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
 	ore->wherein_name   = getstringfield_default(L, index, "wherein", "");
 	ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
 	ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
diff --git a/src/scriptapi_craft.cpp b/src/scriptapi_craft.cpp
index 183eeb84055759ed1f4c534728632df688088c8d..459908237e84c10bcaae43d20f9599ace79426f3 100644
--- a/src/scriptapi_craft.cpp
+++ b/src/scriptapi_craft.cpp
@@ -330,8 +330,7 @@ int l_get_craft_result(lua_State *L)
 // get_craft_recipe(result item)
 int l_get_craft_recipe(lua_State *L)
 {
-	int k = 0;
-	char tmp[20];
+	int k = 1;
 	int input_i = 1;
 	std::string o_item = luaL_checkstring(L,input_i);
 
@@ -351,8 +350,7 @@ int l_get_craft_recipe(lua_State *L)
 			{
 				continue;
 			}
-			sprintf(tmp,"%d",k);
-			lua_pushstring(L,tmp);
+			lua_pushinteger(L,k);
 			lua_pushstring(L,i->name.c_str());
 			lua_settable(L, -3);
 		}
@@ -383,9 +381,7 @@ int l_get_craft_recipe(lua_State *L)
 // get_all_craft_recipes(result item)
 int l_get_all_craft_recipes(lua_State *L)
 {
-	char tmp[20];
-	int input_i = 1;
-	std::string o_item = luaL_checkstring(L,input_i);
+	std::string o_item = luaL_checkstring(L,1);
 	IGameDef *gdef = get_server(L);
 	ICraftDefManager *cdef = gdef->cdef();
 	CraftInput input;
@@ -402,7 +398,7 @@ int l_get_all_craft_recipes(lua_State *L)
 	int table_insert = lua_gettop(L);
 	lua_newtable(L);
 	int table = lua_gettop(L);
-	for(std::vector<CraftDefinition*>::const_iterator
+	for (std::vector<CraftDefinition*>::const_iterator
 		i = recipes_list.begin();
 		i != recipes_list.end(); i++)
 	{
@@ -411,28 +407,29 @@ int l_get_all_craft_recipes(lua_State *L)
 		tmpout.time = 0;
 		CraftDefinition *def = *i;
 		tmpout = def->getOutput(input, gdef);
-		if(tmpout.item.substr(0,output.item.length()) == output.item)
+		std::string query = tmpout.item;
+		char *fmtpos, *fmt = &query[0];
+		if (strtok_r(fmt, " ", &fmtpos) == output.item)
 		{
 			input = def->getInput(output, gdef);
 			lua_pushvalue(L, table_insert);
 			lua_pushvalue(L, table);
 			lua_newtable(L);
-			int k = 0;
+			int k = 1;
 			lua_newtable(L);
 			for(std::vector<ItemStack>::const_iterator
 				i = input.items.begin();
 				i != input.items.end(); i++, k++)
 			{
-				if (i->empty()) continue;
-				sprintf(tmp,"%d",k);
-				lua_pushstring(L,tmp);
-				lua_pushstring(L,i->name.c_str());
+				if (i->empty())
+					continue;
+				lua_pushinteger(L, k);
+				lua_pushstring(L, i->name.c_str());
 				lua_settable(L, -3);
 			}
 			lua_setfield(L, -2, "items");
 			setintfield(L, -1, "width", input.width);
-			switch (input.method)
-				{
+			switch (input.method) {
 				case CRAFT_METHOD_NORMAL:
 					lua_pushstring(L,"normal");
 					break;
@@ -446,8 +443,10 @@ int l_get_all_craft_recipes(lua_State *L)
 					lua_pushstring(L,"unknown");
 				}
 			lua_setfield(L, -2, "type");
-			if(lua_pcall(L, 2, 0, 0))
-			script_error(L, "error: %s", lua_tostring(L, -1));
+			lua_pushstring(L, &tmpout.item[0]);
+			lua_setfield(L, -2, "output");
+			if (lua_pcall(L, 2, 0, 0))
+				script_error(L, "error: %s", lua_tostring(L, -1));
 		}
 	}
 	return 1;
diff --git a/src/scriptapi_env.cpp b/src/scriptapi_env.cpp
index 9bf7f0b556205980d472a890dc0c359921d97d62..efed58e66ed553be454d9035c8d685bf2e1f880a 100644
--- a/src/scriptapi_env.cpp
+++ b/src/scriptapi_env.cpp
@@ -662,9 +662,11 @@ int EnvRef::l_line_of_sight(lua_State *L) {
 	v3f pos2 = checkFloatPos(L, 2);
 	//read step size from lua
 	if(lua_isnumber(L, 3))
-	stepsize = lua_tonumber(L, 3);
+		stepsize = lua_tonumber(L, 3);
 
-	return (env->line_of_sight(pos1,pos2,stepsize));
+	lua_pushboolean(L, env->line_of_sight(pos1,pos2,stepsize));
+
+	return 1;
 }
 
 int EnvRef::l_find_path(lua_State *L)
diff --git a/src/scriptapi_object.cpp b/src/scriptapi_object.cpp
index 05433a598fae6433773dfc2c525f2f6389c97e20..531bb7a58ddf2d8dc1f4650c8b6b058d5e021e54 100644
--- a/src/scriptapi_object.cpp
+++ b/src/scriptapi_object.cpp
@@ -26,6 +26,30 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "scriptapi_item.h"
 #include "scriptapi_entity.h"
 #include "scriptapi_common.h"
+#include "hud.h"
+
+
+struct EnumString es_HudElementType[] =
+{
+	{HUD_ELEM_IMAGE,     "image"},
+	{HUD_ELEM_TEXT,      "text"},
+	{HUD_ELEM_STATBAR,   "statbar"},
+	{HUD_ELEM_INVENTORY, "inventory"},
+	{0, NULL},
+};
+
+struct EnumString es_HudElementStat[] =
+{
+	{HUD_STAT_POS,    "pos"},
+	{HUD_STAT_NAME,   "name"},
+	{HUD_STAT_SCALE,  "scale"},
+	{HUD_STAT_TEXT,   "text"},
+	{HUD_STAT_NUMBER, "number"},
+	{HUD_STAT_ITEM,   "item"},
+	{HUD_STAT_DIR,    "direction"},
+	{0, NULL},
+};
+
 
 /*
 	ObjectRef
@@ -700,6 +724,165 @@ int ObjectRef::l_get_player_control_bits(lua_State *L)
 	return 1;
 }
 
+// hud_add(self, form)
+int ObjectRef::l_hud_add(lua_State *L)
+{
+	ObjectRef *ref = checkobject(L, 1);
+	Player *player = getplayer(ref);
+	if (player == NULL)
+		return 0;
+
+	HudElement *elem = new HudElement;
+	
+	elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type",
+								es_HudElementType, HUD_ELEM_TEXT);
+	
+	lua_getfield(L, 2, "position");
+	elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
+	lua_pop(L, 1);
+	
+	lua_getfield(L, 2, "scale");
+	elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f();
+	lua_pop(L, 1);
+	
+	elem->name   = getstringfield_default(L, 2, "name", "");
+	elem->text   = getstringfield_default(L, 2, "text", "");
+	elem->number = getintfield_default(L, 2, "number", 0);
+	elem->item   = getintfield_default(L, 2, "item", 0);
+	elem->dir    = getintfield_default(L, 2, "dir", 0);
+
+	u32 id = get_server(L)->hudAdd(player, elem);
+	if (id == (u32)-1) {
+		delete elem;
+		return 0;
+	}
+
+	lua_pushnumber(L, id);
+	return 1;
+}
+
+// hud_remove(self, id)
+int ObjectRef::l_hud_remove(lua_State *L)
+{
+	ObjectRef *ref = checkobject(L, 1);
+	Player *player = getplayer(ref);
+	if (player == NULL)
+		return 0;
+
+	u32 id = -1;
+	if (!lua_isnil(L, 2))
+		id = lua_tonumber(L, 2);
+	
+	if (!get_server(L)->hudRemove(player, id))
+		return 0;
+
+	lua_pushboolean(L, true);
+	return 1;
+}
+
+// hud_change(self, id, stat, data)
+int ObjectRef::l_hud_change(lua_State *L)
+{
+	ObjectRef *ref = checkobject(L, 1);
+	Player *player = getplayer(ref);
+	if (player == NULL)
+		return 0;
+
+	u32 id = -1;
+	if (!lua_isnil(L, 2))
+		id = lua_tonumber(L, 2);
+	
+	HudElementStat stat = (HudElementStat)getenumfield(L, 3, "stat",
+								es_HudElementStat, HUD_STAT_NUMBER);
+	
+	if (id >= player->hud.size())
+		return 0;
+	
+	void *value = NULL;
+	HudElement *e = player->hud[id];
+	if (!e)
+		return 0;
+	
+	switch (stat) {
+		case HUD_STAT_POS:
+			e->pos = read_v2f(L, 4);
+			value = &e->pos;
+			break;
+		case HUD_STAT_NAME:
+			e->name = lua_tostring(L, 4);
+			value = &e->name;
+			break;
+		case HUD_STAT_SCALE:
+			e->scale = read_v2f(L, 4);
+			value = &e->scale;
+			break;
+		case HUD_STAT_TEXT:
+			e->text = lua_tostring(L, 4);
+			value = &e->text;
+			break;
+		case HUD_STAT_NUMBER:
+			e->number = lua_tonumber(L, 4);
+			value = &e->number;
+			break;
+		case HUD_STAT_ITEM:
+			e->item = lua_tonumber(L, 4);
+			value = &e->item;
+			break;
+		case HUD_STAT_DIR:
+			e->dir = lua_tonumber(L, 4);
+			value = &e->dir;
+	}
+	
+	get_server(L)->hudChange(player, id, stat, value);
+
+	lua_pushboolean(L, true);
+	return 1;
+}
+
+// hud_get(self, id)
+int ObjectRef::l_hud_get(lua_State *L)
+{
+	ObjectRef *ref = checkobject(L, 1);
+	Player *player = getplayer(ref);
+	if (player == NULL)
+		return 0;
+
+	u32 id = lua_tonumber(L, -1);
+	if (id >= player->hud.size())
+		return 0;
+	
+	HudElement *e = player->hud[id];
+	if (!e)
+		return 0;
+	
+	lua_newtable(L);
+	
+	lua_pushstring(L, es_HudElementType[(u8)e->type].str);
+	lua_setfield(L, -2, "type");
+	
+	push_v2f(L, e->pos);
+	lua_setfield(L, -2, "position");
+	
+	lua_pushstring(L, e->name.c_str());
+	lua_setfield(L, -2, "name");
+	
+	push_v2f(L, e->scale);
+	lua_setfield(L, -2, "scale");
+	
+	lua_pushstring(L, e->text.c_str());
+	lua_setfield(L, -2, "text");
+	
+	lua_pushnumber(L, e->number);
+	lua_setfield(L, -2, "number");
+	
+	lua_pushnumber(L, e->item);
+	lua_setfield(L, -2, "item");
+	
+	lua_pushnumber(L, e->dir);
+	lua_setfield(L, -2, "dir");
+
+	return 1;
+}
 
 ObjectRef::ObjectRef(ServerActiveObject *object):
 	m_object(object)
@@ -807,6 +990,12 @@ const luaL_reg ObjectRef::methods[] = {
 	luamethod(ObjectRef, get_inventory_formspec),
 	luamethod(ObjectRef, get_player_control),
 	luamethod(ObjectRef, get_player_control_bits),
+	luamethod(ObjectRef, hud_add),
+	luamethod(ObjectRef, hud_remove),
+	luamethod(ObjectRef, hud_change),
+	luamethod(ObjectRef, hud_get),
+	//luamethod(ObjectRef, hud_lock_next_bar),
+	//luamethod(ObjectRef, hud_unlock_bar),
 	{0,0}
 };
 
diff --git a/src/scriptapi_object.h b/src/scriptapi_object.h
index a44016933517c8d3f71a2d0042bec8cb52fe980e..fd46f2cf60739141fe91e1083fde7f64a3936e7a 100644
--- a/src/scriptapi_object.h
+++ b/src/scriptapi_object.h
@@ -190,6 +190,18 @@ class ObjectRef
 	// get_player_control_bits(self)
 	static int l_get_player_control_bits(lua_State *L);
 
+	// hud_add(self, id, form)
+	static int l_hud_add(lua_State *L);
+
+	// hud_rm(self, id)
+	static int l_hud_remove(lua_State *L);
+
+	// hud_change(self, id, stat, data)
+	static int l_hud_change(lua_State *L);
+
+	// hud_get(self, id)
+	static int l_hud_get(lua_State *L);
+
 public:
 	ObjectRef(ServerActiveObject *object);
 
diff --git a/src/scriptapi_types.cpp b/src/scriptapi_types.cpp
index 01a9b3bc3bc9c8d2219151afad83ec5b1719cff5..f304511080c57c2fda5b7e504a84cf15da265bf0 100644
--- a/src/scriptapi_types.cpp
+++ b/src/scriptapi_types.cpp
@@ -42,6 +42,15 @@ void push_v3f(lua_State *L, v3f p)
 	lua_setfield(L, -2, "z");
 }
 
+void push_v2f(lua_State *L, v2f p)
+{
+	lua_newtable(L);
+	lua_pushnumber(L, p.X);
+	lua_setfield(L, -2, "x");
+	lua_pushnumber(L, p.Y);
+	lua_setfield(L, -2, "y");
+}
+
 v2s16 read_v2s16(lua_State *L, int index)
 {
 	v2s16 p;
diff --git a/src/scriptapi_types.h b/src/scriptapi_types.h
index 1eeed66df67fc078b45f250b0ed327085cb4e634..dd0b125e6920ad18a3af4064be1fbffd77751e88 100644
--- a/src/scriptapi_types.h
+++ b/src/scriptapi_types.h
@@ -81,6 +81,7 @@ std::vector<aabb3f>
 void          push_v3s16                    (lua_State *L, v3s16 p);
 void          pushFloatPos                  (lua_State *L, v3f p);
 void          push_v3f                      (lua_State *L, v3f p);
+void          push_v2f                      (lua_State *L, v2f p);
 
 
 MapNode readnode(lua_State *L, int index, INodeDefManager *ndef);
diff --git a/src/server.cpp b/src/server.cpp
index 05075a72c3079880805810f089c862f002ba242a..241826ba21c516159da139d70623cac4cc91864d 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -904,6 +904,9 @@ Server::~Server()
 	*/
 	stop();
 
+	//shutdown all emerge threads first!
+	delete m_emerge;
+
 	/*
 		Delete clients
 	*/
@@ -923,7 +926,6 @@ Server::~Server()
 	// Delete things in the reverse order of creation
 	delete m_env;
 	delete m_rollback;
-	delete m_emerge;
 	delete m_event;
 	delete m_itemdef;
 	delete m_nodedef;
@@ -3447,7 +3449,9 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
 	// Send as reliable
 	m_con.Send(peer_id, 0, data, true);
 }
-void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
+
+void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
+					const std::string formname)
 {
 	DSTACK(__FUNCTION_NAME);
 
@@ -3468,7 +3472,9 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, co
 }
 
 // Spawns a particle on peer with peer_id
-void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
+void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
+				float expirationtime, float size, bool collisiondetection,
+				std::string texture)
 {
 	DSTACK(__FUNCTION_NAME);
 
@@ -3490,7 +3496,9 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
 }
 
 // Spawns a particle on all peers
-void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
+void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
+				float expirationtime, float size, bool collisiondetection,
+				std::string texture)
 {
 	for(std::map<u16, RemoteClient*>::iterator
 		i = m_clients.begin();
@@ -3593,6 +3601,76 @@ void Server::SendDeleteParticleSpawnerAll(u32 id)
 	}
 }
 
+void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
+{
+	std::ostringstream os(std::ios_base::binary);
+
+	// Write command
+	writeU16(os, TOCLIENT_HUDADD);
+	writeU32(os, id);
+	writeU8(os, (u8)form->type);
+	writeV2F1000(os, form->pos);
+	os << serializeString(form->name);
+	writeV2F1000(os, form->scale);
+	os << serializeString(form->text);
+	writeU32(os, form->number);
+	writeU32(os, form->item);
+	writeU32(os, form->dir);
+
+	// Make data buffer
+	std::string s = os.str();
+	SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+	// Send as reliable
+	m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendHUDRemove(u16 peer_id, u32 id)
+{
+	std::ostringstream os(std::ios_base::binary);
+
+	// Write command
+	writeU16(os, TOCLIENT_HUDRM);
+	writeU32(os, id);
+
+	// Make data buffer
+	std::string s = os.str();
+	SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+	// Send as reliable
+	m_con.Send(peer_id, 0, data, true);
+}
+
+void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
+{
+	std::ostringstream os(std::ios_base::binary);
+
+	// Write command
+	writeU16(os, TOCLIENT_HUDCHANGE);
+	writeU32(os, id);
+	writeU8(os, (u8)stat);
+	switch (stat) {
+		case HUD_STAT_POS:
+		case HUD_STAT_SCALE:
+			writeV2F1000(os, *(v2f *)value);
+			break;
+		case HUD_STAT_NAME:
+		case HUD_STAT_TEXT:
+			os << serializeString(*(std::string *)value);
+			break;
+		case HUD_STAT_NUMBER:
+		case HUD_STAT_ITEM:
+		case HUD_STAT_DIR:
+		default:
+			writeU32(os, *(u32 *)value);
+			break;
+	}
+
+	// Make data buffer
+	std::string s = os.str();
+	SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
+	// Send as reliable
+	m_con.Send(peer_id, 0, data, true);
+}
+
 void Server::BroadcastChatMessage(const std::wstring &message)
 {
 	for(std::map<u16, RemoteClient*>::iterator
@@ -4546,6 +4624,39 @@ bool Server::showFormspec(const char *playername, const std::string &formspec, c
 	return true;
 }
 
+u32 Server::hudAdd(Player *player, HudElement *form) {
+	if (!player)
+		return -1;
+
+	u32 id = hud_get_free_id(player);
+	if (id < player->hud.size())
+		player->hud[id] = form;
+	else
+		player->hud.push_back(form);
+	
+	SendHUDAdd(player->peer_id, id, form);
+	return id;
+}
+
+bool Server::hudRemove(Player *player, u32 id) {
+	if (!player || id >= player->hud.size() || !player->hud[id])
+		return false;
+
+	delete player->hud[id];
+	player->hud[id] = NULL;
+	
+	SendHUDRemove(player->peer_id, id);
+	return true;
+}
+
+bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
+	if (!player)
+		return false;
+
+	SendHUDChange(player->peer_id, id, stat, data);
+	return true;
+}
+
 void Server::notifyPlayers(const std::wstring msg)
 {
 	BroadcastChatMessage(msg);
diff --git a/src/server.h b/src/server.h
index ea1cb79af529aef55fc09de91c2c583abdd1dac9..52606b0cb75f7fc2d6255e4e273bb344b6229f01 100644
--- a/src/server.h
+++ b/src/server.h
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 #include "inventory.h"
 #include "ban.h"
+#include "hud.h"
 #include "gamedef.h"
 #include "serialization.h" // For SER_FMT_VER_INVALID
 #include "mods.h"
@@ -51,6 +52,7 @@ class EventManager;
 class PlayerSAO;
 class IRollbackManager;
 class EmergeManager;
+//struct HudElement;
 
 class ServerError : public std::exception
 {
@@ -534,6 +536,11 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 	}
 
 	bool showFormspec(const char *name, const std::string &formspec, const std::string &formname);
+	
+	u32 hudAdd(Player *player, HudElement *element);
+	bool hudRemove(Player *player, u32 id);
+	bool hudChange(Player *player, u32 id, HudElementStat stat, void *value);
+	
 private:
 
 	// con::PeerHandler implementation.
@@ -573,6 +580,9 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 	void SendPlayerPrivileges(u16 peer_id);
 	void SendPlayerInventoryFormspec(u16 peer_id);
 	void SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname);
+	void SendHUDAdd(u16 peer_id, u32 id, HudElement *form);
+	void SendHUDRemove(u16 peer_id, u32 id);
+	void SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value);
 	/*
 		Send a node removal/addition event to all clients except ignore_id.
 		Additionally, if far_players!=NULL, players further away than
diff --git a/src/shader.cpp b/src/shader.cpp
index a224c82bb271eda6053f0e57f382c618b4ff9772..62b7c99a936f71d0bd7081b6b3e852a4613e64a0 100644
--- a/src/shader.cpp
+++ b/src/shader.cpp
@@ -388,6 +388,12 @@ ShaderSource::ShaderSource(IrrlichtDevice *device):
 ShaderSource::~ShaderSource()
 {
 	//m_shader_callback->drop();
+
+	for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
+			iter != m_global_setters.end(); iter++) {
+		delete *iter;
+	}
+	m_global_setters.clear();
 }
 
 u32 ShaderSource::getShaderId(const std::string &name)
diff --git a/src/shader.h b/src/shader.h
index a7367eaff46a3895674382501bc8b32aaa16c46c..a62569602e1ac94dc3c329edda3a2be01841b05f 100644
--- a/src/shader.h
+++ b/src/shader.h
@@ -49,6 +49,7 @@ struct ShaderInfo
 	video::E_MATERIAL_TYPE material;
 
 	ShaderInfo(): name(""), material(video::EMT_SOLID) {}
+	virtual ~ShaderInfo() {}
 };
 
 /*
diff --git a/src/sound_openal.cpp b/src/sound_openal.cpp
index cc5261eaeb82619ee2eb4ab3051466ab1c3500d5..0cfbc279829a95978c94979d3339eb4be67332d8 100644
--- a/src/sound_openal.cpp
+++ b/src/sound_openal.cpp
@@ -271,6 +271,16 @@ class OpenALSoundManager: public ISoundManager
 		m_context = NULL;
 		alcCloseDevice(m_device);
 		m_device = NULL;
+
+		for (std::map<std::string, std::vector<SoundBuffer*> >::iterator i = m_buffers.begin();
+				i != m_buffers.end(); i++) {
+			for (std::vector<SoundBuffer*>::iterator iter = (*i).second.begin();
+					iter != (*i).second.end(); iter++) {
+				delete *iter;
+			}
+			(*i).second.clear();
+		}
+		m_buffers.clear();
 		infostream<<"Audio: Deinitialized."<<std::endl;
 	}
 	
diff --git a/src/test.cpp b/src/test.cpp
index d18bd8b931d5064569dc075bf5eb241980714079..d1f53f8803ef8c6b6f3bae2eb73058c1bf292ef8 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -1781,5 +1781,7 @@ void run_tests()
 		errorstream<<"run_tests() aborting."<<std::endl;
 		abort();
 	}
+	delete idef;
+	delete ndef;
 }
 
diff --git a/src/tile.cpp b/src/tile.cpp
index c5e8a2a9dfc354af64eaca9c26a704a91188e02b..39f47962e9da676f07fd09c5216b08ff0499f984 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -201,6 +201,13 @@ struct SourceAtlasPointer
 class SourceImageCache
 {
 public:
+	~SourceImageCache() {
+		for(std::map<std::string, video::IImage*>::iterator iter = m_images.begin();
+				iter != m_images.end(); iter++) {
+			iter->second->drop();
+		}
+		m_images.clear();
+	}
 	void insert(const std::string &name, video::IImage *img,
 			bool prefer_local, video::IVideoDriver *driver)
 	{
@@ -209,23 +216,28 @@ class SourceImageCache
 		std::map<std::string, video::IImage*>::iterator n;
 		n = m_images.find(name);
 		if(n != m_images.end()){
-			video::IImage *oldimg = n->second;
-			if(oldimg)
-				oldimg->drop();
+			if(n->second)
+				n->second->drop();
 		}
+
+		video::IImage* toadd = img;
+		bool need_to_grab = true;
+
 		// Try to use local texture instead if asked to
 		if(prefer_local){
 			std::string path = getTexturePath(name.c_str());
 			if(path != ""){
 				video::IImage *img2 = driver->createImageFromFile(path.c_str());
 				if(img2){
-					m_images[name] = img2;
-					return;
+					toadd = img2;
+					need_to_grab = false;
 				}
 			}
 		}
-		img->grab();
-		m_images[name] = img;
+
+		if (need_to_grab)
+			toadd->grab();
+		m_images[name] = toadd;
 	}
 	video::IImage* get(const std::string &name)
 	{
@@ -254,8 +266,7 @@ class SourceImageCache
 		infostream<<"SourceImageCache::getOrLoad(): Loading path \""<<path
 				<<"\""<<std::endl;
 		video::IImage *img = driver->createImageFromFile(path.c_str());
-		// Even if could not be loaded, put as NULL
-		//m_images[name] = img;
+
 		if(img){
 			m_images[name] = img;
 			img->grab(); // Grab for caller
@@ -274,7 +285,7 @@ class TextureSource : public IWritableTextureSource
 {
 public:
 	TextureSource(IrrlichtDevice *device);
-	~TextureSource();
+	virtual ~TextureSource();
 
 	/*
 		Example case:
@@ -454,6 +465,28 @@ TextureSource::TextureSource(IrrlichtDevice *device):
 
 TextureSource::~TextureSource()
 {
+	video::IVideoDriver* driver = m_device->getVideoDriver();
+
+	unsigned int textures_before = driver->getTextureCount();
+
+	for (std::vector<SourceAtlasPointer>::iterator iter =
+			m_atlaspointer_cache.begin();  iter != m_atlaspointer_cache.end();
+			iter++)
+	{
+		video::ITexture *t = driver->getTexture(iter->name.c_str());
+
+		//cleanup texture
+		if (t)
+			driver->removeTexture(t);
+
+		//cleanup source image
+		if (iter->atlas_img)
+			iter->atlas_img->drop();
+	}
+	m_atlaspointer_cache.clear();
+
+	infostream << "~TextureSource() "<< textures_before << "/"
+			<< driver->getTextureCount() << std::endl;
 }
 
 u32 TextureSource::getTextureId(const std::string &name)
@@ -1205,7 +1238,6 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 			core::dimension2d<u32> dim = image->getDimension();
 			baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
 			image->copyTo(baseimg);
-			image->drop();
 		}
 		// Else blit on base.
 		else
@@ -1224,9 +1256,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 					video::SColor(255,255,255,255),
 					NULL);*/
 			blit_with_alpha(image, baseimg, pos_from, pos_to, dim);
-			// Drop image
-			image->drop();
 		}
+		//cleanup
+		image->drop();
 	}
 	else
 	{
@@ -1630,6 +1662,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 			video::IImage *image = driver->createImage(rtt, v2s32(0,0), dim);
 			assert(image);
 
+			//cleanup texture
+			driver->removeTexture(rtt);
+
 			baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
 
 			if(image)
diff --git a/util/master/index.html b/util/master/index.html
index 63ee5c70fa453a079c7d91cc438c1f7a8f1cd0e1..328dd893424f3908a1779fe494a47c16ca106b06 100644
--- a/util/master/index.html
+++ b/util/master/index.html
@@ -5,7 +5,7 @@
         <title>Minetest server list</title>
         <link rel="stylesheet" href="style.css"/>
     </head>
-    <body><div id="table"></div></body>
+    <body><div id="servers_table"></div></body>
 </html>
 <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
 <script src="list.js"></script>
diff --git a/util/master/list.js b/util/master/list.js
index 990bb6ded9f11f33f5ad162724b34bcb7a540e69..98f5ad490a6ff6b1a3ca7582c638b3a7ba77a0e1 100644
--- a/util/master/list.js
+++ b/util/master/list.js
@@ -1,3 +1,5 @@
+var master_root, output_to;
+
 function e(s) {
     if (typeof s === "undefined") s = '';
     return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); //mc"
@@ -39,7 +41,7 @@ function human_time(t, abs) {
 
 function success(r) {
     if (!r || !r.list) return;
-    var h = '<table class="mts_table"><tr class="mts_head"><th>ip[:port]</th><th>clients/max</th><th>version gameid</th><th>name</th><th>desc</th><th>flags</th><th>uptime</th><th>ping</th></tr>';
+    var h = '<table class="mts_table"><tr class="mts_head"><th>ip[:port]</th><th>clients/max</th><th>version gameid</th><th>name</th><th>description</th><th>flags</th><th>uptime</th><th>ping</th></tr>';
     for (var i = 0; i < r.list.length; ++i) {
         var s = r.list[i];
         if (!s) continue;
@@ -60,9 +62,8 @@ function success(r) {
         h += '</tr>';
     }
     h += '</table>'
-    jQuery('#table').html(h);
+    jQuery(output_to || '#servers_table').html(h);
 }
-var master_root;
 
 function get() {
     jQuery.getJSON((master_root || '') + 'list', success);