← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/fh1_multiline_textarea into lp:widelands

 

GunChleoc has proposed merging lp:~widelands-dev/widelands/fh1_multiline_textarea into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/fh1_multiline_textarea/+merge/292033

DO NOT REVIEW. We just want a Win32 build.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/fh1_multiline_textarea into lp:widelands.
=== modified file 'data/campaigns/atl01.wmf/scripting/init.lua'
--- data/campaigns/atl01.wmf/scripting/init.lua	2016-01-28 05:24:34 +0000
+++ data/campaigns/atl01.wmf/scripting/init.lua	2016-04-23 13:15:34 +0000
@@ -72,9 +72,8 @@
       p1,
       -- TRANSLATORS: Short message title. Translate as "Lost!" if you don't have enough space.
       pgettext("message_short_title", "Building lost!"),
-      rt("image=".. f.immovable.descr.representative_image,
-         p(_"We lost a building to the ocean!")
-      ),
+      rt(p(img(f.immovable.descr.representative_image) ..
+           _"We lost a building to the ocean!")),
       {
          field = f,
          popup = false,

=== modified file 'data/campaigns/atl01.wmf/scripting/texts.lua'
--- data/campaigns/atl01.wmf/scripting/texts.lua	2016-03-03 17:07:13 +0000
+++ data/campaigns/atl01.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -31,12 +31,12 @@
    name = "obj_ensure_build_wares_production",
    title = _"Ensure the supply of building wares",
    number = 6,
-   body = objective_text(_"Supply Building Wares", _
-[[Supply basic building material for your economy:]] .. paragraphdivider() ..
-      listitem_bullet(_[[Build a quarry]]) ..
-      listitem_bullet(_[[Build two woodcutter’s houses]]) ..
-      listitem_bullet(_[[Build two forester’s houses]]) ..
-      listitem_bullet(_[[Build a sawmill]])
+   body = objective_text(_"Supply Building Wares",
+      _[[Supply basic building material for your economy:]] ..
+      li(_[[Build a quarry]]) ..
+      li(_[[Build two woodcutter’s houses]]) ..
+      li(_[[Build two forester’s houses]]) ..
+      li(_[[Build a sawmill]])
    ),
 }
 
@@ -45,8 +45,8 @@
    title = _"Expand your territory and explore",
    number = 1,
    body = objective_text(_"Expand and Explore",
-      _([[The island is huge and as long as we are not sure that we are alone here, we cannot relax. Explore and conquer it, this is the only way to protect us from threats on the island and from Atlantis.]]) .. paragraphdivider() ..
-      listitem_bullet(_[[Build military sites to expand your territory]])
+      _([[The island is huge and as long as we are not sure that we are alone here, we cannot relax. Explore and conquer it, this is the only way to protect us from threats on the island and from Atlantis.]]) ..
+      li(_[[Build military sites to expand your territory]])
    ),
 }
 
@@ -55,16 +55,16 @@
    title = _"Establish a solid food production",
    number = 10,
    body = objective_text(_"Food Production",
-      _[[Food is very important for mines and military training areas. Establish a well working food environment by building at least one farm, one blackroot farm and a mill. The two kinds of flour together with water from a well will be baked into bread in a bakery, so build a bakery and a well, too.]] .. paragraphdivider() ..
-      _[[The other two important food wares are smoked fish and smoked meat. Raw meat is delivered from a hunter. A fisher gets the fish out of the sea while a fish breeder makes sure that a school of fish does not go extinct by breeding more. Make sure that there are always fish left, otherwise the fish breeder won’t be able to breed new ones. The smoking happens in a smokery, you will need at least two of those.]] .. paragraphdivider() ..
-      listitem_bullet(_[[Build a farm and a blackroot farm]]) ..
-      listitem_bullet(_[[Build a mill to make cornmeal and blackroot flour]]) ..
-      listitem_bullet(_[[Build a well]]) ..
-      listitem_bullet(_[[Build a bakery to bake bread from cornmeal, blackroot flour and water]]) ..
-      listitem_bullet(_[[Build a hunter’s house to get raw meat]]) ..
-      listitem_bullet(_[[Build a fisher’s house close to water to get raw fish]]) ..
-      listitem_bullet(_[[Build a fish breeder’s house close to the fisher to make sure the fish do not die out]]) ..
-      listitem_bullet(_[[Build two smokeries to smoke raw meat and fish]])
+      _[[Food is very important for mines and military training areas. Establish a well working food environment by building at least one farm, one blackroot farm and a mill. The two kinds of flour together with water from a well will be baked into bread in a bakery, so build a bakery and a well, too.]] ..
+      p(_[[The other two important food wares are smoked fish and smoked meat. Raw meat is delivered from a hunter. A fisher gets the fish out of the sea while a fish breeder makes sure that a school of fish does not go extinct by breeding more. Make sure that there are always fish left, otherwise the fish breeder won’t be able to breed new ones. The smoking happens in a smokery, you will need at least two of those.]]) ..
+      li(_[[Build a farm and a blackroot farm]]) ..
+      li(_[[Build a mill to make cornmeal and blackroot flour]]) ..
+      li(_[[Build a well]]) ..
+      li(_[[Build a bakery to bake bread from cornmeal, blackroot flour and water]]) ..
+      li(_[[Build a hunter’s house to get raw meat]]) ..
+      li(_[[Build a fisher’s house close to water to get raw fish]]) ..
+      li(_[[Build a fish breeder’s house close to the fisher to make sure the fish do not die out]]) ..
+      li(_[[Build two smokeries to smoke raw meat and fish]])
    )
 }
 
@@ -73,10 +73,10 @@
    title = _"Build a spider farm and a weaving mill",
    number = 3,
    body = objective_text(_"Spidercloth Production",
-      _[[The weavers produce spidercloth and tabards in the weaving mill. Spidercloth is needed for the construction of some buildings and clothing, while tabards are the uniforms of soldiers. The weaving mill needs gold thread and spider silk as raw material. Spider silk is produced by the spider farm, while gold thread is produced by the gold spinning mill out of gold.]] .. paragraphdivider() ..
-      listitem_bullet(_[[Build a weaving mill]]) ..
-      listitem_bullet(_[[Build a spider farm]]) ..
-      listitem_bullet(_[[Build a gold spinning mill]])
+      _[[The weavers produce spidercloth and tabards in the weaving mill. Spidercloth is needed for the construction of some buildings and clothing, while tabards are the uniforms of soldiers. The weaving mill needs gold thread and spider silk as raw material. Spider silk is produced by the spider farm, while gold thread is produced by the gold spinning mill out of gold.]] ..
+      li(_[[Build a weaving mill]]) ..
+      li(_[[Build a spider farm]]) ..
+      li(_[[Build a gold spinning mill]])
  )
 }
 
@@ -85,12 +85,12 @@
    title = _"Build industry and mines",
    number = 5,
    body = objective_text(_"Industry and Mines",
-      _[[Iron ore, gold ore and coal are mined in the respective mines. The crystal mine will dig for quartz and diamonds – all of them are precious materials and very rarely found. It will produce a lot of granite while searching for them.]] .. paragraphdivider() ..
-      listitem_bullet(_[[The ores have to be smelted at a smelting works before they can be used. The refined materials are then used in the weapon smithy, the armor smithy and the toolsmithy.]]) .. paragraphdivider() ..
-      listitem_bullet(_[[Build a mine of each type. Make sure to send geologists to the mountain first.]]) ..
-      listitem_bullet(_[[Build a smelting works]]) ..
-      listitem_bullet(_[[Build an armor smithy and a weapon smithy]]) ..
-      listitem_bullet(_[[Build a toolsmithy]])
+      _[[Iron ore, gold ore and coal are mined in the respective mines. The crystal mine will dig for quartz and diamonds – all of them are precious materials and very rarely found. It will produce a lot of granite while searching for them.]] ..
+      li(_[[The ores have to be smelted at a smelting works before they can be used. The refined materials are then used in the weapon smithy, the armor smithy and the toolsmithy.]]) ..
+      li(_[[Build a mine of each type. Make sure to send geologists to the mountain first.]]) ..
+      li(_[[Build a smelting works]]) ..
+      li(_[[Build an armor smithy and a weapon smithy]]) ..
+      li(_[[Build a toolsmithy]])
    )
 }
 
@@ -99,8 +99,8 @@
    title = _"Build training sites for soldiers",
    number = 2,
    body = objective_text(_"Soldier Training Sites",
-      _[[Like all other tribes, the Atlanteans are also able to train soldiers: the dungeon trains attack – the major attribute of the Atlanteans – and the labyrinth trains evasion, health and defense. The items produced by the industry are used to train better soldiers in the two training sites.]] .. paragraphdivider() ..
-      listitem_bullet(_[[Build a dungeon and a labyrinth]])
+      _[[Like all other tribes, the Atlanteans are also able to train soldiers: the dungeon trains attack – the major attribute of the Atlanteans – and the labyrinth trains evasion, health and defense. The items produced by the industry are used to train better soldiers in the two training sites.]] ..
+      li(_[[Build a dungeon and a labyrinth]])
  )
 }
 
@@ -109,9 +109,9 @@
    title = _"Build a warehouse and a horse farm",
    number = 2,
    body = objective_text(_"Warehouse and Horse Farm",
-      _[[As your road network gets longer and more complicated, you should employ horses to help out your carriers. Horses are bred at horse farms using water and corn. A warehouse will also help to ensure that your transportation system does not collapse.]] .. paragraphdivider() ..
-      listitem_bullet(_[[Build a warehouse]]) ..
-      listitem_bullet(_[[Build a horse farm]])
+      _[[As your road network gets longer and more complicated, you should employ horses to help out your carriers. Horses are bred at horse farms using water and corn. A warehouse will also help to ensure that your transportation system does not collapse.]] ..
+      li(_[[Build a warehouse]]) ..
+      li(_[[Build a horse farm]])
   )
 }
 
@@ -120,8 +120,8 @@
    title = _"Build 3 ships to escape from the island",
    number = 1,
    body = objective_text(_"Escape From the Island",
-      _[[There is a lake at the top of the island. Build three ships in these waters and you might be able to rescue your people before the island is swallowed completely by the ocean.]]  .. paragraphdivider() ..
-      listitem_bullet(_[[Build a shipyard close to the lake to start building ships]])
+      _[[There is a lake at the top of the island. Build three ships in these waters and you might be able to rescue your people before the island is swallowed completely by the ocean.]] ..
+      li(_[[Build a shipyard close to the lake to start building ships]])
    )
 }
 
@@ -133,37 +133,34 @@
 initial_messages = {
    {
       title = _"Proud to the Death",
-      body = rt(
+      body =
          h1(_"Favored by the God") ..
          -- TRANSLATORS: Foreword
          p(_([[On the hidden and lost island of Atlantis, a proud tribe settled since the world was very young. Ruled by the bloodline of King Ajanthul – the first human to be empowered by the sea god Lutas to breathe above sea level – and the wise clerics, who provided the link to Lutas – they prospered and became civilized.]])) ..
          -- TRANSLATORS: Foreword
          p(_([[This story is taking place during the reign of King Askandor, the 43rd successor of King Ajanthul. He had been a good king, ruling Atlantis with wisdom and foresight. But with age, he became afraid of dying and so he began looking for a cure for death even though most clerics warned him against it. Some said that endless life was only for the gods and that to seek for it was forbidden.]]))
-      )
    },
    {
       title = _"Disgraced Before the God",
-      body = rt(
+      body =
          h1(_"The God’s Punishment") ..
          -- TRANSLATORS: Foreword
          p(_([[But all seemed well. Only the horses seemed to feel something was wrong. During the nights, they went crazy and were full of fear. It was not long before the horse breeder Xydra figured out what was wrong with them: the sea level in front of their stable was rising with ever increasing speed.]])) ..
          -- TRANSLATORS: Foreword
          p(_([[The clerics retreated into meditation and the reason for the rising water was soon to be found: the god Lutas had lost faith in the Atlanteans because of the boldness of their king. He decided to withdraw the rights that were granted to King Ajanthul and his children. And so, he called them back below the sea again.]]))
-      )
    },
    {
       title = _"Uproar and Confusion",
-      body = rt(
+      body =
          h1(_"Emerging Chaos…") ..
          -- TRANSLATORS: Foreword
          p(_([[Guilt-ridden, the king committed suicide. Without a monarch, the people turned to the clerics, but they had no substantial help to offer. Most accepted their fate while others tried to change the god’s mind by offering animals in his temple. But to no avail…]])) ..
          -- TRANSLATORS: Foreword
-          p(_([[Jundlina, the late king’s daughter and the highest priestess of the god was the most determined cleric. As countless offerings didn’t change the situation, she convinced herself that to soothe the god, an offer of great personal value was needed. So she offered him her most beloved: her husband, the father of her only child.]])) ..
-          -- TRANSLATORS: Foreword
-          p(_([[But not even this changed the mind of the god. The water kept on rising. Nearly driven insane by guilt, pain and anger, Jundlina became a heretic: Secretly, she gathered people of the common folk who were not in line with the decision of the clerics to accept the god’s will. Together with them, she set the temple on fire and stole a ship to flee from the god’s influence over Atlantis. This small group started praying to Satul, the fire god and the worst enemy of Lutas.]])) ..
-          -- TRANSLATORS: Foreword
-          p(_([[Leaving the dying Atlantis and their past behind, they started on a quest to find a place sheltered by the fire and protected from the sea.]]))
-      )
+         p(_([[Jundlina, the late king’s daughter and the highest priestess of the god was the most determined cleric. As countless offerings didn’t change the situation, she convinced herself that to soothe the god, an offer of great personal value was needed. So she offered him her most beloved: her husband, the father of her only child.]])) ..
+         -- TRANSLATORS: Foreword
+         p(_([[But not even this changed the mind of the god. The water kept on rising. Nearly driven insane by guilt, pain and anger, Jundlina became a heretic: Secretly, she gathered people of the common folk who were not in line with the decision of the clerics to accept the god’s will. Together with them, she set the temple on fire and stole a ship to flee from the god’s influence over Atlantis. This small group started praying to Satul, the fire god and the worst enemy of Lutas.]])) ..
+         -- TRANSLATORS: Foreword
+         p(_([[Leaving the dying Atlantis and their past behind, they started on a quest to find a place sheltered by the fire and protected from the sea.]]))
    },
 } -- end of initial messages.
 
@@ -173,10 +170,10 @@
       body = jundlina(_"Jundlina Writes Down Her Memories",
          -- TRANSLATORS: Jundlina - Diary
          _([[We left Atlantis and sailed east. We entered the forbidden sea on the sixth day without noticing any pursuers from Atlantis and without Lutas having smashed our ship. Now, we are out of his reach. One day later, we sighted an island which seems to have one of these fire spitting mountains on it. I deemed this a sign from the fire god and we landed on its shore.]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Jundlina - Diary
          _([[We spent the last week building two watchtowers on the mountains close to our landing area; and, of course, a hall for us all. We have very talented constructors in our group – still, the buildings do not match the art we had on Atlantis. I hope they will withstand the next rain. At least, the towers will warn us if a ship from Atlantis follows us and if the island is inhabited, we will see attackers a long time before they arrive.]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Jundlina - Diary
          _([[We have established ourselves on this island. The next step is now to make it a home. I reckon we need to establish a sustainable economy and to explore our surroundings. I called for specialists and will follow their advice.]]))
    },
@@ -206,7 +203,7 @@
    {
       title = _"Jundlina is Satisfied",
       body = jundlina(_"Jundlina’s Memoirs",
-         -- TRANSLATORS: Jundlina
+         -- TRANSLATORS: Jundlina - Diary
          _([[Our building infrastructure is finished and I spent some days making sure that everybody is working well together. Now, there are other pressing matters. I called Colionder, my personal cook, before me to get his help with sorting some things out.]]))
    },
    {
@@ -226,10 +223,10 @@
       body = colionder(
          -- TRANSLATORS: Colionder
          _([[Ahh, but I think this is impossible to change. The preparing and eating of food is something deeply ingrained in us Atlanteans – it is a ceremony that we just need for our well-being. So I guess we cannot take this away from the individuals completely.]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Colionder
          _([[But we might find a compromise in between: for me, making bread is a troublesome task. Grinding the blackroot and corn to flour and then baking the bread is tedious and boring; I feel a more industrial approach would be helpful here. I for one would love to just have fresh bread delivered to my house every day.]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Colionder
          _([[Oooh and even more important: the smoking of fish and meat to cleanse them and improve their taste is terrible. My house is full of smoke and stinks for weeks afterwards. Don’t you think that this could be done in a special building where the side effects do not matter? I think those two things would be accepted by the people and would reduce the cooking time without taking away the ritual.]]))
    },
@@ -257,13 +254,13 @@
       body = opol(
          -- TRANSLATORS: Opol
          _([[May Satul warm you, Jundlina. My name is Opol, and I am the highest weaver of the guild abandoning Atlantis and Lutas with you. I come with sad news indeed: we have no more spidercloth. Not a single piece is to be found in our warehouses. Could you not help the weavers’ guild by arranging the building of a weaving mill and a spider farm? The spiders deliver the finest silk and we will produce the finest spidercloth from it.]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Opol
          _([[We offer to also produce the tabards for young soldiers and the golden tabards for officers for you in exchange. You will need them for sure as soon as you want to recruit new soldiers.]]))
    },
    {
-       title = _"Jundlina Replies",
-       body = jundlina(_"Jundlina",
+      title = _"Jundlina Replies",
+      body = jundlina(_"Jundlina",
          -- TRANSLATORS: Jundlina
          _([[May Satul warm you too, Opol. I wanted to delay production of spidercloth, but I understand your urgency. Your suggestion sounds fair to me, I will build your weaving mill and spider farm. I will also build a gold spinning mill so that the golden tabards you make will not be golden by name alone.]]))
          ..  new_objectives(obj_spidercloth_production)
@@ -339,7 +336,7 @@
       body = jundlina(_"Jundlina",
          -- TRANSLATORS: Jundlina
          _([[People are complaining about crowded streets and slow transportation. We need to help out our carriers on the roads. I have decided to build a horse farm so that the horses can help with the heavy wares.]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Jundlina
          _([[Another way to take load from our roads is to build warehouses. We have claimed the mountain now, it seems a good idea to have a warehouse on the plateau to avoid having to transport everything up and down the slopes.]]))
          .. new_objectives(obj_horsefarm_and_warehouse)
@@ -354,13 +351,13 @@
       posx = 100000,
       posy = 0,
       title = _"A Dangerous Discovery",
-      body = jundlina(_"Jundlina is in Thought",
+      body = jundlina(_"Jundlina is in Though",
          -- TRANSLATORS: Jundlina
          _([[We found an old building, destroyed and burned by flames. I am very worried about this discovery. The building is not of any kind I’ve ever seen. It is certainly not designed by any Atlantean architect I’ve ever heard about. The building is crude, the assemblage is sloppy. But the materials are very enduring: the wood used for it seemed to have been burned in a strange way before it was used as building material – it is hard as stone.]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Jundlina
          _([[The implications frighten me. Are there others on this island? Where are they then? They work with fire, are they praying to Satul too? Are they friends or foe? And why is the building burned down? Has this island seen war? Is a war being waged on it right now?]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Jundlina
          _([[We must improve our military capabilities. If there are foes on the island, we have to be prepared when we meet them. We should also enforce the fortification of our borders.]]))
    }
@@ -431,7 +428,7 @@
       body = jundlina(_"Jundlina",
          -- TRANSLATORS: Jundlina
          _([[Your red hair is a signal from the fire god. I will trust you and support your plan. Our survival lies in your hands now, Ostur.]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Jundlina
          _([[Swift now, we need a house for Ostur next to the lake, and we need planks, logs and spidercloth for the construction there. Forget about everything else, we need those wares on top of the mountain before our warehouses are all swallowed by the sea.]]))
          .. new_objectives(obj_build_ships)
@@ -444,10 +441,10 @@
       body = jundlina(_"Jundlina",
          -- TRANSLATORS: Jundlina
          _([[Praise Satul! Ostur, the young ship builder did it. We have three ships – never have I seen sturdier ones – with enough room to carry all of us and some wares too. And this rescue came just in time: Lutas is about to swallow the rest of this island, the water rises faster by the hour. But we can make our escape now and start over in some country farther away…]])
-         .. paragraphdivider() ..
+         .. close_p() .. open_p() ..
          -- TRANSLATORS: Jundlina
          _([[I expect a long journey, but we will find the land of Satul in the end. This is what I promised my people. And myself.]]))
-         .. rt("<p font-size=10> <br></p>" .. h1(_ "Congratulations") ..
-         p(_[[You have won this mission. Continue with the next one or keep playing for as long as you like.]]))
+         .. objective_text(_ "Congratulations",
+            _[[You have won this mission. Continue with the next one or keep playing for as long as you like.]])
    }
 }

=== modified file 'data/campaigns/bar01.wmf/scripting/texts.lua'
--- data/campaigns/bar01.wmf/scripting/texts.lua	2016-01-28 05:24:34 +0000
+++ data/campaigns/bar01.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -23,9 +23,8 @@
    title = _"Build two ranger’s huts",
    number = 1,
    body = objective_text(_"Build two ranger’s huts",
-      listitem_bullet(_"Build a ranger’s hut next to each lumberjack’s hut.") ..
-      listitem_arrow(_"Naturally, trees only grow at a slow rate. To make sure you have enough logs, you have to build rangers.")
-   )
+      li(_"Build a ranger’s hut next to each lumberjack’s hut.") ..
+      li_arrow(_"Naturally, trees only grow at a slow rate. To make sure you have enough logs, you have to build rangers."))
 }
 
 obj_claim_northeastern_rocks = {
@@ -33,8 +32,8 @@
    title = _"Expand north-east and build a quarry",
    number = 1,
    body = objective_text(_"Expand north-east to the rocks",
-      listitem_bullet(_"Build military buildings (like sentries or barriers) to expand your territory.") ..
-      listitem_bullet(_"Get to the rocks north-east from you and build a quarry there."))
+      li(_"Build military buildings (like sentries or barriers) to expand your territory.") ..
+      li(_"Get to the rocks north-east from you and build a quarry there."))
 }
 
 obj_build_mines = {
@@ -42,21 +41,20 @@
    title = _"Start building mines on the mountain",
    number = 2,
    body = objective_text(_"Build coal and iron mines",
-      listitem_bullet(_"Build a coal mine and an iron mine.") ..
-      listitem_arrow(_"To do so, place a flag up on the mountain’s flank to the east (on mountain terrain though, not mountain meadow). When you click on the new flag, you can send geologists there. Because the flag is on a mountain, the geologists will search for ores; otherwise, they would search for water. Then build a mine for both kinds of resources that they will find, choosing the appropriate mine to be built:") ..
-      "</rt>" ..
-      rt("image=tribes/immovables/resi_coal1/idle_00.png", p(_"a bit of coal")) ..
-      rt("image=tribes/immovables/resi_coal2/idle_00.png", p(_"a lot of coal")) ..
-      rt("image=tribes/immovables/resi_iron1/idle_00.png", p(_"a bit of iron")) ..
-      rt("image=tribes/immovables/resi_iron2/idle_00.png", p(_"a lot of iron")) ..
-      rt("image=tribes/immovables/resi_gold1/idle_00.png", p(_"a bit of gold")) ..
-      rt("image=tribes/immovables/resi_gold2/idle_00.png", p(_"a lot of gold")) ..
-      rt("image=tribes/immovables/resi_stones1/idle_00.png", p(_"a bit of granite")) ..
-      rt("image=tribes/immovables/resi_stones2/idle_00.png", p(_"a lot of granite")) ..
-      rt("image=tribes/immovables/resi_water1/idle_00.png", p(_"water")) ..
-      rt("image=tribes/immovables/resi_none/idle_00.png", p(_"nothing was found here")) ..
-      "<rt>" ..
-         p(_[[Mines can only be built on mountain terrain. Suitable places for mines are displayed as orange mine symbols.]]))
+      li(_"Build a coal mine and an iron mine.") ..
+      li_arrow(_"To do so, place a flag up on the mountain’s flank to the east (on mountain terrain though, not mountain meadow). When you click on the new flag, you can send geologists there. Because the flag is on a mountain, the geologists will search for ores; otherwise, they would search for water. Then build a mine for both kinds of resources that they will find, choosing the appropriate mine to be built:") ..
+      -- TODO(GunChleoc): We want functions to get the icons here, which can then be used in the help as well.
+      p(img("tribes/immovables/resi_coal1/idle_00.png") .. _"a bit of coal") ..
+      p(img("tribes/immovables/resi_coal2/idle_00.png") .. _"a lot of coal") ..
+      p(img("tribes/immovables/resi_iron1/idle_00.png") .. _"a bit of iron") ..
+      p(img("tribes/immovables/resi_iron2/idle_00.png") .. _"a lot of iron") ..
+      p(img("tribes/immovables/resi_gold1/idle_00.png") .. _"a bit of gold") ..
+      p(img("tribes/immovables/resi_gold2/idle_00.png") .. _"a lot of gold") ..
+      p(img("tribes/immovables/resi_stones1/idle_00.png") .. _"a bit of granite") ..
+      p(img("tribes/immovables/resi_stones2/idle_00.png") .. _"a lot of granite") ..
+      p(img("tribes/immovables/resi_water1/idle_00.png") .. _"water") ..
+      p(img("tribes/immovables/resi_none/idle_00.png") .. _"nothing was found here") ..
+      p(_[[Mines can only be built on mountain terrain. Suitable places for mines are displayed as orange mine symbols.]]))
 }
 
 obj_basic_food = {
@@ -64,9 +62,9 @@
    title = _"Provide your miners with food",
    number = 3,
    body = objective_text(_"Build a hunter, a gamekeeper and a tavern",
-      listitem_bullet(_"In order to work, your miners need food.") ..
-      listitem_arrow(_"A hunter can hunt down animals, while a gamekeeper prevents them from becoming extinct. The meat is then processed in a tavern into lunches for your miners.") .. " " ..
-      _([[This is only the first example of a ware which has to be refined before being used in a secondary building – others will follow.]]))
+      li(_"In order to work, your miners need food.") ..
+      li_arrow(_"A hunter can hunt down animals, while a gamekeeper prevents them from becoming extinct. The meat is then processed in a tavern into lunches for your miners.") ..
+      p(_([[This is only the first example of a ware which has to be refined before being used in a secondary building – others will follow.]])))
 }
 
 obj_begin_farming = {
@@ -90,11 +88,11 @@
    title = _"Enhance buildings and build a micro brewery",
    number = 3,
    body = objective_text(_[[Enhance a mine and the tavern, and build a micro brewery.]],
-      listitem_bullet(_"Enhance the coal mine or the iron mine to a deep mine, and enhance the tavern to an inn.") ..
-      listitem_bullet(_"Also build a micro brewery.") ..
-      listitem_arrow(_"A normal mine can only dig up about one third of all the resources that lie beneath it; then it must be enhanced to a deep mine in order to keep it working properly. To enhance a building, choose it and then click the appropriate button in the appearing window.")  ..
-      listitem_arrow(_"Workers gain experience by successful work. With enough experience, they become more advanced workers, who are necessary to operate the enhanced buildings. Do not enhance a building before you have enough advanced workers to operate the advanced building!") ..
-      listitem_arrow(_"Such buildings usually have greater demands than the basic kind of that building – for instance, deep mines need snacks instead of rations. You will have to enhance your tavern to an inn in order to produce snacks out of pitta bread AND a second kind of food (meat or fish) AND beer.") ..
+      li(_"Enhance the coal mine or the iron mine to a deep mine, and enhance the tavern to an inn.") ..
+      li(_"Also build a micro brewery.") ..
+      li_arrow(_"A normal mine can only dig up about one third of all the resources that lie beneath it; then it must be enhanced to a deep mine in order to keep it working properly. To enhance a building, choose it and then click the appropriate button in the appearing window.")  ..
+      li_arrow(_"Workers gain experience by successful work. With enough experience, they become more advanced workers, who are necessary to operate the enhanced buildings. Do not enhance a building before you have enough advanced workers to operate the advanced building!") ..
+      li_arrow(_"Such buildings usually have greater demands than the basic kind of that building – for instance, deep mines need snacks instead of rations. You will have to enhance your tavern to an inn in order to produce snacks out of pitta bread AND a second kind of food (meat or fish) AND beer.") ..
       _"You may of course enhance all mines to deep mines instantly given you have the workers – bigger mines work a bit faster, smaller mines need cheaper food. It’s up to you which strategy you prefer.")
 }
 
@@ -103,26 +101,21 @@
    title = _"Build a wood hardener",
    number = 1,
    body = objective_text(_"Build a wood hardener",
-      _([[Bigger and better buildings – including all military ones – require better building materials. They cannot be built out of simple logs – the logs have to be refined to blackwood by a wood hardener first. Always remember to build a wood hardener before you run out of blackwood, as without it you cannot expand.]])
-      .. paragraphdivider() ..
-      listitem_bullet(_"Build a wood hardener"))
+      _([[Bigger and better buildings – including all military ones – require better building materials. They cannot be built out of simple logs – the logs have to be refined to blackwood by a wood hardener first. Always remember to build a wood hardener before you run out of blackwood, as without it you cannot expand.]]) ..
+      li(_"Build a wood hardener"))
 }
 
 obj_better_material_2 = {
    name = "mission grout",
    title = _"Build a lime kiln and coal economy",
    number = 3,
-   body = objective_text(_"Build a lime kiln fed by a well, and by a charcoal kiln or by a coal mine",
-      _([[Better buildings may also require other improved materials besides blackwood. One of these is grout, which is produced out of granite, water and coal by a lime-burner.]])
-      .. paragraphdivider() ..
-      _([[You can obtain water by building a well upon a water source, which your geologists can discover when you send them to any flag that is not on a mountain.]])
-      ..paragraphdivider() ..
-      "</p></rt>" ..
-      rt("image=images/wui/fieldaction/menu_geologist.png", p(_"In order to call a geologist to search for water, click on a flag in the area that you want him to search and then on the button labeled ‘Send geologist to explore site’.")
-      .. paragraphdivider() ..
-      _([[Coal can be obtained by building a charcoal kiln or a coal mine. Burning charcoal out of logs is slow. You should only build a charcoal kiln when no coal is available.]])
-      .. paragraphdivider() ..
-      listitem_bullet(_"Build a lime kiln and a well. Additionally, build either a charcoal kiln or a coal mine for coal supply.")))
+   body =
+      objective_text(_"Build a lime kiln fed by a well, and by a charcoal kiln or by a coal mine",
+      _([[Better buildings may also require other improved materials besides blackwood. One of these is grout, which is produced out of granite, water and coal by a lime-burner.]]) ..
+      p(_([[You can obtain water by building a well upon a water source, which your geologists can discover when you send them to any flag that is not on a mountain.]])) ..
+      p(img("images/wui/fieldaction/menu_geologist.png") .. _"In order to call a geologist to search for water, click on a flag in the area that you want him to search and then on the button labeled ‘Send geologist to explore site’.") ..
+      p(_([[Coal can be obtained by building a charcoal kiln or a coal mine. Burning charcoal out of logs is slow. You should only build a charcoal kiln when no coal is available.]])) ..
+      li(_"Build a lime kiln and a well. Additionally, build either a charcoal kiln or a coal mine for coal supply."))
 }
 
 obj_better_material_3 = {
@@ -130,9 +123,8 @@
    title = _"Build a reed yard",
    number = 1,
    body = objective_text(_"Build a reed yard",
-      _([[The third material necessary for improved buildings is thatch reed, used to cover roofs. Thatch reed is planted by a gardener around his building, the reed yard.]])
-      .. paragraphdivider() ..
-      listitem_bullet(_"Build a reed yard"))
+      _([[The third material necessary for improved buildings is thatch reed, used to cover roofs. Thatch reed is planted by a gardener around his building, the reed yard.]]) ..
+      li(_"Build a reed yard"))
 }
 
 obj_build_cattlefarm = {
@@ -140,11 +132,9 @@
    title = _"Build a cattle farm",
    number = 1,
    body = objective_text(_"Build a cattle farm",
-      _([[When roads are under heavy load for a long time, one carrier is usually not enough to transport goods swiftly. Traffic jams are the consequence. Such roads therefore employ a second carrier: an ox that helps to carry the wares. This doubles the transport capacity.]])
-      .. paragraphdivider() ..
-      _([[Oxen are bred in cattle farms out of wheat and water.]])
-      .. paragraphdivider() ..
-      listitem_bullet(_"Build a cattle farm"))
+      _([[When roads are under heavy load for a long time, one carrier is usually not enough to transport goods swiftly. Traffic jams are the consequence. Such roads therefore employ a second carrier: an ox that helps to carry the wares. This doubles the transport capacity.]]) ..
+      p(_([[Oxen are bred in cattle farms out of wheat and water.]])) ..
+      li(_"Build a cattle farm"))
 }
 
 
@@ -157,7 +147,7 @@
    body = thron(_"Thron sighs…",
       -- TRANSLATORS: Thron
       _[[It’s been months, and we are still hiding where the forests are old and dark.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _[[My warriors hunt at day and lie awake at night – listening to the sounds of the cruel slaughter echoing from afar amongst the ancient trees.]]
    )
@@ -169,7 +159,7 @@
    body = thron(
       -- TRANSLATORS: Thron
       _[[We can see the raging flames that swallow Al’thunran from here, miles away.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _[[The red lights flash in the darkness and dance to the rhythm of the war drums that haunt me even in my nightmares.]]),
    field = al_thunran,
@@ -183,7 +173,7 @@
    body = thron(
       -- TRANSLATORS: Thron
       _[[My father’s bones rest peacefully in the ground on which he once ended the senseless spilling of blood that had arisen amongst us. It pains me that his peace only endured for one generation.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _[[Boldreth, my loyal companion and friend is a source of peace and comfort to me in these dark times. He keeps my spirits high and those of my warriors awake, preventing greed or despair from destroying the bonds between us as well.]]),
    field = grave,
@@ -204,7 +194,7 @@
    body = thron(_"Thron is shaking his head…",
       -- TRANSLATORS: Thron
       _([[Yet the war goes on. More and more of our brothers and sisters flee the brutal war raging in the capital beneath the trees.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[The stories they tell about the deeds of our kin are sad to hear. I’ve spent nights lying awake, restless, more tired than I ever believed one could be. Yet whenever I close my eyes, I see the fortress my father built consumed by flames. The Throne Among the Trees, the symbol of unity and peace among our kin, became the wedge that drives us apart.]])),
    field = sf -- scroll back when showing this and the next few message boxes
@@ -216,7 +206,7 @@
    body = thron(
       -- TRANSLATORS: Thron
       _([[Today my hunters brought men, women and little children before me who had hidden out in the forests, trying to escape the war, hate and revenge that rage among the tribes fighting each other like in olden times, when we were no more but wild beasts driven and controlled by instincts. None of my brothers will ever gain and hold control over the wooden throne, none of the tribes will be strong enough to subdue the other. There will be no end to this slaughter, unless… is this it? As father told me?]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[To rise against whoever threatens our very existence, even though it may be one of your own blood or mind?]]))
 }
@@ -227,7 +217,7 @@
    body = thron(
       -- TRANSLATORS: Thron
       _([[Boldreth seems more and more torn as the days go by. The spirits of my fellows sink as the cold season approaches, and we are still living in no more than huts and barracks. I never intended to stay out here in the wilderness for so long – but I never thought my brothers would engage in this senseless battle for so long either.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[Perhaps it’s time to make ourselves feel a little more at ease here. Perhaps it’s time to give those who still live and think united a new home, replacing what is now lost to us? Until we can return to the place we once called our home…]]))
 }
@@ -238,7 +228,7 @@
    body = khantrukh(_"An old man says…",
       -- TRANSLATORS: Khantrukh
       _[[Hail, chieftain. I am Khantrukh and have seen many winters pass. Please allow me to aid you with my counsel through these darkened days.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Khantrukh
       _[[Only the gods know for how long we have to remain hidden here. The warriors hope we may march back gloriously any day now, but I strongly doubt that will happen soon. And the days are short and cold…]])
 }
@@ -249,10 +239,10 @@
    body = khantrukh(_"Khantrukh notes…",
       -- TRANSLATORS: Khantrukh
       _[[I see you have already built a quarry and two lumberjack’s huts. That is a good beginning if we want to stay here longer.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Khantrukh
       _[[But never forget – these forests are our heritage, entrusted upon us by our ancestors. We must always respect and care for them. What we take, we must give back again.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Khantrukh
       _[[So, in order to replace the trees we chop down, we should build some ranger’s huts, preferably close to the lumberjack’s huts.]])
       .. new_objectives(obj_build_rangers)
@@ -264,7 +254,7 @@
    body = thron(_"Thron says…",
       -- TRANSLATORS: Thron
       _[[During another sleepless night, I went up to the hill and gazed towards the north. The fires are still burning, satisfying their hunger upon my father’s legacy.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _[[They are a constant reminder of why we have to hide here… and why we must return in the end!]]),
    field = al_thunran,
@@ -278,7 +268,7 @@
    body = thron(_"Thron says…",
       -- TRANSLATORS: Thron
       _[[Once again, I went up to my father’s tomb, in a sacred grove at the foot of the great spire of Kal’mavrath. I just stood there and felt neither the hours pass nor the cold rain pouring down from the darkened sky…]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _[[Somehow, it felt like a farewell. For the first time, I wondered what the future might hold for me…]]),
    field = grave,
@@ -292,7 +282,7 @@
   body = thron(_"Thron says thoughtfully…",
       -- TRANSLATORS: Thron
       _[[Some time ago, Boldreth came to me. His advice was to move to a place closer to home – to strike at the first sign of my brothers’ forces wavering.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _[[But when I look over the forests I can still see black smoke rising to the sky. I know – it is too early yet, and what he hopes for will not happen any time soon. He might still be right, but I fear the bloodshed that returning too fast would cause on both sides…]])
 }
@@ -303,7 +293,7 @@
    body = thron(_"Thron looks furious…",
       -- TRANSLATORS: Thron
       _[[Today, my warriors picked up an old man, wandering sick and wounded through the dark forest. We listened in horror as he told us of the atrocities taking place in Al’thunran.]]
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _[[I hereby renew my oath – I will stop this madness at any cost!]])
 }
@@ -353,7 +343,7 @@
    body = boldreth(_"Boldreth exclaims…",
       -- TRANSLATORS: Boldreth
       _([[Just look at that! In the east is the great mountain of Kal’mavrath! I wonder what treasures nature might have hidden beneath its majestic flanks!]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Boldreth
       _([[Let’s expand to the east. There’s a chance for the elderly to become useful once in a while! Let us send out some of those who understand the stone’s tongue to unravel the mountain’s secrets!]]))
       .. new_objectives(obj_build_mines)
@@ -364,7 +354,7 @@
    body = boldreth(_"Boldreth laughs…",
       -- TRANSLATORS: Boldreth
       _([[By Chat’Karuth’s beard, this is amazing! Just imagine what we can use this coal and iron ore for!]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Boldreth
       _([[It might even be enough to…]]))
 }
@@ -382,7 +372,7 @@
    body = boldreth(_"Boldreth nods…",
       -- TRANSLATORS: Boldreth
       _([[I have to hand it to you: you are right here, old man.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Boldreth
       _([[There seem to be quite a lot of animals in the forests here – we might just hunt down more of them. And, of course, the people would cheer a new tavern – hey, we might call it ‘Thron’s Pride’ or so if you want!]]))
       .. new_objectives(obj_basic_food)
@@ -393,7 +383,7 @@
    body = khantrukh(_"The elder jumps into the air…",
       -- TRANSLATORS: Khantrukh
       _([[Wisdom commands to seek variety.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Khantrukh
       _([[North of the great mountain is a large plain – why don’t we use the space Mother Nature gave us and build a farm? I sure would enjoy a freshly baked pitta bread for a change…]]))
       .. new_objectives(obj_begin_farming)
@@ -404,7 +394,7 @@
    body = boldreth(_"Boldreth cheers up…",
       -- TRANSLATORS: Boldreth
       _([[Our hunters are out in the forests, Thron.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Boldreth
       _([[I promise you, before the sun sets today you will have a magnificent meal fit for the chieftain of all clans!]]))
 }
@@ -421,7 +411,7 @@
    body = thron(_"Thron recognizes…",
       -- TRANSLATORS: Thron
       _([[A tavern opened for our people yesterday. While I am hardly in the mood for celebration, I noticed how much this tiny bit of home means to my people. Their songs filled the air until deep in the night, and they were in higher spirits still the day after.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[Maybe we actually are slowly creating a place here which we can… call home.]]))
 }
@@ -439,7 +429,7 @@
    body = khantrukh(_"Khantrukh speaks…",
       -- TRANSLATORS: Khantrukh
       _([[Our miners are digging up less and less by the day! We have to go deeper, closer to the mountain’s core, if we want more of its treasures!]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Khantrukh
       _([[Of course, it is dark and cold in such depths and only a few venture voluntarily into these places. We should reward this bravery with greater rations for them. And a pint of beer or two will keep their spirits high.]]))
       .. new_objectives(obj_enhance_buildings)
@@ -450,7 +440,7 @@
    body = boldreth(_"Boldreth seems concerned…",
       -- TRANSLATORS: Boldreth
       _([[As I just discovered, we are running short on blackwood! We cannot put our warriors into some crumbling huts, and even less so in times as dangerous as ours!]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Boldreth
       _([[We need a wood hardener, and we need one now!]]))
       .. new_objectives(obj_better_material_1)
@@ -461,7 +451,7 @@
    body = boldreth(_"Boldreth smiles…",
       -- TRANSLATORS: Boldreth
       _([[Well, old friend, this should ensure that our fortifications do not break down with our foes’ first battle cry! Now we can expand safely!]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Boldreth
       _([[Still, it would not hurt to accumulate some grout for our further campaign; thus we could, in times of need, build a fortress such as the world has never seen before!]]))
       .. new_objectives(obj_better_material_2)
@@ -472,7 +462,7 @@
    body = khantrukh(_"Khantrukh steps in…",
       -- TRANSLATORS: Khantrukh
       _([[Chieftain, this is a disgrace! It is well that we can produce grout for mighty fortifications and great buildings now – only this does not prevent our roofs from becoming leaky! Maybe the young ones like spending their nights in the rain, but I just can’t find any sleep with these raindrops dripping on my face!]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Khantrukh
       _([[Now this is a problem we should do something about!]]))
       .. new_objectives(obj_better_material_3)
@@ -490,7 +480,7 @@
    body = khantrukh(_"Khantrukh speaks…",
       -- TRANSLATORS: Khantrukh
       _([[As our realm is getting bigger and bigger, the traffic on the roads is overwhelming. Our poor carriers are no longer able to transport the goods as fast as we need them to. I suggest we give them some support by breeding oxen.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Khantrukh
       _([[They are amazing animals: The ox is as swift as a human being while being much stronger and very frugal: all we need is wheat and water to breed them and they will do their work on the roads loyally and reliably.]]))
       .. new_objectives(obj_build_cattlefarm)
@@ -501,10 +491,10 @@
    body = thron(_"Thron speaks…",
       -- TRANSLATORS: Thron
       _([[The other day Boldreth asked me to accompany him to the new inn. It would cheer me up, he said.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[When I looked around, I saw faithful faces, trusting that I could guide them through these dark days. Yet before I could speak any words of gratitude or encouragement, one of my warriors ran into the inn. He had been far out in the forest for the past days and I could see how weary he was.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[The news he brought changed everything…]]))
       .. objective_text(_"Victory",
@@ -516,7 +506,7 @@
    body = thron(_"Thron speaks…",
       -- TRANSLATORS: Thron
       _([[One night, when the moon shone brightly, I climbed to the peak of Kal’mavrath.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[When I gazed at the horizon, I still saw crimson lights flicker in the distance. It is incredible with how much passion my brethren fight this war. I fear the moment I will see Al’thunran again – will there be anything but ashes and wasted ruins left of our once beautiful capital when we get there?]]))
 }
@@ -526,10 +516,10 @@
     body = thron(_"Thron looks worried…",
       -- TRANSLATORS: Thron
       _([[The winter is upon us. Many of us are suffering from the cold, yet we must endure. The day we may return cannot be far anymore – it must not be far anymore.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[I prayed that it might get warmer again, as I prayed that the war would finally come to an end.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[So far, it seems that neither prayer was fulfilled.]]))
 }
@@ -539,10 +529,10 @@
    body = thron(_"Thron speaks…",
       -- TRANSLATORS: Thron
       _([[We have found a village with friendly and productive people, impressed by our wealth, technology and strength.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[They have lived simply, yet blithely, from hunting and farming. They have not been involved in any conflict so far, and are not ready for fighting.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[But they fear that the war around Al’thunran will set an end to this life. Therefore, they have decided to join us, hoping that we can help each other.]])
    )

=== modified file 'data/campaigns/bar02.wmf/scripting/texts.lua'
--- data/campaigns/bar02.wmf/scripting/texts.lua	2016-01-28 05:24:34 +0000
+++ data/campaigns/bar02.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -21,13 +21,12 @@
    title = _"Build up a small food economy",
    number = 5,
    body = objective_text(_"Build up a small food economy",
-      _"Build up a basic food economy to provide your people with food."
-      .. paragraphdivider() ..
-      listitem_bullet(_"Build a fisher’s hut") ..
-      listitem_bullet(_"Build a hunter’s hut") ..
-      listitem_bullet(_"Build a well") ..
-      listitem_bullet(_"Build a farm") ..
-      listitem_bullet(_"Build a bakery"))
+      _"Build up a basic food economy to provide your people with food." ..
+      li(_"Build a fisher’s hut") ..
+      li(_"Build a hunter’s hut") ..
+      li(_"Build a well") ..
+      li(_"Build a farm") ..
+      li(_"Build a bakery"))
 }
 
 obj_build_cattlefarm = {
@@ -35,9 +34,8 @@
    title = _"Build a cattle farm",
    number = 1,
    body = objective_text(_"Remember to build a cattle farm",
-      _"As your roads grow longer and your economy bigger, you should make good use of your oxen to help transport wares more quickly."
-      .. paragraphdivider () ..
-      listitem_bullet(_"Remember to build a cattle farm")
+      _"As your roads grow longer and your economy bigger, you should make good use of your oxen to help transport wares more quickly." ..
+      li(_"Remember to build a cattle farm")
    ),
 }
 
@@ -46,7 +44,7 @@
    title = _"Build a tower",
    number = 1,
    body = objective_text(_"Build a tower",
-      listitem_bullet(_"Build a tower at the north-east border of your territory to get greater visual range and to protect your people from sudden attacks by enemies."))
+      li(_"Build a tower at the north-east border of your territory to get greater visual range and to protect your people from sudden attacks by enemies."))
 }
 
 obj_explore_further = {
@@ -54,7 +52,7 @@
    title = _"Explore further",
    number = 1,
    body = objective_text(_"Explore further",
-      listitem_bullet(_"Build more military buildings to explore the area around the headquarters and to ensure the safety of your people."))
+      li(_"Build more military buildings to explore the area around the headquarters and to ensure the safety of your people."))
 }
 
 obj_build_mining_economy = {
@@ -62,7 +60,7 @@
    title = _"Build a mining infrastructure",
    number = 6,
    body = objective_text(_"Build a mining infrastructure",
-      listitem_bullet(_"Expand your territory to the mountains, send geologists to search for ore and coal and build a mining economy with mines, taverns, smelting works and metal workshop."))
+      li(_"Expand your territory to the mountains, send geologists to search for ore and coal and build a mining economy with mines, taverns, smelting works and metal workshop."))
 }
 
 obj_build_a_fortress = {
@@ -70,7 +68,7 @@
    title = _"Build a fortress",
    number = 1,
    body = objective_text(_"Build a fortress",
-      listitem_bullet(_"Build a fortress to the east of the mountains."))
+      li(_"Build a fortress to the east of the mountains."))
 }
 
 obj_build_training_infrastructure = {
@@ -78,9 +76,9 @@
    title = _"Build a training infrastructure",
    number = 4,
    body = objective_text(_"Build a training infrastructure",
-      listitem_bullet(_"Build a battle arena and a training camp to the west of the mountains.") ..
-      listitem_bullet(_"Enhance your metal workshop to an ax workshop in order to produce weapons, and build up a second metal workshop to ensure the production of tools. When the blacksmith reaches his next level (master blacksmith), you can even enhance the ax workshop to a war mill, which will produce additional weapons.") ..
-      listitem_bullet(_"Build a helm smithy to the west of the mountains to provide your soldiers with better armor."))
+      li(_"Build a battle arena and a training camp to the west of the mountains.") ..
+      li(_"Enhance your metal workshop to an ax workshop in order to produce weapons, and build up a second metal workshop to ensure the production of tools. When the blacksmith reaches his next level (master blacksmith), you can even enhance the ax workshop to a war mill, which will produce additional weapons.") ..
+      li(_"Build a helm smithy to the west of the mountains to provide your soldiers with better armor."))
 }
 
 
@@ -89,8 +87,8 @@
    title = _"Build a warehouse",
    number = 1,
    body = objective_text(_"Build a warehouse",
-      listitem_bullet(_"Build a warehouse to the west of the mountains.") ..
-      listitem_arrow(_"Warehouses are similar to your headquarters, with the only difference that they aren’t defended by soldiers. It is often wise to build a warehouse when your territory is growing and the paths to your headquarters get longer and longer."))
+      li(_"Build a warehouse to the west of the mountains.") ..
+      li_arrow(_"Warehouses are similar to your headquarters, with the only difference that they aren’t defended by soldiers. It is often wise to build a warehouse when your territory is growing and the paths to your headquarters get longer and longer."))
 }
 
 obj_build_trainingssites = {
@@ -98,10 +96,9 @@
    title = _"Build training sites",
    number = 2,
    body = objective_text(_"Build training sites",
-      listitem_bullet(_"Build a battle arena and a training camp to the west of the mountains.") ..
-      listitem_arrow(_"Training sites like a training camp or a battle arena are used for training soldiers in their different attributes. These attributes are important in fights and the better a soldier is, the higher is the chance to win a fight."
-      .. "<br>" ..
-      _"The attributes are: health, attack, defense and evade."))
+      li(_"Build a battle arena and a training camp to the west of the mountains.") ..
+      li_arrow(_"Training sites like a training camp or a battle arena are used for training soldiers in their different attributes. These attributes are important in fights and the better a soldier is, the higher is the chance to win a fight." ..
+         p(_"The attributes are: health, attack, defense and evade.")))
 }
 
 obj_build_weapon_productions = {
@@ -109,7 +106,7 @@
    title = _"Build weapons production",
    number = 3,
    body = objective_text(_"Build weapons production",
-      listitem_bullet(_"Enhance your metal workshop to an ax workshop in order to produce weapons, and build up a second metal workshop to ensure the production of tools. When the blacksmith reaches his next level (master blacksmith), you can even enhance the ax workshop to a war mill, which will produce additional weapons."))
+      li(_"Enhance your metal workshop to an ax workshop in order to produce weapons, and build up a second metal workshop to ensure the production of tools. When the blacksmith reaches his next level (master blacksmith), you can even enhance the ax workshop to a war mill, which will produce additional weapons."))
 }
 
 obj_build_a_helmsmithy = {
@@ -117,7 +114,7 @@
    title=_"Build a helm smithy",
    number = 1,
    body = objective_text(_"Build a helm smithy",
-      listitem_bullet(_"Build a helm smithy to the west of the mountains to provide your soldiers with better armor."))
+      li(_"Build a helm smithy to the west of the mountains to provide your soldiers with better armor."))
 }
 
 obj_destroy_kalitaths_army = {
@@ -125,8 +122,8 @@
    title = _"Destroy Kalitath’s army",
    number = 2,
    body = objective_text(_"Destroy Kalitath’s army",
-      listitem_bullet(_"Destroy Kalitath’s army and expand your territory to the east.") ..
-      listitem_arrow(_"To attack an enemy, you must click on the door of an adversary’s military building. A menu will pop up allowing you to select the number of soldiers that should attack. When you are ready with setting the number, click on the cross (‘Start Attack’)."))
+      li(_"Destroy Kalitath’s army and expand your territory to the east.") ..
+      li_arrow(_"To attack an enemy, you must click on the door of an adversary’s military building. A menu will pop up allowing you to select the number of soldiers that should attack. When you are ready with setting the number, click on the cross (‘Start Attack’)."))
 }
 
 obj_military_assault_on_althunran = {
@@ -134,7 +131,7 @@
    title = _"Military assault on Al’thunran",
    number = 1,
    body = objective_text(_"Military assault on Al’thunran",
-      listitem_bullet(_"Destroy all forces of Thron’s two brothers to liberate the throne-circle."))
+      li(_"Destroy all forces of Thron’s two brothers to liberate the throne-circle."))
 }
 
 -- =======================================================================
@@ -146,7 +143,7 @@
    body =thron(_"Thron looks worried…",
       -- TRANSLATORS: Thron
       _([[These last days, we came closer to our capital. Many people have already joined us on our march and set their hopes on me. However, I fear that we are not strong enough to take up the battle against my brothers.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[For now, we are resting at the borders of the old forest and preparing for the coming days.]]))
 }
@@ -207,10 +204,10 @@
    body = thron(_"Thron says:",
       -- TRANSLATORS: Thron
       _([[The traitor left his armies dying where they lay when he saw that he would not keep my forces back. Kalitath disappeared in the confusion of the war, but I don’t care now. Shall he flee and be forgotten for all times as a tribal leader that would not bow before the wooden throne, that is mine to take now.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[Furthermore, his flight brought us a great benefit: all year, Kalitath was so busy fighting that he did not even care to store enough food for all his men. Now that he has fled, their hunger has caused some of his younger followers to desert. This group holds a strong fortification on the main ring.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[But there is more news: My scouts have reported that the two raging tribes of my brothers are in chaos and have barely noticed the new danger that is about to strike them. However, they would not care if they noticed I guess, blinded by rage and hate, there is no sense left in them at all I believe.]]))
 }
@@ -255,7 +252,7 @@
    body = boldreth(_"Boldreth says:",
       -- TRANSLATORS: Boldreth
       _([[The first fortification Thron ordered has just been completed. At the moment, he seeks to bring trust and belief to those who live inside the walls of our new habitat that we named ‘Ondun’, which means ‘those who wait’ in the old tongue. But Thron is not yet satisfied – and I fully understand his fears: the forests are deep, and the frontier to Al’thunran is near. I am sure that there are a thousand greater dangers out there than the unknown tracks.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Boldreth
       _([[To overlook more of the area around our hall, we should explore further and set up more guards and scouts to observe the frontier and keep an eye on the raging wars on our doorstep. THEN we will be prepared once trouble seeks to capture our woods.]]))
       .. new_objectives(obj_explore_further)
@@ -301,7 +298,7 @@
    body = boldreth(_"Boldreth says:",
       -- TRANSLATORS: Boldreth
       _([[Our mining economy seems to work fine, that is already good news! Anyway, there are still a lot of men and women waiting in our hall to get a task, so they can help our soldiers to prepare for the war to come.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Boldreth
       _([[Our geologists found a lot more deposits of iron ore, coal and even gold. We should enhance our current mines as soon as our miners are more experienced. We should build up some more mines, a bigger food infrastructure to always supply our men with sufficient food and a further processing economy. But that’s still not everything – most of our soldiers are quite young and neither have a good weapon nor are they well trained. We should build up training sites to prepare them for their future tasks.]]))
       .. new_objectives(obj_build_training_infrastructure)
@@ -313,7 +310,7 @@
    body= thron(_"Thron looks worried…",
       -- TRANSLATORS: Thron
       _([[My brothers and their soldiers are dead and left fire and destruction behind. In none of all the ruins could I find any man or woman of the normal folk, and so I just may hope that they fled from this cruel battleground and started a better life somewhere else.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[Nothing is left of that beauty I remember, only ruins remain of the old capital. I am sorrowful but also relieved. I never hoped to see Al’thunran’s old beauty again – it was only a few months ago that I wondered whether I would ever be able to set my feet there again. Now the old town is back in my hands, and I will not hesitate to rebuild it with all the strength my people have. I can’t wait to see it again in its old beauty.]]))
       ..  objective_text(_"Victory",
@@ -326,10 +323,10 @@
    body = thron(_"Thron says:",
       -- TRANSLATORS: Thron
       _([[So be it, the generals are out and about arranging my troops, and Boldreth himself will lead the first strike. I will ride by his side, to free Al’thunran of this war and return peace to our capital.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[When the young sun rises above the trees tomorrow morning, I will order the assault. By dusk, I will celebrate my victory in the wooden halls of the warlord and sacrifice a newborn lamb in the honor of my father, whose eyes are set upon me today.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Thron
       _([[So be it!]]))
       .. new_objectives(obj_military_assault_on_althunran),

=== modified file 'data/campaigns/emp01.wmf/scripting/texts.lua'
--- data/campaigns/emp01.wmf/scripting/texts.lua	2016-02-12 09:15:09 +0000
+++ data/campaigns/emp01.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -28,7 +28,7 @@
    title=_"Build a blockhouse",
    number = 1,
    body = objective_text(_"Blockhouse",
-      listitem_bullet(_[[Build a blockhouse at the red house symbol on the east side of the forests, to the right of your provisional headquarters.]])
+      li(_[[Build a blockhouse at the red house symbol on the east side of the forests, to the right of your provisional headquarters.]])
    ),
 }
 
@@ -37,7 +37,7 @@
    title=_"Build a lumberjack’s house",
    number = 1,
    body = objective_text(_"Lumberjack’s House",
-      listitem_bullet(_[[Build a lumberjack’s house at the red house symbol, south of your provisional headquarters.]])
+      li(_[[Build a lumberjack’s house at the red house symbol, south of your provisional headquarters.]])
    ),
 }
 
@@ -46,7 +46,7 @@
    title=_"Build 2 lumberjack’s houses and a sawmill",
    number = 3,
    body = objective_text(_"Two Lumberjack’s Houses and a Sawmill",
-      listitem_bullet(_[[Build two more lumberjack’s houses and a sawmill as soon as there is enough space for them.]])
+      li(_[[Build two more lumberjack’s houses and a sawmill as soon as there is enough space for them.]])
    ),
 }
 
@@ -55,7 +55,7 @@
    title=_"Build a forester’s house",
    number = 1,
    body = objective_text(_"Forester’s House",
-      listitem_bullet(_[[Build a forester’s house to preserve the wood resources of this island.]])
+      li(_[[Build a forester’s house to preserve the wood resources of this island.]])
    ),
 }
 
@@ -64,13 +64,12 @@
    title=_"Build a quarry",
    number = 5,
    body = objective_text(_"Quarry",
-      listitem_bullet(_[[Build a quarry in the south to cut some granite and marble out of the rocks.]]) ..
-      listitem_arrow(_[[These might be used for future buildings.]])
+      li(_[[Build a quarry in the south to cut some granite and marble out of the rocks.]]) ..
+      li_arrow(_[[These might be used for future buildings.]])
    ),
 }
 
 
-
 -- ==================
 -- Texts to the user
 -- ==================
@@ -79,17 +78,17 @@
    body=lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[What has become of our Empire? I really ask this question – why did my king forbid me from fighting against that monstrous Barbarian tribe, who first acted as a peaceful friend and then attacked my army in the darkest night?]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[With an army of 150 men, I was assigned to patrol on our northern frontier, which lies near the Galdin Mountains in a great, beautiful and ancient forest. Soon, we met a Barbarian tribe, which at first was friendly. A few of my men even traded with them and their children came to us, to admire our clean and tidy uniforms and weapons.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[But during our fifth night in that region, they attacked us with no reason. I lost dozens of good men, and found myself imprisoned and brought to their chieftain. He spat at me, mocked me and told me to leave this land forever. He did not want new land and did not want our land, but he told me that THIS forest was their land – and it would stay theirs until the spirits took the last man of his folk!]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[Three weeks later, I returned to Fremil to speak with our king. He was furious at the Barbarians, yet forbade any attack on these tribes. He believed that our army was too weak to survive in a war against the Barbarians.]])
-      .. paragraphdivider() ..
-      -- TRANSLATORS: Lutius - Diary. Gulf of Perl is a place name.
+      .. close_p() .. open_p() ..
+      -- TRANSLATORS: Lutius - Diary
       _([[Still, I saw no way that I could erase my shame without fighting against these Barbarians. So, I left Fremil by boat to find a new world and a new life for myself, somewhere in the south. Now I am sailing on the Gulf of Perl with my family, some of my friends and a few of my best warriors.]])),
    w=500,
    posy=1,
@@ -100,7 +99,7 @@
    body= lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[It seems as if sailing on the Gulf of Perl was one of our biggest mistakes. Nature was against us and drove us into a dark, wild storm. I really don’t know how many hours have passed since the waves rose higher than our boat, but still it would be suicide to go outside.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[Our ship is badly damaged and is taking in more and more water. We can thank the Gods if we survive this black night with our lives.]])),
    w=400,
@@ -112,10 +111,10 @@
    body= lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[Finally, the Gods were with us!]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[We landed on an unknown coast and found peaceful rest under the palm trees growing at the shore. But that is about as good as it gets. The truth is: when I woke up this morning, I saw nothing but sand around us.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[It really seems as if we have landed under the only palm trees existing in this far-away sandy desert. I fear we won’t find the help we need to get our ship repaired in good time.]])),
    w=400,
@@ -127,10 +126,10 @@
    body= saledus(_"Saledus looks around nervously…",
       -- TRANSLATORS: Saledus
       _([[Sire, I fear we are not safe in this foreign land. Who knows what terrible creatures live beyond this forest, in that mighty desert? What if these creatures enter the woods and await the time to attack us?]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[Well, perhaps my fear is misguided, but it can’t be wrong to keep watch in the forests – so that we can be sure to see any potential enemies before they can see us.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[You really should build a blockhouse in the eastern portion of the forest. Then one of my men can keep watch in the darkness and keep us safe from these creatures.]]))
       .. new_objectives(obj_build_blockhouse),
@@ -143,7 +142,7 @@
    body= saledus(_"Saledus speaks with a sigh of relief…",
       -- TRANSLATORS: Saledus
       _([[Sire, I saw that the construction of the blockhouse was completed, so I have assigned one of my best soldiers to it to keep watch on the desert.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[This is a good step forward. Now we can feel a bit safer and can look forward to repairing our ship.]])),
    w=400,
@@ -154,10 +153,10 @@
    body= amalea(_"Amalea smiles…",
       -- TRANSLATORS: Amalea
       _([[Greetings, Lutius! I just met Saledus outside.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[He told me about the blockhouse. Well, I don’t think we need more blockhouses – instead, we might concentrate on other things now.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[It is absolutely clear that we need wood to repair our ship. So, I walked through the forest yesterday to look for a nice place for a lumberjack’s house and found one right south of our provisional headquarters.]]))
       .. new_objectives(obj_build_lumberjack),
@@ -169,7 +168,7 @@
    body= amalea(_"Amalea recommends…",
       -- TRANSLATORS: Amalea
       _([[I got the message that our first lumberjack has started his work today. Perhaps it would be a good idea to wait until he has cleared enough space for constructing two more lumberjack’s houses, so that we can harvest the logs faster.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[But unfortunately the logs are useless for repairing our ship – we need to turn them into planks, which are needed by every ship and every bigger building too. So we should build a sawmill – as soon as we have enough space for this.]]))
       .. new_objectives(obj_build_sawmill_and_lumberjacks),
@@ -181,16 +180,16 @@
    body= amalea(_"Amalea comes in…",
       -- TRANSLATORS: Amalea
       _([[I’ve got two important things to talk about… First the good news:]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[I noticed that the construction of the sawmill is complete, so we can begin to refine the logs that the lumberjacks are harvesting into lumber.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[But the bad news is that our lumberjacks harvest at an incredible speed. There are almost no trees left on this island.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[These trees provide shelter from the sandstorms that sweep in from the desert, and shade on the hot days, and they are the home of many gentle animals. We shouldn’t leave this island a complete desert.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[Lutius, please find someone who will take care of planting new trees.]]))
       .. new_objectives(obj_build_forester),
@@ -202,7 +201,7 @@
    body= saledus(_"Saledus notes…",
       -- TRANSLATORS: Saledus
       _([[Sire, I just thought about the rocks standing on the south shore of this land. Perhaps we could cut out some useful granite and beautiful marble.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[The repair of our ship will take a few weeks, anyway, and the resources we harvest now might be the base of strong and big buildings in another land.]]))
       .. new_objectives(obj_build_quarry),
@@ -214,7 +213,7 @@
    body= saledus(_"Saledus looks excited…",
       -- TRANSLATORS: Saledus
       _([[Sire, today we got a lot closer to our first castle. The quarry to the south began its work today and will soon provide us with granite and beautiful marble.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[Now we truly can look forward to settling down on another island.]])),
    w=400,
@@ -225,10 +224,10 @@
    body= lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[Today I got the message that our ship is completely repaired. At the moment, my people are loading everything onto our newly repaired ship, hoping it will serve us better than last time.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[Tonight will be our last night on this island. Tomorrow morning we will leave, searching for a new place for our exile.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[I still wonder if we will ever see Fremil again.]]))
       .. objective_text(_"Victory",

=== modified file 'data/campaigns/emp02.wmf/scripting/texts.lua'
--- data/campaigns/emp02.wmf/scripting/texts.lua	2016-01-28 05:24:34 +0000
+++ data/campaigns/emp02.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -28,7 +28,7 @@
    title =_"Build up a wood economy",
    number = 5,
    body = objective_text(_"Wood Economy",
-      listitem_bullet(_[[Build three lumberjack’s houses, a forester’s house and a sawmill.]])
+      li(_[[Build three lumberjack’s houses, a forester’s house and a sawmill.]])
    ),
 }
 
@@ -37,7 +37,7 @@
    title =_"Build a quarry",
    number = 1,
    body = objective_text(_"Quarry",
-      listitem_bullet(_[[Build a quarry to the south of your headquarters.]])
+      li(_[[Build a quarry to the south of your headquarters.]])
    ),
 }
 
@@ -46,7 +46,7 @@
    title =_"Protect your colony",
    number = 1,
    body = objective_text(_"Protect Your Colony",
-      listitem_bullet(_[[Build some blockhouses and sentries around the colony.]])
+      li(_[[Build some blockhouses and sentries around the colony.]])
    ),
 }
 
@@ -55,7 +55,7 @@
    title =_"Start mining marble",
    number = 1,
    body = objective_text(_"Marble",
-      listitem_bullet(_[[Expand to the east, to start mining marble from the mountain.]])
+      li(_[[Expand to the east, to start mining marble from the mountain.]])
    ),
 }
 
@@ -64,7 +64,7 @@
    title =_"Build a stonemason’s house and mining infrastructure",
    number = 7,
    body = objective_text(_"Stonemason’s house and Mining Infrastructure",
-      listitem_bullet(_[[Build a stonemason’s house and then a complete mining and production infrastructure (coal mine and / or charcoal kiln, iron ore mine, toolsmithy, weapon smithy, armor smithy and smelting works).]])
+      li(_[[Build a stonemason’s house and then a complete mining and production infrastructure (coal mine and / or charcoal kiln, iron ore mine, toolsmithy, weapon smithy, armor smithy and smelting works).]])
    ),
 }
 
@@ -73,10 +73,10 @@
    title =_"Provide your miners with food",
    number = 1,
    body = objective_text(_"Food For Your Miners",
-      listitem_bullet(_[[To produce some sustaining food for our miners, we could build up a tavern. To supply them with some good and strong drinks, we could build up a brewery and a winery.]]) ..
-      listitem_bullet(_[[Of course this means we will need more resources for preparing this food – like fish, meat or bread. To provide these foodstuffs, you would have to build a fisher’s house, a farm, a mill and a bakery.]]) ..
-      listitem_bullet(_[[Maybe you will also need a hunter’s house, a piggery, a vineyard and some wells.]]) ..
-      listitem_arrow(_[[It’s up to you what you want to build. But remember – coal and iron ore mines need beer, marble and gold mines need wine and all mines need at least rations, which are produced out of bread OR meat OR fish.]])
+      li(_[[To produce some sustaining food for our miners, we could build up a tavern. To supply them with some good and strong drinks, we could build up a brewery and a winery.]]) ..
+      li(_[[Of course this means we will need more resources for preparing this food – like fish, meat or bread. To provide these foodstuffs, you would have to build a fisher’s house, a farm, a mill and a bakery.]]) ..
+      li(_[[Maybe you will also need a hunter’s house, a piggery, a vineyard and some wells.]]) ..
+      li_arrow(_[[It’s up to you what you want to build. But remember – coal and iron ore mines need beer, marble and gold mines need wine and all mines need at least rations, which are produced out of bread OR meat OR fish.]])
    ),
 }
 
@@ -85,8 +85,8 @@
    title =_"Protect your eastern frontier",
    number = 1,
    body = objective_text(_"Protect Your Eastern Frontier",
-      listitem_bullet(_[[Build up stronger military buildings, such as an outpost, a barrier or a tower, on the eastern frontier.]]) ..
-      listitem_arrow(_[[To watch deep inside the enemy territory, build a tower.]])
+      li(_[[Build up stronger military buildings, such as an outpost, a barrier or a tower, on the eastern frontier.]]) ..
+      li_arrow(_[[To watch deep inside the enemy territory, build a tower.]])
    ),
 }
 
@@ -95,8 +95,8 @@
    title =_"Destroy the Barbarian tribe",
    number = 2,
    body = objective_text(_"Destroy the Barbarian Tribe",
-      listitem_bullet(_[[As soon as you have enough soldiers, attack and completely destroy the Barbarian buildings.]]) ..
-      listitem_bullet(_[[Finally, build up a fortress on the peninsula (near where the Barbarian headquarters stood before), to avoid new settlements of other tribes in that region.]])
+      li(_[[As soon as you have enough soldiers, attack and completely destroy the Barbarian buildings.]]) ..
+      li(_[[Finally, build up a fortress on the peninsula (near where the Barbarian headquarters stood before), to avoid new settlements of other tribes in that region.]])
    ),
 }
 
@@ -109,7 +109,7 @@
    body = lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[Finally! This island appears to have been made for us, it is a gift from the Gods to my people and myself. Until now, we have only seen a small part of this island, but this part alone is already bringing sunlight to my mind. I feel as if we have found a priceless treasure, a land like paradise.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[On this island, we will start our new life. We will build up an outpost for our exile, which perhaps will become a new, beautiful home for every one of us.]])),
 }
@@ -120,10 +120,10 @@
    body= lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[As Saledus and I walked through these wonderful forests in the north, we felt that our future had just begun. This land is so peaceful, good and beautiful, I could stay here until the end of my life.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[But until that day, many years may pass! For now, we must concentrate on the present, and build a few lumberjack’s houses and a sawmill to produce some basic building materials.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[But we mustn’t forget to preserve this natural bounty. These forests should last forever, so we really have to build a forester’s house too.]]))
       .. new_objectives(obj_build_woodeconomy)
@@ -135,7 +135,7 @@
    body= lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[Later, I walked down to the rocks in the south and looked for a place where we could build a quarry to get some granite for our larger buildings.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[Again, I felt like I was in paradise when I noticed that some marble-like stones were among the rocks. It seems that we will soon be able to build strong, luxurious buildings, like those we were accustomed to in Fremil.]]))
       .. new_objectives(obj_build_quarry)
@@ -163,10 +163,10 @@
    body= saledus(_"Saledus looks unhappy",
       -- TRANSLATORS: Saledus
       _([[Sire, I don’t want to start a panic, but I found something which gives me a sinking feeling in my stomach and spreads waves of fear in my heart. As I walked down to the southern shore, I found the remains of another ship. I don’t know whether these parts are all that is left of that ship. In any case, these parts do not seem to be old.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[Perhaps the people aboard that ship were caught in the same storm which brought us to Malac’ Mor – and were brought to this island.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[I beg you to be cautious and to build some blockhouses or sentries around our colony.]]))
       .. new_objectives(obj_build_military_buildings)
@@ -177,10 +177,10 @@
    body= saledus(_"Saledus smiles",
       -- TRANSLATORS: Saledus
       _([[Sire, I’ve got good news for you: As I walked to the east, I found a larger mountain. I am not absolutely sure – a geologist should check if I am right – but I believe we could mine marble from some places on the mountain.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[It would be a good source for bolstering our supply of quality marble, beyond the meager quantities available from the quarry. Perhaps you were right when you said that this island was like paradise.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[Please, expand to that mountain and start mining marble.]]))
       .. new_objectives(obj_build_marblemine)
@@ -191,10 +191,10 @@
    body= saledus(_"Saledus is excited",
       -- TRANSLATORS: Saledus
       _([[By the Gods, this is an unbelievable stroke of fortune! There are two more mountains, and it seems that one has a large quantity of coal and the other of iron ore. I advise you to immediately build iron ore and coal mines (or at least charcoal kilns), smelting works, toolsmithies, armor and weapon smithies.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[However: for all these bigger buildings, we need better and more elegant building materials. So you have to build a house for the stonemason, who will cut columns from marble.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Saledus
       _([[After everything, we can now begin to live like we did in Fremil.]]))
       .. new_objectives(obj_build_mining_infrastructure)
@@ -205,10 +205,10 @@
    body= amalea(_"Amalea enters…",
       -- TRANSLATORS: Amalea
       _([[Lutius, don’t you think you forgot something important?]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[It’s nice, and of course a good idea, to build up mines, which will give us a more comfortable life, but the people working in the mines are unhappy with the current situation. They have to do hard work and have no time for making their own food.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[What do you think about helping them out? I can’t tell you what we need exactly… but here are my recommendations:]]))
       .. new_objectives(obj_build_food_infrastructure)
@@ -219,7 +219,7 @@
    body= amalea(_"Amalea smiles",
       -- TRANSLATORS: Amalea
       _([[I just visited our new tavern ‘At the palms’. The beer they serve is really tasty. You really should have a drink there, too.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Amalea
       _([[It is good to see that we have now got a warmer and more familiar environment on our island. Thank you, Lutius.]]))
 }
@@ -230,13 +230,13 @@
    body= lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[By the Gods! This is absolutely terrible. It seems as if we stand close to a test – and it seems as if Saledus was right with his fear concerning the shipwreck he found.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[Today, as I walked down to the eastern shore, I got a shock. I caught sight of one of those hated, evil, Barbarian tribes with whom we have had so many problems before.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[At first, I was naive and hoped that they were peaceful, but as soon as one of them saw me, they charged towards me and started attacking me with their throwing spears. Thanks be to the Gods that I was able to flee and hide myself, before retreating back to our colony under cover of darkness.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[Anyway, we must build up stronger military buildings as soon as possible.]]))
       .. new_objectives(obj_build_bigger_military_buildings)
@@ -257,10 +257,11 @@
    body= lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[Today is a proud day. We have fought for our new home and risen victorious.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[There are still a few Barbarians hiding on our island, but I am sure that we will find them soon. Every Barbarian who doesn’t attack us will be put in a boat with the other peaceful ones, and sent back to their country.]]))
       ..  objective_text(_"Victory",
+      -- TRANSLATORS: Lutius - Diary
       _[[You have established a working economy, trained new soldiers and driven the Barbarians from the island.]])
 }
 
@@ -268,7 +269,7 @@
    title =_ "As Time is Running By",
    w=200,
    h=150,
-   body=rt(p(_"7 days later…")),
+   body= p(_"7 days later…"),
 }
 
 diary_page_11 = {
@@ -277,9 +278,10 @@
    body= lutius(_"Diary of Lutius",
       -- TRANSLATORS: Lutius - Diary
       _([[Today a pigeon landed on our island. It brought a message which fills me with dark thoughts and brings back my fears.]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
       -- TRANSLATORS: Lutius - Diary
       _([[The message was addressed to me, begging me to come back to Fremil. It says that the Empire is at war with the Barbarians. They were attacked from the north by the tribe that I was forbidden to attack. It is clear to me what I must do…]])
-      .. paragraphdivider() ..
+      .. close_p() .. open_p() ..
+      -- TRANSLATORS: Lutius - Diary
       _([[You have completed this mission. You may continue playing if you wish, otherwise move on to the next mission.]]))
 }

=== modified file 'data/campaigns/tutorial01_basic_control.wmf/scripting/texts.lua'
--- data/campaigns/tutorial01_basic_control.wmf/scripting/texts.lua	2016-03-16 10:41:23 +0000
+++ data/campaigns/tutorial01_basic_control.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -14,22 +14,18 @@
 -- =============
 scold_player = {
    title = _"Nice And Easy Does It All the Time",
-   body = rt(
-      p(_[[I am sorry, but will I have to tear this down again. We might need the space here later on. If I am too slow for you, you might want to play a real game and just find everything out for yourself. Otherwise, please bear with me, I am not the youngest and quickest anymore.]]
-      )
-   ),
+   body =
+      p(_[[I am sorry, but will I have to tear this down again. We might need the space here later on. If I am too slow for you, you might want to play a real game and just find everything out for yourself. Otherwise, please bear with me, I am not the youngest and quickest anymore.]]),
    h = 300,
    show_instantly = true
 }
 
 initial_message_01 = {
    title = _"Welcome to the Widelands Tutorial!",
-   body = rt(
+   body =
       h1(_"Welcome to Widelands!") ..
       p(_[[Widelands is a slow-paced build-up strategy game with an emphasis on construction rather than destruction. This tutorial will guide you through the basics of the game.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Dismiss this box by left-clicking on the button below.]])
-   ),
+      li(_[[Dismiss this box by left-clicking on the button below.]]),
    h = 300,
    w = 400
 }
@@ -37,31 +33,26 @@
    title = _"Diving In",
    position = "topright",
    field = sf,
-   body = rt(
+   body =
       h1(_"Let’s dive right in!") ..
       p(_[[There are three different tribes in Widelands: the Barbarians, the Empire and the Atlanteans. All tribes have a different economy, strength and weaknesses, but the general gameplay is the same for all. We will play the Barbarians for now.]]) ..
       p(_[[You will usually start the game with one headquarters. This is the big building with the blue flag in front of it. The headquarters is a warehouse that stores wares, workers and soldiers. Some wares are needed for building houses, others for making other wares. Obviously, the wares in the headquarters will not last forever, so you must make sure to replace them. The most important wares in the early game are the basic construction wares: logs and granite. Let’s make sure that we do not run out of logs. For this, we need a lumberjack and a hut for him to stay in.]]) ..
       p(_[[We need to find a nice place for the lumberjack’s hut. To make this easier, we can activate ‘Show Building Spaces’. There are two ways you can do this, either by clicking on the ‘Show Building Spaces’ button at the bottom of the screen, which is the fourth one from the left. Or you can use the Space key to toggle it.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Left-click the ‘OK’ button to close this box and then try it.]])
-   ),
+      li(_[[Left-click the ‘OK’ button to close this box and then try it.]]),
    obj_name = "enable_buildhelp",
    obj_title = _"Enable the showing of building spaces",
-   obj_body = rt(
+   obj_body =
       h1(_"Show Building Spaces") ..
       p(_[[It is easier to understand what type of buildings can be built on which field when the symbols for the building spaces are enabled.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Do so now, either by pressing Space or by clicking the fourth button from the left at the very bottom of the screen. Right-click on this window and then give it a try.]])
-   )
+      li(_[[Do so now, either by pressing Space or by clicking the fourth button from the left at the very bottom of the screen. Right-click on this window and then give it a try.]])
 }
 
 lumberjack_message_01 = {
    title = _"Lumberjack’s Spot",
    position = "topright",
    field = first_lumberjack_field,
-   body = rt(
-      p(_[[There you go. I will explain about all those symbols in a minute. First, let me show you how to make a lumberjack’s hut and how to connect it with a road. There is a sweet spot for a lumberjack right next to those trees. I’ll describe the steps I will take and then ask you to click on the ‘OK’ button for me to demonstrate.]])
-   ),
+   body =
+      p(_[[There you go. I will explain about all those symbols in a minute. First, let me show you how to make a lumberjack’s hut and how to connect it with a road. There is a sweet spot for a lumberjack right next to those trees. I’ll describe the steps I will take and then ask you to click on the ‘OK’ button for me to demonstrate.]]),
    h = 300,
    w = 350
 }
@@ -69,20 +60,17 @@
 lumberjack_message_02 = {
    title = _"Building the Lumberjack",
    position = "topright",
-   body = rt(
+   body =
       p(_[[First, I’ll left-click on the symbol where I want the lumberjack’s hut to be built. A window will appear where I can choose between buildings. Because I’ll click a yellow house symbol – which means that its field can house medium and small buildings – I am presented with all the medium buildings that I can build. The lumberjack’s hut is a small building, so I will go on to select the small buildings tab. Then I’ll choose the lumberjack’s hut.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Click the ‘OK’ button to watch me. I’ll go really slowly: I will click – then select the tab – and finally I’ll choose the building.]])
-   ),
+      li(_[[Click the ‘OK’ button to watch me. I’ll go really slowly: I will click – then select the tab – and finally I’ll choose the building.]]),
    h = 300
 }
 
 lumberjack_message_03a = {
    title = _"Building a Connecting Road",
    position = "topright",
-   body = rt(
-      p(_[[That won’t do yet. I still need to connect the lumberjack’s hut to the rest of my road network. After ordering the construction site, I was automatically put into road building mode, so all I have to do is click on the blue flag in front of my headquarters.]])
-   ),
+   body =
+      p(_[[That won’t do yet. I still need to connect the lumberjack’s hut to the rest of my road network. After ordering the construction site, I was automatically put into road building mode, so all I have to do is click on the blue flag in front of my headquarters.]]),
    show_instantly = true,
    h = 300,
    w = 350
@@ -91,9 +79,8 @@
 lumberjack_message_03b = {
    title = _"Building a Connecting Road",
    position = "topright",
-   body = rt(
-      p(_[[That won’t do yet. I still need to connect the lumberjack’s hut to the rest of my road network. You have disabled the option ‘Start building road after placing a flag’ (to change that, choose ‘Options’ in the Widelands main menu). Therefore, I have entered the road building mode manually. I will tell you later how to do that. To build the road, all I have to do now is click on the blue flag in front of my headquarters.]])
-   ),
+   body =
+      p(_[[That won’t do yet. I still need to connect the lumberjack’s hut to the rest of my road network. You have disabled the option ‘Start building road after placing a flag’ (to change that, choose ‘Options’ in the Widelands main menu). Therefore, I have entered the road building mode manually. I will tell you later how to do that. To build the road, all I have to do now is click on the blue flag in front of my headquarters.]]),
    show_instantly = true,
    h = 300,
    w = 350
@@ -102,9 +89,8 @@
 lumberjack_message_04 = {
    title = _"Waiting for the Lumberjack to Go Up",
    position = "topright",
-   body = rt(
-      p(_[[Now watch closely while a builder leaves the headquarters and goes to the construction site. Also, a carrier will take position in between the two blue flags and carry wares from one blue flag to the other.]])
-   ),
+   body =
+      p(_[[Now watch closely while a builder leaves the headquarters and goes to the construction site. Also, a carrier will take position in between the two blue flags and carry wares from one blue flag to the other.]]),
    h = 300,
    w = 350
 }
@@ -112,31 +98,25 @@
 lumberjack_message_05 = {
    title = _"Placing Another Flag",
    position = "topright",
-   body = rt(
+   body =
       p(_[[Nice how they are working, isn’t it? But the poor carrier has a very long way to go. We can make it easier for him (and more efficient for us) by placing another blue flag on the road.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[You try it this time: click on the yellow flag symbol in between the two blue flags we just placed and then click on the]])
-   ) ..
-   rt("image=images/wui/fieldaction/menu_build_flag.png", p(_"build flag symbol.")
-   ),
+      li(_[[You try it this time: click on the yellow flag symbol in between the two blue flags we just placed and then click on the]]) ..
+      p(img("images/wui/fieldaction/menu_build_flag.png") .. _"build flag symbol."),
    h = 300,
    obj_name = "build_flag_on_road_to_lumberjack",
    obj_title = _"Build a flag to divide the road to the lumberjack",
-   obj_body = rt(
+   obj_body =
       h1(_"Build a Flag on the Road") ..
       p(_[[The shorter your road segments are, the faster your wares will be transported. You should therefore make sure that your roads have as many flags as possible.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a blue flag now in the middle of the road that connects your headquarters to your lumberjack’s hut.]])
-   )
+      li(_[[Build a blue flag now in the middle of the road that connects your headquarters to your lumberjack’s hut.]])
 }
 
 lumberjack_message_06 = {
    title = _"Waiting For the Hut to be Finished",
    position = "topright",
-   body = rt(
+   body =
       p(_[[Well done! Let’s wait till the hut is finished.]]) ..
-      p(_[[If you want things to go faster, simply use the Page Up key on your keyboard to increase the game speed. You can use Page Down to make the game slower again.]])
-   ),
+      p(_[[If you want things to go faster, simply use the Page Up key on your keyboard to increase the game speed. You can use Page Down to make the game slower again.]]),
    h = 300,
    w = 350
 }
@@ -144,23 +124,21 @@
 flag_built = {
    title = _"Waiting for the Hut to be Finished",
    position = "topright",
-   body = rt(
+   body =
       p(_[[I wanted to teach you how to build new flags, but it seems you have already found out on your own. Well done!]]) ..
       p(_[[Now you have split the road in two parts with a carrier each. This means less work for him and higher efficiency for us. You should therefore always place as many flags as possible on your roads.]]) ..
       p(_[[Now we only have to wait till the hut is finished.]]) ..
-      p(_[[If you want things to go faster, simply use the Page Up key on your keyboard to increase the game speed. You can use Page Down to make the game slower again.]])
-   ),
+      p(_[[If you want things to go faster, simply use the Page Up key on your keyboard to increase the game speed. You can use Page Down to make the game slower again.]]),
    h = 350
 }
 
 construction_site_window = {
    title = _"The Construction Site",
-   body = rt(
+   body =
       h1(_"Let's see the progress") ..
       p(_[[If you click on the construction site, a window opens. You can see the wares that are still missing grayed out. You can also see the progress of this construction site.]]) ..
       -- The player doesn't know about the statistics yet. First things first.
-      p(_[[To close the window, simply right-click on it. All windows in Widelands can be closed that way, except the ones with instructions, like this one. Try it out!]])
-   ),
+      p(_[[To close the window, simply right-click on it. All windows in Widelands can be closed that way, except the ones with instructions, like this one. Try it out!]]),
    h = 300,
    w = 350
 }
@@ -168,42 +146,34 @@
 lumberjack_message_07 = {
    title = _"Lumberjack is Done",
    position = "topright",
-   body = rt(
-      p(_[[Excellent. The lumberjack’s hut is done. A lumberjack will now move in and start chopping down trees, so our log income is secured for now. Now on to the granite.]])
-   ),
+   body =
+      p(_[[Excellent. The lumberjack’s hut is done. A lumberjack will now move in and start chopping down trees, so our log income is secured for now. Now on to the granite.]]),
    h = 300,
    w = 350
 }
 
 inform_about_rocks = {
    title = _"Some Rocks Were Found",
-   body = rt(h1(_"Getting a Quarry Up")) ..
-   rt(
+      h1(_"Getting a Quarry Up") ..
       p(_[[Granite can be mined in granite mines, but the easier way is to build a quarry next to some rocks lying around. As it happens, there is a pile of them just to the west (left) of your headquarters. I will teach you now how to move your view over there.]]) ..
-      paragraphdivider() ..
-      listitem_arrow(_[[There are three ways to move your view. The first one is using the cursor keys on your keyboard. Go ahead and try this out.]]) ..
-      listitem_bullet(_[[Click the ‘OK’ button and then move the view using the cursor keys]])
-   ),
+      li_arrow(_[[There are three ways to move your view. The first one is using the cursor keys on your keyboard. Go ahead and try this out.]]) ..
+      li(_[[Click the ‘OK’ button and then move the view using the cursor keys]]),
    h = 350,
    obj_name = "move_view_with_cursor_keys",
    obj_title = _"Move your view with the cursor keys",
-   obj_body = rt(
+   obj_body =
       h1(_"Moving Your View") ..
       p(_[[Moving your view is essential to get a complete overview of your whole economy. There are three ways to move your view in Widelands.]]) ..
-      paragraphdivider() ..
-      listitem_arrow(_[[The first one is to use the cursor keys on your keyboard.]]) ..
-      listitem_arrow(_[[The second one is the more common and faster one: press-and-hold the right mouse button anywhere on the map, then move your mouse around and you’ll see the view scroll.]]) ..
-      listitem_arrow(_[[The third one is to use the minimap. It is especially useful for traveling big distances.]])
-   )
+      li_arrow(_[[The first one is to use the cursor keys on your keyboard.]]) ..
+      li_arrow(_[[The second one is the more common and faster one: press-and-hold the right mouse button anywhere on the map, then move your mouse around and you’ll see the view scroll.]]) ..
+      li_arrow(_[[The third one is to use the minimap. It is especially useful for traveling big distances.]])
 }
 
 tell_about_right_drag_move = {
    title = _"Other Ways to Move the View",
-   body = rt(
+   body =
       p(_[[Excellent. Now there is a faster way to move, using the mouse instead:]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Simply right-click-and-hold anywhere on the map, then drag the mouse and instead of the cursor, the view will be moved. Try it.]])
-   ),
+      li(_[[Simply right-click-and-hold anywhere on the map, then drag the mouse and instead of the cursor, the view will be moved. Try it.]]),
    h = 300,
    w = 350,
    obj_name = "move_view_with_mouse",
@@ -213,30 +183,23 @@
 
 tell_about_minimap = {
    title = _"Use the minimap",
-   body = rt(
-      p(_[[Very good. And now about the minimap. You can open it by clicking on the]])
-   ) ..
-   rt("image=images/wui/menus/menu_toggle_minimap.png", p(_[[minimap button at the bottom of the screen or simply by using the keyboard shortcut ‘m’.]])
-   ) ..
-   rt(
+   body =
+      p(_[[Very good. And now about the minimap. You can open it by clicking on the]]) ..
+      p(img("images/wui/menus/menu_toggle_minimap.png") .. _[[minimap button at the bottom of the screen or simply by using the keyboard shortcut ‘m’.]]) ..
       p(_[[The minimap shows the complete map in miniature. You can directly jump to any field by left-clicking on it. You can also toggle buildings, roads, flags and player indicators on and off inside the minimap.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Try it out. Open the minimap, click on a few buttons and try moving around. Close it when you have experimented enough.]])
-   ),
+      li(_[[Try it out. Open the minimap, click on a few buttons and try moving around. Close it when you have experimented enough.]]),
    h = 350,
    obj_name = "use_minimap",
    obj_title = _"Learn to use the minimap",
-   obj_body = rt(
-      paragraphdivider() ..
-      listitem_bullet(_[[Open the minimap by using the third button from the left on the bottom of your screen or the ‘m’ key.]]) ..
-      listitem_bullet(_[[Play around a bit with the different overlays (roads, flags, etc.)]]) ..
-      listitem_bullet(_[[Close the minimap when you are ready to continue by using the same button or ‘m’ again. Of course, a right-click also works.]])
-   )
+   obj_body =
+      li(_[[Open the minimap by using the third button from the left on the bottom of your screen or the ‘m’ key.]]) ..
+      li(_[[Play around a bit with the different overlays (roads, flags, etc.)]]) ..
+      li(_[[Close the minimap when you are ready to continue by using the same button or ‘m’ again. Of course, a right-click also works.]])
 }
 
 congratulate_and_on_to_quarry = {
    title = _"Onward to the Quarry",
-   body = rt(p(_[[Great. Now about that quarry…]])),
+   body = p(_[[Great. Now about that quarry…]]),
    h = 200,
    w = 250
 }
@@ -245,45 +208,35 @@
    field = first_quarry_field,
    position = "topright",
    title = _"How to Build a Quarry",
-   body = rt(
+   body =
       p(_[[Build a quarry next to those rocks here. Remember how I did it earlier?]]) ..
       p(_[[Make sure that you are showing the building spaces, then just click on the space were you want the building to be, choose it from the window that appears, and it is placed. Maybe this is a good time to explain about all those building space symbols we activated earlier.]]) ..
-      p(_[[You can build four things on fields in Widelands: flags, small houses, medium houses and big houses. But not every field can hold everything. The build space symbols ease recognition:]])
-   ) ..
-   rt("image=images/wui/overlays/big.png", p(_[[Everything can be built on the green house symbol.]])) ..
-   rt("image=images/wui/overlays/medium.png", p(_[[Everything except for big buildings can be built on a yellow house symbol.]])) ..
-   rt("image=images/wui/overlays/small.png", p(_[[Red building symbols can only hold small buildings and flags.]])) ..
-   rt("image=images/wui/overlays/set_flag.png", p(_[[And finally, the yellow flag symbol only allows for flags.]])) ..
-   rt(
+      p(_[[You can build four things on fields in Widelands: flags, small houses, medium houses and big houses. But not every field can hold everything. The build space symbols ease recognition:]]) ..
+      p(img("images/wui/overlays/big.png") .. _[[Everything can be built on the green house symbol.]]) ..
+      p(img("images/wui/overlays/medium.png") .. _[[Everything except for big buildings can be built on a yellow house symbol.]]) ..
+      p(img("images/wui/overlays/small.png") .. _[[Red building symbols can only hold small buildings and flags.]]) ..
+      p(img("images/wui/overlays/set_flag.png") .. _[[And finally, the yellow flag symbol only allows for flags.]]) ..
       p(_[[If you place something on a field, the surrounding fields might have less space for holding buildings, so choose your fields wisely.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Now go ahead, try it. The quarry is a small building, so if you click on a medium or big building symbol, you will have to select the small buildings tab first to find it. Go on, check it out!]])
-   ),
+      li(_[[Now go ahead, try it. The quarry is a small building, so if you click on a medium or big building symbol, you will have to select the small buildings tab first to find it. Go on, check it out!]]),
    obj_name = "build_a_quarry",
    obj_title = _"Build a quarry next to the rocks",
-   obj_body = rt(
+   obj_body =
       h1(_"Build a Quarry") ..
-      paragraphdivider() ..
-      listitem_bullet(_[[There are some rocks to the west of your headquarters. Build a quarry right next to them.]]) ..
-      listitem_arrow(_[[The quarry is a small building like the lumberjack’s hut. You can therefore build it on any field that shows a red, yellow or green house when the building spaces symbols are enabled (Press Space for that).]]) ..
-      listitem_arrow(_[[Just click on any house symbol next to the rocks, select the small buildings tab in the window that opens up, then click on the quarry symbol.]])
-   )
+      li(_[[There are some rocks to the west of your headquarters. Build a quarry right next to them.]]) ..
+      li_arrow(_[[The quarry is a small building like the lumberjack’s hut. You can therefore build it on any field that shows a red, yellow or green house when the building spaces symbols are enabled (Press Space for that).]]) ..
+      li_arrow(_[[Just click on any house symbol next to the rocks, select the small buildings tab in the window that opens up, then click on the quarry symbol.]])
 }
 
 talk_about_roadbuilding_00a = {
    position = "topright",
    field = wl.Game().map:get_field(9,12),
    title = _"Road Building",
-   body = rt(
-      p(_[[Excellent! Directly after placing the building, you have been switched into road building mode. The new road will start at the flag in front of your newly placed construction site. You can enter road building mode for any flag by left-clicking on a flag and selecting]])
-      ) ..
-   rt("image=images/wui/fieldaction/menu_build_way.png", p(_[[the road building symbol.]])) ..
-   rt(
-      p(_[[If you decide you do not want to build a road at this time, you can cancel road building by clicking on the starting flag of the road and selecting]])) ..
-   rt("image=images/wui/menu_abort.png", p(_[[the abort symbol.]])) ..
-   rt(
-      p(_[[Now, about this road. Remember: we are already in road building mode since you just ordered the quarry. You can either make it longer by one field at a time by left-clicking multiple times on neighboring fields for perfect control over the route the road takes, like so:]])
-   ),
+   body =
+      p(_[[Excellent! Directly after placing the building, you have been switched into road building mode. The new road will start at the flag in front of your newly placed construction site. You can enter road building mode for any flag by left-clicking on a flag and selecting]]) ..
+      p(img("images/wui/fieldaction/menu_build_way.png") .. _[[the road building symbol.]]) ..
+      p(_[[If you decide you do not want to build a road at this time, you can cancel road building by clicking on the starting flag of the road and selecting]]) ..
+      p(img("images/wui/menu_abort.png") .. _[[the abort symbol.]]) ..
+      p(_[[Now, about this road. Remember: we are already in road building mode since you just ordered the quarry. You can either make it longer by one field at a time by left-clicking multiple times on neighboring fields for perfect control over the route the road takes, like so:]]),
    show_instantly = true
 }
 
@@ -291,16 +244,12 @@
    position = "topright",
    field = road_building_field,
    title = _"Road Building",
-   body = rt(
-      p(_[[Excellent! To enter road building mode for any flag, left-click on a flag and select]])
-      ) ..
-   rt("image=images/wui/fieldaction/menu_build_way.png", p(_[[the road building symbol.]])) ..
-   rt(
-      p(_[[If you decide that you do not want to build a road at this time, you can cancel road building by clicking on the starting flag of the road and selecting]])) ..
-   rt("image=images/wui/menu_abort.png", p(_[[the abort symbol.]])) ..
-   rt(
-      p(_[[Now, about this road. I’ll enter the road building mode and then make it longer by one field at a time by left-clicking multiple times on neighboring fields for perfect control over the route the road takes, like so:]])
-   ),
+   body =
+      p(_[[Excellent! To enter road building mode for any flag, left-click on a flag and select]]) ..
+      p(img("images/wui/fieldaction/menu_build_way.png") .. _[[the road building symbol.]]) ..
+      p(_[[If you decide that you do not want to build a road at this time, you can cancel road building by clicking on the starting flag of the road and selecting]]) ..
+      p(img("images/wui/menu_abort.png") .. _[[the abort symbol.]]) ..
+      p(_[[Now, about this road. I’ll enter the road building mode and then make it longer by one field at a time by left-clicking multiple times on neighboring fields for perfect control over the route the road takes, like so:]]),
    show_instantly = true
 }
 
@@ -308,7 +257,7 @@
    position = "topright",
    field = road_building_field,
    title = _"Road Building",
-   body = rt(p(_[[Or, you can directly click the flag where the road should end, like so:]])),
+   body = p(_[[Or, you can directly click the flag where the road should end, like so:]]),
    h = 200,
    w = 250
 }
@@ -316,42 +265,34 @@
 talk_about_roadbuilding_02 = {
    position = "topright",
    title = _"Road Building",
-   body = rt(
-      p(_[[One more thing: around the field where your road would end, you can see different markers. They have the following meaning:]])
-   ) ..
-   rt("image=images/wui/overlays/roadb_green.png", p(_[[The terrain is flat here. Your carriers will be very swift on this terrain.]])) ..
-   rt("image=images/wui/overlays/roadb_yellow.png", p(_[[There is a small slope to climb to reach this field. This means that your workers will be faster walking downhill than they will be walking uphill.]])) ..
-   rt("image=images/wui/overlays/roadb_red.png", p(_[[The connection between the fields is extremely steep. The speed increase in one direction is huge while the slowdown in the other is also substantial.]])) ..
-   rt(
+   body =
+      p(_[[One more thing: around the field where your road would end, you can see different markers. They have the following meaning:]]) ..
+      p(img("images/wui/overlays/roadb_green.png") .. _[[The terrain is flat here. Your carriers will be very swift on this terrain.]]) ..
+      p(img("images/wui/overlays/roadb_yellow.png") .. _[[There is a small slope to climb to reach this field. This means that your workers will be faster walking downhill than they will be walking uphill.]]) ..
+      p(img("images/wui/overlays/roadb_red.png") .. _[[The connection between the fields is extremely steep. The speed increase in one direction is huge while the slowdown in the other is also substantial.]]) ..
       p(_[[Keep the slopes in mind while placing roads and use them to your advantage. Also, try to keep roads as short as possible and always remember to place as many flags as you can on road segments to share the load better. If you hold Ctrl or Shift+Ctrl while you finish the road, flags are placed automatically.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Now please rebuild the road between your quarry and your headquarters.]])
-   ),
+      li(_[[Now please rebuild the road between your quarry and your headquarters.]]),
    h = 450,
    obj_name = "build_road_to_quarry",
    obj_title = _"Connect the quarry to the headquarters",
-   obj_body = rt(
+   obj_body =
       h1(_"Connect Your Construction Site") ..
       p(_[[Connect your quarry construction site to your headquarters with a road. You would have been put directly into road building mode after ordering a new site. But now, you aren’t.]]) ..
-      paragraphdivider() ..
-      listitem_arrow(_[[To build a completely new road, just click on the flag in front of your construction site, click on the build road icon and then click on the flag in front of your headquarters. Wait for the completion of the quarry.]])
-   )
+      li_arrow(_[[To build a completely new road, just click on the flag in front of your construction site, click on the build road icon and then click on the flag in front of your headquarters. Wait for the completion of the quarry.]])
 }
 
 quarry_not_connected = {
    title = _"Quarry not Connected",
-   body = rt(
-      p(_[[Your workers do not like to walk across country. You have to build a road from your headquarters to the construction site so that carriers can transport wares. The simplest way is to click on the construction site’s flag, choose ‘Build road’, and then click on the destination flag (the one in front of your headquarters), just like I’ve demonstrated.]])
-   ),
+   body =
+      p(_[[Your workers do not like to walk across country. You have to build a road from your headquarters to the construction site so that carriers can transport wares. The simplest way is to click on the construction site’s flag, choose ‘Build road’, and then click on the destination flag (the one in front of your headquarters), just like I’ve demonstrated.]]),
    w = 350,
    h = 250
 }
 
 quarry_illegally_destroyed = {
    title = _"You Destroyed the Construction Site!",
-   body = rt(
-      p(_[[It seems like you destroyed a construction site for a quarry we wanted to build. Since we need the granite, I suggest you reload the game from a previous savegame. Luckily, these are created from time to time. To do so, you have to go back to the main menu and choose ‘Single Player’ → ‘Load Game’. And please be a bit more careful next time.]])
-   ),
+   body =
+      p(_[[It seems like you destroyed a construction site for a quarry we wanted to build. Since we need the granite, I suggest you reload the game from a previous savegame. Luckily, these are created from time to time. To do so, you have to go back to the main menu and choose ‘Single Player’ → ‘Load Game’. And please be a bit more careful next time.]]),
    w = 350,
    h = 250
 }
@@ -359,35 +300,30 @@
 build_second_quarry = {
    position = "topright",
    title = _"Build a second quarry",
-   body = rt(
+   body =
       p(_[[When there are many rocks, you can consider building another quarry. This will make the granite production faster.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a second quarry near the rocks and connect it to your road network.]])
-   ),
+      li(_[[Build a second quarry near the rocks and connect it to your road network.]]),
    obj_name = "build_the_second_quarry",
    obj_title = _"Build another quarry",
-   obj_body = rt(
+   obj_body =
       h1(_"Build another quarry") ..
       p(_[[Build a second quarry next to the rocks. Do not forget to connect it to another flag.]]) ..
-      paragraphdivider() ..
-      listitem_arrow(_[[You can connect the new road to any flag of your existing road network. You can create junctions everywhere, not only in front of buildings.]])
-   ),
+      li_arrow(_[[You can connect the new road to any flag of your existing road network. You can create junctions everywhere, not only in front of buildings.]]),
    h = 300,
    w = 350
 }
 
 census_and_statistics_00 = {
    title = _"Census and Statistics",
-   body = rt(
+   body =
       p(_[[While we wait, I’ll quickly show you another useful feature. All construction sites look the same, and some buildings look alike. It is sometimes hard to tell them apart. Widelands offers a feature to show label texts over the buildings. They are called the ‘census’ and you can toggle them via the ‘c’ key or via the button on the ‘Watch’ tab of any field.]]) ..
       p(_[[Similar to this are the building statistics, which are also toggled via a button on the ‘Watch’ tab of any field. The hotkey for it is ‘s’. This will display information about the productivity of buildings or the progress of construction sites.]]) ..
       p(_[[Let me quickly enable these two for you. Remember: ‘c’ and ‘s’ are the keys. Alternatively, you can click on any field without a building on it, select the watch tab and then click on the corresponding buttons.]])
-   )
 }
 
 census_and_statistics_01 = {
    title = _"Census and Statistics",
-   body = rt(p(_[[Now we know what’s going on. Let’s wait for the quarries to finish.]])),
+   body = p(_[[Now we know what’s going on. Let’s wait for the quarries to finish.]]),
    h = 200,
    w = 250
 }
@@ -396,56 +332,45 @@
    popup = true,
    title = _"Messages",
    heading = _"Introducing Messages",
-   body = rt(
+   body =
       p(_[[Hi, it’s me again! This time, I have sent you a message. Messages are sent to you by Widelands to inform you about important events: empty mines, attacks on your tribe, won or lost military buildings, resources found…]]) ..
       p(_[[The message window can be toggled by the button on the very right at the bottom of the screen. This button will also change appearance whenever new messages are available, but there is also a bell sound played whenever you receive a new message.]]) ..
-      p(_[[You have two messages at the moment. This one, which you are currently reading, and the one that informed you that a new headquarters was added to your economy. Let’s learn how to archive messages: first, select the message that you wish to archive by clicking on it in the list. Then, click the]])
-   ) ..
-   rt("image=images/wui/messages/message_archive.png", p(_[[‘Archive selected message’ button to move it into your archive.]])) ..
-   rt(
+      p(_[[You have two messages at the moment. This one, which you are currently reading, and the one that informed you that a new headquarters was added to your economy. Let’s learn how to archive messages: first, select the message that you wish to archive by clicking on it in the list. Then, click the]]) ..
+      p(img("images/wui/messages/message_archive.png") .. _[[‘Archive selected message’ button to move it into your archive.]]) ..
       p(_[[Once you have deleted a message, another message will be selected automatically from the list.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Archive all messages that you currently have in your inbox, including this one.]])
-   ),
+      li(_[[Archive all messages that you currently have in your inbox, including this one.]]),
    obj_name = "archive_all_messages",
    obj_title = _"Archive all messages in your inbox",
-   obj_body = rt(
+   obj_body =
       h1(_"Archive Your Inbox Messages") ..
       p(_[[The message window is central to fully controlling your tribe’s fortune. However, you will get a lot of messages in a real game. To keep your head straight, you should try to keep the inbox empty.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Archive all your messages in your inbox now.]]) ..
-      listitem_arrow(_[[To do so, open the message window by pressing ‘n’ or clicking the rightmost button at the very bottom of the screen. The newest message will be marked for you automatically. Keep clicking the ‘Archive selected message’ button until all messages have been archived and the list is empty.]])
-   )
+      li(_[[Archive all your messages in your inbox now.]]) ..
+      li_arrow(_[[To do so, open the message window by pressing ‘n’ or clicking the rightmost button at the very bottom of the screen. The newest message will be marked for you automatically. Keep clicking the ‘Archive selected message’ button until all messages have been archived and the list is empty.]])
 }
 
 closing_msg_window_00 = {
    position = "topright",
    field = first_quarry_field,
    title = _"Closing Windows",
-   body = rt(
+   body =
       p(_[[Excellent. Do you remember how to close windows? You simply have to right-click on them. This will work with all windows except for story message windows like this one. Go ahead and try it.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[First, close this window by pressing the button below, then right-click into the messages window to close it.]])
-   ),
+      li(_[[First, close this window by pressing the button below, then right-click into the messages window to close it.]]),
    h = 300,
    w = 350,
    obj_name = "close_message_window",
    obj_title = _"Close the messages window",
-   obj_body = rt(
+   obj_body =
       h1(_"Close the Messages Window") ..
       p(_[[All windows in Widelands can be closed by right-clicking into them. Some windows can also be toggled with the buttons at the very bottom of the screen.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Close the messages window now by right-clicking into it.]])
-   )
+      li(_[[Close the messages window now by right-clicking into it.]])
 }
 
 closing_msg_window_01 = {
    position = "topright",
    field = first_quarry_field,
    title = _"Closing Windows",
-   body = rt(
-      p(_[[Well done! Let’s see how messages work in a real game, shall we? For this, I’ll take all rocks away from the poor stonemasons in the quarries. They will then send a message each that they can’t find any in their work areas the next time they try to do some work.]])
-   ),
+   body =
+      p(_[[Well done! Let’s see how messages work in a real game, shall we? For this, I’ll take all rocks away from the poor stonemasons in the quarries. They will then send a message each that they can’t find any in their work areas the next time they try to do some work.]]),
    h = 300,
    w = 350
 }
@@ -453,68 +378,58 @@
 destroy_quarries_message = {
    position = "topright",
    title = _"Messages Arrived!",
-   body = rt(
+   body =
       p(_[[You received some messages. See how the button at the bottom of the screen has changed appearance? You can destroy the quarries now as they are no longer of any use and just blocking space. To do so, there are two possibilities:]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Burning down the quarry: this is the fastest way of clearing the space. While the worker abandons the building, the wares are lost.]]) ..
-      listitem_bullet(_[[Dismantling the quarry: a builder will walk from the headquarters to dismantle the quarry piece by piece. Thereby, you regain some of the resources you used for the construction.]])
-   ),
+      li(_[[Burning down the quarry: this is the fastest way of clearing the space. While the worker abandons the building, the wares are lost.]]) ..
+      li(_[[Dismantling the quarry: a builder will walk from the headquarters to dismantle the quarry piece by piece. Thereby, you regain some of the resources you used for the construction.]]),
    h = 300,
    obj_name = "destroy_quarries",
    obj_title = "Destroy the two quarries",
-   obj_body = rt(
+   obj_body =
       p(_[[Since our quarries are useless now, you can destroy them and reuse the space later on.]]) ..
-      paragraphdivider() ..
-      listitem_arrow(_[[There are two different ways of destroying a building: burning down and dismantling. Try them both out on your quarries.]]) ..
-      listitem_arrow(_[[Burning down the quarry: This is the fastest way of clearing the space. While the worker abandons the building, the wares are lost.]]) ..
-      listitem_arrow(_[[Dismantling the quarry: A builder will walk from the headquarters to dismantle the quarry piece by piece. Thereby, you regain some of the resources you used for the construction.]])
-   )
+      li_arrow(_[[There are two different ways of destroying a building: burning down and dismantling. Try them both out on your quarries.]]) ..
+      li_arrow(_[[Burning down the quarry: This is the fastest way of clearing the space. While the worker abandons the building, the wares are lost.]]) ..
+      li_arrow(_[[Dismantling the quarry: A builder will walk from the headquarters to dismantle the quarry piece by piece. Thereby, you regain some of the resources you used for the construction.]])
 }
 
 introduce_expansion = {
    title = _"Expanding Your Territory!",
-   body = rt(
+   body =
       p(_[[There is one more thing I’d like to teach you now: Expanding your territory. The place that we started with around our headquarters is barely enough for a basic building infrastructure, and we do not have access to mountains, which we need to mine minerals and coal. So, we have to expand our territory.]]) ..
       p(_[[Expanding is as simple as building a military building at the edge of your territory. The Barbarians have a selection of different military buildings: sentries, barriers, towers, fortresses and citadels. The bigger the building, the more expensive it is to build, but the more land it will conquer around itself and the more soldiers can be stationed there. The buildings also vary in their vision range: buildings with a tower see farther than others.]]) ..
       p(_[[As soon as a military building is manned, it will extend your land. I will tell your more about military buildings in another tutorial.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Let’s try it out now: build a military building on your border.]]) ..
-      listitem_arrow(_[[The sentry is the only military site that fits on a small building plot. If your lumberjack has cleared enough space, you can also build another military building.]])
-   ),
+      li(_[[Let’s try it out now: build a military building on your border.]]) ..
+      li_arrow(_[[The sentry is the only military site that fits on a small building plot. If your lumberjack has cleared enough space, you can also build another military building.]]),
    obj_name = "expand_territory",
    obj_title = _"Expand your territory",
-   obj_body = rt(
+   obj_body =
       h1(_"Make your territory grow") ..
       p(_[[In Widelands, it is necessary to build many buildings, which take up a lot of space. To expand your territory, you have to build military buildings next to your border. Every tribe has several military buildings.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[The Barbarians have four different military buildings you can build: the sentry (small), the barrier and the tower (both medium) and the fortress (big). Just choose the one you like most.]]) ..
-      listitem_arrow(_[[Remember that big buildings (green icon) cannot be built on small (red) or medium (yellow) building plots, but buildings can be built on a building plot that provides more space than they need. You should always keep that in mind when you search for a suitable place.]])
-   )
+      li(_[[The Barbarians have four different military buildings you can build: the sentry (small), the barrier and the tower (both medium) and the fortress (big). Just choose the one you like most.]]) ..
+      li_arrow(_[[Remember that big buildings (green icon) cannot be built on small (red) or medium (yellow) building plots, but buildings can be built on a building plot that provides more space than they need. You should always keep that in mind when you search for a suitable place.]])
 }
 
 
 military_building_finished = {
    title = _"Military Site Occupied",
-   body = rt(
+   body =
       h1(_"Your territory has just grown!") ..
       p(_[[Great. Do you see how your territory has grown since your soldiers entered your new military building?]]) ..
-      p(_[[Every military building has a certain conquer area – the more expensive the building, the more land it conquers.]])
-   ),
+      p(_[[Every military building has a certain conquer area – the more expensive the building, the more land it conquers.]]),
    h = 300,
    w = 350
 }
 
 conclude_tutorial = {
    title = _"Conclusion",
-   body = rt(
+   body =
       h1(_"Conclusion") ..
       p(_[[This concludes the first tutorial. In order to learn more about the game, I suggest to play one of the other tutorials. Each of them covers a different topic.]]) ..
       p(_[[However, since you now know how to control Widelands, you can also start a game (or continue this one) and discover more by yourself.]]) ..
-      p(_[[To leave this game and return to the main menu, click on the]])
-   ) ..
-   rt("image=images/wui/menus/menu_options_menu.png", p(_[[‘Main Menu’ button on the very left at the bottom of the screen. Then click the]])) ..
-   rt("image=images/wui/menus/menu_exit_game.png", p(_[[‘Exit Game’ button.]])) ..
-   rt(p(_[[Thanks for playing this tutorial. Enjoy Widelands and remember to visit us at]])) ..
-   rt("text-align=center", "<p font-size=24 font-decoration=underline>http://www.widelands.org</p>"),
+      p(_[[To leave this game and return to the main menu, click on the]]) ..
+      p(img("images/wui/menus/menu_options_menu.png") .. _[[‘Main Menu’ button on the very left at the bottom of the screen. Then click the]]) ..
+      p(img("images/wui/menus/menu_exit_game.png") .. _[[‘Exit Game’ button.]]) ..
+      p(_[[Thanks for playing this tutorial. Enjoy Widelands and remember to visit us at]]) ..
+      p("halign=center", "<font size=24 underline=1>http://www.widelands.org</font>"),
    h = 450
 }

=== modified file 'data/campaigns/tutorial02_warfare.wmf/scripting/texts.lua'
--- data/campaigns/tutorial02_warfare.wmf/scripting/texts.lua	2016-04-01 19:56:26 +0000
+++ data/campaigns/tutorial02_warfare.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -19,207 +19,179 @@
 
 introduction = {
    title = _"Introduction",
-   body = rt(
+   body =
       h1(_"Soldiers, Training and Warfare") ..
       p(_[[In this scenario, I’m going to tell you about soldiers, their training and their profession: warfare. Although Widelands is about building up, not burning down, there is an enemy you sometimes have to defeat. Yet warfare is mainly focused on economics, not on military strategies, and its mechanics deserve explanation.]]) ..
-      p(_[[I’ve set up a small village that contains the most important buildings. You also have enough wares, so you do not have to take care of your weapons production. In a real game, you will not have this luxury.]])
-   ),
+      p(_[[I’ve set up a small village that contains the most important buildings. You also have enough wares, so you do not have to take care of your weapons production. In a real game, you will not have this luxury.]]),
    h = 300
 }
 
 abilities = {
    position = "topright",
    title = _"Soldiers’ abilities",
-   body = rt(
+   body =
       p(_[[A new soldier is created like a worker: when a military building needs a soldier, a carrier grabs the needed weapons and armor from a warehouse (or your headquarters) and walks up the road to your new building. Basic Barbarian soldiers do not use armor, they only need an ax.]]) ..
       p(_[[Take a look at the soldiers that are on their way to our military buildings. They look different from normal workers: they have a health bar over their head that displays their remaining health, and they have four symbols, which symbolize the individual soldier’s current levels in the four different categories: health, attack, defense and evade.]]) ..
       -- TRANSLATORS: the current stats are: 3 health, 5 attack, 0 defense, 2 evade.
-      p((_[[If a Barbarian soldier is fully trained, he has level %1% health, level %2% attack, level %3% defense and level %4% evade. This is one fearsome warrior then! The individual abilities have the following meaning:]]):bformat(soldier.max_health_level, soldier.max_attack_level, soldier.max_defense_level, soldier.max_evade_level))
-   ) ..
-   rt("image=tribes/workers/barbarians/soldier/health_level0.png", h2(_"Health:")) ..
-   -- TRANSLATORS: the current stats are: 13000 health, 2800 health gain.
-   rt(p((_[[The total life of a soldier. A Barbarian soldier starts with %1% health, and he will gain %2% health with each health level.]]):bformat(soldier.base_health, soldier.health_incr_per_level))) ..
-   rt("image=tribes/workers/barbarians/soldier/attack_level0.png", h2(_"Attack:")) ..
-   -- TRANSLATORS: the current stats are: 1400 damage, gains 850 damage points.
-   rt(p(_[[The amount of damage a soldier will inflict on the enemy when an attack is successful. A Barbarian soldier with attack level 0 inflicts ~%1% points of health damage when he succeeds in hitting an enemy. For each attack level, he gains %2% damage points.]]):bformat(soldier.base_min_attack + (soldier.base_max_attack - soldier.base_min_attack) / 2, soldier.attack_incr_per_level)) ..
-   -- The Atlanteans' image, because the Barbarian one has a white background
-   rt("image=tribes/workers/atlanteans/soldier/defense_level0.png", h2(_"Defense:")) ..
-   -- TRANSLATORS: the current stats are: 3%. The calculated health value is 3395
-   -- TRANSLATORS: The last two %% after the placeholder are the percent symbol.
-   rt(p(_[[The defense is the percentage that is subtracted from the attack value. The Barbarians cannot train in this skill and therefore have always defense level 0, which means that the damage is always reduced by %1%%%. If an attacker with an attack value of 3500 points hits a Barbarian soldier, the Barbarian will lose 3500·%2%%% = %3% health.]]):bformat(soldier.base_defense, (100 - soldier.base_defense), 3500 * (100 - soldier.base_defense) / 100)) ..
-   rt("image=tribes/workers/barbarians/soldier/evade_level0.png", h2(_"Evade:")) ..
-   -- TRANSLATORS: the current stats are: 25% evade, increases in steps of 15%.
-   -- TRANSLATORS: The last two %% after the placeholder are the percent symbol.
-   rt(p(_[[Evade is the chance that the soldier is able to dodge an attack. A level 0 Barbarian has a %1%%% chance to evade an attack, and this increases in steps of %2%%% for each level.]]):bformat(soldier.base_evade, soldier.evade_incr_per_level))
+      p((_[[If a Barbarian soldier is fully trained, he has level %1% health, level %2% attack, level %3% defense and level %4% evade. This is one fearsome warrior then! The individual abilities have the following meaning:]]):bformat(soldier.max_health_level, soldier.max_attack_level, soldier.max_defense_level, soldier.max_evade_level)) ..
+      h2(img("tribes/workers/barbarians/soldier/health_level0.png") .. _"Health:") ..
+      -- TRANSLATORS: the current stats are: 13000 health, 2800 health gain.
+      p((_[[The total life of a soldier. A Barbarian soldier starts with %1% health, and he will gain %2% health with each health level.]]):bformat(soldier.base_health, soldier.health_incr_per_level)) ..
+      h2(img("tribes/workers/barbarians/soldier/attack_level0.png") .. _"Attack:") ..
+      -- TRANSLATORS: the current stats are: 1400 damage, gains 850 damage points.
+      p(_[[The amount of damage a soldier will inflict on the enemy when an attack is successful. A Barbarian soldier with attack level 0 inflicts ~%1% points of health damage when he succeeds in hitting an enemy. For each attack level, he gains %2% damage points.]]):bformat(soldier.base_min_attack + (soldier.base_max_attack - soldier.base_min_attack) / 2, soldier.attack_incr_per_level) ..
+      -- The Atlanteans' image, because the Barbarian one has a white background
+      h2(img("tribes/workers/atlanteans/soldier/defense_level0.png") .. _"Defense:") ..
+      -- TRANSLATORS: the current stats are: 3%. The calculated health value is 3395
+      -- TRANSLATORS: The last two %% after the placeholder are the percent symbol.
+      p(_[[The defense is the percentage that is subtracted from the attack value. The Barbarians cannot train in this skill and therefore have always defense level 0, which means that the damage is always reduced by %1%%%. If an attacker with an attack value of 3500 points hits a Barbarian soldier, the Barbarian will lose 3500·%2%%% = %3% health.]]):bformat(soldier.base_defense, (100 - soldier.base_defense), 3500 * (100 - soldier.base_defense) / 100) ..
+      h2(img("tribes/workers/barbarians/soldier/evade_level0.png") .. _"Evade:") ..
+      -- TRANSLATORS: the current stats are: 25% evade, increases in steps of 15%.
+      -- TRANSLATORS: The last two %% after the placeholder are the percent symbol.
+      p(_[[Evade is the chance that the soldier is able to dodge an attack. A level 0 Barbarian has a %1%%% chance to evade an attack, and this increases in steps of %2%%% for each level.]]):bformat(soldier.base_evade, soldier.evade_incr_per_level)
 }
 
 battlearena1 = {
    position = "topright",
    title = _"The Battle Arena",
-   body = rt(
+   body =
       p(_[[Now I have talked about training and levels. Let me elaborate on that.]]) ..
       p(_[[A newly created soldier has no experience and is not very good at fighting. To make him stronger, you can build training sites.]]) ..
       p(_[[One of these training sites is the battle arena. It is a big and expensive building, and it trains soldiers in evade. Since soldiers get very hungry during their workout, this building needs a lot of food and strong beer. In a real game, you should have a good infrastructure before you build it.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[To see evade training in action, build a battle arena.]]) ..
-      "</p><p font-size=8><br></p>" ..
-      p(_[[While we’re waiting for the battle arena, you’ll probably notice some soldiers walking around. They are automatically exchanged from time to time. I’ll teach you about that later.]])
-   ),
+      li(_[[To see evade training in action, build a battle arena.]]) ..
+      p(_[[While we’re waiting for the battle arena, you’ll probably notice some soldiers walking around. They are automatically exchanged from time to time. I’ll teach you about that later.]]),
    h = 400,
    obj_name = "build_battlearena",
    obj_title = _"Build a battle arena",
-   obj_body = rt(
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a battle arena. It is a big building.]]) ..
-      listitem_arrow(_[[Since the construction will take some time, you can change the game speed using Page Up and Page Down.]])
-   )
+   obj_body =
+      li(_[[Build a battle arena. It is a big building.]]) ..
+      li_arrow(_[[Since the construction will take some time, you can change the game speed using Page Up and Page Down.]])
 }
 
 battlearena2 = {
    position = "topright",
    title = _"The Battle Arena",
-   body = rt(
+   body =
       h1(_"The Battle Arena Has Been Constructed") ..
       p(_[[Very good. Our battle arena has been finished, and the soldiers are already walking towards it.]]) ..
       -- Not perfectly correct (some training steps need either bread or meat), but we do not want to confuse new players
       p(_[[The needed wares are also delivered there. For successful training, you need pitta bread and strong beer, as well as either fish or meat.]] .. " " ..
       _[[For more information, you can have a look at the building’s help window, accessible via the question mark in every building’s window.]]) ..
-      p(_[[To learn how far your soldiers have progressed in their training, you can have a look at their icons. They are modified by red dots:]])
-   ) ..
-   rt("image=tribes/workers/barbarians/soldier/evade_level0.png", p(_[[No red dots means that the soldier is not trained, so he has level 0. All your new recruits have this.]])) ..
-   rt("image=tribes/workers/barbarians/soldier/evade_level1.png", p(_[[With every successful training step, your soldier becomes stronger. This is indicated by a red dot. This soldier is on level 1 in evade training.]])) ..
-   rt("image=tribes/workers/barbarians/soldier/evade_level2.png", p(_[[When your soldier has reached the highest possible level (in this case level 2), this is indicated by a white background color.]])),
+      p(_[[To learn how far your soldiers have progressed in their training, you can have a look at their icons. They are modified by red dots:]]) ..
+      p(img("tribes/workers/barbarians/soldier/evade_level0.png") .._[[No red dots means that the soldier is not trained, so he has level 0. All your new recruits have this.]]) ..
+      p(img("tribes/workers/barbarians/soldier/evade_level1.png") .._[[With every successful training step, your soldier becomes stronger. This is indicated by a red dot. This soldier is on level 1 in evade training.]]) ..
+      p(img("tribes/workers/barbarians/soldier/evade_level2.png") .._[[When your soldier has reached the highest possible level (in this case level 2), this is indicated by a white background color.]]),
    h = 450
 }
 
 trainingcamp1 = {
    position = "topright",
    title = _"The Training Camp",
-   body = rt(
+   body =
       h1(_"The Training Camp") ..
       p(_[[There is a second training site: the training camp. It is a big building too, and to complement the battle arena, it trains attack and health (remember, the Barbarian soldiers cannot be trained in defense).]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a training camp.]])
-   ),
+      li(_[[Build a training camp.]]),
    h = 300,
    obj_name = "build_trainingcamp",
    obj_title = _"Build a training camp",
-   obj_body = rt(
+   obj_body =
       p(_[[The battle arena only trains the soldiers in evade. To get the strongest possible soldier, you also need to build a training camp, which trains them in attack and health.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a training camp.]])
-   )
+      li(_[[Build a training camp.]])
 }
 
 trainingcamp2 = {
    position = "topright",
    title = _"The Training Camp",
-   body = rt(
+   body =
       p(_[[Great, our training camp has now been finished, too. Now nothing will hinder us from getting the strongest warriors the world has ever seen.]]) ..
       p(_[[To train in the training camp, our soldiers need food like in the battle arena, but no strong beer. Instead, they need different axes for attack training and helmets for health training.]]) ..
       p(_[[This equipment is produced in smithies out of coal, iron, and sometimes gold. You will learn more about this in the second scenario of the Barbarian campaign.]]) ..
       p(_[[You should also keep in mind that each of the three tribes in Widelands has its own way of training, so the buildings and wares are different. Also, the ability levels cannot be compared: an Imperial soldier with evade level 0 has a 30% chance of evading, while a Barbarian soldier at the same level only has a 25% chance.]])
-   )
 }
 
 heroes_rookies = {
    position = "topright",
    title = _"Heroes and Rookies",
-   body = rt(
+   body =
       h1(_"Heroes and Rookies") ..
       p(_[[While our soldiers are training, let me tell you what we can do with them.]]) ..
       p(_[[In every military building, you can set the preference for heroes (trained soldiers) or rookies. From time to time, a soldier will walk out of the building and be replaced by a stronger/weaker one automatically – this is what you saw earlier.]]) ..
       p(_[[The initial setting depends on the type of the building. For the Barbarians, the sentry is the only building that prefers rookies by default. You should change this setting to fit your current needs.]]) ..
       p(_[[When you are expanding into no man’s land, you can make your buildings prefer rookies. When you are planning to attack, send heroes into that region. Conquered buildings always prefer heroes.]])
-   )
 }
 
 soldier_capacity = {
    position = "topright",
    title = _"Soldier capacity",
-   body = rt(
+   body =
       h1(_"Adjusting the number of soldiers") ..
       p(_[[There is another way how you can control the strength of a military building: by the number of soldiers stationed there. Just click on the arrow buttons to decrease or increase the desired number of soldiers. Every building has a maximum capacity. In case of the barrier, it is five, for example.]]) ..
       p(_[[If you wish to send a certain soldier away, you can simply click on it. It will then be replaced by another soldier.]]) ..
       p(_[[Let me also describe what the numbers in the statistics string mean. This string can contain up to three numbers, e.g. ‘1 (+5) soldier (+2)’.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[The first number describes how many soldiers are currently in this building. In this example, only one soldier is left inside (each military building is always guarded by at least one soldier).]]) ..
-      listitem_bullet(_[[The second number tells you how many additional soldiers reside in this building, but are currently outside. The five soldiers may be attacking an enemy. They will return when they have been successful.]]) ..
-      listitem_bullet(_[[The third number indicates the missing soldiers. >From the eight soldiers (1 + 5 + 2) you wish to have here, two may have died. They will be replaced by new soldiers from your warehouse, if possible.]])
-   )
+      li(_[[The first number describes how many soldiers are currently in this building. In this example, only one soldier is left inside (each military building is always guarded by at least one soldier).]]) ..
+      li(_[[The second number tells you how many additional soldiers reside in this building, but are currently outside. The five soldiers may be attacking an enemy. They will return when they have been successful.]]) ..
+      li(_[[The third number indicates the missing soldiers. From the eight soldiers (1 + 5 + 2) you wish to have here, two may have died. They will be replaced by new soldiers from your warehouse, if possible.]])
 }
 
 dismantle = {
    position = "topright",
    title = _"Dismantle your sentry",
-   body = rt(
+   body =
       h1(_"Dismantling military buildings") ..
       p(_[[You can only reduce the number of soldiers to one. The last soldier of a building will never come out (unless this building is attacked). If you want to have your soldier elsewhere, you will have to dismantle the building (buildings of an alien tribe cannot be dismantled, only be burned down).]]) ..
       p(_[[However, destroying a military building is always linked with a risk: the land is still yours, but it is no longer protected. Any enemy that builds his own military sites can take over that land without a fight, causing your buildings to burst into flames. Furthermore, some parts of the land can now be hidden under the fog of war. You should therefore only dismantle military buildings deep inside your territory where you are safe from enemies.]]) ..
       p(_[[Have you seen your sentry? Since it cannot contain many soldiers and is next to a stronger barrier, it is rather useless.]]) ..
-      paragraphdivider() ..
       -- TRANSLATORS: 'it' refers to the Barbarian sentry
-      listitem_bullet(_[[Dismantle it.]])
-   ) ..
-   rt(p(_[[You can also use this opportunity to become familiar with the other options: the heroes/rookies preference and the capacity.]])),
+      li(_[[Dismantle it.]]) ..
+      p(_[[You can also use this opportunity to become familiar with the other options: the heroes/rookies preference and the capacity.]]),
    obj_name = "dismantle_sentry",
    obj_title = _"Dismantle your north-western sentry",
-   obj_body = rt(
+   obj_body =
       p(_[[You can control the number of soldiers stationed at a military site with the arrow buttons. If you want to get even your last soldier out, you will have to destroy it. However, it then will no longer protect your territory, which will make it vulnerable to hostile attacks.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Dismantle your sentry in the north-west, next to the barrier.]])
-   )
+      li(_[[Dismantle your sentry in the north-west, next to the barrier.]])
 }
 
 fortress_enhancement = {
    position = "topright",
    title = _"Enhance Your Fortress",
-   body = rt(
+   body =
       h1(_"Enhancing Buildings") ..
       p(_[[Well done. Now you know how to draw back your soldiers from the places where you don’t need them. It is time to tell you how to reinforce your front line.]]) ..
       p(_[[Your fortress is already quite strong and conquers a lot of space. But there is an even bigger building: the citadel.]]) ..
       p(_[[Citadels can’t be built directly. Instead, you’ll have to construct a fortress first and then enhance it to a citadel. To do so, click on the fortress, then choose the ‘Enhance to Citadel’ button.]]) ..
       p(_[[Your soldiers will leave the fortress while the construction is going on. This means that your fortress will lose its military influence, as I described above.]]) ..
-      listitem_bullet(_[[Enhance your fortress to a citadel now.]])
-   ),
+      li(_[[Enhance your fortress to a citadel now.]]),
    obj_name = "enhance_fortress",
    obj_title = _"Enhance your fortress to a citadel",
-   obj_body = rt(
+   obj_body =
       h1(_"Enhance Your Fortress") ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Enhance your fortress to a mighty citadel.]]) ..
-      listitem_arrow(_[[The citadel can house 12 soldiers, and it is the biggest military building the Barbarians can build. It also costs a lot of resources and takes a long time to build. It is most suited to guard strategically important points like constricted points or mountains.]])
-   )
+      li(_[[Enhance your fortress to a mighty citadel.]]) ..
+      li_arrow(_[[The citadel can house 12 soldiers, and it is the biggest military building the Barbarians can build. It also costs a lot of resources and takes a long time to build. It is most suited to guard strategically important points like constricted points or mountains.]])
 }
 
 attack_enemy = {
    position = "topright",
    field = wl.Game().map:get_field(29,4), -- show the lost territory
    title = _"Defeat your Enemy",
-   body = rt(
+   body =
       h1(_"Defeat the Enemy") ..
       p(_[[Great work, the citadel is finished. But what’s that? A hostile tribe has settled next to us while the citadel was under construction! Do you see how they took away a part of our land? And our lumberjack has now lost his place of work. This is what I was talking about. Let’s take our land back and defeat the enemy!]]) ..
       p(_[[To attack a building, click on its doors, choose the number of soldiers that you wish to send and click on the ‘Attack’ button.]] .. " " .. _[[Your soldiers will come from all nearby military buildings. Likewise, the defenders will come from all nearby military buildings of the enemy and intercept your forces.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Attack and conquer all military buildings of the enemy and destroy their headquarters.]])
-   ),
+      li(_[[Attack and conquer all military buildings of the enemy and destroy their headquarters.]]),
    h = 350,
    obj_name = "defeated_the_empire",
    obj_title = _"Defeat the enemy tribe",
-   obj_body = rt(
+   obj_body =
       h1(_"Defeat Your Enemy") ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Defeat the nearby enemy.]]) ..
-      listitem_arrow(_[[To attack a building, click on its doors, choose the number of soldiers that you wish to send and click on the ‘Attack’ button.]])
-   )
+      li(_[[Defeat the nearby enemy.]]) ..
+      li_arrow(_[[To attack a building, click on its doors, choose the number of soldiers that you wish to send and click on the ‘Attack’ button.]])
 }
 
 conclude_tutorial = {
    title = _"Conclusion",
-   body = rt(
+   body =
       h1(_"Conclusion") ..
       p(_[[Thank you for playing this tutorial. I hope you enjoyed it and you learned how to create and train soldiers, how to control where they go and how to defeat an enemy. Did you see how easily you could overwhelm your enemy? Having trained soldiers is a huge advantage.]]) ..
       p(_[[But a war is expensive, and not always the path leading to the goal. When setting up a new game, you can also choose peaceful win conditions. You should definitely try them out, they’re worth it.]]) ..
       p(_[[You are now ready to play the campaigns. They will teach you about the different economies of the tribes. You can also play the remaining tutorials, but they are not crucial for succeeding in the campaigns.]])
-   )
 }

=== modified file 'data/campaigns/tutorial03_seafaring.wmf/scripting/texts.lua'
--- data/campaigns/tutorial03_seafaring.wmf/scripting/texts.lua	2016-01-28 05:24:34 +0000
+++ data/campaigns/tutorial03_seafaring.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -18,11 +18,10 @@
    position = "topright",
    field = sf,
    title = _"Seafaring",
-   body = rt(
+   body =
       h1(_"Seafaring Tutorial") ..
       p(_[[Welcome back. In this tutorial, you are going to learn the most important things about seafaring, that is ships, ports, and expedition.]]) ..
-      p(_[[But let me first give you an overview about your territory: here in the south, you have a whole economy with almost everything you need.]])
-   ),
+      p(_[[But let me first give you an overview about your territory: here in the south, you have a whole economy with almost everything you need.]]),
    h = 250
 }
 
@@ -30,22 +29,20 @@
    position = "topright",
    field = castle_field,
    title = _"The Northern Part",
-   body = rt(
+   body =
       p(_[[Here in the northern part, you only have a goldmine and a warehouse. While the miners are supplied well with food, there is no way to transport the gold ore to our smelting works in the southern part.]]) ..
       p(_[[We have tried to build a road, but the mountain is too wide and too steep. We therefore have only one possibility: we need to establish a sea lane between these two parts.]]) ..
-      p(_[[But I don’t want to rush you: you have just arrived here and you would probably like to have a closer look at your camp. I will also take a short break and be back soon.]])
-   ),
+      p(_[[But I don’t want to rush you: you have just arrived here and you would probably like to have a closer look at your camp. I will also take a short break and be back soon.]]),
    h = 350
 }
 
 tell_about_port = {
    position = "topright",
    title = _"Ports",
-   body = rt(
+   body =
       h1(_"Ports") ..
       p(_[[For everything you do on the high seas, you need a port at the shore. Ports are like headquarters: they can store wares, workers and soldiers. The soldiers inside will automatically come out when an enemy attacks the port.]]) ..
-      p(_[[Additionally, ports offer the possibility of transporting wares via ships. When you click on the port you already have, you will notice two additional tabs: wares and workers in the dock. They are waiting for a ship to transport them to another port. Currently, there are none because we have not yet built a second port. So let’s change this!]])
-   ),
+      p(_[[Additionally, ports offer the possibility of transporting wares via ships. When you click on the port you already have, you will notice two additional tabs: wares and workers in the dock. They are waiting for a ship to transport them to another port. Currently, there are none because we have not yet built a second port. So let’s change this!]]),
    h = 350
 }
 
@@ -53,82 +50,65 @@
    position = "topright",
    field = second_port_field,
    title = _"Building ports",
-   body = rt(
+   body =
       h1(_"How to build a port") ..
-      p(_[[Ports are big buildings, but they can only be built at special locations: those marked with the]])
-   ) ..
-   rt("image=images/wui/overlays/port.png", p(_[[blue port space icon.]])) ..
-   rt(
+      p(_[[Ports are big buildings, but they can only be built at special locations: those marked with the]]) ..
+      p(img("images/wui/overlays/port.png") .. _[[blue port space icon.]]) ..
       p(_[[Port spaces are set by the map designer, so a map will either contain them or not. They might, however, be hidden under trees or be blocked by surrounding buildings.]]) ..
       p(_[[You might already have noticed that you have such an icon next to your castle.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a port in the northern part of your camp.]])
-   ),
+      li(_[[Build a port in the northern part of your camp.]]),
    obj_name = "build_port",
    obj_title = _"Build a port in the northern part of your camp.",
-   obj_body = rt(
+   obj_body =
       h1(_"Build a port") ..
       p(_[[You always need a port when you want to transport wares with a ship.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a port next to your castle, on the blue port space icon.]]) ..
-      listitem_arrow(_[[Ports are built like normal buildings, but are only available on blue port spaces. Just click on a field with the icon and the building menu automatically offers you to build a port.]]) ..
-      listitem_arrow(_[[Although ports act as warehouses, you should not build more than necessary: they cost quartz, diamonds and gold, which makes them quite expensive.]])
-   ),
+      li(_[[Build a port next to your castle, on the blue port space icon.]]) ..
+      li_arrow(_[[Ports are built like normal buildings, but are only available on blue port spaces. Just click on a field with the icon and the building menu automatically offers you to build a port.]]) ..
+      li_arrow(_[[Although ports act as warehouses, you should not build more than necessary: they cost quartz, diamonds and gold, which makes them quite expensive.]]),
 }
 
 tell_about_shipyard = {
    position = "topright",
    title = _"Constructing ships",
-   body = rt(
-      h1(_"Let’s build ships") ..
+   body =      h1(_"Let’s build ships") ..
       p(_[[Great. Your port has just been finished. Now we need some ships.]]) ..
       p(_[[Ships are constructed in a shipyard by a shipwright. We have to build one somewhere close to the shore.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a shipyard close to the coast. It is a medium building.]])
-   ),
+      li(_[[Build a shipyard close to the coast. It is a medium building.]]),
    h = 300,
    obj_name = "build_shipyard",
    obj_title = _"Build a shipyard",
-   obj_body = rt(
-      h1(_"Build a shipyard") ..
+   obj_body =      h1(_"Build a shipyard") ..
       p(_[[Ships are produced in a shipyard.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build a shipyard close to the shore of the southern part of your territory.]]) ..
-      listitem_arrow(_[[The shipyard is a medium building. Although it can be built everywhere on the map, the shipwright only works when he is close to the water and there are no trees or roads at the shoreline.]])
-   ),
+      li(_[[Build a shipyard close to the shore of the southern part of your territory.]]) ..
+      li_arrow(_[[The shipyard is a medium building. Although it can be built everywhere on the map, the shipwright only works when he is close to the water and there are no trees or roads at the shoreline.]]),
 }
 
 tell_about_ships = {
    position = "topright",
    title = _"Constructing ships",
-   body = rt(
+   body =
       h1(_"Waiting for the ships") ..
       p(_[[Very good. Your shipyard is finished and your shipwright immediately started working. For the construction of ships, he needs logs, planks and spidercloth, which will be transported to the shipyard.]] .. " " ..
       _[[The shipwright will take the ware he needs to a free spot at the shoreline and build a ship there. When the first ship is finished, it will launch onto the sea, and the shipwright will construct another one.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[We should wait until we have two ships. That should be enough for now.]]) ..
-      listitem_arrow(_[[You need to stop your shipyard when you have enough ships. Otherwise, your shipwright will consume all your logs and spidercloth, producing dozens of ships.]])
-   ) ..
-   rt("image=images/ui_basic/stop.png",p(_[[This is the icon for stopping production. You will find it in the building window.]])),
+      li(_[[We should wait until we have two ships. That should be enough for now.]]) ..
+      li(_[[You need to stop your shipyard when you have enough ships. Otherwise, your shipwright will consume all your logs and spidercloth, producing dozens of ships.]]) ..
+      p(img("images/ui_basic/stop.png") .. _[[This is the icon for stopping production. You will find it in the building window.]]),
    obj_name = "wait_for_ships",
    obj_title = _"Construct two ships",
-   obj_body = rt(
+   obj_body =
       p(_[[Ships are constructed automatically when the shipyard is complete and the needed wares have been delivered.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Wait until the shipwright has constructed two ships.]]) ..
-      listitem_arrow(_[[Do not forget to stop your shipyard when you have enough ships.]])
-   )
+      li(_[[Wait until the shipwright has constructed two ships.]]) ..
+      li_arrow(_[[Do not forget to stop your shipyard when you have enough ships.]])
 }
 
 expedition1 = {
    position = "topright",
    title = _"No Iron",
-   body = rt(
+   body =
       h1(_"We lack iron") ..
       p(_[[The second ship might not be finished yet, but we have an urgent problem.]]) ..
       p(_[[As you surely have already noticed, there is no iron in the mountain in the west. We have plenty of coal and gold ore, but without iron ore, we cannot produce any tools.]]) ..
-      p(_[[Although it might take long and be expensive and not without dangers – who knows what monsters live in the sea? – I see no other possibility: we will have to undertake an expedition to the unknown seas.]])
-   ),
+      p(_[[Although it might take long and be expensive and not without dangers – who knows what monsters live in the sea? – I see no other possibility: we will have to undertake an expedition to the unknown seas.]]),
    h = 300
 }
 
@@ -136,57 +116,46 @@
    position = "topright",
    -- TRANSLATORS: This shall be the beginning of a poem
    title = _"A trip by the sea, what fun it can be",
-   body = rt(
+   body =
       h1(_"Expeditions") ..
-      p(_[[During an expedition, you send a ship out to discover new islands and maybe found a colony there.]])
-   ) ..
-   rt("image=images/wui/buildings/start_expedition.png",p(_[[Expeditions can be started in every port. Then, all needed wares are transported to that port. The wares are exactly those your tribe needs to build a port (your goal is to build a port far away from home, so this is not surprising), and of course you need a builder, too. When everything is prepared, a ship will come and pick it up.]] .. " " ..
+      p(_[[During an expedition, you send a ship out to discover new islands and maybe found a colony there.]]) ..
+      p(img("images/wui/buildings/start_expedition.png") .. _[[Expeditions can be started in every port. Then, all needed wares are transported to that port. The wares are exactly those your tribe needs to build a port (your goal is to build a port far away from home, so this is not surprising), and of course you need a builder, too. When everything is prepared, a ship will come and pick it up.]] .. " " ..
       _[[You can check out the needed wares in the fifth tab of your port (it will appear when you’ve started an expedition).]]) ..
       p(_[[Now try this out. I will tell you later what the next steps are.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Start an expedition in any of your ports.]])
-   ),
+      li(_[[Start an expedition in any of your ports.]]),
    obj_name = "start_expedition",
    obj_title = _"Start an expedition",
-   obj_body = rt(
-      paragraphdivider() ..
-      listitem_bullet(_[[Start an expedition.]])
-   ) ..
-   rt("image=images/wui/buildings/start_expedition.png",p(_[[To do so, click on the ‘Start Expedition’ button in any port. A new tab where you can see the needed wares will appear.]])
-   )
+   obj_body =
+      li(_[[Start an expedition.]]) ..
+      p(img("images/wui/buildings/start_expedition.png") .. _[[To do so, click on the ‘Start Expedition’ button in any port. A new tab where you can see the needed wares will appear.]])
 }
 
 expedition3 = {
    position = "topright",
    title = _"Off to greener pastures",
-   body = rt(
+   body =
       h1(_"Start your expedition") ..
       p(_[[Your expedition ship is ready. It is waiting for your orders in front of your port. It isn’t transporting wares anymore. Use its buttons to send your ship in any of the six main directions of the Widelands map. When it has reached a coastline, you can make it travel around the coast, where it will look for suitable places for landing.]] .. " " ..
       _[[Once a port space has been found, you can construct a new port with the button in the center of the ship’s control window.]]) ..
       p(_[[The wares will then be unloaded, and the ship will take up the task of transporting wares once again. The builder will start his work and build a port.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Search for an island with a mountain, and look for a port space there. Colonize the island.]])
-   ),
+      li(_[[Search for an island with a mountain, and look for a port space there. Colonize the island.]]),
    obj_name = "found_settlement",
    obj_title = _"Found a settlement",
-   obj_body = rt(
-      paragraphdivider() ..
-      listitem_bullet(_[[Navigate your ship to an island that could contain iron ore.]]) ..
-      listitem_arrow(_[[When you click on the expedition ship, a window opens where you can control your ship.]]) ..
-      listitem_bullet(_[[When you have found a suitable port space, build a port there.]])
-   )
+   obj_body =
+      li(_[[Navigate your ship to an island that could contain iron ore.]]) ..
+      li_arrow(_[[When you click on the expedition ship, a window opens where you can control your ship.]]) ..
+      li(_[[When you have found a suitable port space, build a port there.]])
 }
 
 conclusion = {
    position = "topright",
    field = port_on_island,
    title = _"Conclusion",
-   body = rt(
+   body =
       h1(_"Congratulations") ..
       p(_[[You’ve lead the expedition to a successful end and founded a new colony. I’ve sent out some geologists – they already report that they’ve found some iron ore.]]) ..
       p(_[[In this scenario, you’ve learned everything about seafaring: how to build ports and ships and how to send out an expedition. Remember that expeditions are sometimes the fastest way to reach essential resources – and sometimes the only one.]]) ..
       p(_[[But I want to speak a word of warning. Ports are like headquarters: they can be attacked by a nearby enemy. While your headquarters has soldiers to defend it, your newly built port won’t. You should therefore avoid settling next to an enemy.]]) ..
-      p(_[[On this map, there is no enemy to fear. As always, you can continue playing and watch how the ships deliver wares to the island when you construct some buildings there. There is also another island where you can build a port.]])
-   ),
+      p(_[[On this map, there is no enemy to fear. As always, you can continue playing and watch how the ships deliver wares to the island when you construct some buildings there. There is also another island where you can build a port.]]),
    h = 450
 }

=== modified file 'data/campaigns/tutorial04_economy.wmf/scripting/texts.lua'
--- data/campaigns/tutorial04_economy.wmf/scripting/texts.lua	2016-01-28 05:24:34 +0000
+++ data/campaigns/tutorial04_economy.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -16,12 +16,11 @@
 
 intro1 = {
    title = _"Your Economy and its Settings",
-   body = rt(
+   body =
       h1(_[[Economy]]) ..
       p(_[[Welcome back. In this tutorial, I’ll tell you what you can do to check how well your economy works.]]) ..
       p(_[[Building your economy up and making it work well and grow is the main part of Widelands. But you can’t control the workers directly – they will follow the general conditions you set.]]) ..
-      p(_[[This is what I’ll show you in this tutorial: what actions can you take to define those general conditions?]])
-   ),
+      p(_[[This is what I’ll show you in this tutorial: what actions can you take to define those general conditions?]]),
    h = 300
 }
 
@@ -29,21 +28,19 @@
    position = "topright",
    field = field_near_border,
    title = _"A Peaceful Land",
-   body = rt(
+   body =
       p(_[[Now about the map: you have settled in a nice valley between two mountains, rich in marble, iron ore and coal. All were hoping for a peaceful life.]]) ..
       p(_[[But one day, you discovered a barren wasteland with abandoned buildings in the east. A strange aura came from there, and no one wanted to set foot there. But the border could not be left undefended, and so you constructed three castles.]]) ..
-      p(_[[You had not been prepared for war, and you have to hurry now to build up an army.]])
-   ),
+      p(_[[You had not been prepared for war, and you have to hurry now to build up an army.]]),
    h = 300
 }
 
 tavern_burnt_down = {
    position = "topright",
    title = _"The Tavern is Burning!",
-   body = rt(
+   body =
       h1(_[[An accident]]) ..
-      p(_[[Oh no, look at this: our tavern is burning! In all the hurry, our innkeeper accidentally dropped a torch. She is fine, but we could not extinguish the fire in time.]])
-   ),
+      p(_[[Oh no, look at this: our tavern is burning! In all the hurry, our innkeeper accidentally dropped a torch. She is fine, but we could not extinguish the fire in time.]]),
    w = 300,
    h = 250
 }
@@ -51,61 +48,49 @@
 building_stat = {
    position = "topright",
    title = _"Building statistics",
-   body = rt(
+   body =
       h1(_[[Check out your taverns]]) ..
-      p(_[[At first, we should find out how many taverns we currently have. Widelands offers you a window where you can easily check this.]])
-   ) ..
-   rt("image=images/wui/menus/menu_toggle_menu.png",p(_[[First, you will have to open the statistics menu (you can find the corresponding button at the bottom). We will need this menu several times.]])) ..
-   rt("image=images/wui/menus/menu_building_stats.png",p(_[[Afterwards, choose the ‘Building statistics’.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Open the building statistics window.]]) ..
-      listitem_arrow(_[[You can also use the hotkey ‘b’.]])
-   ),
+      p(_[[At first, we should find out how many taverns we currently have. Widelands offers you a window where you can easily check this.]]) ..
+      p(img("images/wui/menus/menu_toggle_menu.png") .. _[[First, you will have to open the statistics menu (you can find the corresponding button at the bottom). We will need this menu several times.]]) ..
+      p(img("images/wui/menus/menu_building_stats.png") .. _[[Afterwards, choose the ‘Building statistics’.]]) ..
+      li(_[[Open the building statistics window.]]) ..
+      li_arrow(_[[You can also use the hotkey ‘b’.]]),
    h = 350,
    obj_name = "open_building_stat",
    obj_title = _"Open the building statistics window.",
    obj_body =
-      rt("image=images/wui/menus/menu_building_stats.png", p(_[[The building statistics window gives you an overview over the buildings you have.]])) ..
-   rt(
-      paragraphdivider() ..
+      p(img("images/wui/menus/menu_building_stats.png") .. _[[The building statistics window gives you an overview over the buildings you have.]]) ..
       -- TRANSLATORS: "it" refers to the building statistics window
-      listitem_bullet(_[[Open it. You can access it from the statistics menu.]]) ..
-      listitem_arrow(_[[The statistics menu is accessed via the second button at the bottom. It provides several windows that give you information about the game.]])
-   )
+      li(_[[Open it. You can access it from the statistics menu.]]) ..
+      li_arrow(_[[The statistics menu is accessed via the second button at the bottom. It provides several windows that give you information about the game.]])
 }
 
 explain_building_stat = {
    title = _"Building Statistics",
-   body = rt(
+   body =
       p(_[[This is the building statistics window. It shows you all buildings you can own, sorted by their size.]]) ..
       p(_[[Let me now explain what all those numbers mean:]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[‘2/1’ below the quarry: This means that you have two quarries, plus another one which is under construction.]]) ..
-      listitem_bullet(_[[‘0%’: This indicates the average productivity of all buildings of that type. You have just started this game, therefore none of your buildings has done any work yet, but they are going to start working soon.]]) ..
-      listitem_bullet(_[[‘2/4’ below your sentry: For military buildings, the stationed soldiers are shown instead of a productivity. You want to have four soldiers in your sentries, but only two soldiers are stationed in this kind of building. This leaves two vacant positions – we really need more soldiers.]]) ..
-      listitem_arrow(_[[In both cases, the color (green - yellow - red) signals you how good the value is.]]) ..
-      listitem_bullet(_[[If you click on a building, you can scroll through the buildings of the selected type.]]) ..
-      listitem_bullet(_[[If you don’t have any building of a particular building type, it will be shown greyed out.]])
-   ) ..
-   rt(
+      li(_[[‘2/1’ below the quarry: This means that you have two quarries, plus another one which is under construction.]]) ..
+      li(_[[‘0%’: This indicates the average productivity of all buildings of that type. You have just started this game, therefore none of your buildings has done any work yet, but they are going to start working soon.]]) ..
+      li(_[[‘2/4’ below your sentry: For military buildings, the stationed soldiers are shown instead of a productivity. You want to have four soldiers in your sentries, but only two soldiers are stationed in this kind of building. This leaves two vacant positions – we really need more soldiers.]]) ..
+      li_arrow(_[[In both cases, the color (green - yellow - red) signals you how good the value is.]]) ..
+      li(_[[If you click on a building, you can scroll through the buildings of the selected type.]]) ..
+      li(_[[If you don’t have any building of a particular building type, it will be shown greyed out.]]) ..
       h2(_[[Now it’s your turn]]) ..
-      p(_[[This is enough explanation for now. Now try it out yourself. We want to know whether we still have taverns, so you have to choose the ‘Medium Buildings’ tab. Close the building statistics menu afterwards.]])
-   ),
+      p(_[[This is enough explanation for now. Now try it out yourself. We want to know whether we still have taverns, so you have to choose the ‘Medium Buildings’ tab. Close the building statistics menu afterwards.]]),
    obj_name = "check_taverns",
    obj_title = _"Look up your number of taverns in the building statistics window.",
-   obj_body = rt(
-      listitem_bullet(_[[Choose the ‘Medium Buildings’ tab in the building statistics window.]]) ..
-      listitem_bullet(_[[Look up how many taverns you have.]]) ..
-      listitem_arrow(_[[Below every building, there are two lines. The first one shows the number of buildings you own and how many are under construction. The second line shows the average productivity if it is a production site or training site, or the stationed and desired soldiers in military buildings.]]) ..
-      listitem_bullet(_[[Close the building statistics window when you are done.]])
-   )
+   obj_body =
+      li(_[[Choose the ‘Medium Buildings’ tab in the building statistics window.]]) ..
+      li(_[[Look up how many taverns you have.]]) ..
+      li_arrow(_[[Below every building, there are two lines. The first one shows the number of buildings you own and how many are under construction. The second line shows the average productivity if it is a production site or training site, or the stationed and desired soldiers in military buildings.]]) ..
+      li(_[[Close the building statistics window when you are done.]])
 }
 
 reopen_building_stat = {
    title = _"You closed the building statistics window!",
-   body = rt(
-      p(_[[You have closed the building statistics window. I didn’t notice that you switched to the medium buildings to look up the number of taverns. Would you please be so nice and show it to me?]])
-   ),
+   body =
+      p(_[[You have closed the building statistics window. I didn’t notice that you switched to the medium buildings to look up the number of taverns. Would you please be so nice and show it to me?]]),
    show_instantly = true,
    w = 300,
    h = 250
@@ -114,75 +99,62 @@
 reopen_building_stat_obj = {
    obj_name = "open_building_stat_again",
    obj_title = _"Open the building statistics window again.",
-   obj_body = rt(
+   obj_body =
       p(_[[You closed the building statistics window, although you have not yet looked up the number of taverns.]]) ..
-      paragraphdivider() ..
       -- TRANSLATORS: "it" refers to the building statistics window.
-      listitem_bullet(_[[Please reopen it and choose the second tab (medium buildings).]])
-   ),
+      li(_[[Please reopen it and choose the second tab (medium buildings).]]),
    h = 250
 }
 
 inventory1 = {
    position = "topright",
    title = _"Stock",
-   body = rt(
+   body =
       h1(_[[Check for rations]]) ..
-      p(_[[OK. In the list, you’ve seen that you have no more taverns or inns. That means that you’re not producing any rations. But let’s see what we still have in stock.]])
-   ) ..
-   rt("image=images/wui/menus/menu_stock.png",p(_[[Click on the ‘Stock’ button.]])) ..
-   rt(
-      paragraphdivider() ..
-      listitem_arrow(_[[You can also use the hotkey ‘i’ (as in ‘inventory’) to access this window quickly.]])
-   ),
+      p(_[[OK. In the list, you’ve seen that you have no more taverns or inns. That means that you’re not producing any rations. But let’s see what we still have in stock.]]) ..
+      p(img("images/wui/menus/menu_stock.png") .. _[[Click on the ‘Stock’ button.]]) ..
+      li_arrow(_[[You can also use the hotkey ‘i’ (as in ‘inventory’) to access this window quickly.]]),
    h = 300,
    obj_name = "open_inventory",
    obj_title = _"Open your stock window.",
-   obj_body = rt(
+   obj_body =
       p(_[[The stock menu window gives you an overview over the wares you currently have.]]) ..
-      paragraphdivider() ..
       -- TRANSLATORS: "it" refers to the stock menu window
-      listitem_bullet(_[[Open it. You can access it from the statistics menu.]]) ..
-      listitem_arrow(_[[The statistics menu is accessed via the second button at the bottom. It provides several windows that give you information about the game.]])
-   )
+      li(_[[Open it. You can access it from the statistics menu.]]) ..
+      li_arrow(_[[The statistics menu is accessed via the second button at the bottom. It provides several windows that give you information about the game.]])
 }
 
 inventory2 = {
    title = _"Stock",
-   body = rt(
+   body =
       p(_[[The stock menu window has four tabs. The first (and currently selected) one shows you all your current wares, including those on roads, at flags and inside buildings waiting for processing.]]) ..
       p(_[[Looking at the rations, there are currently only five in total, probably on their way to somewhere. Five rations are not much for such a big economy.]]) ..
       p(_[[The second tab shows you all your workers, again those on roads and in buildings summed up.]]) ..
-      p(_[[Now have a look at these two tabs. When you click on the]])) ..
-   rt("image=images/wui/stats/menu_tab_wares_warehouse.png",p(_[[third tab (‘Wares in warehouses’), I’ll continue.]])
-   ),
+      p(_[[Now have a look at these two tabs. When you click on the]]) ..
+      p(img("images/wui/stats/menu_tab_wares_warehouse.png") .. _[[third tab (‘Wares in warehouses’), I’ll continue.]]),
    h = 350,
    show_instantly = true,
    obj_name = "switch_stock_tab",
    obj_title = _"Switch to the third tab in the stock menu window.",
-   obj_body = rt(
+   obj_body =
       p(_[[Have a look at the first two tabs in the stock menu window. They show all the wares and workers you have.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[When you have seen enough, switch to the third tab.]])
-   ),
+      li(_[[When you have seen enough, switch to the third tab.]]),
 }
 
 inventory3 = {
    title = _"Stock",
-   body = rt(
+   body =
       p(_[[The third tab shows you the wares that are stored in your headquarters, your warehouses and ports. They are not needed anywhere and are therefore your reserve.]]) ..
       p(_[[The fourth tab shows the same thing for workers.]]) ..
-      p(_[[The third tab tells you that there are no rations left in your headquarters – that’s not good!]])
-   ),
+      p(_[[The third tab tells you that there are no rations left in your headquarters – that’s not good!]]),
    show_instantly = true,
    h = 300
 }
 
 reopen_stock_menu = {
    title = _"You closed the stock window!",
-   body = rt(
-      p(_[[You have closed the stock menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the third tab?]])
-   ),
+   body =
+      p(_[[You have closed the stock menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the third tab?]]),
    show_instantly = true,
    w = 300,
    h = 250
@@ -191,51 +163,43 @@
 reopen_stock_menu_obj = {
    obj_name = "open_stock_menu_again",
    obj_title = _"Open the stock window again.",
-   obj_body = rt(
+   obj_body =
       p(_[[You closed the stock menu window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
-      paragraphdivider() ..
       -- TRANSLATORS: "it" refers to the stock menu window.
-      listitem_bullet(_[[Otherwise, please reopen it and choose the third tab.]])
-   ),
+      li(_[[Otherwise, please reopen it and choose the third tab.]]),
    h = 250
 }
 
 build_taverns = {
    position = "topright",
    title = _"New taverns",
-   body = rt(
+   body =
       h1(_[[We need new taverns]]) ..
       p(_[[Now that you have an overview, you should act. I think we should build more than one tavern – two or three are better. Remember: as long as we don’t produce rations, our miners won’t dig for ore. And without iron, we cannot forge a single helm.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build at least two taverns.]])
-   ),
+      li(_[[Build at least two taverns.]]),
    h = 300,
    obj_name = "build_taverns",
    obj_title = _"Build new taverns.",
-   obj_body = rt(
+   obj_body =
       p(_[[To make our mines work, we need rations again – the more, the better.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Build at least two taverns.]])
-   )
+      li(_[[Build at least two taverns.]])
 }
 
 ware_encyclopedia = {
    title = _"Ware Encyclopedia",
-   body = rt(
+   body =
       p(_[[I am not sure if you could follow my remarks. Why do we need rations to get soldiers?]]) ..
       p(_[[When you’ve played a lot, you will know such things by heart. But when you’re unsure what this tribe needs for a special ware, you can easily look it up in your tribe’s ware encyclopedia.]]) ..
-      p(_[[This encyclopedia can be accessed via]])
-   ) ..
-   rt("image=images/ui_basic/menu_help.png",p(_[[the help button at the bottom. For all your tribe’s wares, it shows a short help text, a list of buildings that produces the ware and the needed wares.]]) ..
-      p(_[[If you want, you can try it out. A soldier needs a wooden spear and a helmet – from there on out, you can search backwards.]])
-   ),
+      p(_[[This encyclopedia can be accessed via]]) ..
+      p(img("images/ui_basic/menu_help.png") .. _[[the help button at the bottom. For all your tribe’s wares, it shows a short help text, a list of buildings that produces the ware and the needed wares.]]) ..
+      p(_[[If you want, you can try it out. A soldier needs a wooden spear and a helmet – from there on out, you can search backwards.]]),
    h = 350
 }
 
 building_priority_settings = {
    position = "topright",
    title = _"Priority Settings",
-   body = rt(
+   body =
       h1(_[[Send the wares where they’re needed]]) ..
       p(_[[Great. Our taverns have now been built up and are supplying us with rations.]]) ..
       p(_[[At the moment, all mines are supplied with rations. If you want to prioritize a special mine, you simply have to open its window. In the wares tab, behind every ware, you can see ‘traffic lights’.]]) ..
@@ -243,91 +207,73 @@
       p(_[[In our situation, you might want to work the bakeries as fast as possible because they supply our taverns, so you could set water to the highest priority for them. The other buildings (for example the donkey farm) would then get less water, but the bakery could work faster.]])
       -- we cannot check whether the user does this, so no objective
       -- see bug https://bugs.launchpad.net/widelands/+bug/1380288
-   )
 }
 
 ware_stats1 = {
    position = "top",
    title = _"Ware Statistics",
-   body = rt(
-      p(_[[In the statistics menu, there is also a]])) ..
-      rt("image=images/wui/menus/menu_ware_stats.png",p(_[[‘Ware statistics’ button.]])) ..
-      rt(paragraphdivider() ..
+   body =
+      p(_[[In the statistics menu, there is also a]]) ..
+      p(img("images/wui/menus/menu_ware_stats.png") .. _[[‘Ware statistics’ button.]]) ..
       -- TRANSLATORS: "it" refers to the ware statistics button
-      listitem_bullet(_[[Click on it.]])
-   ),
+      li(_[[Click on it.]]),
    w = 200,
    h = 200,
    obj_name = "open_ware_stat",
    obj_title = _"Open the ware statistics window.",
-   obj_body = rt(
-      paragraphdivider() ..
-      listitem_bullet(_[[Open the ‘Ware statistics’ window, accessed via the statistics menu.]])
-   )
+   obj_body =
+      li(_[[Open the ‘Ware statistics’ window, accessed via the statistics menu.]])
 }
 
 ware_stats2 = {
    title = _"Ware Statistics",
-   body = rt(
+   body =
       p(_[[In this menu window, you can select wares to see how their production or consumption has changed over time. Try it out with some wares.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[I’ll continue as soon as you click on the]])) ..
-   rt("image=images/wui/stats/menu_tab_wares_econ_health.png",p(_[[third tab (‘Economy Health’).]])
-   ),
+      li(_[[I’ll continue as soon as you click on the]]) ..
+      p(img("images/wui/stats/menu_tab_wares_econ_health.png") .. _[[third tab (‘Economy Health’).]]),
    h = 250,
    show_instantly = true,
    obj_name = "switch_ware_stat_tab_to_third",
    obj_title = _"Switch to the third tab in the ware statistics menu window.",
-   obj_body = rt(
+   obj_body =
       p(_[[The first two tabs show you the production and consumption of any ware. You can toggle them by simply clicking on them.]]) ..
-      paragraphdivider() ..
       listitem_bullet(_[[When you have seen enough, switch to the third tab.]])
-   )
 }
 
 ware_stats3 = {
    title = _"Ware Statistics",
-   body = rt(
+   body =
       p(_[[In this tab, you can see the difference between production and consumption, called ‘economy health’. You can see at one glance which one of those two is higher for the selected ware, that means whether the amount increases or decreases.]]) ..
       p(_[[Now try this out. You can also compare it with the two previous tabs.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Click on the last tab when I should continue.]])
-   ),
+      li(_[[Click on the last tab when I should continue.]]),
    h = 250,
    show_instantly = true,
    obj_name = "switch_ware_stat_tab_to_forth",
    obj_title = _"Switch to the last tab in the ware statistics menu window.",
-   obj_body = rt(
+   obj_body =
       p(_[[The third tab shows you the economy health of the ware. When the value is positive, this means your stock is growing.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[When you have seen enough, switch to the fourth tab.]])
-   )
+      li(_[[When you have seen enough, switch to the fourth tab.]])
 }
 
 ware_stats4 = {
    title = _"Ware Statistics",
-   body = rt(
+   body =
       p(_[[In the last tab, you can also see your absolute stock. It will increase when the economy health is positive, and decrease otherwise. Compare the two graphs!]]) ..
       p(_[[The last two tabs are good indicators to see whether shortages are about to come. Don’t forget to check them regularly!]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Close this window when you’re done.]])
-   ),
+      li(_[[Close this window when you’re done.]]),
    h = 250,
    show_instantly = true,
    obj_name = "close_ware_stats",
    obj_title = _"Close the ware statistics window.",
-   obj_body = rt(
+   obj_body =
       p(_[[The stock tab shows you how many wares you have. Compare the information from the four tabs to understand the correlation.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[When you have finished, close the ware statistics window.]])
-   ),
+      li(_[[When you have finished, close the ware statistics window.]]),
 }
 
 reopen_ware_stats1 = {
    title = _"You closed the ware statistics window!",
-   body = rt(
-      p(_[[You have closed the ware statistics menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the third tab?]])
-   ),
+   body =
+      p(_[[You have closed the ware statistics menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the third tab?]]),
    show_instantly = true,
    w = 300,
    h = 250
@@ -336,19 +282,16 @@
 reopen_ware_stats1_obj = {
    obj_name = "open_ware_stats_menu_again1",
    obj_title = _"Open the ware statistics window again.",
-   obj_body = rt(
+   obj_body =
       p(_[[You closed the ware statistics menu window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
-      paragraphdivider() ..
       -- TRANSLATORS: "it" refers to the ware statistics window.
-      listitem_bullet(_[[Otherwise, please reopen it and choose the third tab.]])
-   )
+      li(_[[Otherwise, please reopen it and choose the third tab.]])
 }
 
 reopen_ware_stats2 = {
    title = _"You closed the ware statistics window!",
-   body = rt(
-      p(_[[You have closed the ware statistics menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the fourth tab?]])
-   ),
+   body =
+      p(_[[You have closed the ware statistics menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the fourth tab?]]),
    show_instantly = true,
    w = 300,
    h = 250
@@ -357,100 +300,84 @@
 reopen_ware_stats2_obj = {
    obj_name = "open_ware_stats_menu_again2",
    obj_title = _"Open the ware statistics window again.",
-   obj_body = rt(
+   obj_body =
       p(_[[You closed the ware statistics menu window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
-      paragraphdivider() ..
       -- TRANSLATORS: "it" refers to the ware statistics window.
-      listitem_bullet(_[[Otherwise, please reopen it and choose the fourth tab.]])
-   )
+      li(_[[Otherwise, please reopen it and choose the fourth tab.]])
 }
 
 economy_settings1 = {
    position = "topright",
    title = _"Economy options",
-   body = rt(
+   body =
       p(_[[I’ve shown you our stock menu window, where you could see which wares are at the warehouses. You remember?]]) ..
-      p(_[[Now I’ll tell you how you can determine how many wares you want to have. The menu window for this purpose can be accessed via any flag and is called ‘Configure economy’.]])) ..
-   -- Yup, that's indeed the correct icon
-   rt("image=images/wui/stats/genstats_nrwares.png",p(_[[This is the icon.]])) ..
-   rt(
-      paragraphdivider() ..
-      listitem_bullet(_[[Open this window.]])
-   ),
+      p(_[[Now I’ll tell you how you can determine how many wares you want to have. The menu window for this purpose can be accessed via any flag and is called ‘Configure economy’.]]) ..
+      -- Yup, that's indeed the correct icon
+      p(img("images/wui/stats/genstats_nrwares.png") .. _[[This is the icon.]]) ..
+      li(_[[Open this window.]]),
    h = 350,
    obj_name = "open_economy_settings",
    obj_title = _"Open the ‘Configure economy’ window.",
-   obj_body = rt(
-      paragraphdivider() ..
-      listitem_bullet(_[[Open the ‘Configure economy’ window.]]) ..
-      listitem_arrow(_[[The window can be accessed by clicking on any flag you own.]])
-   )
+   obj_body =
+      li(_[[Open the ‘Configure economy’ window.]]) ..
+      li_arrow(_[[The window can be accessed by clicking on any flag you own.]])
 }
 
 economy_settings2 = {
    title = _"Economy options",
-   body = rt(
+   body =
       p(_[[This window looks similar to the stock window, but it has additional buttons at the bottom.]]) ..
       p(_[[You first have to select one or more wares (you can also left-click and drag). Then you can set the desired target quantity for the selected wares.]]) ..
       p(_[[Most buildings will only produce something when the stock level in your warehouses falls below the target quantity, so you should indicate the reserve you want to stockpile.]]) ..
       p(_[[An example: the default value for scythes is 1. If you build a farm, a carrier will take a scythe and become a farmer. Then there will be no scythes left, but the target quantity is 1, therefore your toolsmith will start producing another one.]]) ..
-      p(_[[If you build two farms, only one of them will start working immediately. The second farm will have to wait for its worker, who will lack a scythe. If you had set the target quantity to 2 before, two scythes would have been available and both farms would have been able to start working right away.]])
-   ),
+      p(_[[If you build two farms, only one of them will start working immediately. The second farm will have to wait for its worker, who will lack a scythe. If you had set the target quantity to 2 before, two scythes would have been available and both farms would have been able to start working right away.]]),
    h = 450
 }
 
 economy_settings3 = {
    title = _"Economy options",
-   body = rt(
+   body =
       p(_[[By changing the target quantity, you can therefore decide which wares/tools your resources (in this case: iron) should be turned into or whether you would like to save your iron and wait until you know what you will need it for.]]) ..
       p(_[[Only buildings that consume wares care about this setting. Buildings that produce wares for free (e.g. your farms or wells) will always keep working.]]) ..
       p(_[[Now let’s try it out: the current target quantity for marble columns is 10. Increase it to be prepared in case you will have to build up your fortifications quickly.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Set the target quantity for marble columns to 20 and wait for your stonemason to produce them.]])
-   ),
+      li(_[[Set the target quantity for marble columns to 20 and wait for your stonemason to produce them.]]),
    obj_name = "produce_marble_columns",
    obj_title = "Produce 20 marble columns.",
-   obj_body = rt(
+   obj_body =
       p(_[[Sometimes, you will need many wares at the same time quickly – faster than they can be produced. In this case, it is good to have enough on reserve.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[To be prepared for additional fortifications, you should produce 20 marble columns.]]) ..
-      listitem_arrow(_[[Your stonemason will not produce marble columns when they are not needed. You have to increase the target quantity.]]) ..
-      listitem_arrow(_[[To do so, click on any flag and choose ‘Configure economy’. In this menu window, you can decide how many wares of each type you wish to have in stock.]])
-   )
+      li(_[[To be prepared for additional fortifications, you should produce 20 marble columns.]]) ..
+      li_arrow(_[[Your stonemason will not produce marble columns when they are not needed. You have to increase the target quantity.]]) ..
+      li_arrow(_[[To do so, click on any flag and choose ‘Configure economy’. In this menu window, you can decide how many wares of each type you wish to have in stock.]])
 }
 
 warehouse_preference_settings = {
    field = warehouse_field,
    position = "topright",
    title = _"Warehouse Preferences",
-   body = rt(
+   body =
       h1(_[[Bring the marble columns to the front line]]) ..
       p(_[[The production of marble columns is working fine now, but it would be great if they were stored where we need them.]]) ..
       p(_[[Normally, produced wares are brought to the closest warehouse if they are not needed elsewhere. In this case, this means our headquarters. But we would like to have them in the warehouse near our fortresses.]]) ..
       p(_[[Every warehouse has four buttons to set the preference. If you move your mouse pointer over them, you will see tooltips that explain what the buttons do.]]) ..
-      paragraphdivider() ..
-      listitem_bullet(_[[Bring all the marble columns to the warehouse near the front line.]]) ..
-      listitem_arrow(_[[To achieve this, you will have to do two things. First, set a preference for marble columns in the desired warehouse. All marble columns produced in the future will be brought there if possible.]]) ..
-      listitem_arrow(_[[Then, to move the marble columns out of your headquarters, you will have to click on the remove button there.]])
-   ),
+      li(_[[Bring all the marble columns to the warehouse near the front line.]]) ..
+      li_arrow(_[[To achieve this, you will have to do two things. First, set a preference for marble columns in the desired warehouse. All marble columns produced in the future will be brought there if possible.]]) ..
+      li_arrow(_[[Then, to move the marble columns out of your headquarters, you will have to click on the remove button there.]]),
    obj_name = "bring_marble_columns_to_front",
    obj_title = _"Bring 20 marble columns to the front line.",
-   obj_body = economy_settings3.obj_body .. rt(
+   obj_body = economy_settings3.obj_body ..
       p(_[[To decide where your wares get stored, you can use the preference buttons in the warehouses.]]) ..
-      listitem_bullet(_[[Bring all the marble columns to the warehouse near the front line.]]) ..
-      listitem_arrow(_[[To achieve this, you will have to do two things. First, set a preference for marble columns in the desired warehouse. All marble columns produced in the future will be brought there if possible.]]) ..
-      listitem_arrow(_[[Then, to move the marble columns out of your headquarters, you will have to click on the remove button there.]])
-   )
+      li(_[[Bring all the marble columns to the warehouse near the front line.]]) ..
+      li_arrow(_[[To achieve this, you will have to do two things. First, set a preference for marble columns in the desired warehouse. All marble columns produced in the future will be brought there if possible.]]) ..
+      li_arrow(_[[Then, to move the marble columns out of your headquarters, you will have to click on the remove button there.]])
 }
 
 conclusion = {
    title = _"Borders Secured",
-   body = rt(
+   body =
       h1(_[[We’re safe now]]) ..
       p(_[[Great. We now have enough marble columns so that in case of an aggressor, we can build up our fortifications. But I do not think that that will be necessary. So far, no enemy has shown up.]]) ..
       p(_[[I hope I could teach you how you can control the economy in Widelands. There are many options and they can be confusing at first. Even if you’ve only understood a few concepts, you mustn’t give up. Try them out in some games, become familiar with them and experience the possibilities. Then, return to this tutorial and learn the rest!]]) ..
       p([[]]) ..
-      p(_[[This was the last tutorial I had prepared for you. I’ve now taught you everything I know. There are still secrets hidden in this world even I don’t know about. I will now search for a quiet place to spend my sunset years. If you have still questions, the Widelands community will surely help you. You can find it at:]])
-   ) ..
-   rt("text-align=center", "<p font-size=24 font-decoration=underline>http://www.widelands.org</p>")
+      p(_[[This was the last tutorial I had prepared for you. I’ve now taught you everything I know. There are still secrets hidden in this world even I don’t know about. I will now search for a quiet place to spend my sunset years. If you have still questions, the Widelands community will surely help you. You can find it at:]]) ..
+      p("halign=center", "<font size=24 underline=1>http://www.widelands.org</font>")
 }

=== modified file 'data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/first_island.lua'
--- data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/first_island.lua	2016-01-29 16:36:12 +0000
+++ data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/first_island.lua	2016-04-23 13:15:34 +0000
@@ -21,10 +21,10 @@
    _nplayers_finished_island[island_idx] = rank
 
    local rewards = _finish_rewards[island_idx][rank]
-   send_to_all(rt(
-      p(msgs_finished_island[rank]:bformat(plr.name, island_idx + 1)) ..
-      p(finished_island_continues:format(format_rewards(rewards)))
-   ))
+   send_to_all(
+      msgs_finished_island[rank]:bformat(plr.name, island_idx + 1) ..
+      finished_island_continues:format(format_rewards(rewards))
+   )
 
    local new_hq = hop_to_next_island(plr, island_idx)
    add_wares(new_hq, rewards)

=== modified file 'data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/multiplayer_init.lua'
--- data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/multiplayer_init.lua	2016-01-28 05:24:34 +0000
+++ data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/multiplayer_init.lua	2016-04-23 13:15:34 +0000
@@ -109,7 +109,7 @@
    for name,count in pairs(r) do
       local ware_description = wl.Game():get_ware_description(name)
       -- TRANSLATORS: number + resource name, e.g. '1x Log'
-      rv[#rv + 1] = _"%1$dx %2$s":bformat(count, ware_description.descname) .. "<br>\n"
+      rv[#rv + 1] = li(_"%1$dx %2$s":bformat(count, ware_description.descname))
    end
    return table.concat(rv)
 end

=== modified file 'data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/texts.lua'
--- data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/texts.lua	2016-02-03 09:18:52 +0000
+++ data/maps/MP_Scenarios/Island_Hopping.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -3,7 +3,7 @@
 -- =======================================================================
 welcome_msg = {
    heading = _"Welcome to Island Hopping",
-   body = rt(
+   body =
       h2(_"Rules") ..
       p(_(
    [[Island Hopping is a traditional tournament in Atlantean culture. ]] ..
@@ -37,22 +37,21 @@
    h4(_"2nd to finish") .. p(format_rewards(_finish_rewards[2][2])) ..
    h4(_"3rd to finish") .. p(format_rewards(_finish_rewards[2][3])) ..
    h4(_"4th to finish") .. p(format_rewards(_finish_rewards[2][4]))
-   )
 }
 
 msgs_finished_island = {
-   _"%1$s was the first to reach Island number %2$i.",
-   _"%1$s was the second to reach Island number %2$i.",
-   _"%1$s was the third to reach Island number %2$i.",
-   _"%1$s was the fourth to reach Island number %2$i."
+   p(_"%1$s was the first to reach Island number %2$i."),
+   p(_"%1$s was the second to reach Island number %2$i."),
+   p(_"%1$s was the third to reach Island number %2$i."),
+   p(_"%1$s was the fourth to reach Island number %2$i.")
 }
-finished_island_continues = _ "The reward for this feat amounts to:" .. "<br>%s"
-
-player_claims_hill = rt(p(_
-[[%s is now King of the Hill and will win the game in 20 minutes, if nobody takes over the hill before then.]]
-))
-lost_control = rt(p(_
-[[%s lost control of the hill.]]
-))
-had_control_for = rt(p(_[[%1$s has been King of the Hill for %2$s!]]))
-player_won = rt(p(_[[%s has won the game. Congratulations!]]))
+
+finished_island_continues = p(_"The reward for this feat amounts to:") .. p("%s")
+
+player_claims_hill = p(_[[%s is now King of the Hill and will win the game in 20 minutes, if nobody takes over the hill before then.]])
+
+lost_control = p(_[[%s lost control of the hill.]])
+
+had_control_for = p(_[[%1$s has been King of the Hill for %2$s!]])
+
+player_won = p(_[[%s has won the game. Congratulations!]])

=== modified file 'data/maps/MP_Scenarios/Smugglers.wmf/scripting/texts.lua'
--- data/maps/MP_Scenarios/Smugglers.wmf/scripting/texts.lua	2015-12-03 09:56:01 +0000
+++ data/maps/MP_Scenarios/Smugglers.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -4,17 +4,17 @@
 
 welcome_msg  = {
    heading = _"Smugglers",
-   body = rt(
+   body =
       h2(_"Rules") ..
       p(_([[Smugglers is a fun map for 4 players. You and your partner start diagonally from each other on a point symmetric island. There are plenty of smuggling tunnels on this island, each consisting of a receiving and a sending end.]])) ..
       p(_([[To establish a smuggling route, you need to build a warehouse on a sending/receiving spot while your team mate has to build one on the corresponding receiving/sending spot. A ware is then transported every 10 seconds.]])) ..
    -- TRANSLATORS: %s = '<number> points'
       p(_([[For harder to defend smuggling routes, you get 2 or 3 points per ware smuggled. The first team to collect %s wins.]])) ..
-      rt(h2(_"A sending spot")) .. rt("image=map:send_spot.png", p(" ")) ..
-      rt(h2(_"A receiving spot")) .. rt("image=map:recv_spot.png", p(" ")) ..
-      rt(h2(_"Notes") ..
-         p(_([[Remember that the map has rotational symmetry. For example, when you have found a spot to the top-left of your headquarters, the corresponding spot will be to the bottom-right of the headquarters of your team mate.]])))  ..
-         p(_([[You can see the number of wares traded at any time in the general statistics menu. Good luck!]])))
+      h2(img("map:send_spot.png") .. _"A sending spot") ..
+      h2(img("map:recv_spot.png") .. _"A receiving spot") ..
+      h2(_"Notes") ..
+      p(_([[Remember that the map has rotational symmetry. For example, when you have found a spot to the top-left of your headquarters, the corresponding spot will be to the bottom-right of the headquarters of your team mate.]])) ..
+      p(_([[You can see the number of wares traded at any time in the general statistics menu. Good luck!]]))
 }
 
 smuggling_route_established_other_team = rt(

=== modified file 'data/maps/The_Green_Plateau.wmf/scripting/texts.lua'
--- data/maps/The_Green_Plateau.wmf/scripting/texts.lua	2016-03-21 19:29:24 +0000
+++ data/maps/The_Green_Plateau.wmf/scripting/texts.lua	2016-04-23 13:15:34 +0000
@@ -26,7 +26,7 @@
    title = _"Capture the Ancient Castle",
    number = 1,
    body = objective_text(_"Capture the Ancient Castle",
-      listitem_bullet(_[[Defeat Lanissa and capture the ancient castle.]])
+      li(_[[Defeat Lanissa and capture the ancient castle.]])
    ),
 }
 
@@ -35,7 +35,7 @@
    title = _"Defeat Erwyn",
    number = 1,
    body = objective_text(_"Defeat Erwyn",
-      listitem_bullet(_[[Defeat Erwyn. He commands the strongest opposing military force left on this island.]])
+      li(_[[Defeat Erwyn. He commands the strongest opposing military force left on this island.]])
    ),
 }
 obj_defeat_jomo = {
@@ -43,7 +43,7 @@
    title = _"Defeat Jomo",
    number = 1,
    body = objective_text(_"Defeat Jomo",
-      listitem_bullet(_[[Defeat Jomo. He is taking care of the soldiers’ food supply.]])
+      li(_[[Defeat Jomo. He is taking care of the soldiers’ food supply.]])
    ),
 }
 
@@ -53,11 +53,7 @@
 
 function obj_message(title, text)
    return
-      rt("<p font-size=20 font-weight=bold font-face=serif font-color=3333FF>"
-         .. title ..
-         "</p><p font-size=10> <br></p>"
-         .. p(text)
-         )
+      h1("3333FF", title) .. p(text)
 end
 
 briefing_1_the_forbidden_island = {
@@ -76,7 +72,7 @@
    height = 300,
    posy = 1,
    body = obj_message(_"An Ancient Castle",
-      _([[By the Gods! One of our scouts has discovered a mighty castle at the center of the old plateau. The castle must be quite old and seems to have been built in a foreign style. It’s quite obvious that this is not barbarian craft.]]) .. paragraphdivider() ..
+      _([[By the Gods! One of our scouts has discovered a mighty castle at the center of the old plateau. The castle must be quite old and seems to have been built in a foreign style. It’s quite obvious that this is not barbarian craft.]]) ..
       _([[Let’s hope that Lanissa – the warlord holding sway over that castle – has not discovered our movements yet. Perhaps we have a chance of conquering that mighty building without a bigger fight! However, it is essential that we capture it. It will be the key to our reign over this island!]]))
       .. new_objectives(obj_capture_ancient_castle)
 }
@@ -87,7 +83,7 @@
    height = 300,
    posy = 1,
    body = obj_message(_"Ancient Castle Captured",
-      _([[Wonderful! Our troops have finally defeated Lanissa and her soldiers. The ancient castle is ours!]]) .. paragraphdivider() ..
+      _([[Wonderful! Our troops have finally defeated Lanissa and her soldiers. The ancient castle is ours!]]) ..
       _([[It is amazing how far one can see from the highest tower of the castle. We can watch the whole island. So now I wonder why Lanissa did not see us and thus did not prepare. Be that as it may, some things will never come to the light of day. The only important issue at the moment are the opposing troops still left. We have discovered enemy positions held by Erwyn to the north and east of the castle. He is known to be a strong warlord and surely commands the strongest warriors. In the south, we caught sight of some food infrastructures guarded by Jomo – a younger warlord – and we should take care of those infrastructures so we can cut off our enemies’ food supply.]]))
       .. new_objectives(obj_defeat_erwyn) .. new_objectives(obj_defeat_jomo)
 }
@@ -116,6 +112,6 @@
    height = 300,
    posy = 1,
    body = obj_message(_"Victory!",
-      _([[Finally! The island is completely ours. Now we just have to defend it better than the warlords did.]]) .. paragraphdivider() ..
+      _([[Finally! The island is completely ours. Now we just have to defend it better than the warlords did.]]) ..
       _("Congratulations! You have mastered this scenario. You may play on if you like!"))
 }

=== modified file 'data/scripting/editor/editor_controls.lua'
--- data/scripting/editor/editor_controls.lua	2016-04-06 16:44:00 +0000
+++ data/scripting/editor/editor_controls.lua	2016-04-23 13:15:34 +0000
@@ -6,42 +6,40 @@
 return {
    title = _"Controls",
    text =
-      rt(
-         h2(_"Keyboard Shortcuts") ..
-         p(
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey("F1"), _"Help") ..
-            -- TRANSLATORS: This is an access key combination.
-            dl(help_format_hotkey("H"), _"Toggle main menu") ..
-            -- TRANSLATORS: This is an access key combination. The hotkey is 't'
-            dl(help_format_hotkey("T"), _"Toggle tools menu") ..
-            help_toggle_minimap_hotkey() ..
-            help_toggle_building_spaces_hotkey() ..
-            -- TRANSLATORS: This is an access key combination. The hotkey is 'p'
-            dl(help_format_hotkey("P"), _"Toggle player menu") ..
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey("Ctrl + Z"), _"Undo") ..
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey("Ctrl + Y"), _"Redo") ..
-            -- TRANSLATORS: This is an access key combination. The hotkey is 'i'
-            dl(help_format_hotkey("I"), _"Activate information tool") ..
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey(pgettext("hotkey", "Ctrl + L")), _"Load map") ..
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey(pgettext("hotkey", "Ctrl + S")), _"Save map") ..
-            help_toggle_fullscreen_hotkey()
-         ) ..
+      h2(_"Keyboard Shortcuts") ..
+      p(
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey("F1"), _"Help") ..
+         -- TRANSLATORS: This is an access key combination.
+         dl(help_format_hotkey("H"), _"Toggle main menu") ..
+         -- TRANSLATORS: This is an access key combination. The hotkey is 't'
+         dl(help_format_hotkey("T"), _"Toggle tools menu") ..
+         help_toggle_minimap_hotkey() ..
+         help_toggle_building_spaces_hotkey() ..
+         -- TRANSLATORS: This is an access key combination. The hotkey is 'p'
+         dl(help_format_hotkey("P"), _"Toggle player menu") ..
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey("Ctrl + Z"), _"Undo") ..
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey("Ctrl + Y"), _"Redo") ..
+         -- TRANSLATORS: This is an access key combination. The hotkey is 'i'
+         dl(help_format_hotkey("I"), _"Activate information tool") ..
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey(pgettext("hotkey", "Ctrl + L")), _"Load map") ..
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey(pgettext("hotkey", "Ctrl + S")), _"Save map") ..
+         help_toggle_fullscreen_hotkey()
+      ) ..
 
-         h2(_"Tools") ..
-         p(
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey(pgettext("hotkey", "1-0")), _"Change tool size") ..
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey(pgettext("hotkey", "Click")), _"Place new elements on the map, or increase map elements by the value selected by ‘Increase/Decrease value’") ..
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey(pgettext("hotkey", "Shift + Click")), _"Remove elements from the map, or decrease map elements by the value selected by ‘Increase/Decrease value’") ..
-            -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-            dl(help_format_hotkey(pgettext("hotkey", "Ctrl + Click")), _"Set map elements to the value selected by ‘Set Value’")
-         )
+      h2(_"Tools") ..
+      p(
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey(pgettext("hotkey", "1-0")), _"Change tool size") ..
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey(pgettext("hotkey", "Click")), _"Place new elements on the map, or increase map elements by the value selected by ‘Increase/Decrease value’") ..
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey(pgettext("hotkey", "Shift + Click")), _"Remove elements from the map, or decrease map elements by the value selected by ‘Increase/Decrease value’") ..
+         -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+         dl(help_format_hotkey(pgettext("hotkey", "Ctrl + Click")), _"Set map elements to the value selected by ‘Set Value’")
       )
 }

=== modified file 'data/scripting/editor/editor_introduction.lua'
--- data/scripting/editor/editor_introduction.lua	2016-04-02 08:09:19 +0000
+++ data/scripting/editor/editor_introduction.lua	2016-04-23 13:15:34 +0000
@@ -6,13 +6,11 @@
 return {
    title = _"The Widelands Editor",
    text =
-      rt(
-         h1(_"Introduction") ..
-
-         p(_"This editor is intended for players who would like to design their own maps to use with Widelands.") ..
-         p(_"As you can see, this editor is heavy work in progress and as the editor becomes better and better, this text will also get longer and more complete.") ..
-
-         help_online_help() ..
-         p(_"The wiki also includes a short tutorial on how to build a map.")
-      )
+      h1(_"Introduction") ..
+
+      p(_"This editor is intended for players who would like to design their own maps to use with Widelands.") ..
+      p(_"As you can see, this editor is heavy work in progress and as the editor becomes better and better, this text will also get longer and more complete.") ..
+
+      help_online_help() ..
+      p(_"The wiki also includes a short tutorial on how to build a map.")
 }

=== modified file 'data/scripting/editor/format_editor.lua'
--- data/scripting/editor/format_editor.lua	2016-02-10 14:45:46 +0000
+++ data/scripting/editor/format_editor.lua	2016-04-23 13:15:34 +0000
@@ -7,27 +7,13 @@
 include "scripting/formatting.lua"
 
 -- RST
--- .. function picture_li(imagepath, text)
---
---    Places a paragraph of text to the right of an image
-
---    :arg imagepath: the full path to the image file
---    :arg text: the text to be placed next to the image
---
---    :returns: the text wrapped in a paragraph and placed next to the image
-function picture_li(imagepath, text)
-   return "<rt image=" .. imagepath .. " image-align=left>"
-      .. p(text) .. "</rt>"
-end
-
--- RST
 -- .. function spacer()
 --
 --    Adds a little space between two paragraphs
 --
 --    :returns: a small empty paragraph
 function spacer()
-   return rt(p("font-size=3", ""))
+   return "<vspace gap=12>"
 end
 
 -- RST
@@ -42,13 +28,8 @@
 --
 function text_line(t1, t2, imgstr)
    if imgstr then
-      return "<rt text-align=left image=" .. imgstr ..
-         " image-align=right><p font-size=13 font-color=D1D1D1>" ..
-         t1 .. "</p><p line-spacing=3 font-size=12>" ..
-         t2 .. "<br></p><p font-size=8> <br></p></rt>"
+      return h3(t1 .. img(imgstr)) .. p(t2)
    else
-      return "<rt text-align=left><p font-size=13 font-color=D1D1D1>" ..
-         t1 .. "</p><p line-spacing=3 font-size=12>" ..
-         t2 .. "<br></p><p font-size=8> <br></p></rt>"
+      return h3(t1) .. p(t2)
    end
 end

=== modified file 'data/scripting/editor/terrain_help.lua'
--- data/scripting/editor/terrain_help.lua	2016-04-02 07:33:57 +0000
+++ data/scripting/editor/terrain_help.lua	2016-04-23 13:15:34 +0000
@@ -13,19 +13,19 @@
       local world = wl.World();
       local terrain = wl.Editor():get_terrain_description(terrain_name)
 
-      local result = picture_li(terrain.representative_image, "")
+      local result = p(vspace(6) .. img(terrain.representative_image))
 
       -- Resources
       local valid_resources = terrain.valid_resources
       if (#valid_resources > 0) then
-         result = result .. spacer() .. rt(h2(_"Resources"))
+         result = result .. spacer() .. h2(_"Resources")
          if (#valid_resources > 0) then
             -- TRANSLATORS: A header in the editor help
-            result = result .. rt(h3(ngettext(
-               "Valid Resource:", "Valid Resources:", #valid_resources)))
+            result = result .. h3(ngettext(
+               "Valid Resource:", "Valid Resources:", #valid_resources))
             for count, resource in pairs(valid_resources) do
-               result = result .. picture_li(
-                  resource.representative_image, resource.descname)
+               result = result .. li_image(
+                  resource.representative_image, 70, resource.descname)
             end
          end
 
@@ -59,17 +59,17 @@
 
       local tree_string = ""
       for k,v in ipairs(tree_list) do
-         tree_string = tree_string .. picture_li(v.tree.representative_image,
+         tree_string = tree_string .. li_image(v.tree.representative_image, 70,
             v.tree.species .. ("<br>%2.1f%%"):bformat(100 * v.probability)) .. spacer()
       end
 
       -- TRANSLATORS: A header in the editor help
-      result = result .. spacer() .. rt(h2(_"Probability of trees growing")) .. spacer()
+      result = result .. spacer() .. h2(_"Probability of trees growing") .. spacer()
 
       if (tree_string ~="") then
          result = result .. tree_string
       else
-         result = result .. rt(p(_"No trees will grow here."))
+         result = result .. p(_"No trees will grow here.")
       end
       return {
          title = terrain.descname,

=== modified file 'data/scripting/editor/tree_help.lua'
--- data/scripting/editor/tree_help.lua	2016-04-02 07:33:57 +0000
+++ data/scripting/editor/tree_help.lua	2016-04-23 13:15:34 +0000
@@ -11,10 +11,10 @@
       set_textdomain("widelands_editor")
       local world = wl.World();
       local tree = wl.Editor():get_immovable_description(tree_name)
-      local result = picture_li(tree.representative_image, "")
+      local result = p(vspace(6) .. img(tree.representative_image))
 
       -- TRANSLATORS: A header in the editor help. Terrains preferred by a type of tree.
-      result = result .. rt(p("font-size=3", "")) .. rt(h2(_"Preferred terrains")) .. spacer()
+      result = result .. spacer() .. h2(_"Preferred terrains") .. spacer()
       terrain_list = {}
       for i, terrain in ipairs(world.terrain_descriptions) do
          local probability = tree:probability_to_grow(terrain)
@@ -33,7 +33,7 @@
       end
 
       for k,v in ipairs(terrain_list) do
-         result = result .. picture_li(v.terrain.representative_image,
+         result = result .. li_image(v.terrain.representative_image, 70,
                -- TRANSLATORS: Terrain name (Climate)
                (_"%1% (%2%)"):bformat(v.terrain.descname, v.terrain.editor_category.descname) ..
                "<br>" .. ("%2.1f%%"):bformat(100 * v.probability)

=== modified file 'data/scripting/format_scenario.lua'
--- data/scripting/format_scenario.lua	2016-04-02 10:53:01 +0000
+++ data/scripting/format_scenario.lua	2016-04-23 13:15:34 +0000
@@ -18,14 +18,14 @@
 --           return speech("map:princess.png", "2F9131", title, text)
 --        end
 --
---    :arg img: name of the image to use for this speaker
+--    :arg image: name of the image to use for this speaker
 --    :arg clr: a valid 6 char hex color to use for the name of this speaker
 --    :arg title: Title of this text.
 --    :arg text: The text itself. If this is nil, :const:`title` is used as text
 --       instead and there will not be any title.
 --    :returns: the formatted text.
 --
-function speech(img, clr, g_title, g_text)
+function speech(image, clr, g_title, g_text)
    local title, text = g_title, g_text
    if not text then
       title = nil
@@ -37,25 +37,10 @@
 
    local s = ""
    if title then
-      s = rt("<p font-size=20 font-weight=bold font-face=serif " ..
-         ("font-color=%s>"):format(clr) .. title ..
-         "</p><p font-size=8> <br></p>"
-      )
+      s = h1(clr, title)
    end
-
-   return s .. rt(("image=%s"):format(img), p(text))
-end
-
-
--- RST
--- .. function:: paragraphdivider()
---
---    Closes a paragraph and opens a new paragraph. Use this when you format a string with the speech function
---    and need to divide the speech into multiple paragraphs.
---
---    :returns: <br></p><p font-size=8><br></p><p line-spacing=3 font-size=12>
-function paragraphdivider()
-   return ("<br></p><p font-size=8><br></p><p line-spacing=3 font-size=12>")
+   -- NOCOM(GunChleoc): This only works because all images are the same width...
+   return s .. li_image(image, 63, text)
 end
 
 
@@ -68,7 +53,7 @@
 --       objective text.
 --
 function objective_text(heading, body)
-   return rt(h2(heading) .. p(body))
+   return h2(heading) .. p(body)
 end
 
 
@@ -91,7 +76,5 @@
       s = s .. obj.body
       sum = sum + obj.number
    end
-   return rt("<p font-size=10> <br></p>" ..
-      "<p font=serif font-size=18 font-weight=bold font-color=D1D1D1>"
-      .. ngettext("New Objective", "New Objectives", sum) .. "</p>") .. s
+   return h1(ngettext("New Objective", "New Objectives", sum)) .. s
 end

=== modified file 'data/scripting/formatting.lua'
--- data/scripting/formatting.lua	2016-04-02 10:53:01 +0000
+++ data/scripting/formatting.lua	2016-04-23 13:15:34 +0000
@@ -1,3 +1,4 @@
+-- NOCOM(GunChleoc): Wrap all tags and document allowed attributes when we're done
 -- RST
 -- formatting.lua
 -- --------------
@@ -5,6 +6,7 @@
 -- Function to simplify and unique text formatting in scenarios and help files.
 -- Most of these functions are simple wrapper functions that make working with
 -- widelands rich text formatting system more bearable.
+-- Function names generally follow HTML names.
 
 
 -- RST
@@ -45,195 +47,362 @@
 
 
 -- RST
--- .. function:: rt(text_or_options[, text = nil])
---
---    Wraps a block of text into Lua rich text: <rt>%s</rt>.
---
---    :arg text_or_options: either the text of this rich text
---       or any options you care to give it (e.g. image=pic.png).
---    :type text_or_options: :class:`string`
---    :arg text: if text_or_options is given, this will be the text of the
---       rich text.
+-- .. function:: rt(text_or_attributes[, text = nil])
+--
+--    Wraps a block of text into Lua rich text.
+--    Only call this once for the whole text that gets sent to the backend.
+--    There is no general need to wrap an rt tag around your text,
+--    because the backend will take care of it.
+--    So, only use this function if you wish to add some attributes to the tag.
+--
+--    Allowed attributes are:
+--       padding, padding_r, padding_l, padding_b, padding_t: NOCOM(GunChleoc): Document
+--       background:  a background color or image
+--       debug:       add visual debug information and debug log
+--       editor_mode: allow multiple blank spaces for editing
+--
+--    :arg attributes: the attributes for the rt tag.
+--    :type attributes: :class:`string`
+--    :arg text: the text to be enclosed in rich text tags.
+--    :type text: :class:`string`
 --    :returns: the wrapped rich text.
 --
-function rt(text_or_opts, text)
-   local k = "<rt>"
+function rt(text_or_attributes, text)
    if text then
-      k = ("<rt %s>"):format(text_or_opts)
-   else
-      text = text_or_opts
-   end
-
-   return k .. text .. "</rt>"
-end
-
-
--- RST
--- .. function:: title(s)
---
---    Returns a paragraph formatted as a center-aligned green title heading with a small gap after it.
---
---    :returns: An rt section with s formatted as a title.
-function title(s)
-   return "<rt text-align=center><p font-size=28 font-decoration=bold font-face=serif font-color=2F9131>" .. s .. "</p></rt>"
-end
-
--- RST
--- .. function:: h1(s)
+      return "<rt " .. text_or_attributes .. ">" .. text .. "</rt>"
+   else
+      return "<rt>" .. text_or_attributes .. "</rt>"
+   end
+end
+
+
+-- RST
+-- .. function:: img(src[, attributes = nil])
+--
+--    Turns an image src path into an image tag for richtext.
+--
+--    :arg src: the file path to the image.
+--    :type src: :class:`string`
+--    :arg attributes: the attributes for the div tag.
+--    :type attributes: :class:`string`
+--
+--    Allowed attributes are:
+--       color:     a hex color to be applied to the image's player color mask, if it has any
+--       ref:       NOCOM(GunChleoc): I have no idea what it does.
+--
+--    :returns: the img tag.
+--
+function img(src, attributes)
+   if attributes then
+      return "<img src=" .. src .." " .. attributes .. ">"
+   else
+      return "<img src=" .. src .. ">"
+   end
+end
+
+
+function title(font_face, text)
+   return p_font("align=center", "size=38 face=".. font_face .. " color=2F9131", text)
+end
+
+
+-- RST
+-- .. function:: h1(text_or_color[, text = nil])
 --
 --    Returns a paragraph formatted as a big heading with a small gap after it.
 --    The mnemonic comes from HTML.
 --
---    :returns: A paragraph with s formatted as heading.
-function h1(s)
-   return "<p font-size=18 font-weight=bold font-color=D1D1D1>"
-      ..  s .. "<br></p><p font-size=8> <br></p>"
+--    :returns: A paragraph with text formatted as heading.
+function h1(text_or_color, text)
+   if text then
+      return p_font("", "size=18 bold=1 color=".. text_or_color .. " face=serif", vspace(6) .. text .. vspace(1))
+   else
+      return p_font("", "size=18 bold=1 color=D1D1D1 face=serif", vspace(6) .. text_or_color .. vspace(1))
+   end
 end
 
 -- RST
--- .. function:: h2(s)
+-- .. function:: h2(text)
 --
 --    Like :func:`h1` but smaller.
 --
---    :returns: A paragraph with s formatted as heading.
-function h2(s)
-   return "<p font-size=2> <br></p><p font-size=14 font-weight=bold font-color=D1D1D1>"
-      ..  s .. "<br></p><p font-size=4> <br></p>"
+--    :returns: A paragraph with text formatted as heading.
+function h2(text)
+   return p_font("", "size=14 bold=1 color=D1D1D1 face=serif", vspace(6) .. text .. vspace(1))
 end
 
 -- RST
--- .. function:: h3(s)
+-- .. function:: h3(text)
 --
 --    Like :func:`h2` but smaller.
 --
---    :returns: A paragraph with s formatted as heading.
+--    :returns: A paragraph with text formatted as heading.
 --
-function h3(s)
-   return "<p font-size=13 font-color=D1D1D1>"
-      ..  s .. "<br></p><p font-size=4> <br></p>"
+function h3(text)
+   return p_font("", "size=13 color=D1D1D1 face=serif", vspace(4) .. text .. vspace(1))
 end
 
 -- RST
--- .. function:: h4(s)
+-- .. function:: h4(text)
 --
 --    Like :func:`h3` but smaller.
 --
---    :returns: A paragraph with s formatted as heading.
+--    :returns: A paragraph with text formatted as heading.
 --
-function h4(s)
-   return "<p font-size=12 font-style=italic font-color=D1D1D1>"
-      ..  s .. "<br></p><p font-size=4> <br></p>"
+function h4(text)
+   return p_font("", "size=12 italic=1 color=D1D1D1 face=serif", text)
 end
 
 -- RST
--- .. function:: p(text_or_options[, text = nil])
+-- .. function:: p(text_or_attributes[, text = nil])
 --
 --    Returns one paragraph with text followed by a small vertical gap. Options
---    can be given as first argument similar to :func:`rt`, otherwise the
---    default options will be :const:`line-spacing=3 font-size=12`.
+--    can be given as first argument similar to :func:`rt`.
+--
+--    Allowed attributes are documented in the open_p function.
 --
 --    :returns: The text wrapped in <p>%s</p>
-function p(text_or_opts, text)
-   local opts = "line-spacing=3 font-size=12"
-   if text then
-      opts = text_or_opts
-   else
-      text = text_or_opts
-   end
-
-   return ("<p %s>"):format(opts) .. text .. "<br></p>" ..
-      "<p font-size=8> <br></p>"
-end
-
--- RST
--- .. function:: a(text)
---
---    Underlines the text to show links. Only words with default paragraph text style.
---
---    :returns: Underlined text within a default paragraph
-function a(text)
-   return "</p><p font-size=12 font-decoration=underline>" .. text .. "</p><p font-size=12>"
-end
-
--- RST
--- .. function:: b(text)
---
---    Makes the text bold. Only words with default paragraph text style.
---
---    :returns: Bold text within a default paragraph
+function p(text_or_attributes, text)
+   if text then
+      return open_p(text_or_attributes) .. text .. close_p()
+   else
+      return open_p() .. text_or_attributes .. close_p()
+   end
+end
+
+
+-- RST
+-- .. function:: p(text_or_attributes[, text = nil])
+--
+--    Returns one paragraph with text followed by a small vertical gap. Options
+--    can be given as first argument similar to :func:`rt`.
+--
+--    Allowed p attributes are documented in the open_p function.
+--
+--    Allowed font attributes are are documented in the font function.
+--
+--    :returns: The text wrapped in <p attributes><font attributes>text</font></p>
+function p_font(p_or_font_or_attributes, text_or_font_attributes, text)
+   if text then
+      return ("<p %s>"):format(p_or_font_or_attributes) .. "<font " .. text_or_font_attributes .. ">" .. text .. close_p()
+   else
+      return "<p><font " .. p_or_font_or_attributes .. ">" .. text_or_font_attributes .. close_p()
+   end
+end
+
+
+-- RST
+-- .. function:: open_p([attributes = nil])
+--
+--    Returns a paragraph open tag and default font size. Options
+--    can be given as first argument similar to :func:`rt`.
+--
+--    Allowed attributes are:
+--       indent:  indents the first line of the paragraph
+--       align:   horizontal alignment (left, center, right)
+--       valign:  vertical alignment (top, middle, bottom)
+--       spacing: line spacing in pixels
+--
+--    :returns: <p> with added attributes and default font
+function open_p(attributes)
+   if attributes then
+      return ("<p %s>"):format(attributes) .. "<font size=12>"
+   else
+      return "<p><font size=12>"
+   end
+end
+
+
+-- RST
+-- .. function:: close_p(t)
+--
+--    Closes a paragraph.
+--
+--    :returns: The closing tags for a paragraph
+function close_p(t)
+   return vspace(6) .. "</font></p>"
+end
+
+-- RST
+-- .. function:: font(attributes, text)
+--
+--    Wraps the text in font tags.
+--
+--    Allowed attributes are:
+--       size:      the font size in pt
+--       face:      sans, serif or condensed
+--       color:     a hex color
+--       bold:      if you add bold=1, the text will be bold
+--       italic:    if you add italic=1, the text will be italic
+--       underline: if you add underline=1, the text will be underlined
+--       shadow:    if you add shadow=1, the text will have a shadow
+--       ref:       NOCOM(GunChleoc): I don't know what this does.
+--
+--    :returns: The text wrapped in font tags with the given attributes
+--
+function font(attributes, text)
+   return ("<font %s>"):format(attributes) .. text .. "</font>"
+end
+
+-- RST
+-- .. function:: space(gap)
+--
+--    Adds a horizontal space
+--    :arg gap: the size of the space as pixels.
+--
+--    :returns: a space tag
+--
+function space(gap)
+   return "<space gap="..gap..">"
+end
+
+-- RST
+-- .. function:: vspace(gap)
+--
+--    Adds a vertical space
+--    :arg gap: the size of the space as pixels.
+--
+--    :returns: a vspace tag
+--
+function vspace(gap)
+   return "<vspace gap="..gap..">"
+end
+
+-- RST
+-- .. function:: dl(dt, dd)
+--
+-- This function imitates a HTML description list
+--    :arg dt: "description term", will be rendered in bold.
+--    :arg dd: "description data", will be rendered normally.
+--
+--    :returns: a p tag containing the formatted text
+--
+function dl(dt, dd)
+   return p(b(dt) .. " " .. dd)
+end
+
+-- RST
+-- .. function:: li(text_or_symbol[, text = nil])
+--
+--    Adds the symbol in front of the text to create a list item and
+--    wraps it in a paragraph
+--
+--    :arg symbol: the item symbol for the list, e.g. "•" or "→"
+--    :arg text: the text of the list item
+--
+--    :returns: a p tag containint the formatted text
+function li(text_or_symbol, text)
+   if text then
+      return p(text_or_symbol .. " " .. text)
+   else
+      return p("• " .. text_or_symbol)
+   end
+end
+
+-- RST
+-- .. function:: li_arrow(text)
+--
+--    Creates a list item with an arrow
+--
+--    :arg text: the text of the list item
+--
+--    :returns: li("→", text)
+function li_arrow(text)
+   -- TODO(GunChleoc): Reverse arrow for rtl languages.
+   return li("→", text)
+end
+
+-- RST
+-- .. function li_image(imagepath, text)
+--
+--    Places a paragraph of text to the right of an image
+
+--    :arg imagepath: the full path to the image file
+--    :arg text_width_percent: the percentatge of space that the text will occupy
+--    :arg text: the text to be placed next to the image
+--
+--    :returns: the text wrapped in a paragraph and placed next to the image, The outer tag is a div.
+function li_image(imagepath, text_width_percent, text)
+   return p("<br>") .. div("width=100%", "") ..
+         div(p(img(imagepath))) ..
+         div(p(space(6))) ..
+         div("width="..text_width_percent.."%", p(text)) ..
+         div("width=100%", "")
+end
+
+-- RST
+-- .. function:: a(link)
+--
+-- This function imitates a HTML link. We can't do real links yet, so the text just gets underlines.
+--    :arg link: the text to format
+--
+--    :returns: a font tag containing the underlined text
+--
+function a(link)
+   return font("underline=1", link)
+end
+
+-- RST
+-- .. function:: b(link)
+--
+-- This makes the text bold.
+--    :arg link: the text to format
+--
+--    :returns: a font tag containing the bold text
+--
 function b(text)
-   return "</p><p font-size=12 font-weight=bold>" .. text .. "</p><p font-size=12>"
+   return font("bold=1", text)
 end
 
 -- RST
--- .. function:: i(text)
---
---    Makes the text italic. Only words with default paragraph text style.
---
---    :returns: Italic text within a default paragraph
+-- .. function:: i(link)
+--
+-- This makes the text italic.
+--    :arg link: the text to format
+--
+--    :returns: a font tag containing the italic text
+--
 function i(text)
-   return "</p><p font-size=12 font-style=italic>" .. text .. "</p><p font-size=12>"
-end
-
--- RST
--- .. function:: listdivider()
---
---    Closes a paragraph and opens a new paragraph.
---    Use this before starting a list when it doesn't create a paragraph.
---    If you want more space, before the list, use paragraphdivider().
---
---    :returns: <br></p><p font-size=4><br></p><p line-spacing=3 font-size=12>
-function listdivider()
-   return ("<br></p><p font-size=4><br></p><p line-spacing=3 font-size=12>")
-end
-
-
--- RST
--- .. function:: listitem(symbol, text)
---
---    Adds the symbol in front of the text to create a list item and adds a paragraphdivider
---
---    :arg symbol: the item symbol for the list, e.g. "•" or "→"
---    :arg text: the text of the list item
---
---    :returns: symbol .. " " .. text .. paragraphdivider()
-function listitem(symbol, text)
-   return symbol .. " " .. text .. listdivider()
-end
-
--- RST
--- .. function:: listitem_bullet(text)
---
---    Creates a list item with an arrow
---
---    :arg text: the text of the list item
---
---    :returns: listitem("→", text)
-function listitem_arrow(text)
-   return listitem("→", text)
-end
-
--- RST
--- .. function:: listitem_bullet(text)
---
---    Creates a list item with a bullet point
---
---    :arg text: the text of the list item
---
---    :returns: listitem("•", text)
-function listitem_bullet(text)
-   return listitem("•", text)
-end
-
--- RST
--- .. function:: dl(dt, dd)
---
---    Creates a description list item
---
---    :arg dt: description term, will be shown in bold
---    :arg dd: description data - the text of the list item
---
---    :returns: b(dt) .. " " .. dd .. "<br>"
-function dl(dt, dd)
-   return b(dt) .. " " .. dd .. "<br>"
+   return font("italic=1", text)
+end
+
+-- RST
+-- .. function:: u(link)
+--
+-- This underlines the text.
+--    :arg link: the text to format
+--
+--    :returns: a font tag containing the underlined text
+--
+function u(text)
+   return font("underline=1", text)
+end
+
+-- RST
+-- .. function:: div(text_or_attributes[, text = nil])
+--
+--    Wraps a block of text into a div tag.
+--
+--    :arg attributes: the attributes for the div tag.
+--    :type attributes: :class:`string`
+--
+--    Allowed attributes are:
+--       padding, padding_r, padding_l, padding_b, padding_t: NOCOM(GunChleoc): Document
+--       margin:     NOCOM(GunChleoc): Document
+--       float:      NOCOM(GunChleoc): this does not work yet
+--       margin:     inner margin for the div
+--       valign:     vertical alignment
+--       background: a background color or image
+--       width:      the width of the div in pixels or percent
+--
+--    :arg text: the text to be enclosed in div tags.
+--    :type text: :class:`string`
+--    :returns: the text wrapped in a div tag.
+--
+function div(text_or_attributes, text)
+   if text then
+      return ("<div %s>"):format(text_or_attributes) .. text .. "</div>"
+   else
+      return ("<div>") .. text_or_attributes .. "</div>"
+   end
 end

=== modified file 'data/scripting/messages.lua'
--- data/scripting/messages.lua	2016-01-28 05:24:34 +0000
+++ data/scripting/messages.lua	2016-04-23 13:15:34 +0000
@@ -5,6 +5,7 @@
 -- Functions to send messages to the player and to add objectives to campaigns.
 
 include "scripting/coroutine.lua"
+include "scripting/formatting.lua"
 include "scripting/table.lua"
 include "scripting/ui.lua"
 
@@ -51,7 +52,7 @@
    -- While the message box is shown, the user cannot do anything else anyway.
    local user_input = wl.ui.get_user_input_allowed()
    wl.ui.set_user_input_allowed(true)
-   player:message_box(title, body, parameters)
+   player:message_box(title, rt(body), parameters)
    wl.ui.set_user_input_allowed(user_input)
 end
 
@@ -80,9 +81,9 @@
 --
 function add_campaign_objective(objective)
    if objective.obj_name then
-      return wl.Game().players[1]:add_objective(objective.obj_name, objective.obj_title, objective.obj_body)
+      return wl.Game().players[1]:add_objective(objective.obj_name, objective.obj_title, rt(objective.obj_body))
    else
-      return wl.Game().players[1]:add_objective(objective.name, objective.title, objective.body)
+      return wl.Game().players[1]:add_objective(objective.name, objective.title, rt(objective.body))
    end
 end
 
@@ -148,7 +149,7 @@
       message.obj_number = message.obj_number or message.number or 1
       -- because new_objectives needs a body
       local obj = {body = objective_text(message.obj_title, message.obj_body), number = message.obj_number}
-      message.body = message.body .. new_objectives(obj)
+      message.body = rt(message.body .. new_objectives(obj))
    end
 
    if message.show_instantly then

=== modified file 'data/scripting/win_conditions/collectors.lua'
--- data/scripting/win_conditions/collectors.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/collectors.lua	2016-04-23 13:15:34 +0000
@@ -3,6 +3,7 @@
 -- =======================================================================
 
 include "scripting/coroutine.lua" -- for sleep
+include "scripting/formatting.lua"
 include "scripting/messages.lua"
 include "scripting/formatting.lua"
 include "scripting/format_scenario.lua"
@@ -31,13 +32,6 @@
    -- set the objective with the game type for all players
    broadcast_objective("win_condition", wc_descname, wc_desc)
 
-   -- Simple flowing text. One Paragraph
-   local function p(s)
-      return "<p line-spacing=3 font-size=12>" .. s .. "<br></p>" ..
-         "<p font-size=8> <br></p>"
-   end
-
-
    -- The list of wares that give points
    local point_table = {
       barbarians = {
@@ -101,7 +95,7 @@
       )
 
       local points = 0
-      local descr = { "</p>" .. h2((_"Status for %s"):format(plr.name)) .. "<p line-spacing=3 font-size=12>"}
+      local descr = {h2((_"Status for %s"):format(plr.name))}
       for idx, ware in ipairs(point_table[plr.tribe_name .. "_order"]) do
          local value = point_table[plr.tribe_name][ware]
          local count = 0
@@ -113,13 +107,12 @@
 
          local warename = wl.Game():get_ware_description(ware).descname
          -- TRANSLATORS: For example: 'gold (3 P) x 4 = 12 P', P meaning 'Points'
-         descr[#descr+1] = listitem_bullet(_"%1$s (%2$i P) x %3$i = %4$i P"):bformat(
+         descr[#descr+1] = li(_"%1$s (%2$i P) x %3$i = %4$i P"):bformat(
             warename, value, count, lpoints
          )
       end
-      descr[#descr+1] =  "</p>" .. h3(ngettext("Total: %i point", "Total: %i points", points)):format(points)
-              .. "<p line-spacing=3 font-size=12>"
-      return points, p(table.concat(descr, "\n"))
+      descr[#descr+1] =  h3(ngettext("Total: %i point", "Total: %i points", points)):format(points)
+      return points, table.concat(descr, "")
    end
 
    local plrs = wl.Game().players
@@ -144,7 +137,6 @@
       end
       -- TRANSLATORS: Context: 'The game will end in 2 hours and 30 minutes.'
       local msg = p(_"The game will end in %s."):format(time)
-      msg = msg .. "\n\n"
 
       for idx, plr in ipairs(plrs) do
          local points, pstat = _calc_points(plr)
@@ -153,7 +145,7 @@
       end
 
       for idx, plr in ipairs(plrs) do
-         send_message(plr, game_status.title,  "<rt>" .. msg .. "</rt>", {popup = true})
+         send_message(plr, game_status.title,  msg, {popup = true})
       end
    end
 

=== modified file 'data/scripting/win_conditions/defeat_all.lua'
--- data/scripting/win_conditions/defeat_all.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/defeat_all.lua	2016-04-23 13:15:34 +0000
@@ -3,6 +3,7 @@
 -- =======================================================================
 
 include "scripting/coroutine.lua" -- for sleep
+include "scripting/formatting.lua"
 include "scripting/win_conditions/win_condition_functions.lua"
 
 set_textdomain("win_conditions")

=== modified file 'data/scripting/win_conditions/endless_game.lua'
--- data/scripting/win_conditions/endless_game.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/endless_game.lua	2016-04-23 13:15:34 +0000
@@ -3,6 +3,7 @@
 -- =======================================================================
 
 include "scripting/coroutine.lua" -- for sleep
+include "scripting/formatting.lua"
 include "scripting/win_conditions/win_condition_functions.lua"
 
 set_textdomain("win_conditions")

=== modified file 'data/scripting/win_conditions/endless_game_fogless.lua'
--- data/scripting/win_conditions/endless_game_fogless.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/endless_game_fogless.lua	2016-04-23 13:15:34 +0000
@@ -3,6 +3,7 @@
 -- =======================================================================
 
 include "scripting/coroutine.lua" -- for sleep
+include "scripting/formatting.lua"
 include "scripting/win_conditions/win_condition_functions.lua"
 
 set_textdomain("win_conditions")

=== modified file 'data/scripting/win_conditions/territorial_lord.lua'
--- data/scripting/win_conditions/territorial_lord.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/territorial_lord.lua	2016-04-23 13:15:34 +0000
@@ -3,6 +3,7 @@
 -- =======================================================================
 
 include "scripting/coroutine.lua" -- for sleep
+include "scripting/formatting.lua"
 include "scripting/messages.lua"
 include "scripting/table.lua"
 include "scripting/win_conditions/win_condition_functions.lua"

=== modified file 'data/scripting/win_conditions/territorial_time.lua'
--- data/scripting/win_conditions/territorial_time.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/territorial_time.lua	2016-04-23 13:15:34 +0000
@@ -3,6 +3,7 @@
 -- =======================================================================
 
 include "scripting/coroutine.lua" -- for sleep
+include "scripting/formatting.lua"
 include "scripting/messages.lua"
 include "scripting/table.lua"
 include "scripting/win_conditions/win_condition_functions.lua"

=== modified file 'data/scripting/win_conditions/win_condition_functions.lua'
--- data/scripting/win_conditions/win_condition_functions.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/win_condition_functions.lua	2016-04-23 13:15:34 +0000
@@ -1,3 +1,4 @@
+include "scripting/formatting.lua"
 include "scripting/messages.lua"
 
 -- RST

=== modified file 'data/scripting/win_conditions/win_condition_texts.lua'
--- data/scripting/win_conditions/win_condition_texts.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/win_condition_texts.lua	2016-04-23 13:15:34 +0000
@@ -2,25 +2,25 @@
 
 won_game = {
   title = _"Congratulations!",
-  body = rt(p(_"You have won this game!"))
+  body = p(_"You have won this game!")
 }
 
 lost_game = {
   title = _"You are defeated!",
-  body = rt(p(_"You lost your last warehouse and are therefore defeated. You may continue as spectator if you want."))
+  body = p(_"You lost your last warehouse and are therefore defeated. You may continue as spectator if you want.")
 }
 
 won_game_over = {
   title = _"You won",
-  body = rt(p(_"You are the winner!"))
+  body = p(_"You are the winner!")
 }
 
 lost_game_over = {
   title = _"You lost",
-  body = rt(p(_"You’ve lost this game!"))
+  body = p(_"You’ve lost this game!")
 }
 
 game_status = {
   title = _"Status",
-  body = rt(p(_"Player overview:"))
+  body = h2(_"Player overview:")
 }

=== modified file 'data/scripting/win_conditions/wood_gnome.lua'
--- data/scripting/win_conditions/wood_gnome.lua	2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/wood_gnome.lua	2016-04-23 13:15:34 +0000
@@ -1,8 +1,8 @@
 -- =======================================================================
 --                       Wood Gnome win condition
 -- =======================================================================
-
 include "scripting/coroutine.lua" -- for sleep
+include "scripting/formatting.lua"
 include "scripting/table.lua"
 include "scripting/win_conditions/win_condition_functions.lua"
 
@@ -91,7 +91,7 @@
          msg = msg .. "\n"
          local trees = (ngettext ("%i tree", "%i trees", playerpoints[plr.number]))
                :format(playerpoints[plr.number])
-         msg = msg ..  (_"%1$s has %2$s at the moment."):bformat(plr.name,trees)
+         msg = msg ..  li((_"%1$s has %2$s at the moment."):bformat(plr.name,trees))
       end
 
       broadcast(plrs, game_status.title, msg)

=== modified file 'data/tribes/scripting/help/building_help.lua'
--- data/tribes/scripting/help/building_help.lua	2016-03-22 07:32:14 +0000
+++ data/tribes/scripting/help/building_help.lua	2016-04-23 13:15:34 +0000
@@ -1,4 +1,5 @@
 -- TODO(GunChleoc): get resi_00.png from C++
+-- NOCOM(GunChleoc):: Convert when we have image alignment. Test all help scripts.
 
 include "tribes/scripting/help/format_help.lua"
 
@@ -13,21 +14,18 @@
 --  =======================================================
 
 -- RST
--- .. function text_line(t1, t2[, imgstr = nil])
---
---    Creates a line of h3 formatted text followed by normal text and an image.
---
---    :arg t1: text in h3 format.
+-- .. function text_line(t1, t2)
+--
+--    Creates a line of header colored formatted text followed by normal text and an image.
+--
+--    :arg t1: text in colored p format.
 --    :arg t2: text in p format.
---    :arg imgstr: image aligned right.
---    :returns: header followed by normal text and image.
+--    :returns: header followed by normal text.
 --
-function text_line(t1, t2, imgstr)
-   if imgstr then
-      return "<rt text-align=left image=" .. imgstr .. " image-align=right><p font-size=13 font-color=D1D1D1>" ..  t1 .. "</p><p line-spacing=3 font-size=12>" .. t2 .. "<br></p><p font-size=8> <br></p></rt>"
-   else
-      return "<rt text-align=left><p font-size=13 font-color=D1D1D1>" ..  t1 .. "</p><p line-spacing=3 font-size=12>" .. t2 .. "<br></p><p font-size=8> <br></p></rt>"
-   end
+function text_line(t1, t2)
+   -- NOCOM(GunChleoc): Whitespace gets consumed, so we have to add space(2)
+   return p(vspace(4) .. font("size=13 color=D1D1D1 face=serif", t1 .. space(2))  ..
+            font("size=13", t2))
 end
 
 
@@ -41,6 +39,7 @@
 --    Creates a dependencies line of any length.
 --
 --    :arg images: images in the correct order from left to right as table (set in {}).
+--                 Images need to be wrapped in img tag already.
 --    :arg text: comment of the image.
 --    :returns: a row of pictures connected by arrows.
 --
@@ -49,17 +48,15 @@
       text = ""
    end
 
-   local string = "image=" .. images[1]
+   local string = images[1]
    for k,v in ipairs({table.unpack(images,2)}) do
-      string = string .. ";images/richtext/arrow-right.png;" .. v
+      string = string .. img("images/richtext/arrow-right.png") .. v
    end
-
-   return rt(string, text)
+   return p(string .. "  " .. text)
 end
 
-
 -- RST
--- .. function:: dependencies_resi(resource, items[, text = nil])
+-- .. function:: dependencies_resi(tribename, resource, items[, text = nil])
 --
 --    Creates a dependencies line of any length for resources (that don't have menu.png files).
 --
@@ -72,11 +69,11 @@
    if not text then
       text = ""
    end
-   local string = "image=tribes/immovables/" .. resource  .. "/idle_00.png"
+   local string = img("tribes/immovables/" .. resource  .. "/idle_00.png")
    for k,v in ipairs({table.unpack(items)}) do
-      string = string .. ";images/richtext/arrow-right.png;" ..  v.icon_name
+      string = string .. img("images/richtext/arrow-right.png") ..  img(v.icon_name)
    end
-   return rt(string, p(text))
+   return p(string .. "  " .. text)
 end
 
 
@@ -107,14 +104,14 @@
       if (countlist > 1) then
          text = _"%s and":bformat(text)
       end
-      local images = food_images[1]
+      local images = {food_images[1]}
       for k,v in ipairs({table.unpack(food_images,2)}) do
-         images = images .. ";" .. v
+         table.insert(images, v)
       end
       result = image_line(images, 1, p(text)) .. result
    end
    if (result ~= "") then
-      result = rt(h3(_"Food:")) .. result
+      result = h3(_"Food:") .. result
    end
    return result
 end
@@ -128,41 +125,37 @@
 --    :arg weapons: an array of weapon names
 --    :returns: a list weapons images with the producing and receiving building
 --
+-- NOCOM(GunChleoc): get rid of the line break
 function dependencies_training_weapons(weapons)
-   local result = "";
-   local producers = {};
+   local result = ""
+   local producers = {}
    for count, weaponname in pairs(weapons) do
       local weapon_description = wl.Game():get_ware_description(weaponname)
       for i, producer in ipairs(weapon_description.producers) do
          if (producers[producer.name] == nil) then
             producers[producer.name] = {}
          end
-         producers[producer.name][weaponname] = true;
+         producers[producer.name][weaponname] = true
       end
    end
 
-   local building_count = 0;
    for producer, weaponnames in pairs(producers) do
       local producer_description = wl.Game():get_building_description(producer)
       local weaponsstring = ""
       for weaponname, hasweapon in pairs(weaponnames) do
          if (hasweapon) then
-            if(weaponsstring ~= "") then
-               weaponsstring = weaponsstring .. ";"
-            end
             local weapon_description = wl.Game():get_ware_description(weaponname)
-            weaponsstring = weaponsstring .. weapon_description.icon_name
+            weaponsstring = weaponsstring .. img(weapon_description.icon_name)
          end
       end
-      building_count = building_count + 1;
       result = result ..
          dependencies_basic(
-            {producer_description.icon_name, weaponsstring},
-            rt(p(producer_description.descname))
+            {img(producer_description.icon_name), weaponsstring},
+            p(producer_description.descname)
       )
    end
    if (result ~= "") then
-      result = rt(h3(_"Equipment:")) .. result
+      result = h3(_"Equipment:") .. result
    end
    return result
 end
@@ -185,16 +178,14 @@
 --
 function building_help_general_string(tribe, building_description)
    -- TRANSLATORS: Heading for a flavour text in the building help.
-   local result = rt(h2(_"Lore")) ..
-      rt("image=" .. building_description.representative_image, p(building_helptext_lore()))
+   local result = h2(_"Lore") ..
+      li_image(building_description.representative_image, 60, p(building_helptext_lore()))
    if (building_helptext_lore_author() ~= "") then
-      result = result .. rt("text-align=right",
-                            p("font-size=10 font-style=italic",
-                              building_helptext_lore_author()))
+      result = result .. p_font("align=right", "size=10 italic=1", building_helptext_lore_author())
    end
 
-   result = result .. rt(h2(_"General"))
-   result = result .. rt(h3(_"Purpose:"))
+   result = result .. h2(_"General")
+   result = result .. h3(_"Purpose:")
 
 -- TODO(GunChleoc) "carrier" for headquarters, "ship" for ports, "scout" for scouts_hut, "shipwright" for shipyard?
 -- TODO(GunChleoc) use aihints for gamekeeper, forester?
@@ -215,14 +206,14 @@
       representative_resource = wl.Game():get_ware_description("log")
    end
 
-   if(representative_resource) then
-      result = result .. image_line(representative_resource.icon_name, 1, p(building_helptext_purpose()))
+   if (representative_resource) then
+      result = result .. image_line({representative_resource.icon_name}, 0, p(building_helptext_purpose()))
    else
-      result = result .. rt(p(building_helptext_purpose()))
+      result = result .. p(building_helptext_purpose())
    end
 
    if (building_helptext_note() ~= "") then
-      result = result .. rt(h3(_"Note:")) .. rt(p(building_helptext_note()))
+      result = result .. text_line(_"Note:", building_helptext_note())
    end
 
    if(building_description.type_name == "productionsite") then
@@ -231,13 +222,13 @@
       end
 
    elseif(building_description.type_name == "warehouse") then
-      result = result .. rt(h3(_"Healing:")
-         .. p(ngettext("Garrisoned soldiers heal %d health point per second", "Garrisoned soldiers heal %d health points per second", building_description.heal_per_second):bformat(building_description.heal_per_second)))
+      result = result .. text_line(_"Healing:",
+         ngettext("Garrisoned soldiers heal %d health point per second", "Garrisoned soldiers heal %d health points per second", building_description.heal_per_second):bformat(building_description.heal_per_second))
       result = result .. text_line(_"Conquer range:", building_description.conquers)
 
    elseif(building_description.type_name == "militarysite") then
-      result = result .. rt(h3(_"Healing:")
-         .. p(ngettext("Garrisoned soldiers heal %d health point per second", "Garrisoned soldiers heal %d health points per second", building_description.heal_per_second):bformat(building_description.heal_per_second)))
+      result = result .. text_line(_"Healing:",
+         ngettext("Garrisoned soldiers heal %d health point per second", "Garrisoned soldiers heal %d health points per second", building_description.heal_per_second):bformat(building_description.heal_per_second))
       result = result .. text_line(_"Capacity:", building_description.max_number_of_soldiers)
       result = result .. text_line(_"Conquer range:", building_description.conquers)
 
@@ -276,11 +267,11 @@
    end
    if (hasinput) then
       -- TRANSLATORS: Heading in the building help for wares that a building accepts (e.g. wheat for a mill).
-      result =  rt(h3(_"Incoming:")) .. result
+      result =  h3(_"Incoming:") .. result
    end
 
    if ((not hasinput) and building_description.output_ware_types[1]) then
-      result = result .. rt(h3(_"Collects:"))
+      result = result .. h3(_"Collects:")
       for i, ware_description in ipairs(building_description.output_ware_types) do
          result = result ..
             dependencies({building_description, ware_description}, ware_description.descname)
@@ -292,7 +283,7 @@
 
    elseif (building_description.is_mine) then
       -- TRANSLATORS: This is a verb (The miner mines)
-      result = result .. rt(h3(_"Mines:"))
+      result = result .. h3(_"Mines:")
       for i, ware_description in ipairs(building_description.output_ware_types) do
 
          -- Need to hack this, because resource != produced ware.
@@ -312,7 +303,7 @@
 
    else
       if(building_description.output_ware_types[1] or building_description.output_worker_types[1]) then
-         result = result .. rt(h3(_"Produces:"))
+         result = result .. h3(_"Produces:")
       end
       for i, ware_description in ipairs(building_description.output_ware_types) do
          result = result ..
@@ -354,10 +345,10 @@
          end
       end
    end
-   if (outgoing ~= "") then result = result .. rt(h3(_"Outgoing:")) .. outgoing end
+   if (outgoing ~= "") then result = result .. h3(_"Outgoing:") .. outgoing end
 
-   if (result == "") then result = rt(p(_"None")) end
-   return rt(h2(_"Dependencies")) .. result
+   if (result == "") then result = p(_"None") end
+   return h2(_"Dependencies") .. result
 end
 
 -- RST
@@ -373,54 +364,54 @@
 function building_help_dependencies_training(tribe, building_description)
    local result = ""
    if (building_description.max_health and building_description.min_health) then
-      result = result .. rt(h2(_"Health Training"))
-      result = result .. rt(p(_"Trains ‘Health’ from %1% up to %2%":
-            bformat(building_description.min_health, building_description.max_health+1)))
-      result = result .. rt(h3(_"Soldiers:"))
+      result = result .. h2(_"Health Training")
+      result = result .. p(_"Trains ‘Health’ from %1% up to %2%":
+            bformat(building_description.min_health, building_description.max_health+1))
+      result = result .. h3(_"Soldiers:")
       result = result ..
          dependencies_basic({
-            "tribes/workers/" .. tribe.name .. "/soldier/health_level" .. building_description.min_health .. ".png",
-            building_description.icon_name,
-            "tribes/workers/" .. tribe.name .. "/soldier/health_level" .. (building_description.max_health + 1) ..".png"})
+            img("tribes/workers/" .. tribe.name .. "/soldier/health_level" .. building_description.min_health .. ".png"),
+            img(building_description.icon_name),
+            img("tribes/workers/" .. tribe.name .. "/soldier/health_level" .. (building_description.max_health + 1) ..".png")})
       result = result .. dependencies_training_food(building_description.food_health)
       result = result .. dependencies_training_weapons(building_description.weapons_health)
    end
    if (building_description.max_attack and building_description.min_attack) then
-      result = result .. rt(h2(_"Attack Training"))
+      result = result .. h2(_"Attack Training")
       -- TRANSLATORS: %1$s = Health, Evade, Attack or Defense. %2$s and %3$s are numbers.
-      result = result .. rt(p(_"Trains ‘Attack’ from %1% up to %2%":
-         bformat(building_description.min_attack, building_description.max_attack+1)))
-      result = result .. rt(h3(_"Soldiers:")) ..
+      result = result .. p(_"Trains ‘Attack’ from %1% up to %2%":
+         bformat(building_description.min_attack, building_description.max_attack+1))
+      result = result .. h3(_"Soldiers:") ..
          dependencies_basic({
-            "tribes/workers/" .. tribe.name .. "/soldier/attack_level" .. building_description.min_attack .. ".png",
-            building_description.icon_name,
-            "tribes/workers/" .. tribe.name .. "/soldier/attack_level" .. (building_description.max_attack + 1) ..".png"})
+            img("tribes/workers/" .. tribe.name .. "/soldier/attack_level" .. building_description.min_attack .. ".png"),
+            img(building_description.icon_name),
+            img("tribes/workers/" .. tribe.name .. "/soldier/attack_level" .. (building_description.max_attack + 1) ..".png")})
       result = result .. dependencies_training_food(building_description.food_attack)
       result = result .. dependencies_training_weapons(building_description.weapons_attack)
    end
    if (building_description.max_defense and building_description.min_defense) then
-      result = result .. rt(h2(_"Defense Training"))
-      result = result .. rt(p( _"Trains ‘Defense’ from %1% up to %2%":
-            bformat(building_description.min_defense, building_description.max_defense+1)))
-            result = result .. rt(h3(_"Soldiers:"))
+      result = result .. h2(_"Defense Training")
+      result = result .. p( _"Trains ‘Defense’ from %1% up to %2%":
+            bformat(building_description.min_defense, building_description.max_defense+1))
+            result = result .. h3(_"Soldiers:")
       result = result ..
          dependencies_basic({
-            "tribes/workers/" .. tribe.name .. "/soldier/defense_level" .. building_description.min_defense .. ".png",
-            building_description.icon_name,
-            "tribes/workers/" .. tribe.name .. "/soldier/defense_level" .. (building_description.max_defense + 1) ..".png"})
+            img("tribes/workers/" .. tribe.name .. "/soldier/defense_level" .. building_description.min_defense .. ".png"),
+            img(building_description.icon_name),
+            img("tribes/workers/" .. tribe.name .. "/soldier/defense_level" .. (building_description.max_defense + 1) ..".png")})
       result = result .. dependencies_training_food(building_description.food_defense)
       result = result .. dependencies_training_weapons(building_description.weapons_defense)
    end
    if (building_description.max_evade and building_description.min_evade) then
-      result = result .. rt(h2(_"Evade Training"))
-      result = result .. rt(p( _"Trains ‘Evade’ from %1% up to %2%":
-            bformat(building_description.min_evade, building_description.max_evade+1)))
-      result = result .. rt(h3(_"Soldiers:"))
+      result = result .. h2(_"Evade Training")
+      result = result .. p( _"Trains ‘Evade’ from %1% up to %2%":
+            bformat(building_description.min_evade, building_description.max_evade+1))
+      result = result .. h3(_"Soldiers:")
       result = result ..
          dependencies_basic({
-            "tribes/workers/" .. tribe.name .. "/soldier/evade_level" .. building_description.min_evade .. ".png",
-            building_description.icon_name,
-            "tribes/workers/" .. tribe.name .. "/soldier/evade_level" .. (building_description.max_evade + 1) ..".png"})
+            img("tribes/workers/" .. tribe.name .. "/soldier/evade_level" .. building_description.min_evade .. ".png"),
+            img(building_description.icon_name),
+            img("tribes/workers/" .. tribe.name .. "/soldier/evade_level" .. (building_description.max_evade + 1) ..".png")})
       result = result .. dependencies_training_food(building_description.food_evade)
       result = result .. dependencies_training_weapons(building_description.weapons_evade)
    end
@@ -440,39 +431,48 @@
 --
 function building_help_building_section(building_description)
    -- TRANSLATORS: This is the header for the "Building" section in the building help, containing size info, buildcost etc.
-   local result = rt(h2(_"Building"))
+   local result = h2(_"Building")
 
    -- Space required
+   local space_required_image = ""
+   local space_required_text = ""
    if (building_description.is_mine) then
-      result = result .. text_line(_"Space required:",_"Mine plot","images/wui/overlays/mine.png")
+      space_required_text = _"Mine plot"
+      space_required_image = "images/wui/overlays/mine.png"
    elseif (building_description.is_port) then
-      result = result .. text_line(_"Space required:",_"Port plot","images/wui/overlays/port.png")
+      space_required_text = _"Port plot"
+      space_required_image = "images/wui/overlays/port.png"
    else
       if (building_description.size == "small") then
-         result = result .. text_line(_"Space required:",_"Small plot","images/wui/overlays/small.png")
+         space_required_text = _"Small plot"
+         space_required_image = "images/wui/overlays/small.png"
       elseif (building_description.size == "medium") then
-         result = result .. text_line(_"Space required:",_"Medium plot","images/wui/overlays/medium.png")
+         space_required_text = _"Medium plot"
+         space_required_image = "images/wui/overlays/medium.png"
       elseif (building_description.size == "big") then
-         result = result .. text_line(_"Space required:",_"Big plot","images/wui/overlays/big.png")
-      else
-         result = result .. p(_"Space required:" .. _"Unknown")
+         space_required_text = _"Big plot"
+         space_required_image = "images/wui/overlays/big.png"
       end
    end
+   if space_required_text == "" or space_required_image == "" then
+      result = result .. text_line(_"Space required:", _"Unknown")
+   else
+      result = result .. image_line({space_required_image}, 1, text_line(_"Space required:", space_required_text))
+   end
 
    -- Enhanced from
    if (building_description.buildable or building_description.enhanced) then
 
       if (building_description.buildable and building_description.enhanced) then
-         result = result .. text_line(_"Note:",
-            _"This building can either be built directly or obtained by enhancing another building.")
+         result = result .. h3(_"Note:") .. p(_"This building can either be built directly or obtained by enhancing another building.")
       end
 
       if (building_description.buildable) then
          -- Build cost
          if (building_description.buildable and building_description.enhanced) then
-            result = result .. rt(h3(_"Direct build cost:"))
+            result = result .. h3(_"Direct build cost:")
          else
-            result = result .. rt(h3(_"Build cost:"))
+            result = result .. h3(_"Build cost:")
          end
          for ware, amount in pairs(building_description.build_cost) do
             local ware_description = wl.Game():get_ware_description(ware)
@@ -483,9 +483,9 @@
       if (building_description.enhanced) then
          former_building = building_description.enhanced_from
             if (building_description.buildable) then
-               result = result .. text_line(_"Or enhanced from:", former_building.descname)
+               result = result .. image_line({former_building.icon_name}, 1, h3(_"Or enhanced from:") .. p(former_building.descname))
             else
-               result = result .. text_line(_"Enhanced from:", former_building.descname)
+               result = result .. image_line({former_building.icon_name}, 1, h3(_"Enhanced from:") .. p(former_building.descname))
             end
 
          for ware, amount in pairs(building_description.enhancement_cost) do
@@ -494,7 +494,7 @@
          end
 
          -- Cumulative cost
-         result = result .. rt(h3(_"Cumulative cost:"))
+         result = result .. h3(_"Cumulative cost:")
          local warescost = {}
          for ware, amount in pairs(building_description.enhancement_cost) do
             if (warescost[ware]) then
@@ -504,7 +504,7 @@
             end
          end
 
-         local former_buildings = {};
+         local former_buildings = {}
          former_building = building_description
 
          while former_building.enhanced do
@@ -539,20 +539,20 @@
                result = result .. help_ware_amount_line(ware_description, amount)
             end
          else
-            result = result .. rt(p(_"Unknown"))
+            result = result .. p(_"Unknown")
          end
 
          -- Dismantle yields
          if (building_description.buildable) then
-            result = result .. rt(h3(_"If built directly, dismantle yields:"))
+            result = result .. h3(_"If built directly, dismantle yields:")
             for ware, amount in pairs(building_description.returned_wares) do
                local ware_description = wl.Game():get_ware_description(ware)
                result = result .. help_ware_amount_line(ware_description, amount)
             end
-            result = result .. rt(h3(_"If enhanced, dismantle yields:"))
+            result = result .. h3(_"If enhanced, dismantle yields:")
          else
             -- TRANSLATORS: This is a heading for the resources that you will get back when you dismantle a building of this type. What dismantling will give you.
-            result = result .. rt(h3(_"Dismantle yields:"))
+            result = result .. h3(_"Dismantle yields:")
          end
          local warescost = {}
          for ware, amount in pairs(building_description.returned_wares_enhanced) do
@@ -588,12 +588,12 @@
                result = result .. help_ware_amount_line(ware_description, amount)
             end
          else
-            result = result .. rt(p(_"Unknown"))
+            result = result .. p(_"Unknown")
          end
       -- Buildable
       else
          -- Dismantle yields
-         result = result .. rt(h3(_"Dismantle yields:"))
+         result = result .. h3(_"Dismantle yields:")
          for ware, amount in pairs(building_description.returned_wares) do
             local ware_description = wl.Game():get_ware_description(ware)
             result = result .. help_ware_amount_line(ware_description, amount)
@@ -602,7 +602,8 @@
 
       -- Can be enhanced to
       if (building_description.enhancement) then
-         result = result .. text_line(_"Can be enhanced to:", building_description.enhancement.descname)
+         result = result .. image_line({building_description.enhancement.icon_name}, 1, h3(_"Can be enhanced to:") .. p(building_description.enhancement.descname))
+
          for ware, amount in pairs(building_description.enhancement.enhancement_cost) do
             local ware_description = wl.Game():get_ware_description(ware)
             result = result .. help_ware_amount_line(ware_description, amount)
@@ -632,7 +633,7 @@
 
    if(building_description.type_name == "productionsite" or building_description.type_name == "trainingsite") then
 
-      result = result .. rt(h2(_"Workers")) .. rt(h3(_"Crew required:"))
+      result = result .. h2(_"Workers") .. h3(_"Crew required:")
 
       local worker_description = building_description.working_positions[1]
       local becomes_description = nil
@@ -652,24 +653,26 @@
          number_of_workers = number_of_workers + 1
 
          if(becomes_description) then
-            result = result .. image_line(worker_description.icon_name, 1,
+            result = result .. image_line({worker_description.icon_name}, 1,
                -- TRANSLATORS: %s is a worker name, e.g. "Chief Miner" or "Brewer".
                p(_"%s or better":bformat(worker_description.descname)))
          else
-            result = result .. image_line(worker_description.icon_name, 1,
+            result = result .. image_line({worker_description.icon_name}, 1,
                p(worker_description.descname))
          end
       end
 
       if (number_of_workers > 0) then
          local tool_string = help_tool_string(tribe, toolnames, number_of_workers)
-         -- TRANSLATORS: Tribal Encyclopedia: Heading for which tool workers use
-         result = result .. rt(h3(ngettext("Worker uses:","Workers use:", number_of_workers))) .. tool_string
+         if (tool_string ~= "") then
+            -- TRANSLATORS: Tribal Encyclopedia: Heading for which tool workers use
+            result = result .. h3(ngettext("Worker uses:","Workers use:", number_of_workers)) .. tool_string
+         end
       end
 
       if(becomes_description) then
 
-         result = result .. rt(h3(_"Experience levels:"))
+         result = result .. h3(_"Experience levels:")
          -- TRANSLATORS: EP = Experience Points
          local exp_string = _"%s to %s (%s EP)":format(
                worker_description.descname,
@@ -686,7 +689,7 @@
                   worker_description.needed_experience
                )
          end
-         result = result ..  rt("text-align=right", p(exp_string))
+         result = result ..  p("align=right", exp_string)
       end
    end
 
@@ -703,7 +706,7 @@
 --
 function building_help_production_section()
    if (building_helptext_performance() ~= "") then
-      return rt(h2(_"Production")) ..
+      return h2(_"Production") ..
         text_line(_"Performance:", building_helptext_performance())
    else
       return ""

=== modified file 'data/tribes/scripting/help/controls.lua'
--- data/tribes/scripting/help/controls.lua	2016-04-02 11:12:35 +0000
+++ data/tribes/scripting/help/controls.lua	2016-04-23 13:15:34 +0000
@@ -6,82 +6,80 @@
 return {
    title = _"Controls",
    text =
-      rt(
-         h2(_"Window Control") ..
-         p(
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Right-click")), _"Close window") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Middle-click or Ctrl + Left-click")), _"Minimize/Maximize window") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Ctrl + Left-click on Button")), _"Skip confirmation dialog")) ..
-
-         h2(_"Road Control") ..
-         p(
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Ctrl + Left-click")), _"While connecting two flags: Place flags automatically") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Ctrl + Left-click")), _"While removing a flag: Remove all flags up to the first junction")) ..
-
-         h2(_"Keyboard Shortcuts") ..
-            p(
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Page Up")), _"Increase game speed") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Page Down")), _"Decrease game speed") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Pause")), _"Pause the game") ..
-               -- TRANSLATORS: This is an access key combination. The hotkey is 'c'
-               dl(help_format_hotkey("C"), _"Toggle census") ..
-               -- TRANSLATORS: This is an access key combination. The hotkey is 's'
-               dl(help_format_hotkey("S"), _"Toggle statistics") ..
-               help_toggle_minimap_hotkey() ..
-               help_toggle_building_spaces_hotkey() ..
-               -- TRANSLATORS: This is an access key combination. The hotkey is 'o'
-               dl(help_format_hotkey("O"), _"Toggle objectives") ..
-               -- TRANSLATORS: This is an access key combination. The hotkey is 'n'
-               dl(help_format_hotkey("N"), _"Toggle messages (‘news’)") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("F1"), _"Tribal Encyclopedia") ..
-               -- TRANSLATORS: This is an access key combination. The hotkey is 'i'
-               dl(help_format_hotkey("I"), _"Toggle stock inventory") ..
-               -- TRANSLATORS: This is an access key combination. The hotkey is 'b'
-               dl(help_format_hotkey("B"), _"Toggle building statistics") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Home")), _"Center main mapview on starting location") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "(Ctrl +) 0-9")), _"Remember and go to previously remembered locations") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey(","), _"Go to the previous location") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("."), _"Go to the next location") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Ctrl + F11")), _"Take a screenshot") ..
-               help_toggle_fullscreen_hotkey() ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey(pgettext("hotkey", "Ctrl + F10")), _"Quit the game immediately") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey(pgettext("hotkey", "F6")), _"Show the debug console (only in debug-builds)")
-         ) ..
-
-         h3(_"In the message window, the following additional shortcuts are available:") ..
-         p(
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("0"), _"Show all messages") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("1"), _"Show geologists’ messages only") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("2"), _"Show economy messages only") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("3"), _"Show seafaring messages only") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("4"), _"Show warfare messages only") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("5"), _"Show scenario messages only") ..
-               -- TRANSLATORS: This is an access key combination.
-               dl(help_format_hotkey("G"), _"Jump to the location corresponding to the current message") ..
-               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "Delete")), _"Archive/Restore the current message")
-          )
-      )
+     h2(_"Window Control") ..
+     p(
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Right-click")), _"Close window") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Middle-click or Ctrl + Left-click")), _"Minimize/Maximize window") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Ctrl + Left-click on Button")), _"Skip confirmation dialog")) ..
+
+     h2(_"Road Control") ..
+     p(
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Ctrl + Left-click")), _"While connecting two flags: Place flags automatically") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Ctrl + Left-click")), _"While removing a flag: Remove all flags up to the first junction")) ..
+
+     h2(_"Keyboard Shortcuts") ..
+       p(
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Page Up")), _"Increase game speed") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Page Down")), _"Decrease game speed") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Pause")), _"Pause the game") ..
+          -- TRANSLATORS: This is an access key combination. The hotkey is 'c'
+          dl(help_format_hotkey("C"), _"Toggle census") ..
+          -- TRANSLATORS: This is an access key combination. The hotkey is 's'
+          dl(help_format_hotkey("S"), _"Toggle statistics") ..
+          help_toggle_minimap_hotkey() ..
+          help_toggle_building_spaces_hotkey() ..
+          -- TRANSLATORS: This is an access key combination. The hotkey is 'o'
+          dl(help_format_hotkey("O"), _"Toggle objectives") ..
+          -- TRANSLATORS: This is an access key combination. The hotkey is 'n'
+          dl(help_format_hotkey("N"), _"Toggle messages (‘news’)") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("F1"), _"Tribal Encyclopedia") ..
+          -- TRANSLATORS: This is an access key combination. The hotkey is 'i'
+          dl(help_format_hotkey("I"), _"Toggle stock inventory") ..
+          -- TRANSLATORS: This is an access key combination. The hotkey is 'b'
+          dl(help_format_hotkey("B"), _"Toggle building statistics") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Home")), _"Center main mapview on starting location") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "(Ctrl +) 0-9")), _"Remember and go to previously remembered locations") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey(","), _"Go to the previous location") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("."), _"Go to the next location") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Ctrl + F11")), _"Take a screenshot") ..
+          help_toggle_fullscreen_hotkey() ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey(pgettext("hotkey", "Ctrl + F10")), _"Quit the game immediately") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey(pgettext("hotkey", "F6")), _"Show the debug console (only in debug-builds)")
+     ) ..
+
+     h3(_"In the message window, the following additional shortcuts are available:") ..
+     p(
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("0"), _"Show all messages") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("1"), _"Show geologists’ messages only") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("2"), _"Show economy messages only") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("3"), _"Show seafaring messages only") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("4"), _"Show warfare messages only") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("5"), _"Show scenario messages only") ..
+          -- TRANSLATORS: This is an access key combination.
+          dl(help_format_hotkey("G"), _"Jump to the location corresponding to the current message") ..
+          -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+          dl(help_format_hotkey(pgettext("hotkey", "Delete")), _"Archive/Restore the current message")
+     )
 }

=== modified file 'data/tribes/scripting/help/format_help.lua'
--- data/tribes/scripting/help/format_help.lua	2016-02-27 08:43:39 +0000
+++ data/tribes/scripting/help/format_help.lua	2016-04-23 13:15:34 +0000
@@ -11,28 +11,70 @@
 --  =======================================================
 
 -- RST
+-- .. function:: two_divs(text1, text2, text1_width, text2_width, space_width, text2_alignment)
+--
+--    Returns 2 divs with the specified texts and widths, separated by space_width
+--
+--    :arg text1: Text for the first div.
+--    :arg text2: Text for the second div.
+--    :arg text1_width: Width of the first div.
+--    :arg text2_width: Width of the second div.
+--    :arg space_width: Width of the soace between the two divs.
+--    :arg text2_alignment: Alignment of the second div (left, right, center).
+--
+--    :returns: the text on the left and a picture row on the right.
+--
+function two_divs(text1, text2, text1_width, text2_width, space_width, text2_alignment)
+   return p("<br>") .. div("width=100%", "") ..
+      div("width=" .. text1_width, p(text1))  ..
+      div(p(space(space_width))) ..
+      div("width=" .. (text2_width), p("align=" .. text2_alignment, text2)) ..
+      div("width=100%", "")
+end
+
+
+-- RST
 -- .. function:: image_line(image, count[, text = nil])
 --
 --    Aligns the image to a row on the right side with text on the left.
 --
---    :arg image: the picture to be aligned to a row.
+--    :arg image: an array of the pictures to be aligned to a row.
 --    :arg count: length of the picture row.
 --    :arg text: if given the text aligned on the left side, formatted via
 --       formatting.lua functions.
 --    :returns: the text on the left and a picture row on the right.
 --
-function image_line(image, count, text)
-   local imgs={}
-   for i=1,count do
-      imgs[#imgs + 1] = image
-   end
-   local imgstr = table.concat(imgs, ";")
-
-   if text then
-      return rt("image=" .. imgstr .. " image-align=right", "  " .. text)
-   else
-      return rt("image=" .. imgstr .. " image-align=right", "")
-   end
+function image_line(images, count, text)
+   -- NOCOM(GunChleoc): We are operating with hard-coded width here
+   local available_width = 312
+   local imgstr = ""
+   local imgperline = 5
+
+   -- Give text as much space as possible
+   local actual_imgperline = imgperline
+   if count < actual_imgperline then actual_imgperline = count end
+
+   -- Hack to fit port plot image
+   local image_space_factor = actual_imgperline
+   if image_space_factor < 2 then image_space_factor = image_space_factor + 1 end
+   local text_width = available_width - image_space_factor * 35 -- We assume that images are < 35 pixels wide
+
+   -- Hack to avoid widening for port plot image
+   if count == 0 then count = 1 end
+
+   while count > 0 do
+      local this_line = ""
+      for j=1,imgperline do
+         if count < 1 then break end
+         for imgcount, image in pairs(images) do
+            this_line = this_line .. img(image)
+            count = count - 1
+         end
+      end
+      imgstr = imgstr .. p(this_line)
+   end
+
+   return two_divs(text, imgstr, text_width, available_width - 6 - text_width, 6, "right")
 end
 
 
@@ -54,11 +96,22 @@
    if not text then
       text = ""
    end
-   local string = "image=" .. items[1].icon_name
+   local string = img(items[1].icon_name)
+   local count = 1
    for k,v in ipairs({table.unpack(items,2)}) do
-      string = string .. ";images/richtext/arrow-right.png;" ..  v.icon_name
+      if (string.len(v.icon_name) > 0) then
+         count = count + 2
+         string = string .. img("images/richtext/arrow-right.png") ..  img(v.icon_name)
+      else
+         count = count + 1
+         string = string .. img("images/richtext/arrow-right.png")
+      end
    end
-   return rt(string, p(text))
+
+   -- NOCOM(GunChleoc): hard-coded width
+   local available_width = 312
+   local text_width = available_width - count * 27 -- We assume that images are < 27 pixels wide
+   return two_divs(string, text, available_width - 6 - text_width, text_width, 3, "left")
 end
 
 
@@ -72,19 +125,8 @@
 --    :returns: image_line for the ware type and amount
 --
 function help_ware_amount_line(ware_description, amount)
-   amount = tonumber(amount)
-   local image = ware_description.icon_name
-   local result = ""
-   local imgperline = 6
-   local temp_amount = amount
-
-   while (temp_amount > imgperline) do
-      result = result .. image_line(image, imgperline)
-      temp_amount = temp_amount - imgperline
-   end
    -- TRANSLATORS: %1$d is a number, %2$s the name of a ware, e.g. 12x Stone
-   result = image_line(image, temp_amount, p(_"%1$dx %2$s":bformat(amount, ware_description.descname))) .. result
-   return result
+   return image_line({ware_description.icon_name}, amount, p(_"%1$dx %2$s":bformat(amount, ware_description.descname)))
 end
 
 -- RST
@@ -103,7 +145,7 @@
    for i, toolname in ipairs(toolnames) do
       if (tribe:has_ware(toolname)) then
          local ware_description = game:get_ware_description(toolname)
-         result = result .. image_line(ware_description.icon_name, 1, p(ware_description.descname))
+         result = result .. image_line({ware_description.icon_name}, 1, p(ware_description.descname))
       end
    end
    return result
@@ -134,31 +176,37 @@
          consumed_warenames[count] = _"%1$dx %2$s":bformat(amount, ware_description.descname)
          consumed_images[count] = ware_description.icon_name
          consumed_amount[count] = amount
-         count = count + 1
          consumed_wares_counter = consumed_wares_counter + amount
+         count = count + 1
       end
       local text = localize_list(consumed_warenames, "or")
       if (countlist > 1) then
          text = _"%s and":bformat(text)
       end
-      local images = consumed_images[1]
-      local image_counter = 2
-      while (image_counter <= consumed_amount[1]) do
-         images = images .. ";" .. consumed_images[1]
+
+      -- For the first ware type in a line
+      local images = {consumed_images[1]}
+      local image_counter = 1
+      while (image_counter < consumed_amount[1]) do
+         table.insert(images, consumed_images[1])
          image_counter = image_counter + 1
       end
+
+      -- For mixed ware types in one line
       for k, v in ipairs({table.unpack(consumed_images,2)}) do
-         image_counter = 1
-         while (image_counter <= consumed_amount[k + 1]) do
-            images = images .. ";" .. v
-            image_counter = image_counter + 1
+         local image_counter2 = 1
+         image_counter = image_counter + 1
+         while (image_counter2 <= consumed_amount[k + 1]) do
+            table.insert(images, v)
+            image_counter2 = image_counter2 + 1
          end
       end
-      consumed_wares_string = image_line(images, 1, p(text)) .. consumed_wares_string
+      text = string.gsub(text, " ", "&nbsp;") -- Make sure that we get no line breaks
+      consumed_wares_string = image_line(images, image_counter, p(text)) .. consumed_wares_string
    end
    if (consumed_wares_counter > 0) then
       -- TRANSLATORS: Tribal Encyclopedia: Heading for wares consumed by a productionsite
-      result = result .. rt(h3(ngettext("Ware consumed:", "Wares consumed:", consumed_wares_counter)))
+      result = result .. h3(ngettext("Ware consumed:", "Wares consumed:", consumed_wares_counter))
       result = result .. consumed_wares_string
    end
    return result

=== modified file 'data/tribes/scripting/help/introduction.lua'
--- data/tribes/scripting/help/introduction.lua	2016-04-02 08:21:25 +0000
+++ data/tribes/scripting/help/introduction.lua	2016-04-23 13:15:34 +0000
@@ -6,8 +6,6 @@
 return {
    title = _"About Widelands",
    text =
-      rt(
-         help_introduction() ..
-         help_online_help()
-      )
+      help_introduction() ..
+      help_online_help()
 }

=== modified file 'data/tribes/scripting/help/ware_help.lua'
--- data/tribes/scripting/help/ware_help.lua	2016-03-22 07:32:14 +0000
+++ data/tribes/scripting/help/ware_help.lua	2016-04-23 13:15:34 +0000
@@ -29,8 +29,8 @@
    purpose_text = ware_helptext() .. ware_helptext(tribe.name)
 
    -- TODO(GunChleoc): Split into purpose and note
-   local result = rt(h2(_"Purpose")) ..
-      rt("image=" .. ware_description.icon_name, p(purpose_text))
+   local result = h2(_"Purpose") ..
+      image_line({ware_description.icon_name}, 0, p(purpose_text))
    return result
 end
 
@@ -49,7 +49,7 @@
    for i, building in ipairs(ware_description.producers) do
       if (tribe:has_building(building.name)) then
          -- TRANSLATORS: Ware Encyclopedia: A building producing a ware
-         result = result .. rt(h2(_"Producer"))
+         result = result .. h2(_"Producer")
          result = result .. dependencies({building, ware_description}, building.descname)
 
          -- Find out which programs in the building produce this ware
@@ -90,7 +90,7 @@
             if (produced_wares_counters[program_name] > 0) then
                result = result
                   -- TRANSLATORS: Ware Encyclopedia: Wares produced by a productionsite
-                  .. rt(h3(ngettext("Ware produced:", "Wares produced:", produced_wares_counters[program_name])))
+                  .. h3(ngettext("Ware produced:", "Wares produced:", produced_wares_counters[program_name]))
                   .. produced_wares_strings[program_name]
             end
          end
@@ -144,14 +144,14 @@
          end
       end
       if(add_this_worker) then
-         workers_string = workers_string .. image_line(worker.icon_name, 1, p(worker.descname))
+         workers_string = workers_string .. image_line({worker.icon_name}, 1, p(worker.descname))
       end
    end
 
    -- Now show consumers (buildings + workers)
    if (consumers_amount > 0) then
       -- TRANSLATORS: Ware Encyclopedia: A list of buildings and / or workers that consume a ware
-      result = result .. rt(h2(ngettext("Consumer", "Consumers", consumers_amount)))
+      result = result .. h2(ngettext("Consumer", "Consumers", consumers_amount))
       if (consumers ~= "") then
          result = result .. consumers_string
       end

=== modified file 'data/tribes/scripting/help/worker_help.lua'
--- data/tribes/scripting/help/worker_help.lua	2016-04-04 17:04:56 +0000
+++ data/tribes/scripting/help/worker_help.lua	2016-04-23 13:15:34 +0000
@@ -24,7 +24,7 @@
 
          if (recruits_this) then
             -- TRANSLATORS: Worker Encyclopedia: A building recruiting a worker
-            result = result .. rt(h2(_"Producer"))
+            result = result .. h2(_"Producer")
             result = result .. dependencies({building, worker_description}, building.descname)
 
             -- Find out which programs in the building recruit this worker if any
@@ -65,7 +65,7 @@
                if (recruited_workers_counters[program_name] > 0) then
                   result = result
                      -- TRANSLATORS: Worker Encyclopedia: Workers recruited by a productionsite
-                     .. rt(h3(ngettext("Worker recruited:", "Workers recruited:", recruited_workers_counters[program_name])))
+                     .. h3(ngettext("Worker recruited:", "Workers recruited:", recruited_workers_counters[program_name]))
                      .. recruited_workers_strings[program_name]
                end
             end
@@ -91,7 +91,7 @@
    if (#employers > 0) then
       -- TRANSLATORS: Worker Encyclopedia: A list of buildings where a worker can work
       -- TRANSLATORS: You can also translate this as 'workplace(s)'
-      result = result .. rt(h2(ngettext("Works at", "Works at", #employers)))
+      result = result .. h2(ngettext("Works at", "Works at", #employers))
       for i, building in ipairs(worker_description.employers) do
          result = result .. dependencies({worker_description, building}, building.descname)
       end
@@ -114,8 +114,8 @@
 function worker_help_string(tribe, worker_description)
    include(worker_description.helptext_script)
 
-   local result = rt(h2(_"Purpose")) ..
-      rt("image=" .. worker_description.icon_name, p(worker_helptext()))
+   local result = h2(_"Purpose") ..
+      image_line({worker_description.icon_name}, 0, p(worker_helptext()))
 
    if (worker_description.is_buildable) then
       -- Get the tools for the workers.
@@ -129,7 +129,7 @@
       if (#toolnames > 0) then
          local tool_string = help_tool_string(tribe, toolnames, 1)
          -- TRANSLATORS: Tribal Encyclopedia: Heading for which tool a worker uses
-         result = result .. rt(h2(_"Worker uses")) .. tool_string
+         result = result .. h2(_"Worker uses") .. tool_string
       end
    else
       result = result .. worker_help_producers_string(tribe, worker_description)
@@ -141,7 +141,7 @@
    local becomes_description = worker_description.becomes
    if (becomes_description) then
 
-      result = result .. rt(h2(_"Experience levels"))
+      result = result .. h2(_"Experience levels")
       local exp_string = _"%s to %s (%s EP)":format(
             worker_description.descname,
             becomes_description.descname,
@@ -157,59 +157,47 @@
                worker_description.needed_experience
             )
       end
-      result = result .. rt("text-align=right", p(exp_string))
+      result = result ..  p("align=right", exp_string)
    end
    -- Soldier properties
    if (worker_description.type_name == "soldier") then
       -- TRANSLATORS: Soldier levels
-      result = result .. rt(h2(_"Levels"))
-
-      result = result .. rt(h3(_"Health"))
-      result = result .. rt(p(
-         listitem_bullet(
-            -- TRANSLATORS: Soldier health / defense / evade points. A 5 digit number.
-            (_"Starts at %1% points."):bformat(worker_description.base_health)) ..
-         listitem_bullet(
-            -- TRANSLATORS: Soldier health / attack defense / evade points
-            ngettext("Increased by %1% point for each level.", "Increased by %1% points for each level.", worker_description.health_incr_per_level):bformat(worker_description.health_incr_per_level)) ..
-         listitem_bullet(
-            -- TRANSLATORS: Soldier health / attack defense / evade level
-            ngettext("The maximum level is %1%.", "The maximum level is %1%.", worker_description.max_health_level):bformat(worker_description.max_health_level))))
-
-      result = result .. rt(h3(_"Attack"))
-      result = result .. rt(p(
+      result = result .. h2(_"Levels")
+
+      result = result .. h3(_"Health")
+      result = result .. p(
+      -- TRANSLATORS: Soldier health / defense / evade points. A 5 digit number.
+         li((_"Starts at %1% points."):bformat(worker_description.base_health)) ..
+         -- TRANSLATORS: Soldier health / attack defense / evade points
+         li(ngettext("Increased by %1% point for each level.", "Increased by %1% points for each level.", worker_description.health_incr_per_level):bformat(worker_description.health_incr_per_level)) ..
+         -- TRANSLATORS: Soldier health / attack defense / evade level
+         li(ngettext("The maximum level is %1%.", "The maximum level is %1%.", worker_description.max_health_level):bformat(worker_description.max_health_level)))
+
+      result = result .. h3(_"Attack")
+      result = result .. p(
       -- TRANSLATORS: Points are 4 digit numbers.
-         listitem_bullet(_"A random value between %1% and %2% points is added to each attack."):bformat(worker_description.base_min_attack, worker_description.base_max_attack) ..
-
-         listitem_bullet(
-            ngettext("Increased by %1% point for each level.", "Increased by %1% points for each level.", worker_description.attack_incr_per_level):bformat(worker_description.attack_incr_per_level)) ..
-         listitem_bullet(
-            ngettext("The maximum level is %1%.", "The maximum level is %1%.", worker_description.max_attack_level):bformat(worker_description.max_attack_level))))
-
-      result = result .. rt(h3(_"Defense"))
+         li(_"A random value between %1% and %2% points is added to each attack."):bformat(worker_description.base_min_attack, worker_description.base_max_attack) ..
+         li(ngettext("Increased by %1% point for each level.", "Increased by %1% points for each level.", worker_description.attack_incr_per_level):bformat(worker_description.attack_incr_per_level)) ..
+         li(ngettext("The maximum level is %1%.", "The maximum level is %1%.", worker_description.max_attack_level):bformat(worker_description.max_attack_level)))
+
+      result = result .. h3(_"Defense")
       if (worker_description.max_defense_level > 0) then
-         result = result .. rt(p(
-            listitem_bullet(
-               (_"Starts at %d%%."):bformat(worker_description.base_defense)) ..
-            listitem_bullet(
-               (_"Increased by %d%% for each level."):bformat(worker_description.defense_incr_per_level)) ..
-            listitem_bullet(
-               ngettext("The maximum level is %1%.", "The maximum level is %1%.", worker_description.max_defense_level):bformat(worker_description.max_defense_level))))
+         result = result .. p(
+            li((_"Starts at %d%%."):bformat(worker_description.base_defense)) ..
+            li((_"Increased by %d%% for each level."):bformat(worker_description.defense_incr_per_level)) ..
+            li(ngettext("The maximum level is %1%.", "The maximum level is %1%.", worker_description.max_defense_level):bformat(worker_description.max_defense_level)))
       else
-         result = result .. rt(p(
-            listitem_bullet(
+         result = result .. p(
+            li(
                (_"Starts at %d%%."):bformat(worker_description.base_defense)) ..
-            listitem_bullet(_"This soldier cannot be trained in defense.")))
+            li(_"This soldier cannot be trained in defense."))
       end
 
-      result = result .. rt(h3(_"Evade"))
-      result = result .. rt(p(
-         listitem_bullet(
-            (_"Starts at %d%%."):bformat(worker_description.base_evade)) ..
-         listitem_bullet(
-            (_"Increased by %d%% for each level."):bformat(worker_description.evade_incr_per_level)) ..
-         listitem_bullet(
-            ngettext("The maximum level is %1%.", "The maximum level is %1%.", worker_description.max_evade_level):bformat(worker_description.max_evade_level))))
+      result = result .. h3(_"Evade")
+      result = result .. p(
+         li((_"Starts at %d%%."):bformat(worker_description.base_evade)) ..
+         li((_"Increased by %d%% for each level."):bformat(worker_description.evade_incr_per_level)) ..
+         li(ngettext("The maximum level is %1%.", "The maximum level is %1%.", worker_description.max_evade_level):bformat(worker_description.max_evade_level)))
    end
    return result
 end

=== modified file 'data/txts/AUTHORS.lua'
--- data/txts/AUTHORS.lua	2016-03-14 11:37:49 +0000
+++ data/txts/AUTHORS.lua	2016-04-23 13:15:34 +0000
@@ -1,32 +1,39 @@
-include "txts/format_authors.lua"
+include "scripting/formatting.lua"
 include "txts/developers.lua"
 
 set_textdomain("texts")
 
+local authors = developers()
+
 -- Uses structured data to format authors
-function list_authors()
-   local authors = developers()
+function list_authors(from, to)
    local result = ""
-   for i, category in ipairs(authors) do
-      result = result .. "<rt>" .. h1_authors(category["heading"]) .. "</rt>"
+
+   for i = from, to do
+      local category = authors[i]
+      result = result .. h1("f4a131", category["heading"])
       for j, entry in ipairs(category["entries"])  do
          if (entry["subheading"] ~= nil) then
-            result = result .. h2_authors(entry["subheading"])
+            result = result .. h2(entry["subheading"])
          end
          for k, member in ipairs(entry["members"])  do
-            result = result .. p_authors(member, category["image"] )
+            result = result .. p(img(category["image"]) .. member)
          end
       end
-      result = result .. rt("<p font-size=10> <br></p>")
+      result = result .. p_font("", "size=10 face=serif", " ")
    end
    return result
 end
 
 -- Main script
+local no_auth_cat = #authors
+local limit1 = math.floor(no_auth_cat / 2) - 2
+
 return {
    title = _"Developers",
    text = rt(
-      title(_"Widelands Development Team") ..
-      list_authors()
+      p_font("", "size=28 color=2F9131", _"Widelands Development Team") ..
+      div("width=50%", list_authors(1, limit1)) ..
+      div("width=50%", list_authors(limit1 + 1, no_auth_cat))
    )
 }

=== modified file 'data/txts/LICENSE.lua'
--- data/txts/LICENSE.lua	2016-03-14 11:37:49 +0000
+++ data/txts/LICENSE.lua	2016-04-23 13:15:34 +0000
@@ -2,40 +2,30 @@
 
 set_textdomain("texts")
 
-function a(text)
-   return "</p><p font-size=14 font-decoration=underline>" .. text
-end
-
-function a2(text)
-   return "</p><p font-size=14 font-decoration=underline>" .. text .. "</p><p font-size=14 color=ff4444>"
-end
-
-function i(text)
-   return "</p><p font-size=14 font-style=italic>" .. text
-end
-
 return {
    title = _"License",
    text = rt(
-      title(_"Licensing information for Widelands") ..
-
-      "<rt><p font-size=14><br>" ..
-      _"Copyright 2002 - 2016 by the Widelands Development Team." .. "<br>" ..
-      _"This game is Free and Open Source (FOSS), licensed under the GNU General Public License (GPL) V2.0." .. "<br></p>" ..
-
-      p(_"You can find more information on FOSS and the GPL by visiting the following webpage:  %s"):bformat(a("http://www.gnu.org/licenses/old-licenses/gpl-2.0";)) ..
+      title("sans", _"Licensing information for Widelands") ..
+
+      p("&nbsp;") ..
+
+      p_font("", "size=14 color=ffffff",_"Copyright 2002 - 2016 by the Widelands Development Team.") ..
+      p_font("", "size=14 color=ffffff",_"This game is Free and Open Source (FOSS), licensed under the GNU General Public License (GPL) V2.0.") ..
+
+      p("&nbsp;") ..
+
+      p(_"You can find more information on FOSS and the GPL by visiting the following webpage: %s"):bformat(a("http://www.gnu.org/licenses/old-licenses/gpl-2.0";)) ..
       p(_"You can find the full text of the license there as well as further information about its philosophy and the legal implications.") ..
 
+      p("&nbsp;") ..
+
       p(_"We are also shipping the GPL as a text document with Widelands itself.") ..
-      p(_"On Linux, you can find the file called COPYING in the root of the source or standalone binary package, or in the installation directory (like ‘%1%’)."):bformat(i("/usr/share/games/widelands")) ..
-      p(_"On Windows, you can find the file called COPYING.txt in the installation folder, and the Widelands Start menu entry provides a link to this file.") ..
-      p(_"On MacOS, you can find the file called COPYING in the archive you downloaded from the website.") ..
-
-      "<p font-size=14 color=ff4444>" .. (_"This game comes as-is and without any warranty. For more information and support you can find us at %1% (Website, Wiki, Forum for questions or general support), %2% (Bugtracker), and %3% (Translations)."):
-         bformat(
-            a2("http://wl.widelands.org";),
-            a2("https://launchpad.net/widelands";),
-            a2("https://www.transifex.com/projects/p/widelands/";))
-         .. "</p>"
+      li(_"On Linux, you can find the file called COPYING in the root of the source or standalone binary package, or in the installation directory (like ‘%1%’)"):bformat(i("/usr/share/games/widelands")) ..
+      li(_"On Windows, you can find the file called COPYING.txt in the installation folder, and the Widelands Start menu entry provides a link to this file.") ..
+      li(_"On MacOS, you can find the file called COPYING in the archive you downloaded from the website.") ..
+
+      p("&nbsp;") ..
+
+      p(b(_"This game comes as-is and without any warranty. For more information and support you can find us at %1% (Website, Wiki, Forum for questions or general support), %2% (Bugtracker), and %3% (Translations)."):bformat(a("http://wl.widelands.org";), a("https://launchpad.net/widelands";), a("https://www.transifex.com/projects/p/widelands/";)))
    )
 }

=== modified file 'data/txts/README.lua'
--- data/txts/README.lua	2016-04-02 10:35:21 +0000
+++ data/txts/README.lua	2016-04-23 13:15:34 +0000
@@ -5,38 +5,36 @@
 
 return {
    title = _"Readme",
-   text =
-rt("image=images/logos/wl-logo-64.png image-align=center text-align=center") ..
-rt("text-align=center",
-   p("font-size=38 font-face=Widelands/Widelands font-color=#2F9131", [[Widelands]]) ..
-   p("font-size=14 font-style=italic text-align=center", _[[an open source strategy game]])) ..
-rt(
-   help_introduction() ..
-   h3(_[[Check out the Widelands project homepage:]]) ..
-   p(a([[https://wl.widelands.org]])) ..
-   p(_[[Widelands is licensed under the GNU General Public License (GPL). For more information, see the file ‘COPYING’.]]) ..
-   h3(_[[Status]]) ..
-   p(_[[Widelands is nearly feature complete and is much fun to play alone and even more in multiplayer with others. Still, there is always more work to be done in all areas. If you are interested in contributing – be it by making graphics, fixing bugs or adding new features, translating the game into your language or creating new maps – get in touch on our homepage.]]) ..
-
-   h2(_[[Widelands Help]]) ..
-   -- TRANSLATORS: %1% is a key on the keyboard
-   p((_"You can find help about gameplay or the editor by using the help button on the bottom menu, or by pressing %1%.")
-      -- TRANSLATORS: This is a key on the keyboard
-      :bformat(_"F1")) ..
-   help_online_help() ..
-
-   h2(_[[Reporting Bugs]]) ..
-   p(_[[If you encounter a bug, please report it to our bugtracker:]]) ..
-   p(a([[https://bugs.launchpad.net/widelands]])) ..
-   p(_[[Please provide enough background information. Tell us:]]) ..
-   p(
-       listitem_bullet(_[[Detailed steps on how to trigger the bug, if possible.]]) ..
-       listitem_bullet(_[[What you expected to happen when performing the steps and what actually happened.]]) ..
-       listitem_bullet(_[[Which version of Widelands you are running (i.e. either the build number or the revision number if you are running a development version or a daily build.)]]) ..
-       listitem_bullet(_[[Please also include which operating system you are running Widelands on as some bugs can be platform specific.]]) ..
-       listitem_bullet(_[[Which map you were playing when the bug occurred.]]) ..
-       listitem_bullet(_[[If the bug concerns something not being displayed correctly or if it helps demonstrate the issue, please include one or more screenshots.]]) ..
-       listitem_bullet(_[[If you have a save game or replay demonstrating the issue (for instance crashes where it can be hard to tell exactly what is triggering it), please include that too. For more information, see the section on Replays below.]])) ..
-   help_replays()
-)
+   text = rt(
+      title("Widelands/Widelands.ttf", img("images/logos/wl-logo-64.png") .. [[Widelands]]) ..
+      p_font("align=center", "size=14 italic=true color=D1D1D1", _[[an open source strategy game]]) ..
+
+      help_introduction() ..
+      h3(_[[Check out the Widelands project homepage:]]) ..
+      p(a([[https://wl.widelands.org]])) ..
+      p(_[[Widelands is licensed under the GNU General Public License (GPL). For more information, see the file ‘COPYING’.]]) ..
+      h3(_[[Status]]) ..
+      p(_[[Widelands is nearly feature complete and is much fun to play alone and even more in multiplayer with others. Still, there is always more work to be done in all areas. If you are interested in contributing – be it by making graphics, fixing bugs or adding new features, translating the game into your language or creating new maps – get in touch on our homepage.]]) ..
+
+      h2(_[[Widelands Help]]) ..
+      -- TRANSLATORS: %1% is a key on the keyboard
+      p((_"You can find help about gameplay or the editor by using the help button on the bottom menu, or by pressing %1%.")
+         -- TRANSLATORS: This is a key on the keyboard
+         :bformat(_"F1")) ..
+      help_online_help() ..
+
+      h2(_[[Reporting Bugs]]) ..
+      p(_[[If you encounter a bug, please report it to our bugtracker:]]) ..
+      p(a([[https://bugs.launchpad.net/widelands]])) ..
+      p(_[[Please provide enough background information. Tell us:]]) ..
+      p(
+          li(_[[Detailed steps on how to trigger the bug, if possible.]]) ..
+          li(_[[What you expected to happen when performing the steps and what actually happened.]]) ..
+          li(_[[Which version of Widelands you are running (i.e. either the build number or the revision number if you are running a development version or a daily build.)]]) ..
+          li(_[[Please also include which operating system you are running Widelands on as some bugs can be platform specific.]]) ..
+          li(_[[Which map you were playing when the bug occurred.]]) ..
+          li(_[[If the bug concerns something not being displayed correctly or if it helps demonstrate the issue, please include one or more screenshots.]]) ..
+          li(_[[If you have a save game or replay demonstrating the issue (for instance crashes where it can be hard to tell exactly what is triggering it), please include that too. For more information, see the section on Replays below.]])) ..
+      help_replays()
+   )
 }

=== modified file 'data/txts/TRANSLATORS.lua'
--- data/txts/TRANSLATORS.lua	2016-03-14 11:37:49 +0000
+++ data/txts/TRANSLATORS.lua	2016-04-23 13:15:34 +0000
@@ -1,30 +1,48 @@
-include "txts/format_authors.lua"
+include "scripting/formatting.lua"
 include "txts/translators_data.lua"
 
 set_textdomain("texts")
 
--- Uses structured data to format authors
-function list_authors()
-   local authors = translators()
+-- Comparison function used to sort localized language names alphabetically
+function compare_by_sortname(a, b)
+  return a["sortname"] < b["sortname"]
+end
+
+local translators = translators()
+table.sort(translators, compare_by_sortname)
+
+-- Uses structured data to format translators
+function list_translators(from, to)
    local result = ""
    local translators_image = "images/wui/editor/fsel_editor_set_height.png"
-   for i, category in ipairs(authors) do
-      result = result .. "<rt>" .. h2_authors(category["heading"]) .. "</rt>"
+   for i = from, to do
+      local category = translators[i]
+      result = result .. h2(category["heading"])
       for j, entry in ipairs(category["entries"])  do
          for k, member in ipairs(entry["members"])  do
-            result = result .. p_authors(member, translators_image)
+            result = result .. li(member)
          end
       end
-      result = result .. rt("<p font-size=10> <br></p>")
+      result = result .. p_font("", "size=10 face=serif", " ")
    end
    return result
 end
 
 -- Main script
+local no_trans_cat = #translators
+local limit1 = math.floor(no_trans_cat / 4) - 2
+local limit2 = math.floor(no_trans_cat / 2) - 2
+local limit3 = math.floor(no_trans_cat * 3 / 4) + 2
+
+-- NOCOM(GunChleoc): with 3 columns, this will produce garbage
+-- NOCOM(GunChleoc): with 1 column, this will crash
 return {
    title = _"Translators",
    text = rt(
-      title(_"Widelands Translators") ..
-      list_authors()
+      p_font("", "size=28 color=2F9131", _"Widelands Translators") ..
+      div("width=25%", list_translators(1, limit1)) ..
+      div("width=25%", list_translators(limit1 + 1, limit2)) ..
+      div("width=25%", list_translators(limit2 + 1, limit3)) ..
+      div("width=25%", list_translators(limit3 + 1, no_trans_cat))
    )
 }

=== removed file 'data/txts/format_authors.lua'
--- data/txts/format_authors.lua	2016-03-10 16:36:44 +0000
+++ data/txts/format_authors.lua	1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
-include "scripting/formatting.lua"
-
--- Formatting functions
-function h1_authors(text)
-   return "<rt text-align=left><p font-size=24 font-decoration=bold font-face=serif font-color=f4a131>" .. text .. "</p></rt>"
-end
-
-function h2_authors(text)
-   return "<rt><p font-size=4> <br></p>" .. h2(text) .. "</rt>"
-end
-
-function p_authors(person, image)
-   return "<rt image=" .. image .. " text-align=left image-align=left><p font-size=12>" .. person .. "</p></rt>"
-end

=== modified file 'data/txts/help/multiplayer_help.lua'
--- data/txts/help/multiplayer_help.lua	2016-03-14 11:37:49 +0000
+++ data/txts/help/multiplayer_help.lua	2016-04-23 13:15:34 +0000
@@ -1,31 +1,28 @@
 include "scripting/formatting.lua"
 
-function picture_li(imagepath, text)
-   return "<rt image=" .. imagepath .. " image-align=left>" .. p(text) .. "</rt>"
-end
-
 return {
    func = function()
-      set_textdomain("texts")
-      local result = rt(h1(_"Multiplayer Game Setup"))
-      result = result .. rt(p(_"You are in the multiplayer launch game menu."))
-
-      result = result .. rt(h2(_"Client settings"))
-      result = result .. rt(p(_"On the left side is a list of all clients including you. You can set your role with the button following your nickname. Available roles are:"))
-      result = result .. picture_li("images/players/genstats_enable_plr_08.png", _"The player with the color of the flag. If more than one client selected the same color, these share control over the player (‘shared kingdom mode’).")
-      result = result .. picture_li("images/wui/fieldaction/menu_tab_watch.png", _"Spectator mode, meaning you can see everything, but cannot control any player")
-
-      result = result .. rt(h2(_"Player settings"))
-      result = result .. rt(p(_"In the middle are the settings for the players. To start a game, each player must be one of the following:"))
-      result = result .. picture_li("images/wui/stats/genstats_nrworkers.png", _"Connected to one or more clients (see ‘Client settings’).")
-      result = result .. picture_li("images/ai/ai_normal.png", _"Connected to a computer player (the face in the picture as well as the mouse hover texts indicate the strength of the currently selected computer player).")
-      result = result .. picture_li("images/ui_fsmenu/shared_in.png", _"Set as shared in starting position for another player.")
-      result = result .. picture_li("images/ui_basic/stop.png", _"Closed.")
-      result = result .. rt(p(_"The latter three can only be set by the hosting client by left-clicking the ‘type’ button of a player. Hosting players can also set the initialization of each player (the set of buildings, wares and workers the player starts with) and the tribe and team for computer players"))
-      result = result .. rt(p(_"Every client connected to a player (who isn’t a spectator) can set the tribe and the team for that player"))
-
-      result = result .. rt(h2(_"Map details"))
-      result = result .. rt(p(_"You can see information about the selected map or savegame on the right-hand side. A button next to the map name allows the host to change to a different map. Furthermore, the host is able to set a specific win condition, and finally can start the game as soon as all players are set up."))
-      return result
+      set_textdomain("widelands")
+      local text_width = 70
+      local result = h1(_"Multiplayer Game Setup")
+      .. p(_"You are in the multiplayer launch game menu.")
+
+      .. h2(_"Client settings")
+      .. p(_"On the left side is a list of all clients including you. You can set your role with the button following your nickname. Available roles are:")
+      .. li_image("images/players/genstats_enable_plr_08.png", text_width, _"The player with the color of the flag. If more than one client selected the same color, these share control over the player (‘shared kingdom mode’).")
+      .. li_image("images/wui/fieldaction/menu_tab_watch.png", text_width, _"Spectator mode, meaning you can see everything, but cannot control any player")
+
+      .. h2(_"Player settings")
+      .. p(_"In the middle are the settings for the players. To start a game, each player must be one of the following:")
+      .. li_image("images/wui/stats/genstats_nrworkers.png", text_width, _"Connected to one or more clients (see ‘Client settings’).")
+      .. li_image("images/ai/ai_normal.png", text_width, _"Connected to a computer player (the face in the picture as well as the mouse hover texts indicate the strength of the currently selected computer player).")
+      .. li_image("images/ui_fsmenu/shared_in.png", text_width, _"Set as shared in starting position for another player.")
+      .. li_image("images/ui_basic/stop.png", text_width, _"Closed.")
+      .. p(_"The latter three can only be set by the hosting client by left-clicking the ‘type’ button of a player. Hosting players can also set the initialization of each player (the set of buildings, wares and workers the player starts with) and the tribe and team for computer players.")
+      .. p(_"Every client connected to a player (who isn’t a spectator) can set the tribe and the team for that player.")
+
+      .. h2(_"Map details")
+      .. p(_"You can see information about the selected map or savegame on the right-hand side. A button next to the map name allows the host to change to a different map. Furthermore, the host is able to set a specific win condition, and finally can start the game as soon as all players are set up.")
+      return rt(result)
    end
 }

=== modified file 'data/txts/translators_data.lua'
--- data/txts/translators_data.lua	2016-04-23 08:17:19 +0000
+++ data/txts/translators_data.lua	2016-04-23 13:15:34 +0000
@@ -1,1 +1,1 @@
-function translators() return {{heading = "العربية (Arabic)",entries = {{members = {"abdXelrhman","m-abudrais","someone",},},},},{heading = "Asturianu (Asturian)",entries = {{members = {"Xuacu Saturio",},},},},{heading = "Български (Bulgarian)",entries = {{members = {"А. Ташев","Любомир Василев",},},},},{heading = "Brezhoneg (Breton)",entries = {{members = {"Iriep (Pierre Morvan)",},},},},{heading = "Català (Catalan)",entries = {{members = {"Guybrush88","Joan Josep","Oriol",},},},},{heading = "Čeština (Czech)",entries = {{members = {"Adam Matoušek","David Spanel","Jens Beyer","Jezevec","Jiří Locker","Konki","Marek Donar (Markus7cz)","Martin Volf","Martin Vecera (Marvec)","MaSo_CZ","Matej Svrcek (prometheus)","Milan Fašina","prom","Vit Hrachovy","Zbyněk Schwarz",},},},},{heading = "Dansk (Danish)",entries = {{members = {"Ask Hjorth Larsen","beer","Daniel Ejsing-Duun","David Lamhauge","Erik Soe Sorensen","Esben Aaberg","hulagutten","Joe Hansen (joedalton)","larsch","Nikolaj Sejergaard","silentStatic","Simon Stubben","Ville Witt",},},},},{heading = "Deutsch (German)",entries = {{members = {"Andreas Breitschopp","Astuur","Benedikt Tröster","Bob Johns","Borim","Clemens Dinkel","Daniel Kutrowatz","Daniel Winzen","Das MC","David Allwicher","DelphiMarkus","Dirk Stöcker","Fenris Wolf","Ferdinand T.","FetteNase","Flames_in_Paradise","fraang","Frank Kubitschek","Gabriel Margiani","Hagen","Hanna Podewski (kristin)","herbert","hurz","Johannes (nuefke)","Johannes Haupt","Kaste","Klappstuhl","Koneu","kraileth","LAZA","LennStar","Macedon","Marc Wischnowsky","Markus Pfitzner (janus)","Martin","Matthias Krüger","Max","meru","Mirian Margiani","MirkoWodtke","Mister Pi","Mr. Anderson","Ole","Peter Schwanemann (Nasenbaer)","Philipp Niemann (Azagtoth)","Provetin","Ralf-J. Block","raymond","ronny","Shevonar","SirVer","Sonnrain","Thomas","Tim O.","Timowi","Tino Miegel (TinoM)","Tobias Margiani","Venatrix","wl-zocker","Wolfgang Kurz","Wolfs","Wuzzy",},},},},{heading = "Ελληνικά (Greek)",entries = {{members = {"ptr","Γιάννης Ανθυμίδης",},},},},{heading = "Canadian English",entries = {{members = {"Ne-1",},},},},{heading = "British English",entries = {{members = {"_aD","Alex Denvir","Andi Chandler","Anthony Harrington","Biffaboy","Heber","Jackson Doak","James Thorrold","Jon Senior","LiSrt","Luis Miguel D.P.","mrx5682","Terry Jones","Tinker","UndiFineD","Vladimir Oka",},},},},{heading = "US American English",entries = {{members = {"DragonAtma",},},},},{heading = "Esperanto",entries = {{members = {"alms21","Fenris Wolf","Ivan Camilo Quintero Santacruz","Jens Beyer","Kristjan SCHMIDT","LaPingvino","Manuel Berkemeier","Michael Moroni",},},},},{heading = "Español (Spanish)",entries = {{members = {"Adolfo Jayme","Agustín Vela","Alberto D.V.","Alejandro Pérez","Antonio Trueba (Fasser)","David Mitos","David Pérez","DiegoJ","Dishito","Eduardo Alberto Calvo","Gerardb","ironfisher","Ivan","Ivan Camilo Quintero Santacruz","Javi Sol","Jonay","Joseph Molina","JoseRoberto","Juan Eduardo Riva","Kiibakun","Luis Miguel D.P.","MadkaT","Martín V.","Miguel adre","Miguel de Dios","Monkey","Pablo Frigerio","Paco Molinero","Paulomorales","pescamillam","Rafael Augusto Maguiña Yrivarren","Rafael Medina","Raul Ferriz","Roberto López","schimmm","simon","Siz","WalterCool","zer berros",},},},},{heading = "Eesti keel (Estonian)",entries = {{members = {"gert7","rm87",},},},},{heading = "Euskara (Basque)",entries = {{members = {"Mikel Alzibar",},},},},{heading = "فارسی (Persian)",entries = {{members = {"katy Zahedi",},},},},{heading = "Suomi (Finnish)",entries = {{members = {"Jari Hautio","Juhani Numminen","Markus Hällfors","Pekka Järvinen (Raspi)","Sampo Harjula","Sini Ruohomaa (Byakushin)","Teppo Mäenpää","Tommi Nirha","Vazde",},},},},{heading = "Français (French)",entries = {{members = {"AGuechoum","AnubiS","Audiger Jeremy","Aurelien Pavel","Benjamin Subtil","Bertram","bouchard renaud","Bruno Veilleux","clark17","crep4ever","David .","El Pensador","Eliovir","Emmanuel Andry (Eandry)","fk","François Rousselet","Gilles Aubert","Guillaume Brant","Guybrush88","Immunoman","Jaypad","Jean-Pierre Gemble","Hanna Podewski (kristin)","londumas","Michael Colignon","Michael DOUBEZ","Mohamed SEDKI","NonoSan","Pierre Rudloff","Sébastien Duthil","Sevy Ride","Tarou","Thomas Jungers","tomtom","Tubuntu","Ubuntu1988","verdy_p","wl-zocker","YS1","Yves MATHIEU",},},},},{heading = "Gàidhlig (Scottish Gaelic)",entries = {{members = {"GunChleoc",},},},},{heading = "Galego (Galician)",entries = {{members = {"Adrián Chaves Fernández","Antonio Trueba (Fasser)","Xosé",},},},},{heading = "עברית (Hebrew)",entries = {{members = {"Danny Albocher","Liel Fridman","Michael DOUBEZ","Solomon Gruber (Piql7)","Yaron",},},},},{heading = "हिन्दी (Hindi)",entries = {{members = {"girdhari rao",},},},},{heading = "Hrvatski (Croatian)",entries = {{members = {"Mario Dautović",},},},},{heading = "Magyar (Hungarian)",entries = {{members = {"cn4ij","Dániel Varga (EuroF)","Ferenc Nagy","Gyönki Bendegúz","HUNStree","István Kiss","jzombi","Kiscsirke","Major Gabesz","Muszela Balázs","Papp Bence","Richard Somlói","Robert Roth","SanskritFritz","Szűcs Kornél Géza",},},},},{heading = "Interlingua",entries = {{members = {"alms21",},},},},{heading = "Bahasa Indonesia (Indonesian)",entries = {{members = {"dadanhrn",},},},},{heading = "Italiano (Italian)",entries = {{members = {"Angelo Locritani","Colin Gibson","DarkSaivor","Davidus","Dom De Felice","Doukas7","Eulogy","Gabriel Rota","Guybrush88","ido","king of nowhere","Loris Turchetti","Oibaf","Pierpaolo Pierozzi","pierusch","Pietro Battiston","Roberto Sciascia","Sergio Spinatelli","sgargel","simone.sandri",},},},},{heading = "日本語 (Japanese)",entries = {{members = {"alms21","Dios","guess880","Midori","SevyRide","tubame",},},},},{heading = "Basa jawa (Javanese)",entries = {{members = {"zaenal arifin",},},},},{heading = "ქართული (Georgian)",entries = {{members = {"Gabriel Margiani","Meyer Konrad",},},},},{heading = "한국어 (Korean)",entries = {{members = {"ddfddf2k",},},},},{heading = "Lingua latīna (Latin)",entries = {{members = {"alms21","lopho","Sonnrain","Stephan Lenk","Thorsten",},},},},{heading = "Lietuvių (Lithuanian)",entries = {{members = {"Mantas Kriaučiūnas",},},},},{heading = "मराठी (Marathi)",entries = {{members = {"Amod Ajit Karmarkar",},},},},{heading = "بهاس ملايو (Malay)",entries = {{members = {"abuyop",},},},},{heading = "မြန်မာစ (Burmese)",entries = {{members = {"pyaehtetaung",},},},},{heading = "Norsk (Bokmål) (Norwegian Bokmål)",entries = {{members = {"Fredrik Sudmann","Hans Joachim Desserud","Magnus Meyer Hustveit","Martin Dahl Moe","mr.x","Thorbjørn Bruarøy",},},},},{heading = "Plattdütsch (Low German)",entries = {{members = {"Mister Pi ","Nasenbaer ","Ole ","tando",},},},},{heading = "Nederlands (Dutch)",entries = {{members = {"BenW","Christian Groenendijk","Dirk Schut","fireprog","fk","Foppe Benedictus","Johan Jonkman (Dikjuh)","Maasieboy","Marcel","megabyte","Patrick van der Leer","Pieter Ouwerkerk (Pietertje)","Pietertje","PliniusNeo","REAL NAME","RickvanderZwet","Rob Snelders (Ertai)","Teun Spaans","Victor Pelt","Wim Champagne",},},},},{heading = "Nynorsk (Norwegian Nynorsk)",entries = {{members = {"Alexander Mackinnon Jansen","Hans Joachim Desserud","Odin Hørthe Omdal","Thorbjørn Bruarøy",},},},},{heading = "Occitan",entries = {{members = {"Cédric VALMARY (Tot en òc)",},},},},{heading = "Polski (Polish)",entries = {{members = {"Andrzej Krentosz (Endrju)","Asahi Koishi","BartekChom","Bartosz Wiśniewski","Gabriel Fortin","Hubert Pluta","Jakub Rak (einstein13)","Januzi (januzi)","Jacek Wolszczak (Shutdownrunner)","Jens Beyer","Karol Sobolewski","Łukasz Chełmicki","Mateusz Micał","Michal Maslanko","Michał Rzepiński","orzeh","Patryk Sawicki","Pawel PErz","Stanisław Gackowski (Soeb)","Szymon Fornal","Szymon Gackowski","Szymon Nieznański","tim","Tomasz Sterna","Wesmania","Wojtek","XeonBloomfield",},},},},{heading = "Português (Portuguese)",entries = {{members = {"Almufadado","daniel reis","David Rodrigues","Flávio J. Saraiva","GunChleoc","Marcelo do Pagode","Miguel de Freitas Fonseca","Tiago Silva","trewe",},},},},{heading = "Português do Brasil (Brazilian Portuguese)",entries = {{members = {"Alexandre","alms21","Almufadado","Cleverton","daniel reis","Fabio Garz","Flaviano Angeli","HicHic","Hriostat","Israel","JoãoPedro BrasãoToledo","Juarez S.","Júlio Cezar Santos Pires","Juno","Luiz N","Maraschin","Marcelo do Pagode","Nicolas Abril","Pedro Pisandelli","Proezas","Rafael Neri","Rayback","Rubens Bueno","Samer Ghosnlas.2932","Tomas Abril","Vitor",},},},},{heading = "Română (Romanian)",entries = {{members = {"Ursachi Alexandru",},},},},{heading = "Русский (Russian)",entries = {{members = {"Александр","Александр Бикмеев (Rombal)","Александр Глухов","Алексей Кабанов","Андрей Кулаков ","Андрей Олыкайнен ","Антон Хабаров (lu)","Виктор Биркманис","Владимир Коваленко","Глеб Синковский","Глория Хрусталёва","Денис Дерябин","Егор Панфилов","Константин Щукин","Никита Шехов","Руслан Ковтун","Сергей Фуканчик ","Юрий Соколов (Urra)","CupIvan","Georgiy","gerich","Izon","KroArtem","Lex","Massol","Papazu","SashaQR","TroubleMakerDV","Vampire Hunter D","Vlad",},},},},{heading = "Kinyarwanda",entries = {{members = {"Nasenbaer",},},},},{heading = "සිංහල (Sinhala)",entries = {{members = {"Samith Sandanayake",},},},},{heading = "Slovenčina (Slovak)",entries = {{members = {"Kefir111","Marek Hám","Miroslav Remák","Vladimir","Vladímir Tóth (Ike)",},},},},{heading = "Slovenski jezik (Slovenian)",entries = {{members = {"Andrej Znidarsic","Boštjan Miklavčič","Jure Repinc","kleb","Klemen Košir","Matevž Jekovec","Matic Gradišer","mrt",},},},},{heading = "српски (Serbian)",entries = {{members = {"Никола Павловић",},},},},{heading = "Svenska (Swedish)",entries = {{members = {"Arve Eriksson","Christian Widell","Daniel Nylander (yeager)","Frederik Pettersson (luno)","ivh","Joakim Lundborg","karlrune","Marcus E","Michael Rydén","Patrick H.","Phoenix","Rasmus Olstedt","RasmusBackman","Sigra","Treecko","Tumaini","Ulite",},},},},{heading = "Türkçe (Turkish)",entries = {{members = {"Asiye","Ekrem Kocadere","Ercin Senturk","Recep Hasanbaş","ScriptMonster","Volkan Gezer",},},},},{heading = "українська мова (Ukranian)",entries = {{members = {"Fedik","Shemet Yevhene","Сергій Дубик",},},},},{heading = "Tiếng Việt (Vietnamese)",entries = {{members = {"Nguyen Quang Chien",},},},},{heading = "简体中文 (Simplified Chinese)",entries = {{members = {"luojie-dune","XIA",},},},},{heading = "繁體中文 (Traditional Chinese)",entries = {{members = {"AJ","poormusic","sonny",},},},},} end
+function translators() return {{heading = "العربية",sortname = "Al-ʿArabiyyah",entries = {{members = {"abdXelrhman","m-abudrais","someone",},},},},{heading = "Asturianu",sortname = "Asturianu",entries = {{members = {"Xuacu Saturio",},},},},{heading = "Български",sortname = "Balgarski",entries = {{members = {"А. Ташев","Любомир Василев",},},},},{heading = "Brezhoneg",sortname = "Brezhoneg",entries = {{members = {"Iriep (Pierre Morvan)",},},},},{heading = "Català",sortname = "Catala",entries = {{members = {"Guybrush88","Joan Josep","Oriol",},},},},{heading = "Čeština",sortname = "Cestina",entries = {{members = {"Adam Matoušek","David Spanel","Jens Beyer","Jezevec","Jiří Locker","Konki","Marek Donar (Markus7cz)","Martin Volf","Martin Vecera (Marvec)","MaSo_CZ","Matej Svrcek (prometheus)","Milan Fašina","prom","Vit Hrachovy","Zbyněk Schwarz",},},},},{heading = "Dansk",sortname = "Dansk",entries = {{members = {"Ask Hjorth Larsen","beer","Daniel Ejsing-Duun","David Lamhauge","Erik Soe Sorensen","Esben Aaberg","hulagutten","Joe Hansen (joedalton)","larsch","Nikolaj Sejergaard","silentStatic","Simon Stubben","Ville Witt",},},},},{heading = "Deutsch",sortname = "Deutsch",entries = {{members = {"Andreas Breitschopp","Astuur","Benedikt Tröster","Bob Johns","Borim","Clemens Dinkel","Daniel Kutrowatz","Daniel Winzen","Das MC","David Allwicher","DelphiMarkus","Dirk Stöcker","Fenris Wolf","Ferdinand T.","FetteNase","Flames_in_Paradise","fraang","Frank Kubitschek","Gabriel Margiani","Hagen","Hanna Podewski (kristin)","herbert","hurz","Johannes (nuefke)","Johannes Haupt","Kaste","Klappstuhl","Koneu","kraileth","LAZA","LennStar","Macedon","Marc Wischnowsky","Markus Pfitzner (janus)","Martin","Matthias Krüger","Max","meru","Mirian Margiani","MirkoWodtke","Mister Pi","Mr. Anderson","Ole","Peter Schwanemann (Nasenbaer)","Philipp Niemann (Azagtoth)","Provetin","Ralf-J. Block","raymond","ronny","Shevonar","SirVer","Sonnrain","Thomas","Tim O.","Timowi","Tino Miegel (TinoM)","Tobias Margiani","Venatrix","wl-zocker","Wolfgang Kurz","Wolfs","Wuzzy",},},},},{heading = "Ελληνικά",sortname = "Ellinika",entries = {{members = {"ptr","Γιάννης Ανθυμίδης",},},},},{heading = "Canadian English",sortname = "English (Canada)",entries = {{members = {"Ne-1",},},},},{heading = "British English",sortname = "English (Great Britain)",entries = {{members = {"_aD","Alex Denvir","Andi Chandler","Anthony Harrington","Biffaboy","Heber","Jackson Doak","James Thorrold","Jon Senior","LiSrt","Luis Miguel D.P.","mrx5682","Terry Jones","Tinker","UndiFineD","Vladimir Oka",},},},},{heading = "US American English",sortname = "English (USA)",entries = {{members = {"DragonAtma",},},},},{heading = "Esperanto",sortname = "Esperanto",entries = {{members = {"alms21","Fenris Wolf","Ivan Camilo Quintero Santacruz","Jens Beyer","Kristjan SCHMIDT","LaPingvino","Manuel Berkemeier","Michael Moroni",},},},},{heading = "Español",sortname = "Espanol",entries = {{members = {"Adolfo Jayme","Agustín Vela","Alberto D.V.","Alejandro Pérez","Antonio Trueba (Fasser)","David Mitos","David Pérez","DiegoJ","Dishito","Eduardo Alberto Calvo","Gerardb","ironfisher","Ivan","Ivan Camilo Quintero Santacruz","Javi Sol","Jonay","Joseph Molina","JoseRoberto","Juan Eduardo Riva","Kiibakun","Luis Miguel D.P.","MadkaT","Martín V.","Miguel adre","Miguel de Dios","Monkey","Pablo Frigerio","Paco Molinero","Paulomorales","pescamillam","Rafael Augusto Maguiña Yrivarren","Rafael Medina","Raul Ferriz","Roberto López","schimmm","simon","Siz","WalterCool","zer berros",},},},},{heading = "Eesti keel",sortname = "Eesti keel",entries = {{members = {"gert7","rm87",},},},},{heading = "Euskara",sortname = "Euskara",entries = {{members = {"Mikel Alzibar",},},},},{heading = "فارسی",sortname = "Farsi",entries = {{members = {"katy Zahedi",},},},},{heading = "Suomi",sortname = "Suomi",entries = {{members = {"Jari Hautio","Juhani Numminen","Markus Hällfors","Pekka Järvinen (Raspi)","Sampo Harjula","Sini Ruohomaa (Byakushin)","Teppo Mäenpää","Tommi Nirha","Vazde",},},},},{heading = "Français",sortname = "Francais",entries = {{members = {"AGuechoum","AnubiS","Audiger Jeremy","Aurelien Pavel","Benjamin Subtil","Bertram","bouchard renaud","Bruno Veilleux","clark17","crep4ever","David .","El Pensador","Eliovir","Emmanuel Andry (Eandry)","fk","François Rousselet","Gilles Aubert","Guillaume Brant","Guybrush88","Immunoman","Jaypad","Jean-Pierre Gemble","Hanna Podewski (kristin)","londumas","Michael Colignon","Michael DOUBEZ","Mohamed SEDKI","NonoSan","Pierre Rudloff","Sébastien Duthil","Sevy Ride","Tarou","Thomas Jungers","tomtom","Tubuntu","Ubuntu1988","verdy_p","wl-zocker","YS1","Yves MATHIEU",},},},},{heading = "Gàidhlig",sortname = "Gaidhlig",entries = {{members = {"GunChleoc",},},},},{heading = "Galego",sortname = "Galego",entries = {{members = {"Adrián Chaves Fernández","Antonio Trueba (Fasser)","Xosé",},},},},{heading = "עברית",sortname = "Ivrit",entries = {{members = {"Danny Albocher","Liel Fridman","Michael DOUBEZ","Solomon Gruber (Piql7)","Yaron",},},},},{heading = "हिन्दी",sortname = "Hindi",entries = {{members = {"girdhari rao",},},},},{heading = "Hrvatski",sortname = "Hrvatski",entries = {{members = {"Mario Dautović",},},},},{heading = "Magyar",sortname = "Magyar",entries = {{members = {"cn4ij","Dániel Varga (EuroF)","Ferenc Nagy","Gyönki Bendegúz","HUNStree","István Kiss","jzombi","Kiscsirke","Major Gabesz","Muszela Balázs","Papp Bence","Richard Somlói","Robert Roth","SanskritFritz","Szűcs Kornél Géza",},},},},{heading = "Interlingua",sortname = "Interlingua",entries = {{members = {"alms21",},},},},{heading = "Bahasa Indonesia",sortname = "Indonesia",entries = {{members = {"dadanhrn",},},},},{heading = "Italiano",sortname = "Italiano",entries = {{members = {"Angelo Locritani","Colin Gibson","DarkSaivor","Davidus","Dom De Felice","Doukas7","Eulogy","Gabriel Rota","Guybrush88","ido","king of nowhere","Loris Turchetti","Oibaf","Pierpaolo Pierozzi","pierusch","Pietro Battiston","Roberto Sciascia","Sergio Spinatelli","sgargel","simone.sandri",},},},},{heading = "日本語",sortname = "Nihongo",entries = {{members = {"alms21","Dios","guess880","Midori","SevyRide","tubame",},},},},{heading = "Basa jawa",sortname = "Jawa",entries = {{members = {"zaenal arifin",},},},},{heading = "ქართული",sortname = "Kartuli",entries = {{members = {"Gabriel Margiani","Meyer Konrad",},},},},{heading = "한국어",sortname = "Hangug-eo",entries = {{members = {"ddfddf2k",},},},},{heading = "Lingua latīna",sortname = "Latina",entries = {{members = {"alms21","lopho","Sonnrain","Stephan Lenk","Thorsten",},},},},{heading = "Lietuvių",sortname = "Lietuviu",entries = {{members = {"Mantas Kriaučiūnas",},},},},{heading = "मराठी",sortname = "Marathi",entries = {{members = {"Amod Ajit Karmarkar",},},},},{heading = "بهاس ملايو",sortname = "Melayu",entries = {{members = {"abuyop",},},},},{heading = "မြန်မာစ",sortname = "Myanma",entries = {{members = {"pyaehtetaung",},},},},{heading = "Norsk (Bokmål)",sortname = "Norsk (Bokmal)",entries = {{members = {"Fredrik Sudmann","Hans Joachim Desserud","Magnus Meyer Hustveit","Martin Dahl Moe","mr.x","Thorbjørn Bruarøy",},},},},{heading = "Plattdütsch",sortname = "Plattdutsch",entries = {{members = {"Mister Pi ","Nasenbaer ","Ole ","tando",},},},},{heading = "Nederlands",sortname = "Nederlands",entries = {{members = {"BenW","Christian Groenendijk","Dirk Schut","fireprog","fk","Foppe Benedictus","Johan Jonkman (Dikjuh)","Maasieboy","Marcel","megabyte","Patrick van der Leer","Pieter Ouwerkerk (Pietertje)","Pietertje","PliniusNeo","REAL NAME","RickvanderZwet","Rob Snelders (Ertai)","Teun Spaans","Victor Pelt","Wim Champagne",},},},},{heading = "Nynorsk",sortname = "Norsk (Nynorsk)",entries = {{members = {"Alexander Mackinnon Jansen","Hans Joachim Desserud","Odin Hørthe Omdal","Thorbjørn Bruarøy",},},},},{heading = "Occitan",sortname = "Occitan",entries = {{members = {"Cédric VALMARY (Tot en òc)",},},},},{heading = "Polski",sortname = "Polski",entries = {{members = {"Andrzej Krentosz (Endrju)","Asahi Koishi","BartekChom","Bartosz Wiśniewski","Gabriel Fortin","Hubert Pluta","Jakub Rak (einstein13)","Januzi (januzi)","Jacek Wolszczak (Shutdownrunner)","Jens Beyer","Karol Sobolewski","Łukasz Chełmicki","Mateusz Micał","Michal Maslanko","Michał Rzepiński","orzeh","Patryk Sawicki","Pawel PErz","Stanisław Gackowski (Soeb)","Szymon Fornal","Szymon Gackowski","Szymon Nieznański","tim","Tomasz Sterna","Wesmania","Wojtek","XeonBloomfield",},},},},{heading = "Português",sortname = "Portugues",entries = {{members = {"Almufadado","daniel reis","David Rodrigues","Flávio J. Saraiva","GunChleoc","Marcelo do Pagode","Miguel de Freitas Fonseca","Tiago Silva","trewe",},},},},{heading = "Português do Brasil",sortname = "Portugues (Brasil)",entries = {{members = {"Alexandre","alms21","Almufadado","Cleverton","daniel reis","Fabio Garz","Flaviano Angeli","HicHic","Hriostat","Israel","JoãoPedro BrasãoToledo","Juarez S.","Júlio Cezar Santos Pires","Juno","Luiz N","Maraschin","Marcelo do Pagode","Nicolas Abril","Pedro Pisandelli","Proezas","Rafael Neri","Rayback","Rubens Bueno","Samer Ghosnlas.2932","Tomas Abril","Vitor",},},},},{heading = "Română",sortname = "Romana",entries = {{members = {"Ursachi Alexandru",},},},},{heading = "Русский",sortname = "Russky",entries = {{members = {"Александр","Александр Бикмеев (Rombal)","Александр Глухов","Алексей Кабанов","Андрей Кулаков ","Андрей Олыкайнен ","Антон Хабаров (lu)","Виктор Биркманис","Владимир Коваленко","Глеб Синковский","Глория Хрусталёва","Денис Дерябин","Егор Панфилов","Константин Щукин","Никита Шехов","Руслан Ковтун","Сергей Фуканчик ","Юрий Соколов (Urra)","CupIvan","Georgiy","gerich","Izon","KroArtem","Lex","Massol","Papazu","SashaQR","TroubleMakerDV","Vampire Hunter D","Vlad",},},},},{heading = "Kinyarwanda",sortname = "Kinyarwanda",entries = {{members = {"Nasenbaer",},},},},{heading = "සිංහල",sortname = "Simhala",entries = {{members = {"Samith Sandanayake",},},},},{heading = "Slovenčina",sortname = "Slovencina",entries = {{members = {"Kefir111","Marek Hám","Miroslav Remák","Vladimir","Vladímir Tóth (Ike)",},},},},{heading = "Slovenski jezik",sortname = "Slovenski",entries = {{members = {"Andrej Znidarsic","Boštjan Miklavčič","Jure Repinc","kleb","Klemen Košir","Matevž Jekovec","Matic Gradišer","mrt",},},},},{heading = "српски",sortname = "Srpski",entries = {{members = {"Никола Павловић",},},},},{heading = "Svenska",sortname = "Svenska",entries = {{members = {"Arve Eriksson","Christian Widell","Daniel Nylander (yeager)","Frederik Pettersson (luno)","ivh","Joakim Lundborg","karlrune","Marcus E","Michael Rydén","Patrick H.","Phoenix","Rasmus Olstedt","RasmusBackman","Sigra","Treecko","Tumaini","Ulite",},},},},{heading = "Türkçe",sortname = "Turkce",entries = {{members = {"Asiye","Ekrem Kocadere","Ercin Senturk","Recep Hasanbaş","ScriptMonster","Volkan Gezer",},},},},{heading = "українська мова",sortname = "Ukrayinska",entries = {{members = {"Fedik","Shemet Yevhene","Сергій Дубик",},},},},{heading = "Tiếng Việt",sortname = "Viet",entries = {{members = {"Nguyen Quang Chien",},},},},{heading = "简体中文",sortname = "Jianti Zhongwen",entries = {{members = {"luojie-dune","XIA",},},},},{heading = "繁體中文",sortname = "Fanti Zhongwen",entries = {{members = {"AJ","poormusic","sonny",},},},},} end

=== modified file 'doc/sphinx/source/wlrichtext.rst'
--- doc/sphinx/source/wlrichtext.rst	2016-01-28 05:24:34 +0000
+++ doc/sphinx/source/wlrichtext.rst	2016-04-23 13:15:34 +0000
@@ -1,6 +1,8 @@
 The Widelands Rich Text System
 ==============================
 
+NOCOM(#gunchleoc): Update this documentation when we're finished.
+
 All texts that can be displayed to the user can be formatted to be layouted
 and nicely formatted. This allows for changing of font sizes, weights, colors
 and for the embedding of images. This documents how to format a string to be
@@ -24,7 +26,7 @@
 Starts or ends a rich text. Must be the first tag to appear in the string.
 A full example would be::
 
-   <rt image=map:khanktrukh.png><p line-spacing=3 font-size=12>Hello<br>World</p></rt>
+   <rt image=map:khanktrukh.png><p line-spacing=3 font-size=12>Hello World</p></rt>
 
 This would instruct widelands to use the image of Khankruth that comes with
 the map, left align it. To the right of it there would be two lines of text.
@@ -84,11 +86,7 @@
 line-spacing
    Line spacing in points. Default is 0.
 
-``<br>``
-^^^^^^^^
 
-This inserts a line break into the text. The line break character (``\n``) is
-ignored inside a rich text.
 
 Real world Lua example
 ----------------------
@@ -105,7 +103,7 @@
       "<p font-weight=bold font-decoration=underline font-style=italic font-size=24>" ..
          "YOU so rock dude!" ..
       "</p></rt>" ..
-      "<rt><p>No. I really mean this.<br><br>Seriously.</p></rt>",
+      "<rt><p>No. I really mean this. Seriously.</p></rt>",
       { popup = true }
    )
 

=== modified file 'src/editor/ui_menus/tool_change_resources_options_menu.cc'
--- src/editor/ui_menus/tool_change_resources_options_menu.cc	2016-04-11 06:45:29 +0000
+++ src/editor/ui_menus/tool_change_resources_options_menu.cc	2016-04-23 13:15:34 +0000
@@ -95,7 +95,7 @@
 		radiogroup_.add_button
 				(&resources_box_,
 				 Point(0, 0),
-				 g_gr->images().get(resource.representative_image()),
+				 g_gr->images().get(resource.representative_image_filename()),
 				 resource.descname());
 		resources_box_.add(radiogroup_.get_first_button(), UI::Align::kLeft, false, true);
 	}

=== modified file 'src/graphic/CMakeLists.txt'
--- src/graphic/CMakeLists.txt	2016-02-19 19:10:44 +0000
+++ src/graphic/CMakeLists.txt	2016-04-23 13:15:34 +0000
@@ -225,18 +225,12 @@
     diranimations.h
     font.cc
     font.h
-    font_handler.cc
-    font_handler.h
     font_handler1.cc
     font_handler1.h
     graphic.cc
     graphic.h
     rendertarget.cc
     rendertarget.h
-    richtext.cc
-    richtext.h
-    text_parser.cc
-    text_parser.h
     wordwrap.cc
     wordwrap.h
   USES_OPENGL

=== modified file 'src/graphic/font.cc'
--- src/graphic/font.cc	2016-03-14 19:49:52 +0000
+++ src/graphic/font.cc	2016-04-23 13:15:34 +0000
@@ -24,7 +24,6 @@
 #include "base/utf8.h"
 #include "graphic/font_handler1.h" // We need the fontset for the size offset
 #include "graphic/text/font_set.h"
-#include "graphic/text_constants.h"
 #include "io/filesystem/layered_filesystem.h"
 
 namespace {

=== removed file 'src/graphic/font_handler.cc'
--- src/graphic/font_handler.cc	2016-01-28 05:24:34 +0000
+++ src/graphic/font_handler.cc	1970-01-01 00:00:00 +0000
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2002-2011 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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.
- *
- * Some Methods taken from Wesnoth.
- * http://www.wesnoth.org
- */
-
-#include "graphic/font_handler.h"
-
-#include <list>
-#include <memory>
-
-#include <SDL_ttf.h>
-#include <boost/algorithm/string.hpp>
-#include <boost/format.hpp>
-
-#include "base/log.h"
-#include "base/wexception.h"
-#include "graphic/font_handler1.h" // We need the fontset for the BiDi algorithm
-#include "graphic/graphic.h"
-#include "graphic/rendertarget.h"
-#include "graphic/text/bidi.h"
-#include "graphic/texture.h"
-#include "graphic/wordwrap.h"
-
-namespace UI {
-
-namespace  {
-/**
- * Draw the caret for the given text rendered exactly at the given point
- * (including \ref LINE_MARGIN).
- */
-void draw_caret
-	(RenderTarget & dst,
-	 const TextStyle & style,
-	 const Point& dstpoint,
-	 const std::string & text,
-	 uint32_t caret_offset)
-{
-	int caret_x = style.calc_bare_width(text.substr(0, caret_offset));
-
-	const Image* caret_image = g_gr->images().get("images/ui_basic/caret.png");
-	Point caretpt;
-	caretpt.x = dstpoint.x + caret_x + LINE_MARGIN - caret_image->width();
-	caretpt.y = dstpoint.y + (style.font->height() - caret_image->height()) / 2;
-
-	dst.blit(caretpt, caret_image);
-}
-
-}  // namespace
-
-/// The global unique \ref FontHandler object
-FontHandler * g_fh = nullptr;
-
-/**
- * The line cache stores unprocessed rendered lines of text.
- */
-struct LineCacheEntry {
-	/*@{*/
-	TextStyle style;
-	std::string text;
-	/*@}*/
-
-	/*@{*/
-	std::unique_ptr<const Image> image;
-	uint32_t width;
-	uint32_t height;
-	/*@}*/
-};
-
-using LineCache = std::list<LineCacheEntry>;
-
-static const unsigned MaxLineCacheSize = 500;
-
-/**
- * Internal data of the \ref FontHandler.
- */
-struct FontHandler::Data {
-	LineCache linecache;
-
-	const LineCacheEntry & get_line(const TextStyle & style, const std::string & text);
-
-	~Data() {
-		while (!linecache.empty()) {
-			linecache.pop_back();
-		}
-	}
-
-private:
-	void render_line(LineCacheEntry & lce);
-};
-
-/**
- * Plain Constructor
- */
-FontHandler::FontHandler() :
-	d(new Data)
-{
-}
-
-
-FontHandler::~FontHandler() {
-	flush();
-	Font::shutdown();
-}
-
-void FontHandler::flush() {
-	d.reset(new Data);
-}
-
-/*
- * Returns the height of the font, in pixels.
-*/
-uint32_t FontHandler::get_fontheight
-	(const std::string & name, int32_t const size)
-{
-	TTF_Font * const f = Font::get(name, size)->get_ttf_font();
-	const int32_t fontheight = TTF_FontHeight(f);
-	if (fontheight < 0)
-		throw wexception
-			("TTF_FontHeight returned a negative value, which does not have a "
-			 "known meaning.");
-	return fontheight;
-}
-
-/**
- * Get a cache entry for the given text (without linebreaks!) rendered
- * in the given style.
- *
- * If there is no pre-existing cache entry, a new one is created.
- */
-const LineCacheEntry & FontHandler::Data::get_line(const UI::TextStyle & style, const std::string & text)
-{
-	for (LineCache::iterator it = linecache.begin(); it != linecache.end(); ++it) {
-		if (it->style != style || it->text != text)
-			continue;
-
-		// Found a hit, move to front
-		if (it != linecache.begin())
-			linecache.splice(linecache.begin(), linecache, it);
-		return *it;
-	}
-
-	// Cache miss; render a new image.
-	LineCache::iterator it = linecache.insert(linecache.begin(), LineCacheEntry());
-	it->style = style;
-	it->text = text;
-	it->image = nullptr;
-	render_line(*it);
-
-	while (linecache.size() > MaxLineCacheSize) {
-		linecache.pop_back();
-	}
-
-	return *it;
-}
-
-/**
- * Render the image of a \ref LineCacheEntry whose key data has
- * already been filled in.
- */
-void FontHandler::Data::render_line(LineCacheEntry & lce)
-{
-	TTF_Font * font = lce.style.font->get_ttf_font();
-	SDL_Color sdl_fg = {lce.style.fg.r, lce.style.fg.g, lce.style.fg.b, SDL_ALPHA_OPAQUE};
-	std::string renderme = i18n::make_ligatures(lce.text.c_str());
-
-	if (i18n::has_rtl_character(lce.text.c_str())) {
-		renderme = i18n::line2bidi(renderme.c_str());
-	}
-
-	// Work around an Issue in SDL_TTF that dies when the surface
-	// has zero width
-	int width = 0;
-	if (TTF_SizeUTF8(font, renderme.c_str(), &width, nullptr) < 0 || !width) {
-		lce.width = 0;
-		lce.height = TTF_FontHeight(font);
-		return;
-	}
-
-	lce.style.setup();
-
-	SDL_Surface* text_surface = TTF_RenderUTF8_Blended(font, renderme.c_str(), sdl_fg);
-	if (!text_surface) {
-		log
-			("FontHandler::render_line, an error : %s\n",
-			 TTF_GetError());
-		log("Text was: '%s'\n", renderme.c_str());
-		return;
-	}
-
-	lce.image.reset(new Texture(text_surface));
-	lce.width = lce.image->width();
-	lce.height = lce.image->height();
-}
-
-/**
- * Draw unwrapped, single-line text (i.e. no line breaks).
- */
-void FontHandler::draw_text
-	(RenderTarget & dst,
-	 const TextStyle & style,
-	 Point dstpoint,
-	 const std::string & text,
-	 Align align,
-	 uint32_t caret)
-{
-	// Erase every backslash in front of brackets
-	std::string copytext = boost::replace_all_copy(text, "\\<", "<");
-	boost::replace_all(copytext, "\\>", ">");
-	copytext = i18n::make_ligatures(copytext.c_str());
-	const LineCacheEntry & lce = d->get_line(style, copytext);
-
-	UI::correct_for_align(align, lce.width + 2 * LINE_MARGIN, lce.height, &dstpoint);
-
-	if (lce.image)
-		dst.blit(Point(dstpoint.x + LINE_MARGIN, dstpoint.y), lce.image.get());
-
-	if (caret <= copytext.size())
-		draw_caret(dst, style, dstpoint, copytext, caret);
-}
-
-/**
- * Draw unwrapped, un-aligned single-line text at the given point, and return the width of the text.
- */
-uint32_t FontHandler::draw_text_raw
-	(RenderTarget & dst,
-	 const UI::TextStyle & style,
-	 Point dstpoint,
-	 const std::string & text)
-{
-	const LineCacheEntry & lce = d->get_line(style, text);
-
-	if (lce.image)
-		dst.blit(dstpoint, lce.image.get());
-
-	return lce.width;
-}
-
-
-/**
- * Compute the total size of the given text, when wrapped to the given
- * maximum width and rendered in the given text style.
- */
-void FontHandler::get_size
-	(const TextStyle & textstyle,
-	 const std::string & text,
-	 uint32_t & w, uint32_t & h,
-	 uint32_t wrap)
-{
-	WordWrap ww(textstyle, wrap);
-	ww.wrap(text);
-	w = ww.width();
-	h = ww.height();
-}
-
-/**
- * Calculates size of a given text.
- */
-void FontHandler::get_size
-	(const std::string & fontname, int32_t const fontsize,
-	 const std::string & text,
-	 uint32_t & w, uint32_t & h,
-	 uint32_t const wrap)
-{
-	// use bold style by default for historical reasons
-	get_size(TextStyle::makebold(Font::get(fontname, fontsize), RGBColor(255, 255, 255)), text, w, h, wrap);
-}
-
-} // namespace UI

=== removed file 'src/graphic/font_handler.h'
--- src/graphic/font_handler.h	2015-12-17 09:36:59 +0000
+++ src/graphic/font_handler.h	1970-01-01 00:00:00 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2002-2004, 2006-2011 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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 WL_GRAPHIC_FONT_HANDLER_H
-#define WL_GRAPHIC_FONT_HANDLER_H
-
-#include <limits>
-#include <memory>
-#include <string>
-
-#include "graphic/align.h"
-#include "base/point.h"
-
-class RenderTarget;
-
-namespace UI {
-
-struct TextStyle;
-
-/**
- * Main class for string rendering. Manages the cache of pre-rendered strings.
- */
-struct FontHandler {
-	FontHandler();
-	~FontHandler();
-
-	void draw_text
-		(RenderTarget &,
-		 const TextStyle &,
-		 Point dstpoint,
-		 const std::string & text,
-		 Align align = UI::Align::kCenterLeft,
-		 uint32_t caret = std::numeric_limits<uint32_t>::max());
-	uint32_t draw_text_raw(RenderTarget &, const TextStyle &, Point dstpoint, const std::string & text);
-
-	void get_size
-		(const TextStyle &,
-		 const std::string & text,
-		 uint32_t & w, uint32_t & h,
-		 uint32_t wrap = std::numeric_limits<uint32_t>::max());
-	void get_size
-		(const std::string & fontname, int32_t size,
-		 const std::string & text,
-		 uint32_t & w, uint32_t & h,
-		 uint32_t wrap = std::numeric_limits<uint32_t>::max());
-	uint32_t get_fontheight(const std::string & name, int32_t size);
-
-	// Delete the whole cache.
-	void flush();
-
-private:
-	struct Data;
-	std::unique_ptr<Data> d;
-};
-
-extern FontHandler * g_fh;
-
-}
-
-#endif  // end of include guard: WL_GRAPHIC_FONT_HANDLER_H

=== modified file 'src/graphic/font_handler1.cc'
--- src/graphic/font_handler1.cc	2016-02-03 22:42:34 +0000
+++ src/graphic/font_handler1.cc	2016-04-23 13:15:34 +0000
@@ -52,6 +52,7 @@
 // 30 MB was enough to cache texts for many frames (> 1000), while it is
 // quickly overflowing in the map selection menu.
 // This might need reevaluation is the new font handler is used for more stuff.
+// NOCOM(GunChleoc): review this
 const uint32_t RICHTEXT_TEXTURE_CACHE = 30 << 20;   // shifting converts to MB
 
 // An Image implementation that recreates a rich text texture when needed on
@@ -98,7 +99,7 @@
 	TextureCache* const texture_cache_;
 };
 
-}
+} // namespace
 
 namespace UI {
 

=== modified file 'src/graphic/graphic.cc'
--- src/graphic/graphic.cc	2016-04-20 09:54:55 +0000
+++ src/graphic/graphic.cc	2016-04-23 13:15:34 +0000
@@ -29,7 +29,6 @@
 #include "graphic/animation.h"
 #include "graphic/build_texture_atlas.h"
 #include "graphic/font.h"
-#include "graphic/font_handler.h"
 #include "graphic/font_handler1.h"
 #include "graphic/gl/initialize.h"
 #include "graphic/gl/system_headers.h"
@@ -122,10 +121,6 @@
 
 Graphic::~Graphic()
 {
-	// TODO(unknown): this should really not be needed, but currently is :(
-	if (UI::g_fh)
-		UI::g_fh->flush();
-
 	if (sdl_window_) {
 		SDL_DestroyWindow(sdl_window_);
 		sdl_window_ = nullptr;

=== removed file 'src/graphic/richtext.cc'
--- src/graphic/richtext.cc	2016-03-30 08:38:59 +0000
+++ src/graphic/richtext.cc	1970-01-01 00:00:00 +0000
@@ -1,530 +0,0 @@
-/*
- * Copyright (C) 2002-2011 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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 "graphic/richtext.h"
-
-#include "base/rect.h"
-#include "graphic/font.h"
-#include "graphic/font_handler.h"
-#include "graphic/font_handler1.h" // Needed for fontset's direction
-#include "graphic/graphic.h"
-#include "graphic/image.h"
-#include "graphic/rendertarget.h"
-#include "graphic/text/bidi.h"
-#include "graphic/text_layout.h"
-#include "graphic/text_parser.h"
-
-namespace UI {
-
-namespace {
-int32_t const h_space = 3;
-} // namespace
-
-/**
- * Layouted rich text is essentially a bunch of drawable elements, each with a
- * rectangular bounding box.
- */
-struct Element {
-	explicit Element(const Rect & bounding_box) : bbox(bounding_box) {}
-	virtual ~Element() {}
-
-	/**
-	 * Draw the element, assuming that @p dst is already set up to be
-	 * relative to the element's internal frame of reference.
-	 */
-	virtual void draw(RenderTarget & dst) = 0;
-
-	Rect bbox;
-};
-
-struct ImageElement : Element {
-	ImageElement(const Rect & bounding_box, const Image* init_image)
-		: Element(bounding_box), image(init_image) {}
-
-	void draw(RenderTarget & dst) override
-	{
-		dst.blit(Point(0, 0), image);
-	}
-
-	const Image* image;
-};
-
-struct TextlineElement : Element {
-	TextlineElement
-		(const Rect & bounding_box, const TextStyle & init_style,
-		 std::vector<std::string>::const_iterator words_begin,
-		 std::vector<std::string>::const_iterator words_end)
-		: Element(bounding_box), style(init_style), words(words_begin, words_end) {}
-
-	void draw(RenderTarget & dst) override
-	{
-		assert(words.size());
-		uint32_t spacewidth = style.calc_bare_width(" ");
-
-		std::vector<std::string> result_words;
-		std::vector<std::string>::iterator it = result_words.begin();
-
-		// Reorder words for BiDi
-		if (UI::g_fh1->fontset()->is_rtl() && i18n::has_rtl_character(words)) {
-			std::string previous_word;
-			for (std::vector<std::string>::iterator source_it = words.begin();
-				  source_it != words.end(); ++source_it) {
-				std::string& word = *source_it;
-				if (source_it != words.end()) {
-					if (i18n::has_rtl_character(word.c_str()) || i18n::has_rtl_character(previous_word.c_str())) {
-						it = result_words.insert(result_words.begin(), word);
-					} else { // Sequences of Latin words go to the right from current position
-						if (it < result_words.end()) {
-							++it;
-						}
-						it = result_words.insert(it, word);
-					}
-					previous_word = word;
-				}
-			}
-		} else {
-			for (std::string& word: words) {
-				result_words.push_back(word);
-			}
-		}
-		// Now render
-		uint32_t x = g_fh->draw_text_raw(dst, style, Point(0, 0), result_words[0]);
-
-		it = result_words.begin() + 1;
-		if (it != result_words.end()) {
-			do {
-				if (style.underline)
-					x += g_fh->draw_text_raw(dst, style, Point(x, 0), " ");
-				else
-					x += spacewidth;
-				x += g_fh->draw_text_raw(dst, style, Point(x, 0), *it++);
-			} while (it != result_words.end());
-		}
-	}
-
-	TextStyle style;
-	std::vector<std::string> words;
-};
-
-struct RichTextImpl {
-	/// Solid background color for all elements
-	RGBColor background_color;
-
-	/// Layouted elements
-	std::vector<Element *> elements;
-
-	/// Width of the rich-text area, controlled by the user of the
-	/// rich-text field
-	uint32_t width;
-
-	/// Height of parsed rich-text area, determined by layouting
-	uint32_t height;
-
-	RichTextImpl();
-	~RichTextImpl();
-
-	void clear();
-};
-
-RichText::RichText()
-	: m(new RichTextImpl)
-{
-}
-
-RichText::~RichText()
-{
-}
-
-RichTextImpl::RichTextImpl()
-:
-background_color(0, 0, 0)
-{
-	width = 0;
-	height = 0;
-}
-
-RichTextImpl::~RichTextImpl()
-{
-	clear();
-}
-
-/**
- * Reset all layouting data.
- */
-void RichTextImpl::clear()
-{
-	while (!elements.empty()) {
-		delete elements.back();
-		elements.pop_back();
-	}
-
-	height = 0;
-}
-
-/**
- * Set the width for the rich text field.
- * Default width is undefined. This must be called before @ref parse.
- */
-void RichText::set_width(uint32_t gwidth)
-{
-	m->width = gwidth;
-}
-
-/**
- * Set a solid background color that is used by @ref draw when a
- * solid background is requested.
- */
-void RichText::set_background_color(RGBColor color)
-{
-	m->background_color = color;
-}
-
-/**
- * @return the width of the rich text field, set by @ref set_width
- */
-uint32_t RichText::width()
-{
-	return m->width;
-}
-
-/**
- * @return the actual total height of layouted rich text, computed by @ref parse
- */
-uint32_t RichText::height()
-{
-	return m->height;
-}
-
-struct TextBuilder {
-	RichTextImpl & rti;
-
-	/// Current richtext block
-	std::vector<RichtextBlock>::iterator richtext;
-
-	/// Extent of images in the current richtext block
-	/*@{*/
-	uint32_t images_width;
-	uint32_t images_height;
-	/*@}*/
-
-	/// Maximum width, in pixels, for current line of text
-	uint32_t maxwidth;
-
-	/// y-coordinate of top of current line of text
-	uint32_t text_y;
-
-	/// Width of the current line, in pixels
-	uint32_t linewidth;
-
-	/// Current text block
-	std::vector<TextBlock>::const_iterator textblock;
-	TextStyle style;
-	uint32_t spacewidth;
-	uint32_t linespacing;
-
-	struct Elt {
-		TextlineElement * element;
-		int32_t miny, maxy;
-	};
-
-	/// Elements in the current line (also already added to the full richtext list
-	/// of elements, but we keep this around to store miny/maxy data to adjust all
-	/// parts of a line onto the same text baseline).
-	std::vector<Elt> elements;
-
-	TextBuilder(RichTextImpl & impl) :
-		rti(impl),
-		images_width(0),
-		images_height(0),
-		maxwidth(0),
-		text_y(0),
-		linewidth(0),
-		spacewidth(0),
-		linespacing(0)
-	{}
-
-	/**
-	 * Update data that is specific to the current @ref textblock.
-	 */
-	void reset_block()
-	{
-		style.font = Font::get(textblock->get_font_face(), textblock->get_font_size());
-		style.fg = textblock->get_font_color();
-
-		style.bold = textblock->get_font_weight() == "bold";
-		style.italics = textblock->get_font_style() == "italic";
-		style.underline = textblock->get_font_decoration() == "underline";
-
-		spacewidth = style.calc_bare_width(" ");
-		linespacing = textblock->get_line_spacing();
-	}
-
-	/**
-	 * Properly align elements in the current line, and advance @ref text_y and
-	 * other data so that we can begin the next line.
-	 */
-	void advance_line()
-	{
-		int32_t miny = 0;
-		int32_t maxy = 0;
-
-		if (elements.empty()) {
-			style.calc_bare_height_heuristic(" ", miny, maxy);
-		} else {
-			int32_t alignref_left = 0;
-			int32_t alignref_right = rti.width;
-
-			if (text_y < rti.height + images_height) {
-				if ((mirror_alignment(richtext->get_image_align()) & UI::Align::kHorizontal)
-					 == UI::Align::kRight) {
-					alignref_right -= images_width + h_space;
-				} else {
-					// Note: center image alignment with text is not properly supported
-					// It is unclear what the semantics should be.
-					alignref_left += images_width + h_space;
-				}
-			}
-
-			int32_t textleft;
-
-			switch (mirror_alignment(richtext->get_text_align()) & UI::Align::kHorizontal) {
-			case UI::Align::kRight:
-				textleft = alignref_right - int32_t(linewidth);
-				break;
-			case UI::Align::kHCenter:
-				textleft = alignref_left + (alignref_right - alignref_left - int32_t(linewidth)) / 2;
-				break;
-			default:
-				textleft = alignref_left;
-				break;
-			}
-
-			for (std::vector<Elt>::const_iterator it = elements.begin(); it != elements.end(); ++it) {
-				it->element->bbox.x += textleft;
-				miny = std::min(miny, it->miny);
-				maxy = std::max(maxy, it->maxy);
-			}
-
-			int32_t baseline = text_y + maxy;
-			for (std::vector<Elt>::const_iterator it = elements.begin(); it != elements.end(); ++it)
-				it->element->bbox.y = baseline - it->element->style.font->ascent();
-		}
-
-		text_y += maxy - miny + linespacing;
-		if (text_y >= rti.height + images_height)
-			maxwidth = rti.width;
-
-		elements.clear();
-		linewidth = 0;
-	}
-};
-
-/**
- * Parse and layout the given rich text.
- */
-void RichText::parse(const std::string & rtext)
-{
-	m->clear();
-
-	std::vector<RichtextBlock> blocks;
-	TextParser p;
-	std::string copy(rtext);
-	p.parse(copy, blocks);
-
-	// Guard against weirdness in text and image alignment
-	m->width = std::min(m->width, uint32_t(std::numeric_limits<int32_t>::max()));
-
-	TextBuilder text(*m);
-
-	for (text.richtext = blocks.begin(); text.richtext != blocks.end(); ++text.richtext) {
-		const std::vector<TextBlock> & cur_text_blocks = text.richtext->get_text_blocks();
-		const std::vector<std::string> & cur_block_images = text.richtext->get_images();
-
-		// First obtain the data of all images of this richtext block and prepare
-		// the corresponding elements, then do the alignment once the total width
-		// is known
-		const uint32_t firstimageelement = m->elements.size();
-		text.images_height = 0;
-		text.images_width = 0;
-
-		for
-			(std::vector<std::string>::const_iterator image_it = cur_block_images.begin();
-			 image_it != cur_block_images.end();
-			 ++image_it)
-		{
-			const Image* image = g_gr->images().get(*image_it);
-			if (!image)
-				continue;
-
-			Rect bbox;
-			bbox.x = text.images_width;
-			bbox.y = m->height;
-			bbox.w = image->width();
-			bbox.h = image->height();
-
-			text.images_height = std::max<int>(text.images_height, bbox.h);
-			text.images_width += bbox.w;
-
-			m->elements.push_back(new ImageElement(bbox, image));
-		}
-
-		// Fix up the alignment
-		int32_t imagealigndelta = 0;
-
-		if ((text.richtext->get_image_align() & UI::Align::kHorizontal) == UI::Align::kHCenter) {
-			imagealigndelta = (int32_t(m->width) - int32_t(text.images_width)) / 2;
-		} else if ((mirror_alignment(text.richtext->get_image_align()) & UI::Align::kHorizontal)
-					  == UI::Align::kRight) {
-			imagealigndelta = int32_t(m->width) - int32_t(text.images_width);
-		}
-
-		for (uint32_t idx = firstimageelement; idx < m->elements.size(); ++idx)
-			m->elements[idx]->bbox.x += imagealigndelta;
-
-		// Now layout the text elements; they are already broken down to words,
-		// which makes our job a bit easier.
-		text.text_y = m->height;
-		text.maxwidth = m->width;
-		text.linewidth = 0;
-
-		if (text.images_height > 0) {
-			if (h_space + text.images_width < text.maxwidth)
-				text.maxwidth -= h_space + text.images_width;
-			else
-				text.text_y = m->height + text.images_height;
-		}
-
-		text.textblock = cur_text_blocks.begin();
-
-		while (text.textblock != cur_text_blocks.end()) {
-			text.reset_block();
-
-			const std::vector<std::string> & words = text.textblock->get_words();
-			const std::vector<std::vector<std::string>::size_type> & line_breaks =
-				text.textblock->get_line_breaks();
-
-			uint32_t word_cnt = 0;
-			std::vector<std::vector<std::string>::size_type>::const_iterator br_it = line_breaks.begin();
-
-			while (word_cnt < words.size() || br_it != line_breaks.end()) {
-				if (br_it != line_breaks.end() && *br_it <= word_cnt) {
-					text.advance_line();
-					++br_it;
-					continue;
-				}
-
-				// Now eat up words up to the next line break
-				assert(word_cnt < words.size());
-
-				bool wrap = false;
-				uint32_t nrwords = 0;
-				TextBuilder::Elt elt;
-				elt.miny = elt.maxy = 0;
-
-				Rect bbox;
-				bbox.x = text.linewidth ? text.linewidth + text.spacewidth : 0;
-				bbox.y = 0; // filled in later
-				bbox.w = 0;
-				bbox.h = text.style.font->height();
-
-				// TODO(GunChleoc): Arabic: width calculation for alignment is broken (Arabic)
-				do {
-					uint32_t wordwidth = text.style.calc_bare_width(words[word_cnt + nrwords]);
-
-					if (nrwords)
-						wordwidth += text.spacewidth;
-
-					// Break only if this is not the first word of the line
-					if
-						((text.linewidth || nrwords) &&
-						 bbox.x + bbox.w + wordwidth > text.maxwidth)
-					{
-						wrap = true;
-						break;
-					}
-
-					int32_t wordminy, wordmaxy;
-					text.style.calc_bare_height_heuristic(words[word_cnt + nrwords], wordminy, wordmaxy);
-					elt.maxy = std::max(elt.maxy, wordmaxy);
-					elt.miny = std::min(elt.miny, wordminy);
-
-					bbox.w += wordwidth;
-					++nrwords;
-				} while
-					(word_cnt + nrwords < words.size() &&
-					 (br_it == line_breaks.end() || *br_it > word_cnt + nrwords));
-
-				if (nrwords) {
-					m->elements.push_back
-						(new TextlineElement
-							(bbox, text.style,
-							 words.begin() + word_cnt, words.begin() + word_cnt + nrwords));
-					word_cnt += nrwords;
-
-					elt.element = static_cast<TextlineElement *>(m->elements.back());
-					text.elements.push_back(elt);
-					text.linewidth = bbox.x + bbox.w;
-				}
-
-				if (wrap)
-					text.advance_line();
-			}
-
-			text.textblock++;
-		}
-
-		if (!text.elements.empty())
-			text.advance_line();
-
-		// Update total height
-		m->height = std::max(m->height + text.images_height, text.text_y);
-	}
-}
-
-/**
- * Draw pre-parsed and layouted rich text content at the given offset.
- *
- * @p background if true, all richtext elements are given a solid background,
- * per the color set by @ref set_background_color
- *
- * @note this function may draw content outside the box given offset
- * and @ref width and @ref height, if there were wrapping problems.
- */
-void RichText::draw(RenderTarget & dst, const Point& offset, bool background)
-{
-	for
-		(std::vector<Element *>::const_iterator elt = m->elements.begin();
-		 elt != m->elements.end();
-		 ++elt)
-	{
-		Rect oldbox;
-		Point oldofs;
-		Rect bbox((*elt)->bbox.origin() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
-
-		if (dst.enter_window(bbox, &oldbox, &oldofs)) {
-			if (background)
-				dst.fill_rect(Rect(Point(0, 0), bbox.w, bbox.h), m->background_color);
-			(*elt)->draw(dst);
-			dst.set_window(oldbox, oldofs);
-		}
-	}
-}
-
-
-} // namespace UI

=== removed file 'src/graphic/richtext.h'
--- src/graphic/richtext.h	2014-07-05 16:41:51 +0000
+++ src/graphic/richtext.h	1970-01-01 00:00:00 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2002-2011 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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 WL_GRAPHIC_RICHTEXT_H
-#define WL_GRAPHIC_RICHTEXT_H
-
-#include <limits>
-#include <memory>
-#include <string>
-
-#include "base/point.h"
-#include "graphic/color.h"
-
-
-class RenderTarget;
-
-namespace UI {
-
-struct RichTextImpl;
-
-/**
- * Provides rich-text layouting and rendering functionality.
- *
- * Layouts the rich text as a tight fit, i.e. without any border around the
- * text. The final, layouted extents of the text can be obtained from @ref width and @ref height.
- */
-struct RichText {
-	RichText();
-	~RichText();
-
-	void set_width(uint32_t width = std::numeric_limits<uint32_t>::max());
-	void set_background_color(RGBColor color);
-
-	uint32_t width();
-	uint32_t height();
-
-	void parse(const std::string & text);
-	void draw(RenderTarget & dst, const Point& offset, bool background = false);
-
-private:
-	std::unique_ptr<RichTextImpl> m;
-};
-
-} // namespace UI
-
-#endif  // end of include guard: WL_GRAPHIC_RICHTEXT_H

=== modified file 'src/graphic/text/CMakeLists.txt'
--- src/graphic/text/CMakeLists.txt	2016-02-10 16:37:45 +0000
+++ src/graphic/text/CMakeLists.txt	2016-04-23 13:15:34 +0000
@@ -26,6 +26,7 @@
     base_geometry
     base_i18n
     base_log
+    graphic
     base_macros
     graphic
     graphic_color

=== modified file 'src/graphic/text/rt_parse.cc'
--- src/graphic/text/rt_parse.cc	2016-03-14 19:49:52 +0000
+++ src/graphic/text/rt_parse.cc	2016-04-23 13:15:34 +0000
@@ -31,7 +31,6 @@
 #include "graphic/text/rt_errors_impl.h"
 #include "graphic/text/textstream.h"
 
-
 namespace RT {
 
 Attr::Attr(const std::string& gname, const std::string& value) : name_(gname), value_(value) {
@@ -151,11 +150,22 @@
 		Tag * child = new Tag();
 		line = ts.line(); col = ts.col(); size_t cpos = ts.pos();
 		child->parse(ts, tcs, allowed_tags);
-		if (!tc.allowed_children.count(child->name()))
-			throw SyntaxErrorImpl(line, col, "an allowed tag", child->name(), ts.peek(100, cpos));
-		if (!allowed_tags.empty() && !allowed_tags.count(child->name()))
-			throw SyntaxErrorImpl(line, col, "an allowed tag", child->name(), ts.peek(100, cpos));
-
+		if (!tc.allowed_children.count(child->name())) {
+			std::string tags;
+			for (const std::string& tag : tc.allowed_children) {
+				tags = (boost::format("%s %s") % tags % tag).str();
+			}
+			tags = (boost::format("an allowed tag for '%s': %s") % child->name() % tags).str();
+			throw SyntaxErrorImpl(line, col, tags, child->name(), ts.peek(100, cpos));
+		}
+		if (!allowed_tags.empty() && !allowed_tags.count(child->name())) {
+			std::string tags;
+			for (const std::string& tag : allowed_tags) {
+				tags = (boost::format("%s %s") % tags % tag).str();
+			}
+			tags = (boost::format("an allowed tag for '%s': %s") % child->name() % tags).str();
+			throw SyntaxErrorImpl(line, col, tags, child->name(), ts.peek(100, cpos));
+		}
 		children_.push_back(new Child(child));
 	}
 }
@@ -182,14 +192,15 @@
 		tc.allowed_attrs.insert("padding_l");
 		tc.allowed_attrs.insert("padding_b");
 		tc.allowed_attrs.insert("padding_t");
-		tc.allowed_attrs.insert("db_show_spaces");
-		tc.allowed_attrs.insert("keep_spaces"); // Keeps blank spaces intact for text editing
+		 // Shows whitespace characters as red rectangles and prints log output
+		tc.allowed_attrs.insert("debug");
+		tc.allowed_attrs.insert("editor_mode"); // Keeps blank spaces intact for text editing
 		tc.allowed_attrs.insert("background");
 
 		tc.allowed_children.insert("p");
 		tc.allowed_children.insert("vspace");
 		tc.allowed_children.insert("font");
-		tc.allowed_children.insert("sub");
+		tc.allowed_children.insert("div");
 		tc.text_allowed = false;
 		tc.has_closing_tag = true;
 		tag_constraints_["rt"] = tc;
@@ -204,6 +215,7 @@
 		TagConstraint tc;
 		tc.allowed_attrs.insert("src");
 		tc.allowed_attrs.insert("ref");
+		tc.allowed_attrs.insert("color");
 		tc.text_allowed = false;
 		tc.has_closing_tag = false;
 		tag_constraints_["img"] = tc;
@@ -223,7 +235,7 @@
 		tc.has_closing_tag = false;
 		tag_constraints_["space"] = tc;
 	}
-	{ // sub tag
+	{ // div tag
 		TagConstraint tc;
 		tc.allowed_attrs.insert("padding");
 		tc.allowed_attrs.insert("padding_r");
@@ -231,7 +243,7 @@
 		tc.allowed_attrs.insert("padding_b");
 		tc.allowed_attrs.insert("padding_t");
 		tc.allowed_attrs.insert("margin");
-		tc.allowed_attrs.insert("float");
+		tc.allowed_attrs.insert("float"); // Makes text float around images
 		tc.allowed_attrs.insert("valign");
 		tc.allowed_attrs.insert("background");
 		tc.allowed_attrs.insert("width");
@@ -239,11 +251,11 @@
 		tc.allowed_children.insert("p");
 		tc.allowed_children.insert("vspace");
 		tc.allowed_children.insert("font");
-		tc.allowed_children.insert("sub");
+		tc.allowed_children.insert("div");
 
 		tc.text_allowed = false;
 		tc.has_closing_tag = true;
-		tag_constraints_["sub"] = tc;
+		tag_constraints_["div"] = tc;
 	}
 	{ // p tag
 		TagConstraint tc;
@@ -252,11 +264,12 @@
 		tc.allowed_attrs.insert("valign");
 		tc.allowed_attrs.insert("spacing");
 
+		tc.allowed_children.insert("p");
 		tc.allowed_children.insert("font");
 		tc.allowed_children.insert("space");
 		tc.allowed_children.insert("br");
 		tc.allowed_children.insert("img");
-		tc.allowed_children.insert("sub");
+		tc.allowed_children.insert("div");
 		tc.text_allowed = true;
 		tc.has_closing_tag = true;
 		tag_constraints_["p"] = tc;
@@ -274,9 +287,11 @@
 
 		tc.allowed_children.insert("br");
 		tc.allowed_children.insert("space");
+		tc.allowed_children.insert("vspace");
 		tc.allowed_children.insert("p");
+		tc.allowed_children.insert("img");
 		tc.allowed_children.insert("font");
-		tc.allowed_children.insert("sub");
+		tc.allowed_children.insert("div");
 		tc.text_allowed = true;
 		tc.has_closing_tag = true;
 		tag_constraints_["font"] = tc;

=== modified file 'src/graphic/text/rt_render.cc'
--- src/graphic/text/rt_render.cc	2016-04-20 09:57:21 +0000
+++ src/graphic/text/rt_render.cc	2016-04-23 13:15:34 +0000
@@ -20,13 +20,14 @@
 #include "graphic/text/rt_render.h"
 
 #include <cmath>
+#include <map>
 #include <memory>
 #include <queue>
 #include <string>
 #include <vector>
 
 #include <SDL.h>
-#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string.hpp>
 #include <boost/format.hpp>
 
 #include "base/i18n.h"
@@ -47,13 +48,17 @@
 #include "graphic/text/textstream.h"
 #include "graphic/text_layout.h"
 #include "graphic/texture.h"
-#include "io/filesystem/filesystem_exceptions.h"
+#include "io/filesystem/layered_filesystem.h"
+
+#define DEBUG_COLOR              RGBAColor(0xcc, 0, 0, 80)
+#define DEBUG_FRAME_COLOR_TOP    RGBAColor(255, 255, 255, 60)
+#define DEBUG_FRAME_COLOR_BOTTOM RGBAColor(0, 0, 0, 60)
 
 using namespace std;
 
 namespace RT {
 
-static const uint16_t INFINITE_WIDTH = 65535; // 2^16-1
+constexpr uint16_t kInfiniteWidth = 65535; // 2^16-1
 
 // Helper Stuff
 struct Borders {
@@ -62,7 +67,7 @@
 };
 
 struct NodeStyle {
-	UI::FontSet const * fontset;
+	UI::FontSet const * fontset;  // Not owned.
 	string font_face;
 	uint16_t font_size;
 	RGBColor font_color;
@@ -194,36 +199,56 @@
 
 class RenderNode {
 public:
-	enum Floating {
-		NO_FLOAT = 0,
-		FLOAT_RIGHT,
-		FLOAT_LEFT,
-	};
+	enum class Floating : uint8_t {
+		kNo = 0,
+		kRight,
+		kLeft,
+	};
+	enum class Type {
+		kAbstract,
+		kDiv,
+		kImg,
+		kNewline,
+		kSpace,
+		kText,
+		kTextFilling,
+		kTextWordSpacer
+	};
+
 	RenderNode(NodeStyle& ns)
-		: floating_(NO_FLOAT), halign_(ns.halign), valign_(ns.valign), x_(0), y_(0) {}
+		: floating_(Floating::kNo), halign_(ns.halign), valign_(ns.valign), x_(0), y_(0) {}
 	virtual ~RenderNode() {}
-
-	virtual uint16_t width() = 0;
-	virtual uint16_t height() = 0;
-	virtual uint16_t hotspot_y() = 0;
+	virtual RenderNode::Type type() const {return Type::kAbstract;}
+	bool is_textnode() const {
+		return type() == Type::kText ||
+				type() == Type::kTextFilling ||
+				type() == Type::kTextWordSpacer;
+	}
+	virtual uint16_t width() const = 0;
+	virtual uint16_t height() const = 0;
+	virtual uint16_t hotspot_y() const = 0;
 	virtual Texture* render(TextureCache* texture_cache) = 0;
 
-	virtual bool is_non_mandatory_space() {return false;}
-	virtual bool is_expanding() {return false;}
+	virtual bool is_non_mandatory_space() const {return false;}
+	virtual bool is_expanding() const {return false;}
 	virtual void set_w(uint16_t) {} // Only, when is_expanding
 
 	virtual const vector<Reference> get_references() {return vector<Reference>();}
 
-	Floating get_floating() {return floating_;}
+	Floating get_floating() const {return floating_;}
 	void set_floating(Floating f) {floating_ = f;}
-	UI::Align halign() {return halign_;}
+	UI::Align halign() const {return halign_;}
 	void set_halign(UI::Align ghalign) {halign_ = ghalign;}
-	UI::Align valign() {return valign_;}
+	UI::Align valign() const {return valign_;}
 	void set_valign(UI::Align gvalign) {valign_ = gvalign;}
 	void set_x(int32_t nx) {x_ = nx;}
 	void set_y(int32_t ny) {y_ = ny;}
-	int32_t x() {return x_;}
-	int32_t y() {return y_;}
+	int32_t x() const {return x_;}
+	int32_t y() const {return y_;}
+	virtual void debug_log() const {
+		log("x=%d, y=%d, halign=%d, valign=%d, floating=%d\n", x(), y(), halign(), valign(), get_floating());
+	}
+	static bool debug_;
 
 private:
 	Floating floating_;
@@ -231,6 +256,7 @@
 	UI::Align valign_;
 	int32_t x_, y_;
 };
+bool RenderNode::debug_;
 
 class Layout {
 public:
@@ -269,7 +295,8 @@
 	while (idx_ < all_nodes_.size()
 		&& all_nodes_[idx_]->is_non_mandatory_space()
 		&& shrink_to_fit) {
-			delete all_nodes_[idx_++];
+		delete all_nodes_[idx_];
+		all_nodes_[idx_++] = nullptr;
 	}
 
 	uint16_t x = p.left;
@@ -279,8 +306,11 @@
 	while (idx_ < all_nodes_.size()) {
 		RenderNode* n = all_nodes_[idx_];
 		uint16_t nw = n->width();
-		if (x + nw + p.right > w || n->get_floating() != RenderNode::NO_FLOAT) {
+		if (x + nw + p.right > w || n->get_floating() != RenderNode::Floating::kNo) {
 			if (idx_ == first_idx) {
+				// NOCOM(#sirver) Tried to crop here
+				// The first node does not fit the line. Crop it.
+				// NOCOM(#cgh): node and insert line break
 				nw = w - p.right - x;
 			} else {
 				break;
@@ -301,7 +331,7 @@
 
 	// Remaining space in this line
 	uint16_t remaining_space = 0;
-	if (w < INFINITE_WIDTH) {
+	if (w < kInfiniteWidth) {
 		remaining_space = w - p.right - x;
 	}
 
@@ -353,12 +383,12 @@
 		uint16_t biggest_hotspot = fit_line(w, p, &nodes_in_line, shrink_to_fit);
 
 		int line_height = 0;
-		int line_start = INFINITE_WIDTH;
+		int line_start = kInfiniteWidth;
 		// Compute real line height and width, taking into account alignement
 		for (RenderNode* n : nodes_in_line) {
 			line_height = max(line_height, biggest_hotspot - n->hotspot_y() + n->height());
 			n->set_y(h_ + biggest_hotspot - n->hotspot_y());
-			if (line_start >= INFINITE_WIDTH || n->x() < line_start) {
+			if (line_start >= kInfiniteWidth || n->x() < line_start) {
 				line_start = n->x() - p.left;
 			}
 			max_line_width = std::max<int>(max_line_width, n->x() + n->width() + p.right - line_start);
@@ -367,7 +397,7 @@
 		// Go over again and adjust position for VALIGN
 		for (RenderNode* n : nodes_in_line) {
 			uint16_t space = line_height - n->height();
-			if (!space || n->valign() == UI::Align::kBottom) {
+			if (space == 0 || n->valign() == UI::Align::kBottom) {
 				continue;
 			}
 			if (n->valign() == UI::Align::kCenter) {
@@ -388,11 +418,11 @@
 			constraint_changes_.pop();
 		}
 
-		if ((idx_ < all_nodes_.size()) && all_nodes_[idx_]->get_floating()) {
+		if ((idx_ < all_nodes_.size()) && all_nodes_[idx_]->get_floating() != RenderNode::Floating::kNo) {
 			RenderNode* n = all_nodes_[idx_];
 			n->set_y(h_);
 			ConstraintChange cc = {h_ + n->height(), 0, 0};
-			if (n->get_floating() == RenderNode::FLOAT_LEFT) {
+			if (n->get_floating() == RenderNode::Floating::kLeft) {
 				n->set_x(p.left);
 				p.left += n->width();
 				cc.delta_offset_x = -n->width();
@@ -424,9 +454,10 @@
 	TextNode(FontCache& font, NodeStyle&, const string& txt);
 	virtual ~TextNode() {}
 
-	uint16_t width() override {return w_;}
-	uint16_t height() override {return h_ + nodestyle_.spacing;}
-	uint16_t hotspot_y() override;
+	RenderNode::Type type() const override {return RenderNode::Type::kText;}
+	uint16_t width() const override {return w_;}
+	uint16_t height() const override {return h_ + nodestyle_.spacing;}
+	uint16_t hotspot_y() const override;
 	const vector<Reference> get_references() override {
 		vector<Reference> rv;
 		if (!nodestyle_.reference.empty()) {
@@ -438,6 +469,11 @@
 
 	Texture* render(TextureCache* texture_cache) override;
 
+	void debug_log() const override {
+		log("* TEXT: w=%d, h=%d, hotspot=%d, \"%s\" ", width(), height(), hotspot_y(), txt_.c_str());
+		RenderNode::debug_log();
+	}
+
 protected:
 	uint16_t w_, h_;
 	const string txt_;
@@ -452,11 +488,12 @@
 {
 	font_.dimensions(txt_, ns.font_style, &w_, &h_);
 }
-uint16_t TextNode::hotspot_y() {
+uint16_t TextNode::hotspot_y() const {
 	return font_.ascent(nodestyle_.font_style);
 }
 
 Texture* TextNode::render(TextureCache* texture_cache) {
+	if (debug_) debug_log();
 	const Texture& img = font_.render(txt_, nodestyle_.font_color, nodestyle_.font_style, texture_cache);
 	Texture* rv = new Texture(img.width(), img.height());
 	rv->blit(Rect(0, 0, img.width(), img.height()),
@@ -480,13 +517,20 @@
 	virtual ~FillingTextNode() {}
 	Texture* render(TextureCache*) override;
 
-	bool is_expanding() override {return is_expanding_;}
+	RenderNode::Type type() const override {return RenderNode::Type::kTextFilling;}
+	bool is_expanding() const override {return is_expanding_;}
 	void set_w(uint16_t w) override {w_ = w;}
 
+	void debug_log() const override {
+		log("* FillingText: ");
+		TextNode::debug_log();
+	}
+
 private:
 	bool is_expanding_;
 };
 Texture* FillingTextNode::render(TextureCache* texture_cache) {
+	if (debug_) debug_log();
 	const Texture& t = font_.render(txt_, nodestyle_.font_color, nodestyle_.font_style, texture_cache);
 	Texture* rv = new Texture(w_, h_);
 	for (uint16_t curx = 0; curx < w_; curx += t.width()) {
@@ -503,22 +547,25 @@
 class WordSpacerNode : public TextNode {
 public:
 	WordSpacerNode(FontCache& font, NodeStyle& ns) : TextNode(font, ns, " ") {}
-	static void show_spaces(bool t) {show_spaces_ = t;}
 
 	Texture* render(TextureCache* texture_cache) override {
-		if (show_spaces_) {
-			Texture* rv = new Texture(w_, h_);
-			rv->fill_rect(Rect(0, 0, w_, h_), RGBAColor(0xcc, 0, 0, 0xcc));
+		if (debug_) {
+			debug_log();
+			Texture* rv = new Texture(width(), height());
+			rv->fill_rect(Rect(0, 0, width(), height()), DEBUG_COLOR);
 			return rv;
 		}
 		return TextNode::render(texture_cache);
 	}
-	bool is_non_mandatory_space() override {return true;}
-
-private:
-	static bool show_spaces_;
+
+	RenderNode::Type type() const override {return RenderNode::Type::kTextWordSpacer;}
+	bool is_non_mandatory_space() const override {return true;}
+
+	void debug_log() const override {
+		log("* WordSpacer: ");
+		TextNode::debug_log();
+	}
 };
-bool WordSpacerNode::show_spaces_;
 
 /*
  * This is a forced newline that can either be inside the text from the user or
@@ -527,13 +574,21 @@
 class NewlineNode : public RenderNode {
 public:
 	NewlineNode(NodeStyle& ns) : RenderNode(ns) {}
-	uint16_t height() override {return 0;}
-	uint16_t width() override {return INFINITE_WIDTH; }
-	uint16_t hotspot_y() override {return 0;}
+	RenderNode::Type type() const override {return RenderNode::Type::kNewline;}
+	uint16_t height() const override {return 0;}
+	uint16_t width() const override {return kInfiniteWidth; }
+	uint16_t hotspot_y() const override {return 0;}
 	Texture* render(TextureCache* /* texture_cache */) override {
-		NEVER_HERE();
-	}
-	bool is_non_mandatory_space() override {return true;}
+		if (debug_) debug_log();
+		// NOCOM(GunChleoc): why was this NEVER_HERE()? NEVER_HERE();
+		return new Texture(0, 0);
+	}
+	bool is_non_mandatory_space() const override {return true;}
+
+	void debug_log() const override {
+		log("* Newline: ");
+		RenderNode::debug_log();
+	}
 };
 
 /*
@@ -544,10 +599,12 @@
 	SpaceNode(NodeStyle& ns, uint16_t w, uint16_t h = 0, bool expanding = false) :
 		RenderNode(ns), w_(w), h_(h), background_image_(nullptr), is_expanding_(expanding) {}
 
-	uint16_t height() override {return h_;}
-	uint16_t width() override {return w_;}
-	uint16_t hotspot_y() override {return h_;}
+	RenderNode::Type type() const override {return RenderNode::Type::kSpace;}
+	uint16_t height() const override {return h_;}
+	uint16_t width() const override {return w_;}
+	uint16_t hotspot_y() const override {return h_;}
 	Texture* render(TextureCache* /* texture_cache */) override {
+		if (debug_) debug_log();
 		Texture* rv = new Texture(w_, h_);
 
 		// Draw background image (tiling)
@@ -566,13 +623,18 @@
 		}
 		return rv;
 	}
-	bool is_expanding() override {return is_expanding_;}
+	bool is_expanding() const override {return is_expanding_;}
 	void set_w(uint16_t w) override {w_ = w;}
 
 	void set_background(const Image* s) {
 		background_image_ = s; h_ = s->height();
 	}
 
+	void debug_log() const override {
+		log("* Space: ");
+		RenderNode::debug_log();
+	}
+
 private:
 	uint16_t w_, h_;
 	const Image* background_image_;  // not owned
@@ -580,25 +642,28 @@
 };
 
 /*
- * This is a sub tag node. It is also the same as a full rich text render node.
+ * This is a div tag node. It is also the same as a full rich text render node.
  */
-class SubTagRenderNode : public RenderNode {
+class DivTagRenderNode : public RenderNode {
 public:
-	SubTagRenderNode(NodeStyle& ns) : RenderNode(ns),
+	DivTagRenderNode(NodeStyle& ns) : RenderNode(ns),
 		background_color_(0, 0, 0), is_background_color_set_(false), background_image_(nullptr) {
 	}
-	virtual ~SubTagRenderNode() {
+	virtual ~DivTagRenderNode() {
 		for (RenderNode* n : nodes_to_render_) {
 			delete n;
 		}
 		nodes_to_render_.clear();
 	}
 
-	uint16_t width() override {return w_ + margin_.left + margin_.right;}
-	uint16_t height() override {return h_ + margin_.top + margin_.bottom;}
-	uint16_t hotspot_y() override {return height();}
+	RenderNode::Type type() const override {return RenderNode::Type::kDiv;}
+	uint16_t width() const override {return w_ + margin_.left + margin_.right;}
+	uint16_t height() const override {return h_ + margin_.top + margin_.bottom;}
+	uint16_t hotspot_y() const override {return height();}
 
 	Texture* render(TextureCache* texture_cache) override {
+		if (debug_) debug_log();
+
 		if (width() > g_gr->max_texture_size() || height() > g_gr->max_texture_size()) {
 			const std::string error_message =
 					(boost::format("Texture (%d, %d) too big! Maximum size is %d.")
@@ -606,7 +671,9 @@
 			log((error_message + "\n").c_str());
 			throw TextureTooBig(error_message);
 		}
+
 		Texture* rv = new Texture(width(), height());
+		if (RenderNode::debug_) log("* Total Size: %d, %d\n", width(), height());
 		rv->fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
 
 		// Draw Solid background Color
@@ -641,15 +708,22 @@
 				                node_texture->width(),
 				                node_texture->height());
 				Rect src = Rect(0, 0, node_texture->width(), node_texture->height());
-
 				rv->blit(dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha);
 				delete node_texture;
 			}
 			delete n;
 		}
-
 		nodes_to_render_.clear();
-
+		if (debug_) {
+			//  top edge
+			rv->fill_rect(Rect(Point(0, 0), width() - 2, 2), DEBUG_FRAME_COLOR_TOP);
+			//  left edge
+			rv->fill_rect(Rect(Point(0, 0), 2, height() - 2), DEBUG_FRAME_COLOR_TOP);
+			//  bottom edge
+			rv->fill_rect(Rect(Point(0, height() - 2), width(), 2), DEBUG_FRAME_COLOR_BOTTOM);
+			//  right edge
+			rv->fill_rect(Rect(Point(width() - 2, 0), 2, height() - 2), DEBUG_FRAME_COLOR_BOTTOM);
+		}
 		return rv;
 	}
 	const vector<Reference> get_references() override {return refs_;}
@@ -667,6 +741,11 @@
 		refs_.push_back(r);
 	}
 
+	void debug_log() const override {
+		log("* Div: w=%d, h=%d, hotspot=%d ", width(), height(), hotspot_y());
+		RenderNode::debug_log();
+	}
+
 private:
 	uint16_t w_, h_;
 	vector<RenderNode*> nodes_to_render_;
@@ -679,25 +758,51 @@
 
 class ImgRenderNode : public RenderNode {
 public:
-	ImgRenderNode(NodeStyle& ns, const Image& image) : RenderNode(ns), image_(image) {
+	ImgRenderNode(NodeStyle& ns, const std::string& image_filename, const RGBColor& color) :
+		RenderNode(ns),
+		image_(*g_gr->images().get(image_filename)),
+		color_mask_(nullptr),
+		color_(color) {
+		if (color_.hex_value() != "000000") {
+			std::string pc_image_filename = image_filename;
+			boost::replace_all(pc_image_filename, ".png", "_pc.png");
+			if (g_fs->file_exists(pc_image_filename)) {
+				color_mask_ = g_gr->images().get(pc_image_filename);
+			}
+		}
 	}
 
-	uint16_t width() override {return image_.width();}
-	uint16_t height() override {return image_.height();}
-	uint16_t hotspot_y() override {return image_.height();}
+	RenderNode::Type type() const override {return RenderNode::Type::kImg;}
+	uint16_t width() const override {return image_.width();}
+	uint16_t height() const override {return image_.height();}
+	uint16_t hotspot_y() const override {return image_.height();}
 	Texture* render(TextureCache* texture_cache) override;
 
+	void debug_log() const override {
+		log("* Img: w=%d, h=%d, hotspot=%d ", width(), height(), hotspot_y());
+		RenderNode::debug_log();
+	}
+
 private:
 	const Image& image_;
+	const Image* color_mask_;
+	const RGBColor color_;
 };
 
 Texture* ImgRenderNode::render(TextureCache* /* texture_cache */) {
-	Texture* rv = new Texture(image_.width(), image_.height());
-	rv->blit(Rect(0, 0, image_.width(), image_.height()),
-				image_,
-				Rect(0, 0, image_.width(), image_.height()),
-				1.,
-	         BlendMode::Copy);
+	if (debug_) debug_log();
+	Texture* rv = new Texture(width(), height());
+	if (color_mask_ != nullptr) {
+		rv->fill_rect(Rect(Point(0, 0), width(), height()), RGBAColor(0, 0, 0, 0));
+		rv->blit_blended(Rect(Point(0, 0), width(), height()), image_,
+							  *color_mask_, Rect(Point(0, 0), width(), height()), color_);
+	} else {
+		rv->blit(Rect(0, 0, width(), height()),
+					image_,
+					Rect(0, 0, width(), height()),
+					1.,
+					BlendMode::Copy);
+	}
 	return rv;
 }
 // End: Helper Stuff
@@ -718,6 +823,8 @@
 	virtual void enter() {}
 	virtual void emit_nodes(vector<RenderNode*>&);
 
+	static bool editor_mode_;
+
 private:
 	void make_text_nodes(const string& txt, vector<RenderNode*>& nodes, NodeStyle& ns);
 
@@ -729,20 +836,29 @@
 	RendererStyle& renderer_style_; // Reference to global renderer style in the renderer
 	const UI::FontSets& fontsets_;
 };
+bool TagHandler::editor_mode_;
 
 void TagHandler::make_text_nodes(const string& txt, vector<RenderNode*>& nodes, NodeStyle& ns) {
-	TextStream ts(txt);
+	std::string renderme = txt;
+
+	// Clean up a bit to make rendering faster
+	if (!TagHandler::editor_mode_) {
+		boost::trim(renderme);
+		boost::replace_all(renderme, "  ", " ");
+	}
+
+	TextStream ts(renderme);
 	std::string word;
 	std::vector<RenderNode*> text_nodes;
 
 	// Bidirectional text (Arabic etc.)
-	if (i18n::has_rtl_character(txt.c_str())) {
+	if (i18n::has_rtl_character(renderme.c_str())) {
 		std::string previous_word;
 		std::vector<RenderNode*>::iterator it = text_nodes.begin();
 		std::vector<WordSpacerNode*> spacer_nodes;
 
 		// Collect the word nodes
-		while (ts.pos() < txt.size()) {
+		while (ts.pos() < renderme.size()) {
 			std::size_t cpos = ts.pos();
 			ts.skip_ws();
 			spacer_nodes.clear();
@@ -788,7 +904,7 @@
 		}
 
 	} else {  // LTR
-		while (ts.pos() < txt.size()) {
+		while (ts.pos() < renderme.size()) {
 			std::size_t cpos = ts.pos();
 			ts.skip_ws();
 			for (uint16_t ws_indx = 0; ws_indx < ts.pos() - cpos; ws_indx++) {
@@ -819,8 +935,9 @@
 																			 renderer_style_, fontsets_));
 			th->enter();
 			th->emit_nodes(nodes);
-		} else
+		} else {
 			make_text_nodes(c->text, nodes, nodestyle_);
+		}
 	}
 }
 
@@ -833,7 +950,20 @@
 	void enter() override {
 		const AttrMap& a = tag_.attrs();
 		if (a.has("color")) nodestyle_.font_color = a["color"].get_color();
-		if (a.has("size")) nodestyle_.font_size = a["size"].get_int();
+
+		// NOCOM(GunChleoc): Stacking font sizes on the same line will screw up the y position.
+		if (a.has("size")) {
+			std::string font_size_string = a["size"].get_string();
+			if (boost::algorithm::ends_with(font_size_string, "%")) {
+				font_size_string = font_size_string.substr(0, font_size_string.length() - 1);
+				uint8_t new_font_percent = strtol(font_size_string.c_str(), nullptr, 10);
+				nodestyle_.font_size = ceil(renderer_style_.font_size * new_font_percent / 100);
+			} else {
+				nodestyle_.font_size = a["size"].get_int();
+			}
+			// NOCOM(GunChleoc): Do we want font sizes to stack?
+			renderer_style_.font_size = nodestyle_.font_size; // Make font sizes stack.
+		}
 		if (a.has("face")) nodestyle_.font_face = a["face"].get_string();
 		if (a.has("bold")) nodestyle_.font_style |= a["bold"].get_bool() ? IFont::BOLD : 0;
 		if (a.has("italic")) nodestyle_.font_style |= a["italic"].get_bool() ? IFont::ITALIC : 0;
@@ -901,7 +1031,12 @@
 
 	void enter() override {
 		const AttrMap& a = tag_.attrs();
-		render_node_ = new ImgRenderNode(nodestyle_, *image_cache_->get(a["src"].get_string()));
+		RGBColor clr;
+		if (a.has("color"))
+		{
+			clr = a["color"].get_color();
+		}
+		render_node_ = new ImgRenderNode(nodestyle_, a["src"].get_string(), clr);
 	}
 	void emit_nodes(vector<RenderNode*>& nodes) override {
 		nodes.push_back(render_node_);
@@ -945,7 +1080,7 @@
 		if (a.has("gap"))
 			space_ = a["gap"].get_int();
 		else
-			space_ = INFINITE_WIDTH;
+			space_ = kInfiniteWidth;
 
 		if (a.has("fill")) {
 			fill_text_ = a["fill"].get_string();
@@ -961,13 +1096,13 @@
 	void emit_nodes(vector<RenderNode*>& nodes) override {
 		RenderNode* rn = nullptr;
 		if (!fill_text_.empty()) {
-			if (space_ < INFINITE_WIDTH)
+			if (space_ < kInfiniteWidth)
 				rn = new FillingTextNode(font_cache_, nodestyle_, space_, fill_text_);
 			else
 				rn = new FillingTextNode(font_cache_, nodestyle_, 0, fill_text_, true);
 		} else {
 			SpaceNode* sn;
-			if (space_ < INFINITE_WIDTH)
+			if (space_ < kInfiniteWidth)
 				sn = new SpaceNode(nodestyle_, space_, 0);
 			else
 				sn = new SpaceNode(nodestyle_, 0, 0, true);
@@ -998,17 +1133,17 @@
 };
 
 
-class SubTagHandler : public TagHandler {
+class DivTagHandler : public TagHandler {
 public:
-	SubTagHandler
+	DivTagHandler
 		(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
 		 RendererStyle& init_renderer_style, const UI::FontSets& fontsets,
-		 uint16_t max_w = 0, bool shrink_to_fit = true)
+		 uint16_t max_w = 0)
 		:
 			TagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets),
-			shrink_to_fit_(shrink_to_fit),
+			shrink_to_fit_(true),
 			w_(max_w),
-			render_node_(new SubTagRenderNode(ns))
+			render_node_(new DivTagRenderNode(ns))
 	{
 	}
 
@@ -1044,7 +1179,7 @@
 
 		if (! w_) { // Determine the width by the width of the widest subnode
 			for (RenderNode* n : subnodes) {
-				if (n->width() >= INFINITE_WIDTH)
+				if (n->width() >= kInfiniteWidth)
 					continue;
 				w_ = max<int>(w_, n->width() + padding.left + padding.right);
 			}
@@ -1053,18 +1188,43 @@
 		// Layout takes ownership of subnodes
 		Layout layout(subnodes);
 		vector<RenderNode*> nodes_to_render;
-		uint16_t max_line_width = layout.fit_nodes(nodes_to_render, w_, padding, shrink_to_fit_);
+		uint16_t max_line_width = layout.fit_nodes(nodes_to_render, w_, padding,
+																 !TagHandler::editor_mode_ && shrink_to_fit_);
 		uint16_t extra_width = 0;
-		if (w_ < INFINITE_WIDTH && w_ > max_line_width) {
+		if (w_ < kInfiniteWidth && w_ > max_line_width) {
 			extra_width = w_ - max_line_width;
 		}
 
+		// Delete single preceding and trailing WordSpacerNodes that weren't taken care of in fit_line
+		if (!TagHandler::editor_mode_) {
+			for (auto node_it = nodes_to_render.begin(); node_it != nodes_to_render.end(); ++node_it) {
+				if (*node_it != nullptr && is_a(WordSpacerNode, *node_it)) {
+					// Preceding whitespace
+					if ((*node_it)->x() == 0) {
+						const int32_t width_to_deduct = (*node_it)->width();
+						const int32_t deleted_y = (*node_it)->y();
+						nodes_to_render.erase(node_it);
+						 // Fix offset for remaining nodes in the line
+						 while ((*node_it)->y() <= deleted_y && node_it != nodes_to_render.end()) {
+							 (*node_it)->set_x((*node_it)->x() - width_to_deduct);
+							 ++node_it;
+						 }
+					// Trailing whitespace
+					} else {
+						if ((node_it + 1 == nodes_to_render.end()) || ((*node_it)->y() < (*(node_it + 1))->y())) {
+							nodes_to_render.erase(node_it);
+						}
+					}
+				}
+			}
+		}
+
 		// Collect all tags from children
 		for (RenderNode* rn : nodes_to_render) {
 			for (const Reference& r : rn->get_references()) {
 				render_node_->add_reference(rn->x() + r.dim.x, rn->y() + r.dim.y, r.dim.w, r.dim.h, r.ref);
 			}
-			if (shrink_to_fit_) {
+			if (!TagHandler::editor_mode_ && shrink_to_fit_) {
 				if (rn->halign() == UI::Align::kCenter) {
 					rn->set_x(rn->x() - extra_width / 2);
 				} else if (rn->halign() == UI::Align::kRight) {
@@ -1072,16 +1232,10 @@
 				}
 			}
 		}
-		if (shrink_to_fit_ || w_ >= INFINITE_WIDTH) {
+		if ((!TagHandler::editor_mode_ && shrink_to_fit_) || w_ >= kInfiniteWidth) {
 			w_ = max_line_width;
 		}
 
-		if (renderer_style_.remaining_width >= w_) {
-			renderer_style_.remaining_width -= w_;
-		} else {
-			renderer_style_.remaining_width = renderer_style_.overall_width;
-		}
-
 		render_node_->set_dimensions(w_, layout.height(), margin);
 		render_node_->set_nodes_to_render(nodes_to_render);
 	}
@@ -1089,18 +1243,19 @@
 		nodes.push_back(render_node_);
 	}
 
-	// Handle attributes that are in sub, but not in rt.
+	// Handle attributes that are in div, but not in rt.
 	virtual void handle_unique_attributes() {
 		const AttrMap& a = tag_.attrs();
 		if (a.has("width")) {
 			std::string width_string = a["width"].get_string();
 			if (width_string == "*") {
-				w_ = renderer_style_.remaining_width;
+				// NOCOM(GunChleoc) width = * doesn't work. We would need it e.g. in the Barbarian Well lore text.
+				// The available width will need to be determined in fit_nodes or fit_line.
+				w_ = 0;
 			} else if (boost::algorithm::ends_with(width_string, "%")) {
 				width_string = width_string.substr(0, width_string.length() - 1);
 				uint8_t new_width_percent = strtol(width_string.c_str(), nullptr, 10);
 				w_ = floor(renderer_style_.overall_width * new_width_percent / 100);
-				w_ = std::min(w_, renderer_style_.remaining_width);
 			} else {
 				w_ = a["width"].get_int();
 			}
@@ -1108,8 +1263,8 @@
 		}
 		if (a.has("float")) {
 			const string s = a["float"].get_string();
-			if (s == "right") render_node_->set_floating(RenderNode::FLOAT_RIGHT);
-			else if (s == "left") render_node_->set_floating(RenderNode::FLOAT_LEFT);
+			if (s == "right") render_node_->set_floating(RenderNode::Floating::kRight);
+			else if (s == "left") render_node_->set_floating(RenderNode::Floating::kLeft);
 		}
 		if (a.has("valign")) {
 			const string align = a["valign"].get_string();
@@ -1118,25 +1273,27 @@
 			else if (align == "center" || align == "middle") render_node_->set_valign(UI::Align::kCenter);
 		}
 	}
-protected:
+private:
 	bool shrink_to_fit_;
-private:
 	uint16_t w_;
-	SubTagRenderNode* render_node_;
+	DivTagRenderNode* render_node_;
 };
 
-class RTTagHandler : public SubTagHandler {
+class RTTagHandler : public DivTagHandler {
 public:
 	RTTagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
 					 RendererStyle& init_renderer_style, const UI::FontSets& fontsets, uint16_t w) :
-		SubTagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets, w, true) {
+		DivTagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets, w) {
 	}
 
-	// Handle attributes that are in rt, but not in sub.
+	// Handle attributes that are in rt, but not in div.
 	void handle_unique_attributes() override {
 		const AttrMap& a = tag_.attrs();
-		WordSpacerNode::show_spaces(a.has("db_show_spaces") ? a["db_show_spaces"].get_bool() : 0);
-		shrink_to_fit_ = shrink_to_fit_ && (a.has("keep_spaces") ? !a["keep_spaces"].get_bool() : true);
+		RenderNode::debug_ = a.has("debug") ? a["debug"].get_bool() : 0;
+		TagHandler::editor_mode_ = a.has("editor_mode") ? a["editor_mode"].get_bool() : false;
+		if (RenderNode::debug_) {
+			log("\n*** Rendering richtext ***\n");
+		}
 	}
 };
 
@@ -1156,7 +1313,7 @@
 	if (map.empty()) {
 		map["br"] = &create_taghandler<BrTagHandler>;
 		map["font"] = &create_taghandler<FontTagHandler>;
-		map["sub"] = &create_taghandler<SubTagHandler>;
+		map["div"] = &create_taghandler<DivTagHandler>;
 		map["p"] = &create_taghandler<PTagHandler>;
 		map["img"] = &create_taghandler<ImgTagHandler>;
 		map["vspace"] = &create_taghandler<VspaceTagHandler>;
@@ -1173,9 +1330,8 @@
 Renderer::Renderer(ImageCache* image_cache, TextureCache* texture_cache, const UI::FontSets& fontsets) :
 	font_cache_(new FontCache()), parser_(new Parser()),
 	image_cache_(image_cache), texture_cache_(texture_cache), fontsets_(fontsets),
-	renderer_style_("sans", 16, INFINITE_WIDTH, INFINITE_WIDTH) {
-	TextureCache* render
-		(const std::string&, uint16_t, const TagSet&);
+	renderer_style_("sans", kFontSizeDefault, kInfiniteWidth) {
+	TextureCache* render(const std::string&, uint16_t, const TagSet&);
 }
 
 Renderer::~Renderer() {
@@ -1185,10 +1341,9 @@
 	std::unique_ptr<Tag> rt(parser_->parse(text, allowed_tags));
 
 	if (!width) {
-		width = INFINITE_WIDTH;
+		width = kInfiniteWidth;
 	}
 
-	renderer_style_.remaining_width = width;
 	renderer_style_.overall_width = width;
 
 	UI::FontSet const * fontset = fontsets_.get_fontset(i18n::get_locale());
@@ -1212,7 +1367,6 @@
 
 Texture* Renderer::render(const string& text, uint16_t width, const TagSet& allowed_tags) {
 	std::unique_ptr<RenderNode> node(layout_(text, width, allowed_tags));
-
 	return node->render(texture_cache_);
 }
 
@@ -1221,4 +1375,4 @@
 	return new RefMap(node->get_references());
 }
 
-}
+} //namespace RT

=== modified file 'src/graphic/text/rt_render.h'
--- src/graphic/text/rt_render.h	2016-02-14 11:39:28 +0000
+++ src/graphic/text/rt_render.h	2016-04-23 13:15:34 +0000
@@ -41,14 +41,12 @@
 class RenderNode;
 
 struct RendererStyle {
-	RendererStyle(const std::string& font_face_, uint8_t font_size_,
-						  uint16_t remaining_width_, uint16_t overall_width_) :
+	RendererStyle(const std::string& font_face_, uint8_t font_size_, uint16_t overall_width_) :
 		font_face(font_face_), font_size(font_size_),
-		remaining_width(remaining_width_), overall_width(overall_width_) {}
+		overall_width(overall_width_) {}
 
 	std::string font_face;
 	uint8_t font_size;
-	uint16_t remaining_width;
 	uint16_t overall_width;
 };
 

=== added directory 'src/graphic/text/test/data/br'
=== removed directory 'src/graphic/text/test/data/br'
=== added file 'src/graphic/text/test/data/br/correct.png'
Binary files src/graphic/text/test/data/br/correct.png	1970-01-01 00:00:00 +0000 and src/graphic/text/test/data/br/correct.png	2016-04-23 13:15:34 +0000 differ
=== removed file 'src/graphic/text/test/data/br/correct.png'
Binary files src/graphic/text/test/data/br/correct.png	2014-07-14 10:45:44 +0000 and src/graphic/text/test/data/br/correct.png	1970-01-01 00:00:00 +0000 differ
=== added file 'src/graphic/text/test/data/br/input00.txt'
--- src/graphic/text/test/data/br/input00.txt	1970-01-01 00:00:00 +0000
+++ src/graphic/text/test/data/br/input00.txt	2016-04-23 13:15:34 +0000
@@ -0,0 +1,13 @@
+<rt db_show_spaces=1>
+<p indent=20>
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
+tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
+vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
+no sea takimata sanctus est Lorem ipsum dolor sit amet.
+<br>
+Lorem2 ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
+tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
+vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
+no sea takimata sanctus est Lorem ipsum dolor sit amet.
+</p>
+</rt>

=== removed file 'src/graphic/text/test/data/br/input00.txt'
--- src/graphic/text/test/data/br/input00.txt	2012-06-20 09:59:07 +0000
+++ src/graphic/text/test/data/br/input00.txt	1970-01-01 00:00:00 +0000
@@ -1,13 +0,0 @@
-<rt db_show_spaces=1>
-<p indent=20>
-Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
-tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
-vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
-no sea takimata sanctus est Lorem ipsum dolor sit amet.
-<br>
-Lorem2 ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
-tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
-vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
-no sea takimata sanctus est Lorem ipsum dolor sit amet.
-</p>
-</rt>

=== added file 'src/graphic/text/test/data/br/width'
--- src/graphic/text/test/data/br/width	1970-01-01 00:00:00 +0000
+++ src/graphic/text/test/data/br/width	2016-04-23 13:15:34 +0000
@@ -0,0 +1,1 @@
+300

=== removed file 'src/graphic/text/test/data/br/width'
--- src/graphic/text/test/data/br/width	2012-06-20 09:59:07 +0000
+++ src/graphic/text/test/data/br/width	1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-300

=== modified file 'src/graphic/text/test/data/bullet_point/input00.txt'
--- src/graphic/text/test/data/bullet_point/input00.txt	2014-07-14 10:45:44 +0000
+++ src/graphic/text/test/data/bullet_point/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,30 +1,30 @@
 <rt>
 <p><font size=20 underline=1>A bullet list</font></p>
-<sub padding=10 width=490>
+<div padding=10 width=490>
 <p>
-<sub valign=top><p><space><img src="pics/bullet.png"></p></sub><sub width=450>
+<div valign=top><p><space><img src="pics/bullet.png"></p></div><div width=450>
 <p>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor.
 </p>
-</sub>
+</div>
 
-<sub valign=top><p><space ><img src="pics/bullet.png"></p></sub><sub width=450>
+<div valign=top><p><space ><img src="pics/bullet.png"></p></div><div width=450>
 <p>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
 vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd
 gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
 </p>
-</sub>
+</div>
 
-<sub valign=top><p><space><img src="pics/bullet.png"></p></sub><sub width=450>
+<div valign=top><p><space><img src="pics/bullet.png"></p></div><div width=450>
 <p>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor.
 </p>
-</sub>
+</div>
 </p>
 
-</sub>
+</div>
 </rt>

=== renamed directory 'src/graphic/text/test/data/sub_autowidth_floatleftimg' => 'src/graphic/text/test/data/div_autowidth_floatleftimg'
=== modified file 'src/graphic/text/test/data/div_autowidth_floatleftimg/input00.txt'
--- src/graphic/text/test/data/sub_autowidth_floatleftimg/input00.txt	2016-02-02 06:13:58 +0000
+++ src/graphic/text/test/data/div_autowidth_floatleftimg/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,9 +1,9 @@
 <rt>
-<sub float=left background=00ff00>
+<div float=left background=00ff00>
    <p>
    <img src="images/logos/wl-ico-128.png">
    </p>
-</sub>
+</div>
 <p>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At

=== renamed directory 'src/graphic/text/test/data/sub_background_img' => 'src/graphic/text/test/data/div_background_img'
=== modified file 'src/graphic/text/test/data/div_background_img/input00.txt'
--- src/graphic/text/test/data/sub_background_img/input00.txt	2014-07-14 10:45:44 +0000
+++ src/graphic/text/test/data/div_background_img/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,10 +1,10 @@
 <rt>
-<sub padding=16 background="pics/chessboard.png" width=380>
+<div padding=16 background="pics/chessboard.png" width=380>
 <p><font color=ff0000 bold=true>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
 vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
 no sea takimata sanctus est Lorem ipsum dolor sit amet.
 </font></p>
-</sub>
+</div>
 </rt>

=== renamed directory 'src/graphic/text/test/data/sub_fixedwidth_floatbothsides' => 'src/graphic/text/test/data/div_fixedwidth_floatbothsides'
=== modified file 'src/graphic/text/test/data/div_fixedwidth_floatbothsides/input00.txt'
--- src/graphic/text/test/data/sub_fixedwidth_floatbothsides/input00.txt	2012-06-20 09:59:07 +0000
+++ src/graphic/text/test/data/div_fixedwidth_floatbothsides/input00.txt	2016-04-23 13:15:34 +0000
@@ -6,7 +6,7 @@
 vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
 no sea takimata sanctus est Lorem ipsum dolor sit amet.
 </p>
-<sub width=100 float=right background=ff0000>
+<div width=100 float=right background=ff0000>
    <p>
 Hello World
 Hello World
@@ -14,11 +14,11 @@
 Hello World
 Hello World
    </p>
-</sub>
+</div>
 <p>
 Lorem ipsum dolor sit amet, consetetur sadipscing
 </p>
-<sub width=100 float=left background=00ff00>
+<div width=100 float=left background=00ff00>
    <p>
 Hello World
 Hello World
@@ -26,7 +26,7 @@
 Hello World
 Hello World
    </p>
-</sub>
+</div>
 <p>elitr, sed diam nonumy eir mod tem por invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
 vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
 no sea takimata sanctus est Lorem ipsum dolor sit amet.

=== renamed directory 'src/graphic/text/test/data/sub_fixedwidth_floatleft' => 'src/graphic/text/test/data/div_fixedwidth_floatleft'
=== modified file 'src/graphic/text/test/data/div_fixedwidth_floatleft/input00.txt'
--- src/graphic/text/test/data/sub_fixedwidth_floatleft/input00.txt	2012-06-20 09:59:07 +0000
+++ src/graphic/text/test/data/div_fixedwidth_floatleft/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,9 +1,9 @@
 <rt>
-<sub width=93 float=left background=00ff00>
+<div width=93 float=left background=00ff00>
    <p><font color=ff0000 size=21>
    This text is inside Sub
    </font></p>
-</sub>
+</div>
 <p>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At

=== renamed directory 'src/graphic/text/test/data/sub_fixedwidth_floatleftimg' => 'src/graphic/text/test/data/div_fixedwidth_floatleftimg'
=== modified file 'src/graphic/text/test/data/div_fixedwidth_floatleftimg/input00.txt'
--- src/graphic/text/test/data/sub_fixedwidth_floatleftimg/input00.txt	2016-02-02 06:13:58 +0000
+++ src/graphic/text/test/data/div_fixedwidth_floatleftimg/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,9 +1,9 @@
 <rt>
-<sub float=left background=00ff00>
+<div float=left background=00ff00>
    <p>
    <img src="images/logos/wl-ico-128.png">
    </p>
-</sub>
+</div>
 <p>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At

=== renamed directory 'src/graphic/text/test/data/sub_fixedwidth_floatright' => 'src/graphic/text/test/data/div_fixedwidth_floatright'
=== modified file 'src/graphic/text/test/data/div_fixedwidth_floatright/input00.txt'
--- src/graphic/text/test/data/sub_fixedwidth_floatright/input00.txt	2012-06-20 09:59:07 +0000
+++ src/graphic/text/test/data/div_fixedwidth_floatright/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,9 +1,9 @@
 <rt>
-<sub width=106 float=right background=00ff00>
+<div width=106 float=right background=00ff00>
    <p><font color=ff0000 size=21>
    This text is inside Sub
    </font></p>
-</sub>
+</div>
 <p>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At

=== renamed directory 'src/graphic/text/test/data/sub_margin_bgclr' => 'src/graphic/text/test/data/div_margin_bgclr'
=== modified file 'src/graphic/text/test/data/div_margin_bgclr/input00.txt'
--- src/graphic/text/test/data/sub_margin_bgclr/input00.txt	2012-06-20 09:59:07 +0000
+++ src/graphic/text/test/data/div_margin_bgclr/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,12 +1,12 @@
 <rt>
-<sub background="ff0000">
-<sub margin=2 padding=16 background=00ff00 width=370>
+<div background="ff0000">
+<div margin=2 padding=16 background=00ff00 width=370>
 <p><font color=ff0000 bold=true>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
 vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
 no sea takimata sanctus est Lorem ipsum dolor sit amet.
 </font></p>
-</sub>
-</sub>
+</div>
+</div>
 </rt>

=== renamed directory 'src/graphic/text/test/data/sub_margin_bgimg' => 'src/graphic/text/test/data/div_margin_bgimg'
=== modified file 'src/graphic/text/test/data/div_margin_bgimg/input00.txt'
--- src/graphic/text/test/data/sub_margin_bgimg/input00.txt	2014-07-14 10:45:44 +0000
+++ src/graphic/text/test/data/div_margin_bgimg/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,12 +1,12 @@
 <rt>
-<sub background="ff0000">
-<sub margin=5 padding=16 background=pics/chessboard.png width=370>
+<div background="ff0000">
+<div margin=5 padding=16 background=pics/chessboard.png width=370>
 <p><font color=ff0000 bold=true>
 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
 tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
 vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
 no sea takimata sanctus est Lorem ipsum dolor sit amet.
 </font></p>
-</sub>
-</sub>
+</div>
+</div>
 </rt>

=== renamed directory 'src/graphic/text/test/data/sub_nonfloating_valign' => 'src/graphic/text/test/data/div_nonfloating_valign'
=== modified file 'src/graphic/text/test/data/div_nonfloating_valign/input00.txt'
--- src/graphic/text/test/data/sub_nonfloating_valign/input00.txt	2016-02-02 06:13:58 +0000
+++ src/graphic/text/test/data/div_nonfloating_valign/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,7 +1,7 @@
 <rt db_show_spaces=1>
-<p><img src="images/logos/wl-ico-128.png"><sub valign=center width=100 padding=5 background="ffffff">
+<p><img src="images/logos/wl-ico-128.png"><div valign=center width=100 padding=5 background="ffffff">
    <p align=center>
 		<font size=10>lorem larum loeffestiel blad lorem lorem loerm ljsdf kljs df</font>
 	</p>
-</sub><img src="images/logos/wl-ico-128.png"></p>
+</div><img src="images/logos/wl-ico-128.png"></p>
 </rt>

=== renamed directory 'src/graphic/text/test/data/sub_padding' => 'src/graphic/text/test/data/div_padding'
=== modified file 'src/graphic/text/test/data/div_padding/input00.txt'
--- src/graphic/text/test/data/sub_padding/input00.txt	2014-07-14 10:45:44 +0000
+++ src/graphic/text/test/data/div_padding/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,7 +1,7 @@
 <rt padding=5>
-<sub padding=7 background=00ff00>
+<div padding=7 background=00ff00>
 <p>
 <img src="pics/red_box.png">
 </p>
-</sub>
+</div>
 </rt>

=== modified file 'src/graphic/text/test/data/font_shadow/input00.txt'
--- src/graphic/text/test/data/font_shadow/input00.txt	2012-06-21 13:06:00 +0000
+++ src/graphic/text/test/data/font_shadow/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,2 +1,2 @@
-<rt><sub width=130><p><font color=ff0000>Hello <font shadow=yes>some shadow</font> World</font></p></sub></rt>
+<rt><div width=130><p><font color=ff0000>Hello <font shadow=yes>some shadow</font> World</font></p></div></rt>
 

=== modified file 'src/graphic/text/test/data/table_like/input00.txt'
--- src/graphic/text/test/data/table_like/input00.txt	2012-06-20 09:59:07 +0000
+++ src/graphic/text/test/data/table_like/input00.txt	2016-04-23 13:15:34 +0000
@@ -1,16 +1,19 @@
 <rt>
-<sub width=10></sub><sub width=240>
-<p>
-<sub width=80 background=638c57><p>Hello</p></sub><space><sub
-width=80 background=42deb7><p>Nice</p></sub><space><sub
-width=80 background=43f447><p>World</p></sub>
-<br>
-
-<sub width=80 background=404542 valign=center><p align=center>Upsy</p></sub><space><sub
-width=80 background=e21038><p>And more</p></sub><space><sub
-width=80 background=0c7e8f valign=center><p>Thats all</p></sub>
-<br>
-
-</p>
-</sub>
+<div width=10></div><div width=240>
+	<p>
+		<div width=80 background=638c57><p>Hello</p></div>
+		<space>
+		<div width=80 background=42deb7><p>Nice</p></div>
+		<space>
+		<div width=80 background=43f447><p>World</p></div>
+	</p>
+	<p>
+		<div width=80 background=404542 valign=center><p align=center>Upsy</p></div>
+		<space>
+		<div width=80 background=e21038><p>And more</p></div>
+		<space>
+		<div width=80 background=0c7e8f valign=center><p>Thats all</p></div>
+		<br>
+	</p>
+</div>
 </rt>

=== added file 'src/graphic/text_constants.h'
--- src/graphic/text_constants.h	1970-01-01 00:00:00 +0000
+++ src/graphic/text_constants.h	2016-04-23 13:15:34 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006-2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_TEXT_CONSTANTS_H
+#define WL_GRAPHIC_TEXT_CONSTANTS_H
+
+// Basic constants for often used text attributes.
+
+/// Font Sizes
+constexpr int kFontSizeBig = 22;
+constexpr int kFontSizeDefault = 14;
+constexpr int kFontSizeSmall = 12;
+constexpr int kFontSizeVerySmall = 10;
+constexpr int kMinimumFontSize = 6;
+
+/// Global UI font colors
+#define UI_FONT_CLR_FG           RGBColor(255, 255,   0)
+#define UI_FONT_CLR_DISABLED     RGBColor(127, 127, 127)
+#define UI_FONT_CLR_WARNING      RGBColor(255,  22,  22)
+#define UI_FONT_CLR_BRIGHT       RGBColor(255, 250, 170)
+#define UI_FONT_CLR_DARK         RGBColor(163, 144,  19)
+#define UI_FONT_CLR_BAD          RGBColor(187,   0,   0)
+#define UI_FONT_CLR_OK           RGBColor(255, 225,  30)
+#define UI_FONT_CLR_GOOD         RGBColor(  0, 187,   0)
+
+#endif  // end of include guard: WL_GRAPHIC_TEXT_CONSTANTS_H

=== removed file 'src/graphic/text_constants.h'
--- src/graphic/text_constants.h	2016-02-08 20:04:17 +0000
+++ src/graphic/text_constants.h	1970-01-01 00:00:00 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2006-2015 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef WL_GRAPHIC_TEXT_CONSTANTS_H
-#define WL_GRAPHIC_TEXT_CONSTANTS_H
-
-// Basic constants for often used text attributes.
-
-/// Font Sizes
-#define UI_FONT_SIZE_BIG        22
-#define UI_FONT_SIZE_SMALL      14
-#define UI_FONT_SIZE_ULTRASMALL 10
-constexpr int kMinimumFontSize = 6;
-
-/// Font colors
-
-/// Global UI font color
-#define UI_FONT_CLR_FG       RGBColor(255, 255,   0)
-#define UI_FONT_CLR_DISABLED RGBColor(127, 127, 127)
-#define UI_FONT_CLR_WARNING  RGBColor(255,  22,  22)
-
-/// Tooltip font color
-#define UI_FONT_TOOLTIP_CLR  RGBColor(255, 255,   0)
-
-/// Colors for good/ok/bad
-#define UI_FONT_CLR_BRIGHT   RGBColor(255, 250, 170)
-#define UI_FONT_CLR_DARK     RGBColor(163, 144,  19)
-#define UI_FONT_CLR_BAD      RGBColor(187,   0,   0)
-#define UI_FONT_CLR_OK       RGBColor(255, 225,  30)
-#define UI_FONT_CLR_GOOD     RGBColor(  0, 187,   0)
-
-#endif  // end of include guard: WL_GRAPHIC_TEXT_CONSTANTS_H

=== modified file 'src/graphic/text_layout.cc'
--- src/graphic/text_layout.cc	2016-03-30 08:38:59 +0000
+++ src/graphic/text_layout.cc	2016-04-23 13:15:34 +0000
@@ -48,6 +48,18 @@
 														ptsize - UI::g_fh1->fontset()->size_offset()))->height();
 }
 
+bool is_richtext(const std::string& text) {
+	return boost::starts_with(text, "<rt");
+}
+
+bool is_paragraph(const std::string& text) {
+	return boost::starts_with(text, "<p");
+}
+
+bool is_div(const std::string& text) {
+	return boost::starts_with(text, "<div");
+}
+
 std::string richtext_escape(const std::string& given_text) {
 	std::string text = given_text;
 	boost::replace_all(text, "&", "&amp;"); // Must be performed first
@@ -76,7 +88,7 @@
 std::string as_editorfont(const std::string& text, int ptsize, const RGBColor& clr) {
 	// UI Text is always bold due to historic reasons
 	static boost::format
-			f("<rt keep_spaces=1><p><font face=sans size=%i bold=1 shadow=1 color=%s>%s</font></p></rt>");
+			f("<rt editor_mode=1><p><font face=sans size=%i bold=1 shadow=1 color=%s>%s</font></p></rt>");
 	f % ptsize;
 	f % clr.hex_value();
 	f % richtext_escape(text);
@@ -120,8 +132,8 @@
 std::string as_tooltip(const std::string & txt) {
 	static boost::format f("<rt><p><font face=sans size=%i bold=1 color=%s>%s</font></p></rt>");
 
-	f % UI_FONT_SIZE_SMALL;
-	f % UI_FONT_TOOLTIP_CLR.hex_value();
+	f % kFontSizeDefault;
+	f % UI_FONT_CLR_FG.hex_value();
 	f % txt;
 	return f.str();
 }
@@ -129,11 +141,17 @@
 std::string as_waresinfo(const std::string & txt) {
 	static boost::format f
 		("<rt><p><font face=condensed size=10 bold=0 color=%s>%s</font></p></rt>");
-	f % UI_FONT_TOOLTIP_CLR.hex_value();
+	f % UI_FONT_CLR_FG.hex_value();
 	f % txt;
 	return f.str();
 }
 
+std::string as_message(const std::string& heading, const std::string& body) {
+	return ((boost::format("<rt><p><font size=18 bold=1 color=D1D1D1>%s<br></font></p><vspace gap=6>%s</rt>")
+				% heading
+				% (is_paragraph(body) || is_div(body) ? body : "<p>" + body + "</p>")).str());
+}
+
 const Image* autofit_ui_text(const std::string& text, int width, RGBColor color, int fontsize) {
 	const Image* result =
 		UI::g_fh1->render(as_uifont(richtext_escape(text), fontsize, color));
@@ -236,7 +254,7 @@
 */
 
 TextStyle::TextStyle() :
-	font(Font::get(UI::g_fh1->fontset()->sans(), UI_FONT_SIZE_SMALL)),
+	font(Font::get(UI::g_fh1->fontset()->sans(), kFontSizeDefault)),
 	fg(UI_FONT_CLR_FG),
 	bold(true),
 	italics(false),

=== modified file 'src/graphic/text_layout.h'
--- src/graphic/text_layout.h	2016-03-02 17:54:32 +0000
+++ src/graphic/text_layout.h	2016-04-23 13:15:34 +0000
@@ -53,9 +53,18 @@
 /**
  * Checks it the given string is RichText or not. Does not do validity checking.
  */
-inline bool is_richtext(const std::string& text) {
-	return text.compare(0, 3, "<rt") == 0;
-}
+bool is_richtext(const std::string& text);
+
+
+/**
+ * Checks it the given string is a RichText paragraph or not. Does not do validity checking.
+ */
+bool is_paragraph(const std::string& text);
+
+/**
+ * Checks it the given string is a RichText div or not. Does not do validity checking.
+ */
+bool is_div(const std::string& text);
 
 /**
  * Escapes reserved characters for Richtext.
@@ -67,26 +76,27 @@
  * of rich text which can be rendered.
  */
 std::string as_uifont
-	(const std::string&, int ptsize = UI_FONT_SIZE_SMALL, const RGBColor& clr = UI_FONT_CLR_FG,
+	(const std::string&, int ptsize = kFontSizeDefault, const RGBColor& clr = UI_FONT_CLR_FG,
 	 UI::FontSet::Face face = UI::FontSet::Face::kSans);
 
 // Same as as_aligned, but with the condensed font preselected.
 std::string as_condensed
 	(const std::string& text,
 	 UI::Align align = UI::Align::kLeft,
-	 int ptsize = UI_FONT_SIZE_SMALL,
+	 int ptsize = kFontSizeDefault,
 	 const RGBColor& clr = UI_FONT_CLR_FG);
 
-std::string as_editorfont(const std::string& text, int ptsize = UI_FONT_SIZE_SMALL,
+std::string as_editorfont(const std::string& text, int ptsize = kFontSizeDefault,
 								  const RGBColor& clr = UI_FONT_CLR_FG);
 
-std::string as_aligned(const std::string & txt, UI::Align align, int ptsize = UI_FONT_SIZE_SMALL,
+std::string as_aligned(const std::string & txt, UI::Align align, int ptsize = kFontSizeDefault,
 							  const RGBColor& clr = UI_FONT_CLR_FG,
 							  UI::FontSet::Face face = UI::FontSet::Face::kSans);
 
 std::string as_tooltip(const std::string&);
 std::string as_waresinfo(const std::string&);
 std::string as_game_tip(const std::string&);
+std::string as_message(const std::string& heading, const std::string& body);
 
 /**
   * Render 'text' as ui_font. If 'width' > 0 and the rendered image is too
@@ -97,7 +107,7 @@
 const Image* autofit_ui_text(const std::string& text,
 									  int width = 0,
 									  RGBColor color = UI_FONT_CLR_FG,
-									  int fontsize = UI_FONT_SIZE_SMALL);
+									  int fontsize = kFontSizeDefault);
 
 namespace UI {
 

=== removed file 'src/graphic/text_parser.cc'
--- src/graphic/text_parser.cc	2016-04-03 12:52:20 +0000
+++ src/graphic/text_parser.cc	1970-01-01 00:00:00 +0000
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2002-2005, 2007-2011 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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 "graphic/text_parser.h"
-
-#include <algorithm>
-#include <cstring>
-#include <string>
-#include <vector>
-
-#include "base/log.h"
-#include "graphic/font_handler1.h"
-#include "graphic/text/bidi.h"
-#include "graphic/text/font_set.h"
-#include "graphic/text_layout.h"
-#include "helper.h"
-
-namespace UI {
-
-RichtextBlock::RichtextBlock() :
-	image_align_(UI::Align::kLeft),
-	text_align_ (UI::Align::kLeft)
-{}
-
-RichtextBlock::RichtextBlock(const RichtextBlock & src) {
-	images_.clear();
-	text_blocks_.clear();
-	for (uint32_t i = 0; i < src.images_.size(); ++i)
-		images_.push_back(src.images_[i]);
-	for (uint32_t i = 0; i < src.text_blocks_.size(); ++i)
-		text_blocks_.push_back(src.text_blocks_[i]);
-	image_align_ = src.image_align_;
-	text_align_ = src.text_align_;
-}
-
-TextBlock::TextBlock() {
-	font_size_ = 10;
-	font_color_ = RGBColor(255, 255, 0);
-	font_weight_ = "normal";
-	font_style_ = "normal";
-	font_decoration_ = "none";
-	font_face_ = (UI::g_fh1->fontset())->sans();
-	line_spacing_ = 0;
-}
-
-void TextParser::parse
-	(std::string                 & text,
-	 std::vector<RichtextBlock> & blocks)
-{
-	bool more_richtext_blocks = true;
-	// First while loop parses all richtext blocks (images)
-	while (more_richtext_blocks) {
-		RichtextBlock new_richtext_block;
-		std::string unparsed_text;
-		std::string richtext_format;
-
-		more_richtext_blocks =
-			extract_format_block
-				(text,
-				 unparsed_text,
-				 richtext_format,
-				 std::string("<rt"),
-				 std::string(">"),
-				 std::string("</rt>"));
-		parse_richtexttext_attributes(richtext_format, &new_richtext_block);
-
-		std::vector<TextBlock> text_blocks;
-
-		// Second while loop parses all textblocks of current richtext block
-		bool more_text_blocks = true;
-		while (more_text_blocks) {
-			std::string block_format;
-			TextBlock new_block;
-
-			std::vector<std::string> words;
-			std::vector<std::vector<std::string>::size_type> line_breaks;
-
-			more_text_blocks =
-				parse_textblock
-					(unparsed_text, block_format, words, line_breaks);
-			parse_text_attributes(block_format, new_block);
-
-			new_block.set_words(words);
-			new_block.set_line_breaks(line_breaks);
-			text_blocks.push_back(new_block);
-		}
-		new_richtext_block.set_text_blocks(text_blocks);
-		blocks.push_back(new_richtext_block);
-	}
-}
-
-bool TextParser::parse_textblock
-	(std::string                                      & block,
-	 std::string                                      & block_format,
-	 std::vector<std::string>                         & words,
-	 std::vector<std::vector<std::string>::size_type> & line_breaks)
-{
-	std::string block_text;
-
-	const bool extract_more = extract_format_block(block, block_text, block_format, "<p", ">", "</p>");
-
-	// Split the the text because of " "
-	std::vector<std::string> unwrapped_words;
-	split_words(block_text, &unwrapped_words);
-
-	// Handle user defined line breaks, and save them
-	for (const std::string& temp_words : unwrapped_words) {
-		for (std::string line = temp_words;;) {
-			line = i18n::make_ligatures(line.c_str());
-			std::string::size_type next_break = line.find("<br>");
-
-			if (next_break == std::string::npos) {
-				if (line.size()) {
-					std::string word = line;
-					replace_entities(&word);
-					words.push_back(word);
-				}
-				break;
-			} else if (next_break) {
-				std::string word = line.substr(0, next_break);
-				replace_entities(&word);
-				words.push_back(word);
-			}
-			line_breaks.push_back(words.size());
-			line.erase(0, next_break + 4);
-		}
-	}
-	return extract_more;
-}
-
-void TextParser::split_words(const std::string & in, std::vector<std::string>* plist)
-{
-	std::string::size_type pos = 0;
-
-	while (pos < in.size()) {
-		while (pos < in.size() && isspace(in[pos]))
-			++pos;
-		if (pos >= in.size())
-			break;
-
-		std::string::size_type nextspace = pos;
-		while (nextspace < in.size() && !isspace(in[nextspace]))
-			++nextspace;
-
-		if (nextspace > pos)
-			plist->push_back(in.substr(pos, nextspace - pos));
-
-		pos = nextspace;
-	}
-}
-
-bool TextParser::extract_format_block
-	(std::string       & block,
-	 std::string       & block_text,
-	 std::string       & block_format,
-	 const std::string & block_start,
-	 const std::string & format_end,
-	 const std::string & block_end)
-{
-	if (block.compare(0, block_start.size(), block_start)) {
-		const std::string::size_type format_begin_pos = block.find(block_start);
-		if (format_begin_pos == std::string::npos) {
-			return false;
-		}
-		block.erase(0, format_begin_pos);
-	}
-
-	block.erase(0, block_start.size());
-	if (block.size() && *block.begin() == ' ')
-		block.erase(0, 1);
-
-	const std::string::size_type format_end_pos = block.find(format_end);
-	if (format_end_pos == std::string::npos) {
-		return false;
-	}
-
-	// Append block_format
-	block_format.erase();
-	block_format.append(block.substr(0, format_end_pos));
-
-	// Delete whole format block
-	block.erase(0, format_end_pos + format_end.size());
-
-	// Find end of block
-	const std::string::size_type block_end_pos = block.find(block_end);
-	if (block_end_pos == std::string::npos) {
-		return false;
-	}
-	// Extract text of block
-	block_text.erase();
-	block_text.append(block.substr(0, block_end_pos));
-
-	// Erase text including closing tag
-	block.erase(0, block_end_pos + block_end.size());
-	// Is something left
-	return block.find(block_start) != std::string::npos;
-}
-
-void TextParser::parse_richtexttext_attributes
-	(std::string format, RichtextBlock * const element)
-{
-	if (format.empty())
-		return;
-	if (format[0] == ' ')
-		format.erase(0, 1);
-
-	while (format.size()) {
-		std::string::size_type const key_end = format.find('=');
-		if (key_end == std::string::npos)
-			return;
-		else {
-			std::string const key = format.substr(0, key_end);
-			format.erase(0, key_end + 1);
-			std::string::size_type val_end = format.find(' ');
-			if (val_end == std::string::npos)
-				val_end = format.size();
-			std::string val = format.substr(0, val_end);
-			format.erase(0, val_end + 1);
-			if        (key == "image") {
-				const std::vector<std::string> images(split_string(val, ";"));
-				element->set_images(images);
-			} else if (key == "image-align")
-				element->set_image_align(set_align(val));
-			else if   (key == "text-align")
-				element->set_text_align(set_align(val));
-		}
-	}
-}
-
-void TextParser::parse_text_attributes
-	(std::string format, TextBlock & element)
-{
-	if (format.empty())
-		return;
-	if (format[0] == ' ')
-		format.erase(0, 1);
-
-	while (format.size()) {
-		std::string::size_type const key_end = format.find('=');
-		if (key_end == std::string::npos) {
-			return;
-		} else {
-			std::string key = format.substr(0, key_end);
-			format.erase(0, key_end + 1);
-			std::string::size_type val_end = format.find(' ');
-			if (val_end == std::string::npos)
-				val_end = format.size();
-			std::string val = format.substr(0, val_end);
-			format.erase(0, val_end + 1);
-			if (key == "font-size") {
-				element.set_font_size(atoi(val.c_str()));
-			} else if (key == "font-face") {
-				const UI::FontSet& fontset = *UI::g_fh1->fontset();
-				if (val == fontset.condensed() || val == "condensed") {
-					val = fontset.condensed();
-				} else if (val == fontset.serif() || val == "serif") {
-					val = fontset.serif();
-				} else {
-					val = fontset.sans();
-				}
-				element.set_font_style(val);
-			} else if (key == "line-spacing") {
-				element.set_line_spacing(atoi(val.c_str()));
-			} else if (key == "font-color") {
-				std::string::size_type const offset = val[0] == '#';
-				std::string const r = "0x" + val.substr(offset,     2);
-				std::string const g = "0x" + val.substr(offset + 2, 2);
-				std::string const b = "0x" + val.substr(offset + 4, 2);
-
-				char * ptr;
-				long int const red   = strtol(r.c_str(), &ptr, 0);
-				long int const green = strtol(g.c_str(), &ptr, 0);
-				long int const blue  = strtol(b.c_str(), &ptr, 0);
-				element.set_font_color(RGBColor(red, green, blue));
-			} else if (key == "font-weight") {
-				element.set_font_weight(val);
-			} else if (key == "font-style") {
-				element.set_font_style(val);
-			} else if (key == "font-decoration") {
-				element.set_font_decoration(val);
-			}
-		}
-	}
-}
-
-Align TextParser::set_align(const std::string & align) {
-	return
-		align == "right"  ? UI::Align::kRight   :
-		align == "center" ? UI::Align::kHCenter :
-		UI::Align::kLeft;
-}
-
-}

=== removed file 'src/graphic/text_parser.h'
--- src/graphic/text_parser.h	2016-03-14 19:49:52 +0000
+++ src/graphic/text_parser.h	1970-01-01 00:00:00 +0000
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2002-2011 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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 WL_GRAPHIC_TEXT_PARSER_H
-#define WL_GRAPHIC_TEXT_PARSER_H
-
-#include <string>
-#include <vector>
-
-#include "graphic/align.h"
-#include "graphic/color.h"
-
-namespace UI {
-
-/**
- * Corresponds to a richtext block that is enclosed in <p></p> tags.
- * Has uniform font style, contains text pre-split into words, and keeps track of
- * manual line breaks (<br>) in a separate structure.
- */
-struct TextBlock {
-	TextBlock();
-	// Copy and assignement operators are autogenerated.
-
-	void set_font_size(int32_t const font_size) {font_size_ = font_size;}
-	int32_t get_font_size() const {return font_size_;}
-
-	void set_font_color(const RGBColor & font_color) {font_color_ = font_color;}
-	RGBColor get_font_color() const {return font_color_;}
-
-	void set_font_weight(const std::string & font_weight) {
-		font_weight_ = font_weight;
-	}
-	const std::string & get_font_weight() const {return font_weight_;}
-
-	void set_font_style(const std::string & font_style) {
-		font_style_ = font_style;
-	}
-	const std::string & get_font_style() const {return font_style_;}
-
-	void set_font_decoration(const std::string & font_decoration) {
-		font_decoration_ = font_decoration;
-	}
-	const std::string & get_font_decoration() const {return font_decoration_;}
-
-	void set_font_face(const std::string & font_face) {font_face_ = font_face;}
-	const std::string & get_font_face() const {return font_face_;}
-
-	void set_line_spacing(int32_t const line_spacing) {
-		line_spacing_ = line_spacing;
-	}
-	int32_t get_line_spacing() const {return line_spacing_;}
-
-	void set_words(const std::vector<std::string> & words) {words_ = words;}
-	const std::vector<std::string> & get_words() const {return words_;}
-
-	void set_line_breaks
-		(const std::vector<std::vector<std::string>::size_type> & line_breaks)
-	{
-		line_breaks_ = line_breaks;
-	}
-	const std::vector<std::vector<std::string>::size_type> & get_line_breaks
-		() const
-	{
-		return line_breaks_;
-	}
-private:
-	int32_t                                          font_size_;
-	RGBColor                                         font_color_;
-	std::string                                      font_weight_;
-	std::string                                      font_style_;
-	std::string                                      font_decoration_;
-	std::string                                      font_face_;
-	int32_t                                          line_spacing_;
-	std::vector<std::string>                         words_;
-
-	/**
-	 * Position of manual line breaks (<br>) with respect to @ref words_.
-	 * Sorted in ascending order.
-	 * An entry j in this vector means that a manual line break occurs
-	 * before the j-th word in @ref words_. In particular, an entry 0
-	 * means that a manual line break occurs before the first word.
-	 * Entries can appear with multiplicity, indicating that multiple
-	 * manual line breaks exist without any words in-between.
-	 */
-	std::vector<std::vector<std::string>::size_type> line_breaks_;
-};
-
-struct RichtextBlock {
-	RichtextBlock();
-	RichtextBlock(const RichtextBlock & src);
-
-	void set_images(const std::vector<std::string> & images) {
-		images_ = images;
-	}
-	const std::vector<std::string> & get_images() const {return images_;}
-
-	void set_image_align(Align const image_align) {image_align_ = image_align;}
-	Align get_image_align() const {return image_align_;}
-
-	void set_text_align(Align const text_align) {text_align_ = text_align;}
-	Align get_text_align() const {return text_align_;}
-
-	void set_text_blocks(const std::vector<TextBlock> & text_blocks) {
-		text_blocks_ = text_blocks;
-	}
-	const std::vector<TextBlock> & get_text_blocks() const {
-		return text_blocks_;
-	}
-private:
-	std::vector<std::string> images_;
-	std::vector<TextBlock>  text_blocks_;
-	Align image_align_;
-	Align text_align_;
-};
-
-struct TextParser {
-	void parse
-		(std::string & text,
-		 std::vector<RichtextBlock> & blocks);
-private:
-	void parse_richtexttext_attributes(std::string format, RichtextBlock *);
-	bool parse_textblock
-		(std::string                                       & block,
-		 std::string                                       & block_format,
-		 std::vector<std::string>                          & words,
-		 std::vector<std::vector<std::string>::size_type>  & line_breaks);
-	void parse_text_attributes(std::string format, TextBlock &);
-	bool extract_format_block
-		(std      ::string & block,
-		 std      ::string & block_text,
-		 std      ::string & block_format,
-		 const std::string & block_start,
-		 const std::string & format_end,
-		 const std::string & block_end);
-	Align set_align(const std::string &);
-	void split_words(const std::string & in, std::vector<std::string> * plist);
-};
-
-}
-
-#endif  // end of include guard: WL_GRAPHIC_TEXT_PARSER_H

=== modified file 'src/logic/cmd_luacoroutine.cc'
--- src/logic/cmd_luacoroutine.cc	2016-04-10 16:53:41 +0000
+++ src/logic/cmd_luacoroutine.cc	2016-04-23 13:15:34 +0000
@@ -19,8 +19,6 @@
 
 #include "logic/cmd_luacoroutine.h"
 
-#include <boost/format.hpp>
-
 #include "base/log.h"
 #include "base/macros.h"
 #include "io/fileread.h"
@@ -57,7 +55,7 @@
 				 "Coroutine",
 				 "images/ui_basic/menu_help.png",
 				 "Lua Coroutine Failed",
-				 (boost::format("<rt><p font-size=12>%s</p></rt>") % e.what()).str());
+				 e.what());
 			game.player(i).add_message(game, msg, true);
 		}
 		game.game_controller()->set_desired_speed(0);

=== modified file 'src/logic/map_objects/map_object.cc'
--- src/logic/map_objects/map_object.cc	2016-03-19 12:51:22 +0000
+++ src/logic/map_objects/map_object.cc	2016-04-23 13:15:34 +0000
@@ -26,6 +26,8 @@
 #include <memory>
 #include <string>
 
+#include <boost/format.hpp>
+
 #include "base/log.h"
 #include "base/wexception.h"
 #include "graphic/font_handler1.h"
@@ -36,6 +38,7 @@
 #include "io/filewrite.h"
 #include "logic/cmd_queue.h"
 #include "logic/game.h"
+#include "logic/player.h"
 #include "logic/queue_cmd_ids.h"
 #include "map_io/map_object_loader.h"
 #include "map_io/map_object_saver.h"
@@ -574,6 +577,71 @@
 	log("MO(%u,%s): %s", serial_, descr().name().c_str(), buffer);
 }
 
+
+/**
+ * Send a message about this map object to the owning player.
+ *
+ * It will have the map object's coordinates, and display a picture of the
+ * map object in its description.
+ * \param game the current game
+ * \param owner the player who owns this map object
+ * \param msgtype the category for this message, for playing sounds and assigning message filter buttons
+ * \param title a short title of the message used in listings
+ * \param icon_filename picture name relative to the data/ directory, used in listings
+ * \param heading a long title, used in the message itself
+ * \param representative_image_filename picture name to be displayed within the message
+ * \param description user-visible message body, will be placed in an
+ *   appropriate rich-text div
+ * \param position the current position of the map object
+ * \param link_to_lifetime if true, the message will be deleted when this
+ *   map object is removed from the game. Default is true
+ * \param throttle_time if non-zero, the minimum time delay in milliseconds
+ *   between messages of this type (see \p msgsender) within the
+ *   given \p throttle_radius
+ */
+void MapObject::send_message
+	(Game& game,
+	 Player* owner,
+	 const Message::Type msgtype,
+	 const std::string& title,
+	 const std::string& icon_filename,
+	 const std::string& heading,
+	 const std::string& representative_image_filename,
+	 const std::string& description,
+	 const Coords& position,
+	 bool link_to_lifetime,
+	 uint32_t throttle_time,
+	 uint32_t throttle_radius)
+{
+	// TODO(sirver): add support into the font renderer to get to representative
+	// animations of buildings.
+
+	// NOCOM(GunChleoc): We need to specify the width, because the second div won't expand automatically.
+	// This depends on the width of the message window.
+	constexpr int message_width = 315;
+	const int image_width = g_gr->images().get(representative_image_filename)->width();
+	const std::string rt_description =
+			(boost::format("<div width=100%%></div><div width=%d padding_r=4><p><img src=%s color=%s></p></div>"
+								"<div width=%d><p><font size=%d>%s</font></p></div>")
+			 % image_width
+			 % representative_image_filename
+			 % owner->get_playercolor().hex_value()
+			 % (message_width - image_width)
+			 % kFontSizeSmall
+			 % description).str();
+
+	Message* msg = new Message
+		(msgtype, game.get_gametime(), title, icon_filename, heading, rt_description,
+		 position, (link_to_lifetime ? serial_ : 0));
+
+	if (throttle_time) {
+		owner->add_message_with_timeout(game, *msg, throttle_time, throttle_radius);
+	} else {
+		owner->add_message(game, *msg);
+	}
+}
+
+
 bool MapObject::is_reserved_by_worker() const
 {
 	return reserved_by_worker_;

=== modified file 'src/logic/map_objects/map_object.h'
--- src/logic/map_objects/map_object.h	2016-03-19 11:38:22 +0000
+++ src/logic/map_objects/map_object.h	2016-04-23 13:15:34 +0000
@@ -36,6 +36,7 @@
 #include "graphic/image.h"
 #include "logic/cmd_queue.h"
 #include "logic/map_objects/tribes/training_attribute.h"
+#include "logic/message.h"
 #include "logic/widelands.h"
 #include "scripting/lua_table.h"
 
@@ -233,7 +234,7 @@
 	};
 
 	struct LogSink {
-		virtual void log(std::string str) = 0;
+		virtual void log(const std::string& str) = 0;
 		virtual ~LogSink() {}
 	};
 
@@ -292,6 +293,19 @@
 	/// Called when a new logsink is set. Used to give general information.
 	virtual void log_general_info(const EditorGameBase &);
 
+	void send_message
+		(Game& game, Player* owner,
+		 const Message::Type msgtype,
+		 const std::string& title,
+		 const std::string& icon_filename,
+		 const std::string& heading,
+		 const std::string& representative_image_filename,
+		 const std::string& description,
+		 const Coords& position,
+		 bool link_to_lifetime = true,
+		 uint32_t throttle_time = 0,
+		 uint32_t throttle_radius = 0);
+
 	// Header bytes to distinguish between data packages for the different
 	// MapObject classes. Be careful in changing those, since they are written
 	// to files.

=== modified file 'src/logic/map_objects/tribes/building.cc'
--- src/logic/map_objects/tribes/building.cc	2016-04-01 09:29:17 +0000
+++ src/logic/map_objects/tribes/building.cc	2016-04-23 13:15:34 +0000
@@ -25,7 +25,6 @@
 #include <sstream>
 
 #include <boost/algorithm/string.hpp>
-#include <boost/format.hpp>
 
 #include "base/macros.h"
 #include "base/wexception.h"
@@ -793,63 +792,4 @@
 	seeing_ = see;
 }
 
-/**
- * Send a message about this building to the owning player.
- *
- * It will have the building's coordinates, and display a picture of the
- * building in its description.
- *
- * \param msgsender a computer-readable description of why the message was sent
- * \param title user-visible title of the message
- * \param description user-visible message body, will be placed in an
- *   appropriate rich-text paragraph
- * \param link_to_building_lifetime if true, the message will be deleted when this
- *   building is removed from the game. Default is true
- * \param throttle_time if non-zero, the minimum time delay in milliseconds
- *   between messages of this type (see \p msgsender) within the
- *   given \p throttle_radius
- */
-void Building::send_message
-	(Game & game,
-	 const Message::Type msgtype,
-	 const std::string & title,
-	 const std::string & icon_filename,
-	 const std::string & heading,
-	 const std::string & description,
-	 bool link_to_building_lifetime,
-	 uint32_t throttle_time,
-	 uint32_t throttle_radius)
-{
-	// TODO(sirver): add support into the font renderer to get to representative
-	// animations of buildings so that the messages can still be displayed, even
-	// after reload.
-	const std::string& img = descr().representative_image_filename();
-	std::string rt_description;
-	rt_description.reserve
-		(strlen("<rt image=") + img.size() + 1 +
-		 strlen("<p font-size=14 font-face=serif>") +
-		 description.size() +
-		 strlen("</p></rt>"));
-	rt_description  = "<rt image=";
-	rt_description += img;
-	{
-		std::string::iterator it = rt_description.end() - 1;
-		for (; it != rt_description.begin() && *it != '?'; --it) {}
-		for (;                                 *it == '?'; --it)
-			*it = '0';
-	}
-	rt_description = (boost::format("%s><p font-face=serif font-size=14>%s</p></rt>")
-			% rt_description % description).str();
-
-	Message * msg = new Message
-		(msgtype, game.get_gametime(), title, icon_filename, heading, rt_description,
-		 get_position(), (link_to_building_lifetime ? serial_ : 0));
-
-	if (throttle_time)
-		owner().add_message_with_timeout
-			(game, *msg, throttle_time, throttle_radius);
-	else
-		owner().add_message(game, *msg);
-}
-
-}
+} // namespace Widelands

=== modified file 'src/logic/map_objects/tribes/building.h'
--- src/logic/map_objects/tribes/building.h	2016-03-19 09:58:41 +0000
+++ src/logic/map_objects/tribes/building.h	2016-04-23 13:15:34 +0000
@@ -256,16 +256,6 @@
 	void remove_worker(Worker &) override;
 	mutable boost::signals2::signal<void ()> workers_changed;
 
-	void send_message
-		(Game & game,
-		 const Message::Type msgtype,
-		 const std::string & title,
-		 const std::string& icon_filename, const std::string& heading,
-		 const std::string & description,
-		 bool link_to_building_lifetime = true,
-		 uint32_t throttle_time = 0,
-		 uint32_t throttle_radius = 0);
-
 protected:
 	// Updates 'statistics_string' with the string that should be displayed for
 	// this building right now. Overwritten by child classes.

=== modified file 'src/logic/map_objects/tribes/militarysite.cc'
--- src/logic/map_objects/tribes/militarysite.cc	2016-04-03 08:01:49 +0000
+++ src/logic/map_objects/tribes/militarysite.cc	2016-04-23 13:15:34 +0000
@@ -256,11 +256,14 @@
 		if (upcast(Game, game, &egbase)) {
 			send_message
 				(*game,
+				 get_owner(),
 				 Message::Type::kEconomySiteOccupied,
 				 descr().descname(),
 				 descr().icon_filename(),
 				 descr().descname(),
+				 descr().representative_image_filename(),
 				 descr().occupied_str_,
+				 get_position(),
 				 true);
 		}
 	}
@@ -868,12 +871,15 @@
 		{
 			send_message
 				(game,
+				 get_owner(),
 				 Message::Type::kWarfareSiteLost,
 				 /** TRANSLATORS: Militarysite lost (taken/destroyed by enemy) */
 				 pgettext("building", "Lost!"),
 				 descr().icon_filename(),
 				 _("Militarysite lost!"),
+				 descr().representative_image_filename(),
 				 descr().defeated_enemy_str_,
+				 get_position(),
 				 false);
 		}
 
@@ -912,13 +918,16 @@
 		// Of course we should inform the victorious player as well
 		newsite->send_message
 			(game,
+			 newsite->get_owner(),
 			 Message::Type::kWarfareSiteDefeated,
 			 /** TRANSLATORS: Message title. */
 			 /** TRANSLATORS: If you run out of space, you can also translate this as "Success!" */
 			 _("Enemy Defeated!"),
 			 newsite->descr().icon_filename(),
 			 _("Enemy at site defeated!"),
+			 newsite->descr().representative_image_filename(),
 			 newsite->descr().defeated_you_str_,
+			 newsite->get_position(),
 			 true);
 
 		return false;
@@ -966,12 +975,15 @@
 	// radius <= 5 near the current location in the last 60 seconds
 	send_message
 		(game,
+		 get_owner(),
 		 Message::Type::kWarfareUnderAttack,
 		 /** TRANSLATORS: Militarysite is being attacked */
 		 pgettext("building", "Attack!"),
 		 descr().icon_filename(),
 		 _("You are under attack"),
+		 descr().representative_image_filename(),
 		 discovered ? descr().aggressor_str_ : descr().attack_str_,
+		 get_position(),
 		 false,
 		 60 * 1000, 5);
 }

=== modified file 'src/logic/map_objects/tribes/productionsite.cc'
--- src/logic/map_objects/tribes/productionsite.cc	2016-03-12 07:07:12 +0000
+++ src/logic/map_objects/tribes/productionsite.cc	2016-04-23 13:15:34 +0000
@@ -986,11 +986,14 @@
 			assert(!descr().out_of_resource_message().empty());
 			send_message
 				(game,
+				 get_owner(),
 				 Message::Type::kEconomy,
 				 descr().out_of_resource_title(),
 				 descr().icon_filename(),
 				 descr().out_of_resource_heading(),
+				 descr().representative_image_filename(),
 				 descr().out_of_resource_message(),
+				 get_position(),
 				 true,
 				 minutes * 60000, 0);
 		}

=== modified file 'src/logic/map_objects/tribes/ship.cc'
--- src/logic/map_objects/tribes/ship.cc	2016-04-05 07:51:48 +0000
+++ src/logic/map_objects/tribes/ship.cc	2016-04-23 13:15:34 +0000
@@ -413,12 +413,17 @@
 
 		if (new_port_space) {
 			ship_state_ = ShipStates::kExpeditionPortspaceFound;
+
 			send_message(
 						game,
+						get_owner(),
+						Message::Type::kSeafaring,
 						_("Port Space"),
+						"images/wui/editor/fsel_editor_set_port_space.png",
 						_("Port Space Found"),
+						"images/wui/editor/fsel_editor_set_port_space.png",
 						_("An expedition ship found a new port build space."),
-						"images/wui/editor/fsel_editor_set_port_space.png");
+						position);
 		}
 		expedition_->seen_port_buildspaces = temp_port_buildspaces;
 		if (new_port_space) {
@@ -532,14 +537,19 @@
 					expedition_->exploration_start = get_position();
 				} else {
 					// Check whether the island was completely surrounded
-					if (get_position() == expedition_->exploration_start) {
+					const FCoords& position = get_position();
+					if (position == expedition_->exploration_start) {
 						send_message(
 									game,
+									get_owner(),
+									Message::Type::kSeafaring,
 									/** TRANSLATORS: A ship has circumnavigated an island and is waiting for orders */
 									pgettext("ship", "Waiting"),
+									"images/wui/ship/ship_explore_island_cw.png",
 									_("Island Circumnavigated"),
+									"images/wui/ship/ship_explore_island_cw.png",
 									_("An expedition ship sailed around its island without any events."),
-									"images/wui/ship/ship_explore_island_cw.png");
+									position);
 						ship_state_ = ShipStates::kExpeditionWaiting;
 
 						Notifications::publish(
@@ -599,11 +609,15 @@
 			// Send a message to the player, that a new coast was reached
 			send_message(
 						game,
+						get_owner(),
+						Message::Type::kSeafaring,
 						/** TRANSLATORS: A ship has discovered land */
 						_("Land Ahoy!"),
+						"images/wui/ship/ship_scout_ne.png",
 						_("Coast Reached"),
+						"images/wui/ship/ship_scout_ne.png",
 						_("An expedition ship reached a coast and is waiting for further commands."),
-						"images/wui/ship/ship_scout_ne.png");
+						get_position());
 
 			Notifications::publish(
 			   NoteShipMessage(this, NoteShipMessage::Message::kWaitingForCommand));
@@ -662,10 +676,14 @@
 			// Send a message to the player, that a port constructionsite is gone
 			send_message(
 						game,
+						get_owner(),
+						Message::Type::kSeafaring,
 						_("Port Lost!"),
+						"images/wui/ship/menu_ship_cancel_expedition.png",
 						_("New port construction site is gone"),
+						"images/wui/ship/menu_ship_cancel_expedition.png",
 						_("Unloading of wares failed, expedition is cancelled now."),
-						"images/wui/ship/menu_ship_cancel_expedition.png");
+						get_position());
 			send_signal(game, "cancel_expedition");
 		}
 
@@ -844,11 +862,15 @@
 	// Send a message to the player, that an expedition is ready to go
 	send_message(
 				game,
+				get_owner(),
+				Message::Type::kSeafaring,
 				/** TRANSLATORS: Ship expedition ready */
 				pgettext("ship", "Expedition"),
+				"images/wui/buildings/start_expedition.png",
 				_("Expedition Ready"),
+				"images/wui/buildings/start_expedition.png",
 				_("An expedition ship is waiting for your commands."),
-				"images/wui/buildings/start_expedition.png");
+				get_position());
 	Notifications::publish(NoteShipMessage(this, NoteShipMessage::Message::kWaitingForCommand));
 }
 
@@ -1032,43 +1054,6 @@
 	}
 }
 
-/**
- * Send a message to the owning player.
- *
- * It will have the ship's coordinates, and display a picture in its description.
- *
- * \param msgsender a computer-readable description of why the message was sent
- * \param title user-visible title of the message
- * \param description user-visible message body, will be placed in an appropriate rich-text
- *paragraph
- * \param picture picture name relative to the data/ directory
- */
-void Ship::send_message(Game& game,
-								const std::string& title,
-								const std::string& heading,
-                        const std::string& description,
-                        const std::string& picture) {
-	std::string rt_description;
-	if (picture.size() > 3) {
-		rt_description = "<rt image=";
-		rt_description += picture;
-		rt_description += "><p font-size=14 font-face=serif>";
-	} else
-		rt_description = "<rt><p font-size=14 font-face=serif>";
-	rt_description += description;
-	rt_description += "</p></rt>";
-
-	Message* msg = new Message(Message::Type::kSeafaring,
-	                           game.get_gametime(),
-										title,
-										picture,
-										heading,
-	                           rt_description,
-	                           get_position(),
-	                           serial_);
-
-	get_owner()->add_message(game, *msg);
-}
 
 /*
 ==============================

=== modified file 'src/logic/map_objects/tribes/ship.h'
--- src/logic/map_objects/tribes/ship.h	2016-04-03 08:01:49 +0000
+++ src/logic/map_objects/tribes/ship.h	2016-04-23 13:15:34 +0000
@@ -238,12 +238,6 @@
 	void init_fleet(EditorGameBase &);
 	void set_fleet(Fleet * fleet);
 
-	void send_message(Game& game,
-							const std::string& title,
-							const std::string& heading,
-							const std::string& description,
-							const std::string& picture);
-
 	UI::Window * window_;
 
 	Fleet   * fleet_;

=== modified file 'src/logic/map_objects/tribes/soldier.cc'
--- src/logic/map_objects/tribes/soldier.cc	2016-04-10 16:53:41 +0000
+++ src/logic/map_objects/tribes/soldier.cc	2016-04-23 13:15:34 +0000
@@ -1483,7 +1483,7 @@
 							 descr().descname(),
 							 "images/ui_basic/menu_help.png",
 							 _("Logic error"),
-							 (boost::format("<rt><p font-size=12>%s</p></rt>") % messagetext).str(),
+							 messagetext,
 						 	 get_position(),
 							 serial_));
 					opponent.owner().add_message
@@ -1494,7 +1494,7 @@
 							 descr().descname(),
 							 "images/ui_basic/menu_help.png",
 							 _("Logic error"),
-							 (boost::format("<rt><p font-size=12>%s</p></rt>") % messagetext).str(),
+							 messagetext,
 						 	 opponent.get_position(),
 							 serial_));
 					game.game_controller()->set_desired_speed(0);

=== modified file 'src/logic/map_objects/tribes/warehouse.cc'
--- src/logic/map_objects/tribes/warehouse.cc	2016-04-03 08:01:49 +0000
+++ src/logic/map_objects/tribes/warehouse.cc	2016-04-23 13:15:34 +0000
@@ -452,29 +452,38 @@
 		if (descr().get_isport()) {
 			send_message
 				(*game,
+				 get_owner(),
 				 Message::Type::kSeafaring,
 				 descr().descname(),
 				 descr().icon_filename(),
 				 descr().descname(),
+				 descr().representative_image_filename(),
 				 _("A new port was added to your economy."),
+				 get_position(),
 				 true);
 		} else if (!descr().is_buildable()) {
 			send_message
 				(*game,
+				 get_owner(),
 				 Message::Type::kEconomy,
 				 descr().descname(),
 				 descr().icon_filename(),
 				 descr().descname(),
+				 descr().representative_image_filename(),
 				 _("A new headquarters was added to your economy."),
+				 get_position(),
 				 true);
 		} else {
 			send_message
 				(*game,
+				 get_owner(),
 				 Message::Type::kEconomy,
 				 descr().descname(),
 				 descr().icon_filename(),
 				 descr().descname(),
+				 descr().representative_image_filename(),
 				 _("A new warehouse was added to your economy."),
+				 get_position(),
 				 true);
 		}
 	}

=== modified file 'src/logic/map_objects/tribes/worker.cc'
--- src/logic/map_objects/tribes/worker.cc	2016-04-11 06:45:29 +0000
+++ src/logic/map_objects/tribes/worker.cc	2016-04-23 13:15:34 +0000
@@ -924,11 +924,6 @@
 
 		// Geologist also sends a message notifying the player
 		if (rdescr && rdescr->detectable() && position.field->get_resources_amount()) {
-			const std::string message =
-					(boost::format("<rt image=%s><p font-face=serif font-size=14>%s</p></rt>")
-					 % rdescr->representative_image()
-					 % _("A geologist found resources.")).str();
-
 			Message::Type message_type = Message::Type::kGeologists;
 			if (rdescr->name() == "coal")
 				message_type = Message::Type::kGeologistsCoal;
@@ -941,20 +936,19 @@
 			else if (rdescr->name() == "water")
 				message_type = Message::Type::kGeologistsWater;
 
-			//  We should add a message to the player's message queue - but only,
-			//  if there is not already a similar one in list.
-			owner().add_message_with_timeout
-					(game,
-					 *new Message
-							 (message_type,
-							  game.get_gametime(),
-							  rdescr->descname(),
-							  ri.descr().representative_image_filename(),
-							  rdescr->descname(),
-							  message,
-							  position,
-							  serial_),
-					 300000, 8);
+			send_message
+				(game,
+				 get_owner(),
+				 message_type,
+				 rdescr->descname(),
+				 ri.descr().representative_image_filename(),
+				 rdescr->descname(),
+				 rdescr->representative_image_filename(),
+				 _("A geologist found resources."),
+				 get_position(),
+				 false,
+				 300000,
+				 8);
 		}
 	}
 
@@ -1844,9 +1838,9 @@
 				 _("Worker"),
 				 "images/ui_basic/menu_help.png",
 				 _("Worker got lost!"),
-				 (boost::format("<rt><p font-size=12>%s</p></rt>") % message).str(),
-				 get_position()),
-				 serial_);
+				 message,
+				 get_position(),
+				 serial_));
 		set_location(nullptr);
 		return pop_task(game);
 	}

=== modified file 'src/logic/map_objects/world/resource_description.cc'
--- src/logic/map_objects/world/resource_description.cc	2016-03-09 09:35:13 +0000
+++ src/logic/map_objects/world/resource_description.cc	2016-04-23 13:15:34 +0000
@@ -32,7 +32,7 @@
      descname_(table.get_string("descname")),
      detectable_(table.get_bool("detectable")),
 	  max_amount_(table.get_int("max_amount")),
-	  representative_image_(table.get_string("representative_image")) {
+	  representative_image_filename_(table.get_string("representative_image")) {
 
 	std::unique_ptr<LuaTable> st = table.get_table("editor_pictures");
 	const std::set<int> keys = st->keys<int>();

=== modified file 'src/logic/map_objects/world/resource_description.h'
--- src/logic/map_objects/world/resource_description.h	2016-03-09 09:35:13 +0000
+++ src/logic/map_objects/world/resource_description.h	2016-04-23 13:15:34 +0000
@@ -56,14 +56,14 @@
 	const std::string& editor_image(uint32_t amount) const;
 
 	/// Returns the path to the image that should be used in menus to represent this resource
-	const std::string& representative_image() const {return representative_image_;}
+	const std::string& representative_image_filename() const {return representative_image_filename_;}
 
 private:
 	const std::string name_;
 	const std::string descname_;
 	const bool detectable_;
 	const ResourceAmount max_amount_;
-	const std::string representative_image_;
+	const std::string representative_image_filename_;
 	std::vector<EditorPicture> editor_pictures_;
 
 	DISALLOW_COPY_AND_ASSIGN(ResourceDescription);

=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc	2016-04-22 06:55:37 +0000
+++ src/scripting/lua_map.cc	2016-04-23 13:15:34 +0000
@@ -2978,7 +2978,7 @@
 			(RO) the :class:`string` path to the image representing this resource in the GUI
 */
 int LuaResourceDescription::get_representative_image(lua_State * L) {
-	lua_pushstring(L, get()->representative_image());
+	lua_pushstring(L, get()->representative_image_filename());
 	return 1;
 }
 

=== modified file 'src/ui_basic/button.h'
--- src/ui_basic/button.h	2016-02-09 16:29:48 +0000
+++ src/ui_basic/button.h	2016-04-23 13:15:34 +0000
@@ -30,8 +30,6 @@
 
 namespace UI {
 
-struct Font;
-
 /// This is simply a button. Override void clicked() to react to the click.
 /// This is all that is needed in most cases, but if there is a need to give a
 /// callback function to the button, there are some templates for that below.

=== modified file 'src/ui_basic/editbox.cc'
--- src/ui_basic/editbox.cc	2016-04-20 09:57:21 +0000
+++ src/ui_basic/editbox.cc	2016-04-23 13:15:34 +0000
@@ -95,7 +95,7 @@
 	m_->caret = 0;
 	m_->scrolloffset = 0;
 	// yes, use *signed* max as maximum length; just a small safe-guard.
-	m_->maxLength = std::min(g_gr->max_texture_size() / UI_FONT_SIZE_SMALL,
+	m_->maxLength = std::min(g_gr->max_texture_size() / kFontSizeDefault,
 									 std::numeric_limits<int32_t>::max());
 
 	set_handle_mouse(true);
@@ -158,7 +158,7 @@
  */
 void EditBox::set_max_length(uint32_t const n)
 {
-	m_->maxLength = std::min(g_gr->max_texture_size() / UI_FONT_SIZE_SMALL, static_cast<int>(n));
+	m_->maxLength = std::min(g_gr->max_texture_size() / kFontSizeDefault, static_cast<int>(n));
 
 	if (m_->text.size() > m_->maxLength) {
 		m_->text.erase(m_->text.begin() + m_->maxLength, m_->text.end());

=== modified file 'src/ui_basic/editbox.h'
--- src/ui_basic/editbox.h	2016-02-04 19:22:16 +0000
+++ src/ui_basic/editbox.h	2016-04-23 13:15:34 +0000
@@ -45,7 +45,7 @@
 		(Panel *,
 		 int32_t x, int32_t y, uint32_t w,
 		 const Image* background = g_gr->images().get("images/ui_basic/but2.png"),
-		 int font_size = UI_FONT_SIZE_SMALL);
+		 int font_size = kFontSizeDefault);
 	virtual ~EditBox();
 
 	boost::signals2::signal<void ()> changed;

=== modified file 'src/ui_basic/icongrid.h'
--- src/ui_basic/icongrid.h	2016-02-03 18:09:15 +0000
+++ src/ui_basic/icongrid.h	2016-04-23 13:15:34 +0000
@@ -25,7 +25,6 @@
 #include <boost/signals2.hpp>
 
 #include "ui_basic/panel.h"
-#include "ui_basic/textarea.h"
 
 namespace UI {
 

=== modified file 'src/ui_basic/listselect.cc'
--- src/ui_basic/listselect.cc	2016-03-25 17:01:05 +0000
+++ src/ui_basic/listselect.cc	2016-04-23 13:15:34 +0000
@@ -375,7 +375,7 @@
 						er.pic);
 		}
 
-		const Image* entry_text_im = UI::g_fh1->render(as_uifont(richtext_escape(er.name), UI_FONT_SIZE_SMALL,
+		const Image* entry_text_im = UI::g_fh1->render(as_uifont(richtext_escape(er.name), kFontSizeDefault,
 																					er.use_clr ? er.clr : UI_FONT_CLR_FG));
 
 		Align alignment = i18n::has_rtl_character(er.name.c_str(), 20) ? UI::Align::kRight : UI::Align::kLeft;

=== modified file 'src/ui_basic/messagebox.cc'
--- src/ui_basic/messagebox.cc	2016-02-09 21:14:53 +0000
+++ src/ui_basic/messagebox.cc	2016-04-23 13:15:34 +0000
@@ -54,7 +54,7 @@
 	}
 
 	// Stupid heuristic to avoid excessively long lines
-	if (height < 2 * UI_FONT_SIZE_SMALL) {
+	if (height < 2 * kFontSizeDefault) {
 		const Image* temp_rendered_text = g_fh1->render(as_uifont(text), maxwidth / 2);
 		width = temp_rendered_text->width();
 		height = temp_rendered_text->height();

=== modified file 'src/ui_basic/multilineeditbox.cc'
--- src/ui_basic/multilineeditbox.cc	2016-04-20 09:54:55 +0000
+++ src/ui_basic/multilineeditbox.cc	2016-04-23 13:15:34 +0000
@@ -103,7 +103,7 @@
 :
 scrollbar(&o, o.get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, o.get_h(), false),
 cursor_pos(0),
-maxbytes(std::min(g_gr->max_texture_size() / UI_FONT_SIZE_SMALL, 0xffff)),
+maxbytes(std::min(g_gr->max_texture_size() / kFontSizeDefault, 0xffff)),
 ww_valid(false),
 owner(o)
 {

=== modified file 'src/ui_basic/multilinetextarea.cc'
--- src/ui_basic/multilinetextarea.cc	2016-04-01 09:29:17 +0000
+++ src/ui_basic/multilinetextarea.cc	2016-04-23 13:15:34 +0000
@@ -21,11 +21,14 @@
 
 #include <boost/algorithm/string.hpp>
 #include <boost/bind.hpp>
+#include <boost/format.hpp>
 
+#include "base/log.h"
 #include "graphic/font_handler1.h"
 #include "graphic/rendertarget.h"
 #include "graphic/text/font_set.h"
 #include "graphic/text_constants.h"
+#include "graphic/text/rt_errors.h"
 
 namespace UI {
 
@@ -41,7 +44,7 @@
 	Panel       (parent, x, y, w, h),
 	text_      (text),
 	color_(UI_FONT_CLR_FG),
-	isrichtext(false),
+	rendered_text_(nullptr),
 	scrollbar_ (this, get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, h, false),
 	scrollmode_(scroll_mode)
 {
@@ -55,10 +58,10 @@
 
 	scrollbar_.set_singlestepsize(UI::g_fh1->render(as_uifont(
 																		UI::g_fh1->fontset()->representative_character(),
-																		UI_FONT_SIZE_SMALL))->height());
+																		kFontSizeDefault))->height());
 	scrollbar_.set_pagesize(h - 2 * UI::g_fh1->render(as_uifont(
 																		  UI::g_fh1->fontset()->representative_character(),
-																		  UI_FONT_SIZE_BIG))->height());
+																		  kFontSizeBig))->height());
 	scrollbar_.set_steps(1);
 	scrollbar_.set_force_draw(scrollmode_ == ScrollMode::kScrollNormalForced ||
 										scrollmode_ == ScrollMode::kScrollLogForced);
@@ -88,17 +91,29 @@
 	// We wrap the text twice. We need to do this to account for the presence/absence of the scollbar.
 	bool scrollbar_was_enabled = scrollbar_.is_enabled();
 	for (int i = 0; i < 2; ++i) {
-		if (text_.compare(0, 3, "<rt")) {
-			isrichtext = false;
-			const Image* text_im = UI::g_fh1->render(make_richtext(), get_eff_w() - 2 * RICHTEXT_MARGIN);
-			height = text_im->height();
-		} else {
-			isrichtext = true;
-			rt.set_width(get_eff_w() - 2 * RICHTEXT_MARGIN);
-			rt.parse(text_);
-			height = rt.height() + 2 * RICHTEXT_MARGIN;
+		try {
+			rendered_text_ = UI::g_fh1->render(is_richtext(text_) ? text_ : make_richtext(),
+														  get_eff_w() - 2 * RICHTEXT_MARGIN);
+		} catch (RT::Exception& e) {
+			// Error handling: We first try to display the error message.
+			// If that won't work, we generate log output only.
+			log("\nRichtext rendering error: %s\n\nThe text to be rendered was: %s\n", e.what(), text_.c_str());
+			std::string error_message =
+					(boost::format(
+						 "<rt><p><font bold=1>Unable to render text. The error message is:</font><br>%s</p>"
+						 "<p><font bold=1>The text to be rendered was:</font><br>%s</p></rt>")
+					 % richtext_escape(e.what()) % richtext_escape(text_)).str();
+			try {
+				rendered_text_ = UI::g_fh1->render(error_message, get_eff_w() - 2 * RICHTEXT_MARGIN);
+			} catch (RT::Exception& err) {
+				log("\nFailed to render error message: %s\n", err.what());
+				rendered_text_ = nullptr;
+				return;
+			}
 		}
 
+		height = rendered_text_->height();
+
 		bool setbottom = false;
 
 		if (scrollmode_ == ScrollMode::kScrollLog || scrollmode_ == ScrollMode::kScrollLogForced) {
@@ -143,35 +158,36 @@
  */
 void MultilineTextarea::draw(RenderTarget& dst)
 {
-	if (isrichtext) {
-		rt.draw(dst, Point(RICHTEXT_MARGIN, RICHTEXT_MARGIN - scrollbar_.get_scrollpos()));
-	} else {
-		const Image* text_im = UI::g_fh1->render(make_richtext(), get_eff_w() - 2 * RICHTEXT_MARGIN);
-
-		uint32_t blit_width = std::min(text_im->width(), static_cast<int>(get_eff_w()));
-		uint32_t blit_height = std::min(text_im->height(), static_cast<int>(get_inner_h()));
-
-		if (blit_width > 0 && blit_height > 0) {
-			int32_t anchor = 0;
-			Align alignment = mirror_alignment(align_);
-			switch (alignment & UI::Align::kHorizontal) {
-			case UI::Align::kHCenter:
-				anchor = (get_eff_w() - blit_width) / 2;
-				break;
-			case UI::Align::kRight:
-				anchor = get_eff_w() - blit_width - RICHTEXT_MARGIN;
-				break;
-			default:
-				anchor = RICHTEXT_MARGIN;
-			}
-
-			dst.blitrect_scale(
-				Rect(anchor, 0, blit_width, blit_height),
-				text_im,
-				Rect(0, scrollbar_.get_scrollpos(), blit_width, blit_height),
-				1.,
-				BlendMode::UseAlpha);
+	if (text_.empty()) {
+		return;
+	}
+	if (rendered_text_ == nullptr) {
+		return;
+	}
+	uint32_t blit_width = std::min(rendered_text_->width(), static_cast<int>(get_eff_w()));
+	uint32_t blit_height = std::min(rendered_text_->height(), static_cast<int>(get_inner_h()));
+
+	if (blit_width > 0 && blit_height > 0) {
+		int32_t anchor = 0;
+		Align alignment = mirror_alignment(align_);
+		switch (alignment & UI::Align::kHorizontal) {
+		case UI::Align::kHCenter:
+			anchor = (get_eff_w() - blit_width) / 2;
+			break;
+		case UI::Align::kRight:
+			anchor = get_eff_w() - blit_width - RICHTEXT_MARGIN;
+			break;
+		default:
+			anchor = RICHTEXT_MARGIN;
+			break;
 		}
+
+		dst.blitrect_scale(
+			Rect(anchor, 0, blit_width, blit_height),
+			rendered_text_,
+			Rect(0, scrollbar_.get_scrollpos(), blit_width, blit_height),
+			1.,
+			BlendMode::UseAlpha);
 	}
 }
 
@@ -194,7 +210,7 @@
 	// TODO(GunChleoc): Revisit this once the old font renderer is completely gone.
 	boost::replace_all(temp, "\n\n", "<br>&nbsp;<br>");
 	boost::replace_all(temp, "\n", "<br>");
-	return as_aligned(temp, align_, UI_FONT_SIZE_SMALL, color_);
+	return as_aligned(temp, align_, kFontSizeDefault, color_);
 }
 
 } // namespace UI

=== modified file 'src/ui_basic/multilinetextarea.h'
--- src/ui_basic/multilinetextarea.h	2016-04-01 12:22:09 +0000
+++ src/ui_basic/multilinetextarea.h	2016-04-23 13:15:34 +0000
@@ -20,11 +20,8 @@
 #ifndef WL_UI_BASIC_MULTILINETEXTAREA_H
 #define WL_UI_BASIC_MULTILINETEXTAREA_H
 
-#include <memory>
-
 #include "graphic/align.h"
 #include "graphic/color.h"
-#include "graphic/richtext.h"
 #include "graphic/text_layout.h"
 #include "ui_basic/panel.h"
 #include "ui_basic/scrollbar.h"
@@ -36,7 +33,8 @@
  * This defines an area, where a text can easily be printed.
  * The textarea transparently handles explicit line-breaks and word wrapping.
  */
-struct MultilineTextarea : public Panel {
+class MultilineTextarea : public Panel {
+public:
 	enum class ScrollMode {
 		kNoScrolling,        // Expand the height instead of showing a scroll bar
 		kScrollNormal,       // (default) only explicit scrolling
@@ -82,8 +80,7 @@
 	RGBColor color_;
 	Align align_;
 
-	bool isrichtext;
-	RichText rt;
+	const Image* rendered_text_;
 
 	Scrollbar   scrollbar_;
 	ScrollMode  scrollmode_;

=== modified file 'src/ui_basic/panel.cc'
--- src/ui_basic/panel.cc	2016-03-10 15:00:32 +0000
+++ src/ui_basic/panel.cc	2016-04-23 13:15:34 +0000
@@ -32,6 +32,8 @@
 
 using namespace std;
 
+#define SHOW_DEBUG_FRAME false
+
 namespace UI {
 
 Panel * Panel::modal_       = nullptr;
@@ -431,7 +433,14 @@
  * Draw overlays that appear over all child panels.
  * This can be used e.g. for debug information.
 */
-void Panel::draw_overlay(RenderTarget &) {}
+void Panel::draw_overlay(RenderTarget & rt) {
+	if (SHOW_DEBUG_FRAME) {
+		rt.draw_rect(
+			Rect(0, 0, get_w(), get_h()),
+			RGBColor(255, 0, 0)
+		);
+	}
+}
 
 /**
  * Called once per event loop pass, unless set_think(false) has

=== modified file 'src/ui_basic/progressbar.cc'
--- src/ui_basic/progressbar.cc	2016-02-03 18:09:15 +0000
+++ src/ui_basic/progressbar.cc	2016-04-23 13:15:34 +0000
@@ -99,10 +99,9 @@
 	}
 
 	// Print the state in percent
-	// TODO(unknown): use UI_FNT_COLOR_BRIGHT when merged
 	uint32_t percent = static_cast<uint32_t>(fraction * 100);
 	const std::string progress_text =
-		(boost::format("<font color=%1$s>%2$i%%</font>") % "ffffff" % percent).str();
+		(boost::format("<font color=%1$s>%2$i%%</font>") % UI_FONT_CLR_BRIGHT.hex_value() % percent).str();
 	const Point pos(get_w() / 2, get_h() / 2);
 	dst.blit(pos, UI::g_fh1->render(as_uifont(progress_text)), BlendMode::UseAlpha, UI::Align::kCenter);
 }

=== modified file 'src/ui_basic/progresswindow.cc'
--- src/ui_basic/progresswindow.cc	2016-04-01 08:51:58 +0000
+++ src/ui_basic/progresswindow.cc	2016-04-23 13:15:34 +0000
@@ -107,7 +107,7 @@
 
 	rt.fill_rect(label_rectangle_, PROGRESS_FONT_COLOR_BG);
 	rt.blit(label_center_,
-			 UI::g_fh1->render(as_uifont(description, UI_FONT_SIZE_SMALL, PROGRESS_FONT_COLOR_FG)),
+			 UI::g_fh1->render(as_uifont(description, kFontSizeDefault, PROGRESS_FONT_COLOR_FG)),
 			 BlendMode::UseAlpha,
 			 UI::Align::kCenter);
 

=== modified file 'src/ui_basic/slider.cc'
--- src/ui_basic/slider.cc	2016-03-30 07:20:05 +0000
+++ src/ui_basic/slider.cc	2016-04-23 13:15:34 +0000
@@ -552,7 +552,7 @@
 		 w / (2 * labels_in.size()) - cursor_size / 2, 0,
 		 w - (w / labels_in.size()) + cursor_size,
 		 h - UI::g_fh1->render(as_condensed(UI::g_fh1->fontset()->representative_character(),
-														UI::Align::kLeft, UI_FONT_SIZE_SMALL - 2))->height() - 2,
+														UI::Align::kLeft, kFontSizeSmall - 2))->height() - 2,
 		 0, labels_in.size() - 1, value_,
 		 background_picture_id,
 		 tooltip_text,
@@ -578,7 +578,7 @@
 
 	for (uint32_t i = 0; i < labels.size(); i++) {
 		dst.blit(Point(gap_1 + i * gap_n, get_h()),
-				 UI::g_fh1->render(as_condensed(labels[i], UI::Align::kBottomCenter, UI_FONT_SIZE_SMALL - 2)),
+				 UI::g_fh1->render(as_condensed(labels[i], UI::Align::kBottomCenter, kFontSizeSmall - 2)),
 				 BlendMode::UseAlpha,
 				 UI::Align::kBottomCenter);
 	}
@@ -599,7 +599,7 @@
 	slider.set_size
 		(w - (w / labels.size()) + slider.cursor_size_,
 		 h - UI::g_fh1->render(as_condensed(UI::g_fh1->fontset()->representative_character(),
-														UI::Align::kLeft, UI_FONT_SIZE_SMALL - 2))->height() + 2);
+														UI::Align::kLeft, kFontSizeSmall - 2))->height() + 2);
 	Panel::layout();
 }
 

=== modified file 'src/ui_basic/textarea.cc'
--- src/ui_basic/textarea.cc	2016-02-17 08:48:02 +0000
+++ src/ui_basic/textarea.cc	2016-04-23 13:15:34 +0000
@@ -84,7 +84,7 @@
 	set_handle_mouse(false);
 	set_thinks(false);
 	color_ = UI_FONT_CLR_FG;
-	fontsize_ = UI_FONT_SIZE_SMALL;
+	fontsize_ = kFontSizeDefault;
 	update();
 }
 

=== modified file 'src/ui_fsmenu/about.cc'
--- src/ui_fsmenu/about.cc	2016-04-03 17:03:17 +0000
+++ src/ui_fsmenu/about.cc	2016-04-23 13:15:34 +0000
@@ -51,7 +51,7 @@
 			g_gr->images().get("images/ui_basic/but1.png"),
 			UI::TabPanel::Type::kBorder)
 {
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
+	title_.set_fontsize(kFontSizeBig);
 	tabs_.set_pos(Point(hmargin_, tab_panel_y_));
 
 	tabs_.add_tab("txts/README.lua");

=== modified file 'src/ui_fsmenu/base.cc'
--- src/ui_fsmenu/base.cc	2016-02-07 18:10:53 +0000
+++ src/ui_fsmenu/base.cc	2016-04-23 13:15:34 +0000
@@ -71,11 +71,11 @@
 }
 
 int FullscreenMenuBase::fs_small() {
-	return UI_FONT_SIZE_SMALL * get_h() / 600;
+	return kFontSizeDefault * get_h() / 600;
 }
 
 int FullscreenMenuBase::fs_big() {
-	return UI_FONT_SIZE_BIG * get_h() / 600;
+	return kFontSizeBig * get_h() / 600;
 }
 
 bool FullscreenMenuBase::handle_key(bool down, SDL_Keysym code)

=== modified file 'src/ui_fsmenu/campaign_select.cc'
--- src/ui_fsmenu/campaign_select.cc	2016-04-01 09:20:31 +0000
+++ src/ui_fsmenu/campaign_select.cc	2016-04-23 13:15:34 +0000
@@ -86,7 +86,7 @@
 		 get_right_column_w(right_column_x_ + indent_),
 		 buty_ - get_y_from_preceding(label_description_) - 4 * padding_)
 {
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
+	title_.set_fontsize(kFontSizeBig);
 	back_.set_tooltip(_("Return to the main menu"));
 	ok_.set_tooltip(_("Play this campaign"));
 	ta_campname_.set_tooltip(_("The name of this campaign"));
@@ -325,7 +325,7 @@
 
 	is_tutorial_(is_tutorial)
 {
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
+	title_.set_fontsize(kFontSizeBig);
 	back_.set_tooltip(_("Return to the main menu"));
 	if (is_tutorial_) {
 		ok_.set_tooltip(_("Play this tutorial"));

=== modified file 'src/ui_fsmenu/internet_lobby.h'
--- src/ui_fsmenu/internet_lobby.h	2016-02-19 19:45:57 +0000
+++ src/ui_fsmenu/internet_lobby.h	2016-04-23 13:15:34 +0000
@@ -24,7 +24,6 @@
 #include <string>
 #include <vector>
 
-#include "ui_fsmenu/base.h"
 #include "network/internet_gaming.h"
 #include "network/network_lan_promotion.h"
 #include "ui_basic/button.h"
@@ -32,6 +31,7 @@
 #include "ui_basic/listselect.h"
 #include "ui_basic/table.h"
 #include "ui_basic/textarea.h"
+#include "ui_fsmenu/base.h"
 #include "wui/gamechatpanel.h"
 
 class FullscreenMenuInternetLobby : public FullscreenMenuBase {

=== modified file 'src/ui_fsmenu/launch_spg.cc'
--- src/ui_fsmenu/launch_spg.cc	2016-04-01 07:50:48 +0000
+++ src/ui_fsmenu/launch_spg.cc	2016-04-23 13:15:34 +0000
@@ -144,7 +144,7 @@
 	cur_wincondition_ = -1;
 	win_condition_clicked();
 
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
+	title_.set_fontsize(kFontSizeBig);
 
 	int smaller_fontsize = fs_small() * 4 / 5;
 	name_.set_fontsize(smaller_fontsize);

=== modified file 'src/ui_fsmenu/loadgame.cc'
--- src/ui_fsmenu/loadgame.cc	2016-03-20 15:51:39 +0000
+++ src/ui_fsmenu/loadgame.cc	2016-04-23 13:15:34 +0000
@@ -153,7 +153,7 @@
 	settings_(gsp),
 	ctrl_(gc)
 {
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
+	title_.set_fontsize(kFontSizeBig);
 	ta_gametime_.set_tooltip(_("The time that elapsed inside this game"));
 	ta_players_.set_tooltip(_("The number of players"));
 	ta_version_.set_tooltip(_("The version of Widelands that this game was played under"));

=== modified file 'src/ui_fsmenu/mapselect.cc'
--- src/ui_fsmenu/mapselect.cc	2016-03-25 17:40:51 +0000
+++ src/ui_fsmenu/mapselect.cc	2016-04-23 13:15:34 +0000
@@ -60,7 +60,7 @@
 	has_translated_mapname_(false)
 {
 	curdir_ = basedir_,
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
+	title_.set_fontsize(kFontSizeBig);
 	if (settings_->settings().multiplayer) {
 		back_.set_tooltip(_("Return to the multiplayer game setup"));
 	} else {

=== modified file 'src/ui_fsmenu/netsetup_lan.cc'
--- src/ui_fsmenu/netsetup_lan.cc	2016-02-07 16:31:06 +0000
+++ src/ui_fsmenu/netsetup_lan.cc	2016-04-23 13:15:34 +0000
@@ -105,7 +105,7 @@
 
 	Section & s = g_options.pull_section("global"); //  for playername
 
-	title       .set_fontsize(UI_FONT_SIZE_BIG);
+	title       .set_fontsize(kFontSizeBig);
 	hostname    .changed.connect
 		(boost::bind(&FullscreenMenuNetSetupLAN::change_hostname, this));
 	playername  .set_text  (s.get_string("nickname", (_("nobody"))));

=== modified file 'src/ui_fsmenu/options.cc'
--- src/ui_fsmenu/options.cc	2016-03-29 06:41:46 +0000
+++ src/ui_fsmenu/options.cc	2016-04-23 13:15:34 +0000
@@ -217,7 +217,7 @@
 	os_(opt)
 {
 	// Set up UI Elements
-	title_           .set_fontsize(UI_FONT_SIZE_BIG);
+	title_           .set_fontsize(kFontSizeBig);
 
 	tabs_.add("options_interface", _("Interface"), &box_interface_, "");
 	tabs_.add("options_windows", _("Windows"), &box_windows_, "");

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2016-04-02 16:26:33 +0000
+++ src/wlapplication.cc	2016-04-23 13:15:34 +0000
@@ -52,7 +52,6 @@
 #include "config.h"
 #include "editor/editorinteractive.h"
 #include "graphic/default_resolution.h"
-#include "graphic/font_handler.h"
 #include "graphic/font_handler1.h"
 #include "graphic/text/font_set.h"
 #include "graphic/text_constants.h"
@@ -337,9 +336,7 @@
 		throw wexception
 			("True Type library did not initialize: %s\n", TTF_GetError());
 
-	UI::g_fh1 =
-	   UI::create_fonthandler(&g_gr->images());  // This will create the fontset, so loading it first.
-	UI::g_fh = new UI::FontHandler();
+	UI::g_fh1 = UI::create_fonthandler(&g_gr->images());
 
 	g_gr->initialize(
 	   config.get_bool("debug_gl_trace", false) ? Graphic::TraceGl::kYes : Graphic::TraceGl::kNo,
@@ -372,10 +369,6 @@
 	shutdown_hardware();
 	shutdown_settings();
 
-	assert(UI::g_fh);
-	delete UI::g_fh;
-	UI::g_fh = nullptr;
-
 	assert(UI::g_fh1);
 	delete UI::g_fh1;
 	UI::g_fh1 = nullptr;

=== modified file 'src/wui/attack_box.cc'
--- src/wui/attack_box.cc	2016-02-09 21:14:53 +0000
+++ src/wui/attack_box.cc	2016-04-23 13:15:34 +0000
@@ -143,7 +143,7 @@
 	const std::string attack_string =
 	   (boost::format(_("%1% / %2%")) % (max_attackers > 0 ? 1 : 0) % max_attackers).str();
 
-	soldiers_text_.reset(&add_text(columnbox, attack_string, UI::Align::kHCenter, UI_FONT_SIZE_ULTRASMALL));
+	soldiers_text_.reset(&add_text(columnbox, attack_string, UI::Align::kHCenter, kFontSizeVerySmall));
 
 	soldiers_slider_ = add_slider(columnbox,
 	                              100,

=== modified file 'src/wui/attack_box.h'
--- src/wui/attack_box.h	2016-02-09 21:14:53 +0000
+++ src/wui/attack_box.h	2016-04-23 13:15:34 +0000
@@ -68,7 +68,7 @@
 	UI::Textarea& add_text(UI::Box& parent,
 								  std::string str,
 								  UI::Align alignment = UI::Align::kTop,
-								  int fontsize = UI_FONT_SIZE_SMALL);
+								  int fontsize = kFontSizeDefault);
 	std::unique_ptr<UI::Button> add_button(UI::Box& parent,
 	                                       const std::string& text,
 	                                       void (AttackBox::*fn)(),

=== modified file 'src/wui/chat_msg_layout.cc'
--- src/wui/chat_msg_layout.cc	2016-03-30 08:38:59 +0000
+++ src/wui/chat_msg_layout.cc	2016-04-23 13:15:34 +0000
@@ -43,70 +43,6 @@
 
 }  // namespace
 
-// TODO(sirver): remove as soon as old text renderer is gone.
-std::string format_as_old_richtext(const ChatMessage& chat_message) {
-	const std::string& font_face = "serif";
-	std::string message = "<p font-color=#33ff33 font-size=9>";
-
-	std::string sanitized = sanitize_message(chat_message);
-
-	// time calculation
-	char ts[13];
-	strftime(ts, sizeof(ts), "[%H:%M] </p>", localtime(&chat_message.time));
-	message += ts;
-
-	message = (boost::format("%s<p font-size=14 font-face=%s font-color=#%s")
-				  % message % font_face % color(chat_message.playern)).str();
-
-	std::string sender_escaped = richtext_escape(chat_message.sender);
-	std::string recipient_escaped = richtext_escape(chat_message.recipient);
-
-	if (chat_message.recipient.size() && chat_message.sender.size()) {
-		// Personal message handling
-		if (sanitized.compare(0, 3, "/me")) {
-
-			message = (boost::format("%s font-decoration=underline>%s @ %s:</p><p font-size=14 font-face=%s> %s")
-						  % message
-						  % sender_escaped
-						  % recipient_escaped
-						  % font_face
-						  % sanitized).str();
-		} else {
-
-			message =
-				(boost::format("%s>@%s &gt;&gt; </p>"
-									"<p font-size=14 font-face=%s font-color=#%s font-style=italic> %s%s")
-				 % message
-				 % recipient_escaped
-				 % font_face
-				 % color(chat_message.playern)
-				 % sender_escaped
-				 % sanitized.substr(3)).str();
-		}
-	} else {
-		// Normal messages handling
-		if (!sanitized.compare(0, 3, "/me")) {
-			message = (boost::format("%s font-style=italic>-&gt; %s%s")
-						  % message
-						  % (chat_message.sender.size() ? chat_message.sender.c_str() : "***")
-						  % sanitized.substr(3)).str();
-
-		} else if (chat_message.sender.size()) {
-			message = (boost::format("%s font-decoration=underline>%s:</p><p font-size=14 font-face=%s> %s")
-						  % message
-						  % sender_escaped
-						  % font_face
-						  % sanitized).str();
-		} else {
-			message += " font-weight=bold>*** ";
-			message += sanitized;
-		}
-	}
-
-	// return the formated message
-	return message + "<br></p>";
-}
-
 // Returns a richtext string that can be displayed to the user.
 std::string format_as_richtext(const ChatMessage& chat_message) {
 	const std::string& font_face = "serif";

=== modified file 'src/wui/chat_msg_layout.h'
--- src/wui/chat_msg_layout.h	2016-03-30 08:38:59 +0000
+++ src/wui/chat_msg_layout.h	2016-04-23 13:15:34 +0000
@@ -24,9 +24,6 @@
 
 struct ChatMessage;
 
-// Formats 'chat_message' as old richtext.
-std::string format_as_old_richtext(const ChatMessage& chat_message);
-
 // Formats 'chat_message' as richtext.
 std::string format_as_richtext(const ChatMessage& chat_message);
 

=== modified file 'src/wui/encyclopedia_window.cc'
--- src/wui/encyclopedia_window.cc	2016-04-02 08:28:29 +0000
+++ src/wui/encyclopedia_window.cc	2016-04-23 13:15:34 +0000
@@ -42,8 +42,8 @@
 constexpr int kTabHeight = 35;
 
 const std::string heading(const std::string& text) {
-	return ((boost::format("<rt><p font-size=18 font-weight=bold font-color=D1D1D1>"
-	                       "%s<br></p><p font-size=8> <br></p></rt>") %
+	return ((boost::format("<p><font size=18 bold=1 color=D1D1D1>"
+								  "%s<vspace gap=6></font></p>") %
 	         text).str());
 }
 
@@ -184,7 +184,7 @@
 			cr->resume();
 			table = cr->pop_table();
 		}
-		contents_.at(tab_name)->set_text((boost::format("%s%s")
+		contents_.at(tab_name)->set_text((boost::format("<rt>%s%s</rt>")
 													 % heading(table->get_string("title"))
 													 % table->get_string("text")).str());
 	} catch (LuaError& err) {

=== modified file 'src/wui/game_debug_ui.cc'
--- src/wui/game_debug_ui.cc	2016-04-03 08:01:49 +0000
+++ src/wui/game_debug_ui.cc	2016-04-23 13:15:34 +0000
@@ -52,7 +52,7 @@
 		 Widelands::MapObject       &);
 	~MapObjectDebugPanel();
 
-	void log(std::string str) override;
+	void log(const std::string& str) override;
 
 private:
 	const Widelands::EditorGameBase& egbase_;
@@ -89,7 +89,7 @@
 Append the string to the log textarea.
 ===============
 */
-void MapObjectDebugPanel::log(std::string str)
+void MapObjectDebugPanel::log(const std::string& str)
 {
 	log_.set_text((log_.get_text() + str).c_str());
 }

=== modified file 'src/wui/game_message_menu.cc'
--- src/wui/game_message_menu.cc	2016-03-12 07:07:12 +0000
+++ src/wui/game_message_menu.cc	2016-04-23 13:15:34 +0000
@@ -375,11 +375,7 @@
 			}
 			centerviewbtn_->set_enabled(message->position());
 
-			message_body.set_text(
-						(boost::format("<rt><p font-size=18 font-weight=bold font-color=D1D1D1>%s<br></p>"
-											"<p font-size=8> <br></p></rt>%s")
-						 % message->heading()
-						 % message->body()).str());
+			message_body.set_text(as_message(message->heading(), message->body()));
 			return;
 		}
 	}

=== modified file 'src/wui/game_summary.cc'
--- src/wui/game_summary.cc	2016-02-18 18:27:52 +0000
+++ src/wui/game_summary.cc	2016-04-23 13:15:34 +0000
@@ -122,7 +122,7 @@
 	players_table_->add_column(100, _("Time"));
 
 	// Prepare Elements
-	title_area_->set_fontsize(UI_FONT_SIZE_BIG);
+	title_area_->set_fontsize(kFontSizeBig);
 
 	// Connections
 	continue_button_->sigclicked.connect

=== modified file 'src/wui/gamechatpanel.cc'
--- src/wui/gamechatpanel.cc	2016-02-01 17:20:23 +0000
+++ src/wui/gamechatpanel.cc	2016-04-23 13:15:34 +0000
@@ -58,14 +58,12 @@
 {
 	const std::vector<ChatMessage> msgs = chat_.get_messages();
 
-	std::string str = "<rt>";
+	std::string str = "";
 	for (uint32_t i = 0; i < msgs.size(); ++i) {
-		str += format_as_old_richtext(msgs[i]);
-		str += '\n';
+		str += format_as_richtext(msgs[i]);
 	}
-	str += "</rt>";
 
-	chatbox.set_text(str);
+	chatbox.set_text("<rt>" + str + "</rt>");
 
 	// If there are new messages, play a sound
 	if (0 < msgs.size() && msgs.size() != chat_message_counter)
@@ -85,7 +83,7 @@
 				play_new_chat_message();
 			}
 		}
-		chat_message_counter = msgs . size();
+		chat_message_counter = msgs.size();
 
 	}
 }

=== modified file 'src/wui/helpwindow.cc'
--- src/wui/helpwindow.cc	2016-03-22 12:34:52 +0000
+++ src/wui/helpwindow.cc	2016-04-23 13:15:34 +0000
@@ -55,7 +55,7 @@
 		cr->resume();
 		std::unique_ptr<LuaTable> return_table = cr->pop_table();
 		return_table->do_not_warn_about_unaccessed_keys();  // We won't display the title here
-		textarea_->set_text(return_table->get_string("text"));
+		textarea_->set_text("<rt>" + return_table->get_string("text") + "</rt>");
 	} catch (LuaError& err) {
 		textarea_->set_text(err.what());
 	}

=== modified file 'src/wui/helpwindow.h'
--- src/wui/helpwindow.h	2016-01-28 05:24:34 +0000
+++ src/wui/helpwindow.h	2016-04-23 13:15:34 +0000
@@ -46,7 +46,9 @@
 		 const Widelands::BuildingDescr& building_description,
 		 const Widelands::TribeDescr& tribe,
 		 LuaInterface * const lua,
-		 uint32_t width = 300, uint32_t height = 400);
+		 // NOCOM(GunChleoc): width used to be 300. Making this wider to be identical to
+		 // the encyclopedia (richtext hacks)
+		 uint32_t width = 350, uint32_t height = 400);
 
 private:
 	std::unique_ptr<MultilineTextarea> textarea_;

=== modified file 'src/wui/multiplayersetupgroup.cc'
--- src/wui/multiplayersetupgroup.cc	2016-04-03 13:00:14 +0000
+++ src/wui/multiplayersetupgroup.cc	2016-04-23 13:15:34 +0000
@@ -408,7 +408,7 @@
 playerbox(this, w * 6 / 15, buth, UI::Box::Vertical, w * 9 / 15, h - buth),
 buth_(buth)
 {
-	int small_font = UI_FONT_SIZE_SMALL * 3 / 4;
+	int small_font = kFontSizeDefault * 3 / 4;
 
 	// Clientbox and labels
 	labels.push_back

=== modified file 'src/wui/waresdisplay.cc'
--- src/wui/waresdisplay.cc	2016-03-08 21:14:48 +0000
+++ src/wui/waresdisplay.cc	2016-04-23 13:15:34 +0000
@@ -467,12 +467,13 @@
 	for (i = order.begin(); i != order.end(); i++)
 		for (j = i->begin(); j != i->end(); ++j)
 			if ((c = map.find(*j)) != map.end()) {
-				ret += "<sub width=30 padding=2><p align=center>"
-						 "<sub width=26 background=454545><p align=center><img src=\""
+				ret += "<div width=30 padding=2><p align=center>"
+						 "<div width=26 background=454545><p align=center><img src=\""
 						+ tribe.get_ware_descr(c->first)->icon_filename()
-						+ "\"></p></sub><sub width=26 background=000000><p><font size=9>"
+						+ "\"></p></div><div width=26 background=000000>"
+						+ "<p><font size=9>"
 						+ boost::lexical_cast<std::string>(static_cast<int32_t>(c->second))
-						+ "</font></p></sub></p></sub>";
+						+ "</font></p></div></p></div>";
 			}
 	return ret;
 }

=== modified file 'utils/update_authors.py'
--- utils/update_authors.py	2016-03-10 16:36:44 +0000
+++ utils/update_authors.py	2016-04-23 13:15:34 +0000
@@ -54,10 +54,8 @@
 		if translators["translator-list"] != 'translator-credits':
 			locale_message += " translators and"
 			lua_translators += '{' # entry
-			lua_translators += 'heading = "' + translators["your-language-name"]
-			if translators["your-language-name-in-english"] != 'English' and translators["your-language-name-in-english"] != translators["your-language-name"] :
-				lua_translators += ' (' + translators["your-language-name-in-english"] + ')'
-			lua_translators += '",'
+			lua_translators += 'heading = "' + translators["your-language-name"] + '",'
+			lua_translators += 'sortname = "' + translators["language-sort-name"] + '",'
 			lua_translators += 'entries = {' # entries
 			lua_translators += '{' # entry
 			lua_translators += 'members = {' # members


Follow ups