diff --git a/game/engines/default/engine/ui/TextzoneList.lua b/game/engines/default/engine/ui/TextzoneList.lua
index 24a35ddec8069c2645debe7ce1a7904fc57d3d22..85bb6d808175002faec3f69a59332e96dcd007ef 100644
--- a/game/engines/default/engine/ui/TextzoneList.lua
+++ b/game/engines/default/engine/ui/TextzoneList.lua
@@ -74,7 +74,7 @@ function _M:createItem(item, text)
 	local old_style = self.font:getStyle()
 
 	-- Handle normal text
-	if type(text) == "string" then
+	if false and type(text) == "string" then
 		local list = text:splitLines(self.w, self.font)
 		local scroll = 1
 		local max = #list
@@ -109,6 +109,21 @@ function _M:createItem(item, text)
 		-- Draw the list items
 		local gen = self.font:draw(text:toString(), self.fw, 255, 255, 255)
 
+		for i = 1, #gen do
+			if gen[i].line_extra then
+				if gen[i].line_extra:sub(1, 7) == "linebg:" then
+					local color = colors[gen[i].line_extra:sub(8)]
+					if color then
+						gen[i].background = colors.simple(color)
+						gen[i].background[4] = 255
+					else
+						local c = gen[i].line_extra
+						gen[i].background = {string.parseHex(c:sub(8, 9)), string.parseHex(c:sub(10, 11)), string.parseHex(c:sub(12, 13)), string.parseHex(c:sub(14, 15))}
+					end
+				end
+			end
+		end
+
 		local scroll = 1
 		local max = #gen
 		local max_display = math.floor(self.h / self.fh)
@@ -154,6 +169,11 @@ function _M:display(x, y)
 	for i = self.scroll, max do
 		local item = self.list[i]
 		if not item then break end
+
+		if item.background then
+			core.display.drawQuad(x, y, self.fw, self.fh, item.background[1], item.background[2], item.background[3], item.background[4])
+		end
+
 		if item.is_separator then
 			self.sep:display(x, y + (self.fh - self.sep.h) / 2)
 		else
diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua
index 8a51d57c64bb7942a24772fdcdbdbb9b03fe8382..c7edf150a496bbe7733bb28b1478ee24459329f2 100644
--- a/game/engines/default/engine/utils.lua
+++ b/game/engines/default/engine/utils.lua
@@ -211,6 +211,7 @@ function string.lpegSub(s, patt, repl)
 end
 
 -- Those matching patterns are used both by splitLine and drawColorString*
+local Pextra = "&" * -lpeg.S"#"^1
 local Puid = "UID:" * lpeg.R"09"^1 * ":" * lpeg.R"09"
 local Puid_cap = "UID:" * lpeg.C(lpeg.R"09"^1) * ":" * lpeg.C(lpeg.R"09")
 local Pcolorname = (lpeg.R"AZ" + "_")^3
@@ -236,7 +237,7 @@ function string.splitLine(str, max_width, font)
 	local ls = str:split(lpeg.S"\n ")
 	for i = 1, #ls do
 		local v = ls[i]
-		local shortv = v:lpegSub("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle) * "#", "")
+		local shortv = v:lpegSub("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle + Pextra) * "#", "")
 		local w, h = font:size(shortv)
 
 		if cur_size + space_w + w < max_width then
@@ -323,7 +324,7 @@ end
 
 local tmps = core.display.newSurface(1, 1)
 getmetatable(tmps).__index.drawColorString = function(s, font, str, x, y, r, g, b, alpha_from_texture, limit_w)
-	local list = str:split("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle) * "#", true)
+	local list = str:split("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle + Pextra) * "#", true)
 	r = r or 255
 	g = g or 255
 	b = b or 255
@@ -337,6 +338,7 @@ getmetatable(tmps).__index.drawColorString = function(s, font, str, x, y, r, g,
 		local col = lpeg.match("#" * lpeg.C(Pcolorname) * "#", v)
 		local uid, mo = lpeg.match("#" * Puid_cap * "#", v)
 		local fontstyle = lpeg.match("#" * Pfontstyle_cap * "#", v)
+		local extra = lpeg.match("#" * lpeg.C(Pextra) * "#", v)
 		if nr and ng and nb then
 			oldr, oldg, oldb = r, g, b
 			r, g, b = nr:parseHex(), ng:parseHex(), nb:parseHex()
@@ -364,6 +366,8 @@ getmetatable(tmps).__index.drawColorString = function(s, font, str, x, y, r, g,
 			end
 		elseif fontstyle then
 			font:setStyle(fontstyle)
+		elseif extra then
+			--
 		else
 			local w, h = font:size(v)
 			local stop = false
@@ -391,7 +395,7 @@ end
 
 
 getmetatable(tmps).__index.drawColorStringBlended = function(s, font, str, x, y, r, g, b, alpha_from_texture, limit_w)
-	local list = str:split("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle) * "#", true)
+	local list = str:split("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle + Pextra) * "#", true)
 	r = r or 255
 	g = g or 255
 	b = b or 255
@@ -405,6 +409,7 @@ getmetatable(tmps).__index.drawColorStringBlended = function(s, font, str, x, y,
 		local col = lpeg.match("#" * lpeg.C(Pcolorname) * "#", v)
 		local uid, mo = lpeg.match("#" * Puid_cap * "#", v)
 		local fontstyle = lpeg.match("#" * Pfontstyle_cap * "#", v)
+		local extra = lpeg.match("#" * lpeg.C(Pextra) * "#", v)
 		if nr and ng and nb then
 			oldr, oldg, oldb = r, g, b
 			r, g, b = nr:parseHex(), ng:parseHex(), nb:parseHex()
@@ -432,6 +437,8 @@ getmetatable(tmps).__index.drawColorStringBlended = function(s, font, str, x, y,
 			end
 		elseif fontstyle then
 			font:setStyle(fontstyle)
+		elseif extra then
+			--
 		else
 			local w, h = font:size(v)
 			local stop = false
@@ -470,7 +477,7 @@ local tmps = core.display.newFont("/data/font/Vera.ttf", 12)
 local word_size_cache = {}
 local fontoldsize = getmetatable(tmps).__index.size
 getmetatable(tmps).__index.size = function(font, str)
-	local list = str:split("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle) * "#", true)
+	local list = str:split("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle + Pextra) * "#", true)
 	local mw, mh = 0, 0
 	local fstyle = font:getStyle()
 	word_size_cache[font] = word_size_cache[font] or {}
@@ -482,6 +489,7 @@ getmetatable(tmps).__index.size = function(font, str)
 		local col = lpeg.match("#" * lpeg.C(Pcolorname) * "#", v)
 		local uid, mo = lpeg.match("#" * Puid_cap * "#", v)
 		local fontstyle = lpeg.match("#" * Pfontstyle_cap * "#", v)
+		local extra = lpeg.match("#" * lpeg.C(Pextra) * "#", v)
 		if nr and ng and nb then
 			-- Ignore
 		elseif col then
@@ -502,6 +510,8 @@ getmetatable(tmps).__index.size = function(font, str)
 			font:setStyle(fontstyle)
 			fstyle = fontstyle
 			word_size_cache[font][fstyle] = word_size_cache[font][fstyle] or {}
+		elseif extra then
+			--
 		else
 			local w, h
 			if word_size_cache[font][fstyle][v] then
@@ -557,13 +567,14 @@ end
 --- Parse a string and return a tstring
 function string.toTString(str)
 	local tstr = tstring{}
-	local list = str:split(("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle) * "#") + lpeg.P"\n", true)
+	local list = str:split(("#" * (Puid + Pcolorcodefull + Pcolorname + Pfontstyle + Pextra) * "#") + lpeg.P"\n", true)
 	for i = 1, #list do
 		v = list[i]
 		local nr, ng, nb = lpeg.match("#" * lpeg.C(Pcolorcode) * lpeg.C(Pcolorcode) * lpeg.C(Pcolorcode) * "#", v)
 		local col = lpeg.match("#" * lpeg.C(Pcolorname) * "#", v)
 		local uid, mo = lpeg.match("#" * Puid_cap * "#", v)
 		local fontstyle = lpeg.match("#" * Pfontstyle_cap * "#", v)
+		local extra = lpeg.match("#" * lpeg.C(Pextra) * "#", v)
 		if nr and ng and nb then
 			tstr:add({"color", nr:parseHex(), ng:parseHex(), nb:parseHex()})
 		elseif col then
@@ -572,6 +583,8 @@ function string.toTString(str)
 			tstr:add({"uid", tonumber(uid)})
 		elseif fontstyle then
 			tstr:add({"font", fontstyle})
+		elseif extra then
+			tstr:add({"extra", extra:sub(2)})
 		elseif v == "\n" then
 			tstr:add(true)
 		else
@@ -596,6 +609,7 @@ function tstring:toString()
 			elseif v[1] == "color" then ret[#ret+1] = ("#%02x%02x%02x#"):format(v[2], v[3], v[4]):upper()
 			elseif v[1] == "font" then ret[#ret+1] = "#{"..v[2].."}#"
 			elseif v[1] == "uid" then ret[#ret+1] = "#UID:"..v[2]..":0#"
+			elseif v[1] == "extra" then ret[#ret+1] = "#&"..v[2].."#"
 			end
 		end
 	end
@@ -639,6 +653,8 @@ function tstring:splitLines(max_width, font)
 		elseif tv == "table" and v[1] == "font" then
 			font:setStyle(v[2])
 			ret[#ret+1] = v
+		elseif tv == "table" and v[1] == "extra" then
+			ret[#ret+1] = v
 		elseif tv == "table" and v[1] == "uid" then
 			local e = __uids[v[2]]
 			if e and game.level then
@@ -724,6 +740,8 @@ function tstring:makeLineTextures(max_width, font, no_split, r, g, b)
 				r, g, b = v[2], v[3], v[4]
 			elseif v[1] == "font" then
 				font:setStyle(v[2])
+			elseif v[1] == "extra" then
+				--
 			elseif v[1] == "uid" then
 				local e = __uids[v[2]]
 				if e then
@@ -782,6 +800,8 @@ function tstring:drawOnSurface(s, max_width, max_lines, font, x, y, r, g, b, no_
 				r, g, b = v[2], v[3], v[4]
 			elseif v[1] == "font" then
 				font:setStyle(v[2])
+			elseif v[1] == "extra" then
+				--
 			elseif v[1] == "uid" then
 				local e = __uids[v[2]]
 				if e then
diff --git a/src/core_lua.c b/src/core_lua.c
index 92fbfa8fa23ec8dc96e56aa22673e689fb1bb6c4..18adbb245f7057168b07bf6d4ddb86945b75fa92 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -486,7 +486,7 @@ static int sdl_surface_drawstring_newsurface_aa(lua_State *L)
 	return 1;
 }
 
-static font_make_texture_line(lua_State *L, SDL_Surface *s, int id, bool is_separator)
+static font_make_texture_line(lua_State *L, SDL_Surface *s, int id, bool is_separator, int id_real_line, char *line_data)
 {
 	lua_createtable(L, 0, 5);
 
@@ -515,6 +515,17 @@ static font_make_texture_line(lua_State *L, SDL_Surface *s, int id, bool is_sepa
 	lua_pushnumber(L, s->h);
 	lua_rawset(L, -3);
 
+	lua_pushliteral(L, "line");
+	lua_pushnumber(L, id_real_line);
+	lua_rawset(L, -3);
+
+	if (line_data)
+	{
+		lua_pushliteral(L, "line_extra");
+		lua_pushstring(L, line_data);
+		lua_rawset(L, -3);
+	}
+
 	if (is_separator)
 	{
 		lua_pushliteral(L, "is_separator");
@@ -549,6 +560,8 @@ static int sdl_font_draw(lua_State *L)
 	lua_newtable(L);
 
 	int nb_lines = 1;
+	int id_real_line = 1;
+	char *line_data = NULL;
 	char *start = (char*)str, *stop = (char*)str, *next = (char*)str;
 	int max_size = 0;
 	int size = 0;
@@ -580,13 +593,18 @@ static int sdl_font_draw(lua_State *L)
 			if (!no_linefeed && (force_nl || (txt && (size + txt->w > max_width))))
 			{
 				// Push it & reset the surface
-				font_make_texture_line(L, s, nb_lines, is_separator);
+				font_make_texture_line(L, s, nb_lines, is_separator, id_real_line, line_data);
 				is_separator = FALSE;
 				SDL_FillRect(s, NULL, SDL_MapRGBA(s->format, 0, 0, 0, 0));
 //				printf("Ending previous line at size %d\n", size);
 				if (size > max_size) max_size = size;
 				size = 0;
 				nb_lines++;
+				if (force_nl)
+				{
+					id_real_line++;
+					if (line_data) { free(line_data); line_data = NULL; }
+				}
 				force_nl = FALSE;
 			}
 
@@ -637,6 +655,11 @@ static int sdl_font_draw(lua_State *L)
 					}
 					lua_pop(L, 1);
 				}
+				// Extra data
+				else if ((*(next+1) == '&')) {
+					if (line_data) { free(line_data); line_data = NULL; }
+					line_data = strndup(next + 2, codestop - (next+2));
+				}
 				// Color
 				else {
 					if ((codestop - (next+1) == 4) && (*(next+1) == 'L') && (*(next+2) == 'A') && (*(next+3) == 'S') && (*(next+4) == 'T'))
@@ -715,12 +738,14 @@ static int sdl_font_draw(lua_State *L)
 		next++;
 	}
 
-	font_make_texture_line(L, s, nb_lines, is_separator);
+	font_make_texture_line(L, s, nb_lines, is_separator, id_real_line, line_data);
 	if (size > max_size) max_size = size;
 
 	if (txt) SDL_FreeSurface(txt);
 	SDL_FreeSurface(s);
 
+	if (line_data) free(line_data);
+
 	lua_pushnumber(L, nb_lines);
 	lua_pushnumber(L, max_size);