← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/bug-1492114 into lp:widelands

 

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

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1492114 in widelands: "Making the message window smaller"
  https://bugs.launchpad.net/widelands/+bug/1492114

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/bug-1492114/+merge/272292

A redesign of the message window, see also the forum discussion:

https://wl.widelands.org/forum/topic/1795/

This also fixes some stuff in ui_basic/Table:

- Right and Center horizontal align now take the scrollbar into account for the rightmost element
- Images for table entries are shrunk down if necessary.

There is 1 known issue: When an image is resized, it will visible below the table's bottom edge while scrolling. I would prefer to hunt this down in a separate bug.

Also, this class should ber refactored to use some Box layout - I don't want to do this here though, because it would make the diff hard to read.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1492114 into lp:widelands.
=== modified file 'campaigns/atl01.wmf/scripting/init.lua'
--- campaigns/atl01.wmf/scripting/init.lua	2014-10-03 08:58:44 +0000
+++ campaigns/atl01.wmf/scripting/init.lua	2015-09-24 16:48:57 +0000
@@ -68,10 +68,19 @@
 end
 
 function send_building_lost_message(f)
-   send_message(p1, _"Building lost!",
+   send_message(
+		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!")
-      ), { field = f, popup = false }
+      ),
+      {
+			field = f,
+			popup = false,
+			icon = f.immovable.descr.representative_image,
+			heading = pgettext("message_heading", "Building lost!")
+		}
    )
 end
 

=== modified file 'campaigns/tutorial01_basic_control.wmf/scripting/helper_functions_demonstration.lua'
--- campaigns/tutorial01_basic_control.wmf/scripting/helper_functions_demonstration.lua	2014-10-19 09:39:36 +0000
+++ campaigns/tutorial01_basic_control.wmf/scripting/helper_functions_demonstration.lua	2015-09-24 16:48:57 +0000
@@ -118,9 +118,9 @@
                -- Give the callback a chance to veto the deletion. Maybe
                -- we expect the player to build something at the moment
                if not immovable_is_legal(f.immovable) then
-                  -- scould the player
+                  -- scold the player
                   if not sent_msg then
-                     message_box_objective(plr, scould_player)
+                     message_box_objective(plr, scold_player)
                      sent_msg = true
                   end
 

=== modified file 'campaigns/tutorial01_basic_control.wmf/scripting/mission_thread.lua'
--- campaigns/tutorial01_basic_control.wmf/scripting/mission_thread.lua	2015-06-01 20:08:40 +0000
+++ campaigns/tutorial01_basic_control.wmf/scripting/mission_thread.lua	2015-09-24 16:48:57 +0000
@@ -306,7 +306,7 @@
    -- Teach the player about receiving messages
    sleep(10)
 
-   send_message(plr, teaching_about_messages.title, teaching_about_messages.body, teaching_about_messages)
+   send_message(plr, teaching_about_messages.title, teaching_about_messages.body, teaching_about_messages, {heading = teaching_about_messages.heading})
    local o = add_campaign_objective(teaching_about_messages)
 
    while #plr.inbox > 0 do sleep(200) end

=== modified file 'campaigns/tutorial01_basic_control.wmf/scripting/texts.lua'
--- campaigns/tutorial01_basic_control.wmf/scripting/texts.lua	2015-07-30 07:16:09 +0000
+++ campaigns/tutorial01_basic_control.wmf/scripting/texts.lua	2015-09-24 16:48:57 +0000
@@ -12,7 +12,7 @@
 -- =============
 -- Texts below
 -- =============
-scould_player = {
+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.]]
@@ -394,15 +394,16 @@
 
 teaching_about_messages = {
    popup = true,
-   title = _"Introducing Messages",
+   title = _"Messages",
+   heading = _"Introducing Messages",
    body = rt(
-      h1(_"Messages") ..
       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: You can check them off in your inbox so that they get a tick-symbol in front of them. Then, you can click the]])
+      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=pics/message_archive.png", p(_[[archive message button to move them into your archive.]])) ..
+   rt("image=pics/message_archive.png", p(_[[‘Archive selected message’ button to move it into your archive.]])) ..
    rt(
+		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.]])
    ),
@@ -413,7 +414,7 @@
       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. Then mark all messages by checking the check box in front of them. Then, click the ‘Archive All’ button.]])
+      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.]])
    )
 }
 

=== modified file 'maps/MP Scenarios/Island Hopping.wmf/scripting/multiplayer_init.lua'
--- maps/MP Scenarios/Island Hopping.wmf/scripting/multiplayer_init.lua	2015-09-15 06:44:11 +0000
+++ maps/MP Scenarios/Island Hopping.wmf/scripting/multiplayer_init.lua	2015-09-24 16:48:57 +0000
@@ -93,9 +93,13 @@
 -- ==================
 
 -- Sends a game status message to all players
-function send_to_all(text)
+function send_to_all(text, long_title)
    for idx,plr in ipairs(game.players) do
-      send_message(plr, _ "Game Status", text, {popup=true})
+      if (long_title ~= nil and long_title ~= "") then
+         send_message(plr, _"Status", text, {popup=true, heading=long_title})
+      else
+         send_message(plr, _"Status", text, {popup=true})
+      end
    end
 end
 
@@ -213,10 +217,10 @@
    place_headquarters()
    disable_unused_buildings()
 
-   send_to_all(welcome_msg)
+   send_to_all(welcome_msg.body, welcome_msg.heading)
    -- set the objective with the game type for all players
    -- TODO change this to a broadcast once individual game objectives have been implemented
-   game.players[1]:add_objective("win_conditions", _"Rules", welcome_msg)
+   game.players[1]:add_objective("win_conditions", _"Rules", welcome_msg.body)
 
    for idx,plr in ipairs(game.players) do
       run(function() run_island(plr, 1) end)

=== modified file 'maps/MP Scenarios/Island Hopping.wmf/scripting/texts.lua'
--- maps/MP Scenarios/Island Hopping.wmf/scripting/texts.lua	2015-07-26 10:39:48 +0000
+++ maps/MP Scenarios/Island Hopping.wmf/scripting/texts.lua	2015-09-24 16:48:57 +0000
@@ -1,42 +1,44 @@
 -- =======================================================================
 --                          Texts for this scenario
 -- =======================================================================
-welcome_msg = rt(
-   h1(_"Welcome to Island Hopping") ..
-   h2(_"Rules") ..
-   p(_(
-[[Island Hopping is a traditional tournament in Atlantean culture. ]] ..
-[[The rules of the game are simple: you start with a headquarters on an island. ]] ..
-[[When you finish a castle at the end of the first island, you are granted a ]] ..
-[[second headquarters on a second island, which will contain all wares from your ]] ..
-[[first headquarters.]]
-)) ..
- p(_(
-[[If you finish a castle in the target area on the second island, you will get ]] ..
-[[a third headquarters on the third island. You must build a castle at ]] ..
-[[the center of the third island and hold it for 20 minutes to win the game.]]
-)) ..
- p(_(
-[[Whenever you finish an island, you will get bonus wares, depending on how many players ]] ..
-[[have finished the island before you. The earlier you finish, the fewer wares you will get. ]] ..
-[[See below for the details.]])) .. p(_(
-[[The point is that the first island only provides stones and wood, the second only meadows and resources. The economies you leave behind will continue to work for you, but you will only reap the benefits at the moment you reach a new island.]])
-) ..
-p(_
-[[Finally, be careful not to waste your quartz and diamonds.]]
-) ..
-h2(_"Finish Rewards") ..
-h3(_"First Island") ..
-h4(_"1st to finish") .. p(format_rewards(_finish_rewards[1][1])) ..
-h4(_"2nd to finish") .. p(format_rewards(_finish_rewards[1][2])) ..
-h4(_"3rd to finish") .. p(format_rewards(_finish_rewards[1][3])) ..
-h4(_"4th to finish") .. p(format_rewards(_finish_rewards[1][4])) ..
-h3(_"Second Island") ..
-h4(_"1st to finish") .. p(format_rewards(_finish_rewards[2][1])) ..
-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]))
-)
+welcome_msg = {
+	heading = _"Welcome to Island Hopping",
+	body = rt(
+		h2(_"Rules") ..
+		p(_(
+	[[Island Hopping is a traditional tournament in Atlantean culture. ]] ..
+	[[The rules of the game are simple: you start with a headquarters on an island. ]] ..
+	[[When you finish a castle at the end of the first island, you are granted a ]] ..
+	[[second headquarters on a second island, which will contain all wares from your ]] ..
+	[[first headquarters.]]
+	)) ..
+	 p(_(
+	[[If you finish a castle in the target area on the second island, you will get ]] ..
+	[[a third headquarters on the third island. You must build a castle at ]] ..
+	[[the center of the third island and hold it for 20 minutes to win the game.]]
+	)) ..
+	 p(_(
+	[[Whenever you finish an island, you will get bonus wares, depending on how many players ]] ..
+	[[have finished the island before you. The earlier you finish, the fewer wares you will get. ]] ..
+	[[See below for the details.]])) .. p(_(
+	[[The point is that the first island only provides stones and wood, the second only meadows and resources. The economies you leave behind will continue to work for you, but you will only reap the benefits at the moment you reach a new island.]])
+	) ..
+	p(_
+	[[Finally, be careful not to waste your quartz and diamonds.]]
+	) ..
+	h2(_"Finish Rewards") ..
+	h3(_"First Island") ..
+	h4(_"1st to finish") .. p(format_rewards(_finish_rewards[1][1])) ..
+	h4(_"2nd to finish") .. p(format_rewards(_finish_rewards[1][2])) ..
+	h4(_"3rd to finish") .. p(format_rewards(_finish_rewards[1][3])) ..
+	h4(_"4th to finish") .. p(format_rewards(_finish_rewards[1][4])) ..
+	h3(_"Second Island") ..
+	h4(_"1st to finish") .. p(format_rewards(_finish_rewards[2][1])) ..
+	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 = {

=== modified file 'maps/MP Scenarios/Smugglers.wmf/scripting/multiplayer_init.lua'
--- maps/MP Scenarios/Smugglers.wmf/scripting/multiplayer_init.lua	2015-03-21 13:18:02 +0000
+++ maps/MP Scenarios/Smugglers.wmf/scripting/multiplayer_init.lua	2015-09-24 16:48:57 +0000
@@ -38,9 +38,13 @@
 -- =================
 -- Utility functions
 -- =================
-function send_to_all(text)
+function send_to_all(text, long_title)
    for idx,plr in ipairs(game.players) do
-      plr:send_message(_ "Game Status", text, {popup=true})
+      if (long_title ~= nil and long_title ~= "") then
+         send_message(plr, _"Status", text, {popup=true, heading=long_title})
+      else
+         send_message(plr, _"Status", text, {popup=true})
+      end
    end
 end
 
@@ -138,10 +142,10 @@
       end
    end
 
-   send_to_all(welcome_msg:format((ngettext("%i point", "%i points", points_to_win)):format(points_to_win)))
+   send_to_all(welcome_msg.body:format((ngettext("%i point", "%i points", points_to_win)):format(points_to_win)), welcome_msg.heading)
    -- set the objective with the game type for all players
    -- TODO change this to a broadcast once individual game objectives have been implementes
-   game.players[1]:add_objective("win_conditions", _"Rules", welcome_msg:format((ngettext("%i point", "%i points", points_to_win)):format(points_to_win)))
+   game.players[1]:add_objective("win_conditions", _"Rules", welcome_msg.body:format((ngettext("%i point", "%i points", points_to_win)):format(points_to_win)))
 
    for idx,descr in ipairs(route_descrs) do
       run(wait_for_established_route, descr)

=== modified file 'maps/MP Scenarios/Smugglers.wmf/scripting/smuggling.lua'
--- maps/MP Scenarios/Smugglers.wmf/scripting/smuggling.lua	2014-10-03 20:16:29 +0000
+++ maps/MP Scenarios/Smugglers.wmf/scripting/smuggling.lua	2015-09-24 16:48:57 +0000
@@ -93,13 +93,13 @@
    )
    for idx,plr in ipairs(game.players) do
       if plr.number ~= receiving_wh.owner.number and plr.number ~= sending_wh.owner.number then
-         send_message(plr, _"Game Status", non_team_message, {popup=true})
+         send_message(plr, _"Status", non_team_message, {popup=true})
       end
    end
-   send_message(receiving_wh.owner, _"Game Status",
+   send_message(receiving_wh.owner, _"Status",
       smuggling_route_established_receiver:format(points), {popup=true, field=receiving_wh.fields[1]}
    )
-   send_message(sending_wh.owner, _"Game Status",
+   send_message(sending_wh.owner, _"Status",
       smuggling_route_established_sender:format(points), {popup=true, field=sending_wh.fields[1]}
    )
 

=== modified file 'maps/MP Scenarios/Smugglers.wmf/scripting/texts.lua'
--- maps/MP Scenarios/Smugglers.wmf/scripting/texts.lua	2015-07-30 07:16:09 +0000
+++ maps/MP Scenarios/Smugglers.wmf/scripting/texts.lua	2015-09-24 16:48:57 +0000
@@ -1,18 +1,20 @@
 -- =======================================================================
 --                          Texts for this scenario
 -- =======================================================================
-welcome_msg = rt(
-   h1(_"Smugglers") ..
-   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!]])))
+welcome_msg  = {
+	heading = _"Smugglers",
+	body = rt(
+		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!]])))
+}
 
 smuggling_route_established_other_team = rt(
 -- TRANSLATORS: the first 2 parameters are player names, the last parameter is '<number> points'

=== modified file 'scripting/win_condition_texts.lua'
--- scripting/win_condition_texts.lua	2014-02-25 15:08:42 +0000
+++ scripting/win_condition_texts.lua	2015-09-24 16:48:57 +0000
@@ -1,25 +1,27 @@
+include "scripting/formatting.lua"
+
 won_game = {
-  title = _ "Congratulations!",
-  body = _ "You have won this game!"
+  title = _"Congratulations!",
+  body = rt(p(_"You have won this game!"))
 }
 
 lost_game = {
-  title = _ "You are defeated!",
-  body = _ "You lost your last warehouse and are therefore defeated. You may continue as spectator if you want."
+  title = _"You are defeated!",
+  body = rt(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 = _"You are the winner!"
+  title = _"You won",
+  body = rt(p(_"You are the winner!"))
 }
 
 lost_game_over = {
-  title = _ "You lost",
-  body = _"You’ve lost this game!"
+  title = _"You lost",
+  body = rt(p(_"You’ve lost this game!"))
 }
 
 game_status = {
-  title = _ "Status",
-  body = _ "Player overview:"
+  title = _"Status",
+  body = rt(p(_"Player overview:"))
 }
 

=== modified file 'src/base/time_string.cc'
--- src/base/time_string.cc	2014-10-12 08:39:48 +0000
+++ src/base/time_string.cc	2015-09-24 16:48:57 +0000
@@ -177,15 +177,24 @@
 	return gamestringbuffer;
 }
 
-std::string gametimestring(uint32_t gametime)
+std::string gametimestring(uint32_t gametime, bool show_seconds)
 {
 	// update buffer
 	std::string result = gamestring_with_leading_zeros(gametime);
+	if (!show_seconds) {
+		result = result.substr(0, result.size() - 3);
+	}
 
 	// remove leading 0s
 	int i = 0;
 	while (result.at(i) == '0') ++i;
-	if (result.at(i) == ':') ++i;
+	if (result.at(i) == ':') {
+		if (show_seconds) {
+			++i;
+		} else {
+			--i;
+		}
+	}
 
 	return result.substr(i);
 }

=== modified file 'src/base/time_string.h'
--- src/base/time_string.h	2014-10-12 08:39:48 +0000
+++ src/base/time_string.h	2015-09-24 16:48:57 +0000
@@ -38,9 +38,9 @@
 /// for easy sorting.
 char * gamestring_with_leading_zeros(uint32_t gametime);
 
-/// Get a string representation of the game time
-/// as [hhh:]mm:ss. If Time represents more than
-/// 999 hours, it wraps around
-std::string gametimestring(uint32_t gametime);
+/// Get a string representation of the game time as [hh]h:mm.
+/// If show_seconds = true, this returns [hhh:]mm:ss instead.
+/// If Time represents more than 999 hours, it wraps around
+std::string gametimestring(uint32_t gametime, bool show_seconds = false);
 
 #endif  // end of include guard: WL_BASE_TIME_STRING_H

=== modified file 'src/logic/building.cc'
--- src/logic/building.cc	2015-02-05 11:26:01 +0000
+++ src/logic/building.cc	2015-09-24 16:48:57 +0000
@@ -131,11 +131,12 @@
 
 	m_enhanced_building = global_s.get_bool("enhanced_building", false);
 	m_global = directory.find("global/") < directory.size();
+
+	//  get build icon
+	m_icon_fname  = directory;
+	m_icon_fname += "/menu.png";
+
 	if (m_buildable || m_enhanced_building) {
-		//  get build icon
-		m_icon_fname  = directory;
-		m_icon_fname += "/menu.png";
-
 		//  build animation
 		if (Section * const build_s = prof.get_section("build")) {
 			if (build_s->get_int("fps", -1) != -1)
@@ -886,6 +887,8 @@
 	(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,
@@ -914,7 +917,7 @@
 			% rt_description % description).str();
 
 	Message * msg = new Message
-		(msgtype, game.get_gametime(), title, rt_description,
+		(msgtype, game.get_gametime(), title, icon_filename, heading, rt_description,
 		 get_position(), (link_to_building_lifetime ? m_serial : 0));
 
 	if (throttle_time)

=== modified file 'src/logic/building.h'
--- src/logic/building.h	2015-02-08 18:16:41 +0000
+++ src/logic/building.h	2015-09-24 16:48:57 +0000
@@ -262,6 +262,7 @@
 		(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,

=== modified file 'src/logic/cmd_luacoroutine.cc'
--- src/logic/cmd_luacoroutine.cc	2015-01-31 16:03:59 +0000
+++ src/logic/cmd_luacoroutine.cc	2015-09-24 16:48:57 +0000
@@ -50,7 +50,12 @@
 		for (int i = 1; i <= game.map().get_nrplayers(); i++) {
 			Widelands::Message & msg =
 				*new Widelands::Message
-				(Message::Type::kGameLogic, game.get_gametime(), "Lua Coroutine Failed", e.what());
+				(Message::Type::kGameLogic,
+				 game.get_gametime(),
+				 "pics/menu_help.png",
+				 "Coroutine",
+				 "Lua Coroutine Failed",
+				 e.what());
 			game.player(i).add_message(game, msg, true);
 		}
 		game.game_controller()->set_desired_speed(0);

=== modified file 'src/logic/message.h'
--- src/logic/message.h	2014-09-30 07:55:22 +0000
+++ src/logic/message.h	2015-09-24 16:48:57 +0000
@@ -23,6 +23,7 @@
 #include <string>
 #include <boost/signals2.hpp>
 
+#include "graphic/graphic.h"
 #include "logic/widelands.h"
 #include "logic/widelands_geometry.h"
 
@@ -65,55 +66,66 @@
 	Message
 		(Message::Type             msgtype,
 		 uint32_t                  sent_time,
-		 const std::string &       t,
-		 const std::string &       b,
+		 const std::string&        init_title,
+		 const std::string&        init_icon_filename,
+		 const std::string&        init_heading,
+		 const std::string&        init_body,
 		 Widelands::Coords   const c = Coords::null(),
 		 Widelands::Serial         ser = 0,
 		 Status                    s = Status::kNew)
 		:
-		m_type    (msgtype),
-		m_title   (t),
-		m_body    (b),
-		m_sent    (sent_time),
-		m_position(c),
-		m_serial  (ser),
-		m_status  (s)
+		type_    (msgtype),
+		title_   (init_title),
+		icon_filename_(init_icon_filename),
+		icon_    (g_gr->images().get(init_icon_filename)),
+		heading_ (init_heading),
+		body_    (init_body),
+		sent_    (sent_time),
+		position_(c),
+		serial_  (ser),
+		status_  (s)
 	{}
 
-	Message::Type         type    () const   {return m_type;}
-	uint32_t              sent    () const   {return m_sent;}
-	const std::string &   title   () const   {return m_title;}
-	const std::string &   body    () const   {return m_body;}
-	Widelands::Coords     position() const   {return m_position;}
-	Widelands::Serial     serial  () const   {return m_serial;}
-	Status                status  () const   {return m_status;}
-	Status set_status(Status const s)        {return m_status = s;}
+	Message::Type         type    () const   {return type_;}
+	uint32_t              sent    () const   {return sent_;}
+	const std::string &   title   () const   {return title_;}
+	const std::string& icon_filename() const {return icon_filename_;}
+	const Image*          icon    () const   {return icon_;}
+	const std::string &   heading () const   {return heading_;}
+	const std::string &   body    () const   {return body_;}
+	Widelands::Coords     position() const   {return position_;}
+	Widelands::Serial     serial  () const   {return serial_;}
+	Status                status  () const   {return status_;}
+	Status set_status(Status const s)        {return status_ = s;}
 
 	/**
 	 * Returns the main type for the message's sub type
 	 */
 	Message::Type message_type_category() const {
-		if (m_type >=  Widelands::Message::Type::kWarfare) {
+		if (type_ >=  Widelands::Message::Type::kWarfare) {
 			return Widelands::Message::Type::kWarfare;
 
-		} else if (m_type >= Widelands::Message::Type::kEconomy &&
-					  m_type <= Widelands::Message::Type::kEconomySiteOccupied) {
+		} else if (type_ >= Widelands::Message::Type::kEconomy &&
+					  type_ <= Widelands::Message::Type::kEconomySiteOccupied) {
 			return Widelands::Message::Type::kEconomy;
-		} else if (m_type >= Widelands::Message::Type::kGeologists &&
-					 m_type <= Widelands::Message::Type::kGeologistsWater) {
+		} else if (type_ >= Widelands::Message::Type::kGeologists &&
+					 type_ <= Widelands::Message::Type::kGeologistsWater) {
 		  return Widelands::Message::Type::kGeologists;
 	  }
-		return m_type;
+		return type_;
 	}
 
 private:
-	Message::Type     m_type;
-	std::string       m_title;
-	std::string       m_body;
-	uint32_t          m_sent;
-	Widelands::Coords m_position;
-	Widelands::Serial m_serial; // serial to map object
-	Status            m_status;
+	Message::Type     type_;
+	const std::string title_;
+	const std::string icon_filename_;
+	const Image     * icon_;   // Pointer to icon into picture stack
+	const std::string heading_;
+	const std::string body_;
+	uint32_t          sent_;
+	Widelands::Coords position_;
+	Widelands::Serial serial_; // serial to map object
+	Status            status_;
 };
 
 }

=== modified file 'src/logic/militarysite.cc'
--- src/logic/militarysite.cc	2015-09-07 12:12:32 +0000
+++ src/logic/militarysite.cc	2015-09-24 16:48:57 +0000
@@ -250,6 +250,8 @@
 				(*game,
 				 Message::Type::kEconomySiteOccupied,
 				 descr().descname(),
+				 descr().icon_name(),
+				 descr().descname(),
 				 descr().m_occupied_str,
 				 true);
 		}
@@ -860,6 +862,9 @@
 			send_message
 				(game,
 				 Message::Type::kWarfareSiteLost,
+				 /** TRANSLATORS: Militarysite lost (taken/destroyed by enemy) */
+				 pgettext("building", "Lost!"),
+				 descr().icon_name(),
 				 _("Militarysite lost!"),
 				 descr().m_defeated_enemy_str,
 				 false);
@@ -914,6 +919,10 @@
 		newsite->send_message
 			(game,
 			 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_name(),
 			 _("Enemy at site defeated!"),
 			 newsite->descr().m_defeated_you_str,
 			 true);
@@ -964,6 +973,9 @@
 	send_message
 		(game,
 		 Message::Type::kWarfareUnderAttack,
+		 /** TRANSLATORS: Militarysite is being attacked */
+		 pgettext("building", "Attack!"),
+		 descr().icon_name(),
 		 _("You are under attack"),
 		 discovered ? descr().m_aggressor_str : descr().m_attack_str,
 		 false,

=== modified file 'src/logic/player.cc'
--- src/logic/player.cc	2015-07-29 07:47:10 +0000
+++ src/logic/player.cc	2015-09-24 16:48:57 +0000
@@ -1320,7 +1320,7 @@
 			WareIndex idx = tribe().ware_index(name);
 			if (idx == INVALID_INDEX) {
 				log
-					("Player %u statistics: unknown ware name %s",
+					("Player %u statistics: unknown ware name %s\n",
 					 player_number(), name.c_str());
 				continue;
 			}
@@ -1344,7 +1344,7 @@
 				WareIndex idx = tribe().ware_index(name);
 				if (idx == INVALID_INDEX) {
 					log
-						("Player %u consumption statistics: unknown ware name %s",
+						("Player %u consumption statistics: unknown ware name %s\n",
 						player_number(), name.c_str());
 					continue;
 				}
@@ -1368,7 +1368,7 @@
 					WareIndex idx = tribe().ware_index(name);
 					if (idx == INVALID_INDEX) {
 						log
-							("Player %u stock statistics: unknown ware name %s",
+							("Player %u stock statistics: unknown ware name %s\n",
 							player_number(), name.c_str());
 						continue;
 					}

=== modified file 'src/logic/productionsite.cc'
--- src/logic/productionsite.cc	2015-09-03 13:09:49 +0000
+++ src/logic/productionsite.cc	2015-09-24 16:48:57 +0000
@@ -64,12 +64,14 @@
 	if (section != nullptr)
 	{
 		m_out_of_resource_title = section->get_string("title", "");
+		m_out_of_resource_heading = section->get_string("heading", "");
 		m_out_of_resource_message = section->get_string("message", "");
 		out_of_resource_productivity_threshold_ = section->get_natural("productivity_threshold", 100);
 	}
 	else
 	{
 		m_out_of_resource_title = "";
+		m_out_of_resource_heading = "";
 		m_out_of_resource_message = "";
 		out_of_resource_productivity_threshold_ = 100;
 	}
@@ -923,18 +925,20 @@
 	if (m_last_stat_percent == 0 ||
 		 (m_last_stat_percent <= descr().out_of_resource_productivity_threshold()
 		  && trend_ == Trend::kFalling)) {
-		if (descr().out_of_resource_title().empty())
+		if (descr().out_of_resource_heading().empty())
 		{
 			set_production_result(_("Can’t find any more resources!"));
 		}
 		else {
-			set_production_result(descr().out_of_resource_title());
+			set_production_result(descr().out_of_resource_heading());
 
 			assert(!descr().out_of_resource_message().empty());
 			send_message
 				(game,
 				 Message::Type::kEconomy,
 				 descr().out_of_resource_title(),
+				 descr().icon_name(),
+				 descr().out_of_resource_heading(),
 				 descr().out_of_resource_message(),
 				 true,
 				 minutes * 60000, 0);

=== modified file 'src/logic/productionsite.h'
--- src/logic/productionsite.h	2015-06-10 06:46:40 +0000
+++ src/logic/productionsite.h	2015-09-24 16:48:57 +0000
@@ -91,6 +91,10 @@
 		return m_out_of_resource_title;
 	}
 
+	const std::string& out_of_resource_heading() const {
+		return m_out_of_resource_heading;
+	}
+
 	const std::string& out_of_resource_message() const {
 		return m_out_of_resource_message;
 	}
@@ -105,6 +109,7 @@
 	Output   m_output_worker_types;
 	Programs m_programs;
 	std::string m_out_of_resource_title;
+	std::string m_out_of_resource_heading;
 	std::string m_out_of_resource_message;
 	int         out_of_resource_productivity_threshold_;
 

=== modified file 'src/logic/ship.cc'
--- src/logic/ship.cc	2015-09-03 12:56:54 +0000
+++ src/logic/ship.cc	2015-09-24 16:48:57 +0000
@@ -21,6 +21,8 @@
 
 #include <memory>
 
+#include <boost/format.hpp>
+
 #include "base/macros.h"
 #include "economy/economy.h"
 #include "economy/flag.h"
@@ -438,9 +440,12 @@
 		if (new_port_space) {
 			m_ship_state = EXP_FOUNDPORTSPACE;
 			// Send a message to the player, that a new port space was found
-			std::string msg_head = _("Port Space Found");
-			std::string msg_body = _("An expedition ship found a new port build space.");
-			send_message(game, msg_head, msg_body, "port.png");
+			send_message(
+						game,
+						_("Port Space"),
+						_("Port Space Found"),
+						_("An expedition ship found a new port build space."),
+						"fsel_editor_set_port_space.png");
 		}
 		m_expedition->seen_port_buildspaces.swap(temp_port_buildspaces);
 		if (new_port_space) {
@@ -554,10 +559,13 @@
 				} else {
 					// Check whether the island was completely surrounded
 					if (get_position() == m_expedition->exploration_start) {
-						std::string msg_head = _("Island Circumnavigated");
-						std::string msg_body = _("An expedition ship sailed around its"
-						                         " island without any events.");
-						send_message(game, msg_head, msg_body, "ship_explore_island_cw.png");
+						send_message(
+									game,
+									/** TRANSLATORS: A ship has circumnavigated an island and is waiting for orders */
+									pgettext("ship", "Waiting"),
+									_("Island Circumnavigated"),
+									_("An expedition ship sailed around its island without any events."),
+									"ship_explore_island_cw.png");
 						m_ship_state = EXP_WAITING;
 
 						Notifications::publish(
@@ -615,10 +623,13 @@
 			m_ship_state = EXP_WAITING;
 			start_task_idle(game, descr().main_animation(), 1500);
 			// Send a message to the player, that a new coast was reached
-			std::string msg_head = _("Coast Reached");
-			std::string msg_body =
-			   _("An expedition ship reached a coast and is waiting for further commands.");
-			send_message(game, msg_head, msg_body, "ship_explore_island_cw.png");
+			send_message(
+						game,
+						/** TRANSLATORS: A ship has discovered land */
+						_("Land Ahoy!"),
+						_("Coast Reached"),
+						_("An expedition ship reached a coast and is waiting for further commands."),
+						"ship_scout_ne.png");
 
 			Notifications::publish(
 			   NoteShipMessage(this, NoteShipMessage::Message::kWaitingForCommand));
@@ -661,9 +672,12 @@
 			}
 		} else {  // it seems that port constructionsite has dissapeared
 			// Send a message to the player, that a port constructionsite is gone
-			std::string msg_head = _("New port construction site is gone");
-			std::string msg_body = _("Unloading of wares failed, expedition is cancelled now.");
-			send_message(game, msg_head, msg_body, "port.png");
+			send_message(
+						game,
+						_("Port Lost!"),
+						_("New port construction site is gone"),
+						_("Unloading of wares failed, expedition is cancelled now."),
+						"menu_ship_cancel_expedition.png");
 			send_signal(game, "cancel_expedition");
 		}
 
@@ -839,9 +853,13 @@
 	}
 
 	// Send a message to the player, that an expedition is ready to go
-	const std::string msg_head = _("Expedition Ready");
-	const std::string msg_body = _("An expedition ship is waiting for your commands.");
-	send_message(game, msg_head, msg_body, "start_expedition.png");
+	send_message(
+				game,
+				/** TRANSLATORS: Ship expedition ready */
+				pgettext("ship", "Expedition"),
+				_("Expedition Ready"),
+				_("An expedition ship is waiting for your commands."),
+				"start_expedition.png");
 	Notifications::publish(NoteShipMessage(this, NoteShipMessage::Message::kWaitingForCommand));
 }
 
@@ -968,7 +986,8 @@
  * \param picture picture name relative to the pics directory
  */
 void Ship::send_message(Game& game,
-                        const std::string& title,
+								const std::string& title,
+								const std::string& heading,
                         const std::string& description,
                         const std::string& picture) {
 	std::string rt_description;
@@ -984,6 +1003,8 @@
 	Message* msg = new Message(Message::Type::kSeafaring,
 	                           game.get_gametime(),
 	                           title,
+										(boost::format("pics/%s") % picture).str(),
+										heading,
 	                           rt_description,
 	                           get_position(),
 	                           m_serial);

=== modified file 'src/logic/ship.h'
--- src/logic/ship.h	2015-07-21 18:52:14 +0000
+++ src/logic/ship.h	2015-09-24 16:48:57 +0000
@@ -239,7 +239,11 @@
 	void init_fleet(EditorGameBase &);
 	void set_fleet(Fleet * fleet);
 
-	void send_message(Game &, const std::string &, const std::string &, const std::string &);
+	void send_message(Game& game,
+							const std::string& title,
+							const std::string& heading,
+							const std::string& description,
+							const std::string& picture);
 
 	UI::Window * m_window;
 

=== modified file 'src/logic/soldier.cc'
--- src/logic/soldier.cc	2014-12-08 11:08:38 +0000
+++ src/logic/soldier.cc	2015-09-24 16:48:57 +0000
@@ -1573,7 +1573,9 @@
 						 *new Message
 							(Message::Type::kGameLogic,
 							 game.get_gametime(),
-						 	 _("Logic error"),
+							 _("Soldier"),
+							 "pics/menu_help.png",
+							 _("Logic error"),
 							 messagetext,
 						 	 get_position(),
 							 m_serial));
@@ -1582,7 +1584,9 @@
 						 *new Message
 							(Message::Type::kGameLogic,
 							 game.get_gametime(),
-						 	 _("Logic error"),
+							 _("Soldier"),
+							 "pics/menu_help.png",
+							 _("Logic error"),
 							 messagetext,
 						 	 opponent.get_position(),
 							 m_serial));

=== modified file 'src/logic/warehouse.cc'
--- src/logic/warehouse.cc	2015-07-24 18:21:58 +0000
+++ src/logic/warehouse.cc	2015-09-24 16:48:57 +0000
@@ -454,6 +454,8 @@
 				(*game,
 				 Message::Type::kSeafaring,
 				 descr().descname(),
+				 descr().icon_name(),
+				 descr().descname(),
 				 _("A new port was added to your economy."),
 				 true);
 		} else if (descr().name() == "headquarters") {
@@ -461,6 +463,8 @@
 				(*game,
 				 Message::Type::kEconomy,
 				 descr().descname(),
+				 descr().icon_name(),
+				 descr().descname(),
 				 _("A new headquarters was added to your economy."),
 				 true);
 		} else {
@@ -468,6 +472,8 @@
 				(*game,
 				 Message::Type::kEconomy,
 				 descr().descname(),
+				 descr().icon_name(),
+				 descr().descname(),
 				 _("A new warehouse was added to your economy."),
 				 true);
 		}

=== modified file 'src/logic/worker.cc'
--- src/logic/worker.cc	2015-04-25 17:40:22 +0000
+++ src/logic/worker.cc	2015-09-24 16:48:57 +0000
@@ -945,14 +945,21 @@
 		(const ResourceDescription * const rdescr =
 			world.get_resource(position.field->get_resources()))
 	{
+		const TribeDescr & t = descr().tribe();
+		Immovable& ri = game.create_immovable
+			(position,
+			 t.get_resource_indicator
+				(rdescr,
+				 rdescr->detectable() ?
+				 position.field->get_resources_amount() : 0),
+			 &t);
+
 		// Geologist also sends a message notifying the player
 		if (rdescr->detectable() && position.field->get_resources_amount()) {
-			// TODO(sirver): this is very wrong: It assumes a directory layout
-			// that might not be around forever.
 			const std::string message =
-					(boost::format("<rt image=world/resources/pics/%s4.png>"
+					(boost::format("<rt image=%s>"
 										"<p font-face=serif font-size=14>%s</p></rt>")
-					 % rdescr->name().c_str()
+					 % rdescr->get_editor_pic(rdescr->max_amount())
 					 % _("A geologist found resources.")).str();
 
 			Message::Type message_type = Message::Type::kGeologists;
@@ -967,6 +974,9 @@
 			else if (rdescr->name() == "water")
 				message_type = Message::Type::kGeologistsWater;
 
+			const std::string& img = g_gr->animations().get_animation
+											 (ri.descr().main_animation()).representative_image_from_disk_filename();
+
 			//  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
@@ -975,21 +985,14 @@
 					(message_type,
 					 game.get_gametime(),
 					 rdescr->descname(),
+					 img,
+					 rdescr->descname(),
 					 message,
 					 position,
 					 m_serial
 					),
 				 300000, 8);
 		}
-
-		const TribeDescr & t = descr().tribe();
-		game.create_immovable
-			(position,
-			 t.get_resource_indicator
-				(rdescr,
-				 rdescr->detectable() ?
-				 position.field->get_resources_amount() : 0),
-			 &t);
 	}
 
 	++state.ivar1;
@@ -1874,6 +1877,8 @@
 			 *new Message
 				(Message::Type::kGameLogic,
 				 game.get_gametime(),
+				 _("Worker"),
+				 "pics/menu_help.png",
 				 _("Worker got lost!"),
 				 message,
 				 get_position()),

=== modified file 'src/map_io/map_players_messages_packet.cc'
--- src/map_io/map_players_messages_packet.cc	2014-10-28 16:59:19 +0000
+++ src/map_io/map_players_messages_packet.cc	2015-09-24 16:48:57 +0000
@@ -31,7 +31,7 @@
 
 namespace Widelands {
 
-#define CURRENT_PACKET_VERSION 1
+#define CURRENT_PACKET_VERSION 2
 #define PLAYERDIRNAME_TEMPLATE "player/%u"
 #define FILENAME_TEMPLATE PLAYERDIRNAME_TEMPLATE "/messages"
 
@@ -127,6 +127,8 @@
 							(static_cast<Message::Type>(s->get_natural("type")),
 						 	 sent,
 						 	 s->get_name       (),
+							 s->get_safe_string("icon"),
+							 s->get_safe_string("heading"),
 						 	 s->get_safe_string("body"),
 							 get_coords("position", extent, Coords::null(), s),
 							 serial,
@@ -161,6 +163,8 @@
 
 			Section & s = prof.create_section_duplicate(message.title().c_str());
 			s.set_int    ("type",      static_cast<int32_t>(message.type()));
+			s.set_string ("heading",   message.heading());
+			s.set_string ("icon",      message.icon_filename());
 			s.set_int    ("sent",      message.sent    ());
 			s.set_string ("body",      message.body    ());
 			if (Coords const c =       message.position())

=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc	2015-08-06 17:14:34 +0000
+++ src/scripting/lua_game.cc	2015-09-24 16:48:57 +0000
@@ -282,17 +282,31 @@
 			Default: :const:`false`
 		:type popup: :class:`boolean`
 
+		:arg icon: show a custom icon instead of the standard scenario message icon.
+			Default: "pics/menu_toggle_objectives_menu.png""
+		:type icon: :class:`string` The icon's file path.
+
+		:arg heading: a longer message heading to be shown within the message.
+			If this is not set, `title` is used instead.
+			Default: ""
+		:type building: :class:`string`
+
 		:returns: the message created
 		:rtype: :class:`wl.game.Message`
 */
 int LuaPlayer::send_message(lua_State * L) {
 	uint32_t n = lua_gettop(L);
 	std::string title = luaL_checkstring(L, 2);
+	std::string heading = title;
 	std::string body = luaL_checkstring(L, 3);
+	std::string icon = "pics/menu_toggle_objectives_menu.png";
 	Coords c = Coords::null();
 	Message::Status st = Message::Status::kNew;
 	bool popup = false;
 
+	Game & game = get_game(L);
+	Player & plr = get(L, game);
+
 	if (n == 4) {
 		// Optional arguments
 		lua_getfield(L, 4, "field");
@@ -314,11 +328,23 @@
 		if (!lua_isnil(L, -1))
 			popup = luaL_checkboolean(L, -1);
 		lua_pop(L, 1);
+
+		lua_getfield(L, 4, "icon");
+		if (!lua_isnil(L, -1)) {
+			std::string s = luaL_checkstring(L, -1);
+			if (!s.empty()) {
+				icon = s;
+			}
+		}
+		lua_getfield(L, 4, "heading");
+		if (!lua_isnil(L, -1)) {
+			std::string s = luaL_checkstring(L, -1);
+			if (!s.empty()) {
+				heading = s;
+			}
+		}
 	}
 
-	Game & game = get_game(L);
-	Player & plr = get(L, game);
-
 	MessageId const message =
 		plr.add_message
 			(game,
@@ -326,6 +352,8 @@
 				(Message::Type::kScenario,
 			 	 game.get_gametime(),
 			 	 title,
+				 icon,
+				 heading,
 			 	 body,
 				 c,
 				 0,
@@ -1082,6 +1110,8 @@
 	PROP_RO(LuaMessage, sent),
 	PROP_RO(LuaMessage, field),
 	PROP_RW(LuaMessage, status),
+	PROP_RO(LuaMessage, heading),
+	PROP_RO(LuaMessage, icon_name),
 	{nullptr, nullptr, nullptr},
 };
 
@@ -1180,6 +1210,28 @@
 	return 0;
 }
 
+/* RST
+	.. attribute:: heading
+
+		(RO) The long heading of this message that is shown in the body
+*/
+int LuaMessage::get_heading(lua_State * L) {
+	lua_pushstring(L, get(L, get_game(L)).heading());
+	return 1;
+}
+
+/* RST
+	.. attribute:: icon_name
+
+		(RO) The filename for the icon that is shown with the message title
+*/
+int LuaMessage::get_icon_name(lua_State * L) {
+	lua_pushstring(L, get(L, get_game(L)).icon_filename());
+	return 1;
+}
+
+
+
 /*
  ==========================================================
  LUA METHODS

=== modified file 'src/scripting/lua_game.h'
--- src/scripting/lua_game.h	2015-03-10 20:10:31 +0000
+++ src/scripting/lua_game.h	2015-09-24 16:48:57 +0000
@@ -168,6 +168,8 @@
 	int get_field(lua_State * L);
 	int get_status(lua_State * L);
 	int set_status(lua_State * L);
+	int get_heading(lua_State * L);
+	int get_icon_name(lua_State * L);
 
 	/*
 	 * Lua Methods

=== modified file 'src/ui_basic/scrollbar.cc'
--- src/ui_basic/scrollbar.cc	2014-11-22 10:18:20 +0000
+++ src/ui_basic/scrollbar.cc	2015-09-24 16:48:57 +0000
@@ -83,6 +83,10 @@
 }
 
 
+bool Scrollbar::is_enabled() const {
+	return m_steps != 1 || m_force_draw;
+}
+
 /**
  * \return the number of steps
  */
@@ -309,8 +313,9 @@
 	uint32_t knobpos = get_knob_pos();
 	uint32_t knobsize = get_knob_size();
 
-	if (m_steps == 1 && !m_force_draw)
-		return; // don't draw a not doing scrollbar
+	if (!is_enabled()) {
+		return; // Don't draw a scrollbar that doesn't do anything
+	}
 
 	if (m_horizontal) {
 		if ((2 * Size + knobsize) > static_cast<uint32_t>(get_w())) {

=== modified file 'src/ui_basic/scrollbar.h'
--- src/ui_basic/scrollbar.h	2014-10-27 08:37:54 +0000
+++ src/ui_basic/scrollbar.h	2015-09-24 16:48:57 +0000
@@ -57,6 +57,7 @@
 	void set_pagesize(int32_t pagesize);
 	void set_scrollpos(int32_t pos);
 
+	bool is_enabled() const;
 	uint32_t get_steps() const;
 	uint32_t get_singlestepsize() const {return m_singlestepsize;}
 	uint32_t get_pagesize() const {return m_pagesize;}

=== modified file 'src/ui_basic/table.cc'
--- src/ui_basic/table.cc	2014-12-06 12:22:35 +0000
+++ src/ui_basic/table.cc	2015-09-24 16:48:57 +0000
@@ -278,24 +278,52 @@
 			Align    const alignment = column.alignment;
 
 			const Image* entry_picture = er.get_picture(i);
-			const std::string &       entry_string  = er.get_string (i);
-			uint32_t picw = 0;
-			uint32_t pich = 0;
+			const std::string& entry_string = er.get_string(i);
+
+			Point point(curx, y);
+			int picw = 0;
+			int pich = 0;
 
 			if (entry_picture) {
 				picw = entry_picture->width();
 				pich = entry_picture->height();
-			}
-			Point point(curx, y);
-			if (entry_picture) {
-				dst.blit
-					(point +
-					 Point
-					 	(0,
-					 	 (static_cast<int32_t>(lineheight) -
-					 	  static_cast<int32_t>(pich))
-					 	 / 2),
-					 entry_picture);
+
+				int draw_x = point.x;
+
+				if (pich > 0 && pich > lineheight) {
+					// Scale image to fit lineheight
+					double image_scale = static_cast<double>(lineheight) / pich;
+					int blit_width = image_scale * picw;
+
+					if (entry_string.empty()) {
+						if (i == nr_columns - 1 && m_scrollbar->is_enabled()) {
+							draw_x = point.x + (curw - blit_width - m_scrollbar->get_w()) / 2 ;
+						} else {
+							draw_x = point.x + (curw - blit_width) / 2 ;
+						}
+					}
+
+					dst.blitrect_scale(
+								// Center align if text is empty
+								Rect(draw_x,
+									  point.y,
+									  blit_width,
+									  lineheight),
+								entry_picture,
+								Rect(0, 0, picw, pich),
+								1.,
+								BlendMode::UseAlpha);
+					picw = blit_width;
+				} else {
+					if (entry_string.empty()) {
+						if (i == nr_columns - 1 && m_scrollbar->is_enabled()) {
+							draw_x = point.x + (curw - picw - m_scrollbar->get_w()) / 2 ;
+						} else {
+							draw_x = point.x + (curw - picw) / 2 ;
+						}
+					}
+					dst.blit(Point(draw_x, point.y + (lineheight - pich) / 2), entry_picture);
+				}
 				point.x += picw;
 			}
 
@@ -304,12 +332,18 @@
 				continue;
 			}
 			const Image* entry_text_im = UI::g_fh1->render(as_uifont(entry_string, m_fontsize));
-			uint16_t text_width = entry_text_im->width();
+
 			if (alignment & Align_Right) {
 				point.x += curw - picw;
 			} else if (alignment & Align_HCenter) {
 				point.x += (curw - picw) / 2;
 			}
+
+			// Add an offset for rightmost column when the scrollbar is shown.
+			uint16_t text_width = entry_text_im->width();
+			if (i == nr_columns - 1 && m_scrollbar->is_enabled()) {
+				text_width = text_width + m_scrollbar->get_w();
+			}
 			UI::correct_for_align(alignment, text_width, entry_text_im->height(), &point);
 			// Crop to column width
 			dst.blitrect(point, entry_text_im, Rect(0, 0, curw - picw, lineheight));

=== modified file 'src/wui/game_message_menu.cc'
--- src/wui/game_message_menu.cc	2015-07-25 17:44:08 +0000
+++ src/wui/game_message_menu.cc	2015-09-24 16:48:57 +0000
@@ -38,33 +38,50 @@
 	return dynamic_cast<InteractivePlayer&>(*get_parent());
 }
 
+constexpr int kWindowWidth = 355;
+constexpr int kWindowHeight = 375;
+constexpr int kTableHeight = 125;
+constexpr int kPadding = 5;
+constexpr int kButtonSize = 34;
+constexpr int kMessageBodyY = kButtonSize + 3 * kPadding + kTableHeight;
+
 
 GameMessageMenu::GameMessageMenu
 	(InteractivePlayer & plr, UI::UniqueWindow::Registry & registry)
 	:
 	UI::UniqueWindow
-		(&plr, "messages", &registry, 580, 375, _("Messages: Inbox")),
+		(&plr, "messages", &registry, kWindowWidth, kWindowHeight, _("Messages: Inbox")),
 	message_body
 		(this,
-		 5, 154, 570, 216 - 5 - 34, // Subtracting height for message type icon
+		 kPadding,
+		 kMessageBodyY,
+		 kWindowWidth - 2 * kPadding,
+		 get_inner_h() - kMessageBodyY - 2 * kPadding - kButtonSize,
 		 "", UI::Align_Left, 1),
 	mode(Inbox)
 {
 
-	list = new UI::Table<uintptr_t>(this, 5, message_body.get_y() - 110, 570, 110);
+	list = new UI::Table<uintptr_t>(
+				 this,
+				 kPadding,
+				 kButtonSize + 2 * kPadding,
+				 kWindowWidth - 2 * kPadding,
+				 kTableHeight);
 	list->selected.connect(boost::bind(&GameMessageMenu::selected, this, _1));
 	list->double_clicked.connect(boost::bind(&GameMessageMenu::double_clicked, this, _1));
-	list->add_column (60, _("Select"), "", UI::Align_HCenter, true);
+	list->add_column(kWindowWidth - 2 * kPadding - 60 - 60 - 75, _("Title"));
+	list->add_column (60, pgettext("message", "Type"), "", UI::Align_HCenter, true);
 	list->add_column (60, _("Status"), "", UI::Align_HCenter);
-	list->add_column(330, _("Title"));
-	list->add_column(120, _("Time sent"));
+	/** TRANSLATORS: We have very little space here. You can also translate this as "Time" or "Time Sent" */
+	/** TRANSLATORS: This is used in the game messages menu - please open an issue if you need more space. */
+	list->add_column(75, pgettext("message", "Sent"), "", UI::Align_Right);
 	list->focus();
 
 	// Buttons for message types
 	m_geologistsbtn =
 			new UI::Button
 				(this, "filter_geologists_messages",
-				 5, 5, 34, 34,
+				 kPadding, kPadding, kButtonSize, kButtonSize,
 				 g_gr->images().get("pics/but0.png"),
 				 g_gr->images().get("pics/menu_geologist.png"),
 				 "",
@@ -75,9 +92,9 @@
 	m_economybtn =
 			new UI::Button
 				(this, "filter_economy_messages",
-				 2 * 5 + 34, 5, 34, 34,
+				 2 * kPadding + kButtonSize, kPadding, kButtonSize, kButtonSize,
 				 g_gr->images().get("pics/but0.png"),
-				 g_gr->images().get("pics/menu_build_flag.png"),
+				 g_gr->images().get("pics/genstats_nrwares.png"),
 				 "",
 				 true);
 	m_economybtn->sigclicked.connect
@@ -86,7 +103,7 @@
 	m_seafaringbtn =
 			new UI::Button
 				(this, "filter_seafaring_messages",
-				 3 * 5 + 2 * 34, 5, 34, 34,
+				 3 * kPadding + 2 * kButtonSize, kPadding, kButtonSize, kButtonSize,
 				 g_gr->images().get("pics/but0.png"),
 				 g_gr->images().get("pics/start_expedition.png"),
 				 "",
@@ -97,7 +114,7 @@
 	m_warfarebtn =
 			new UI::Button
 				(this, "filter_warfare_messages",
-				 4 * 5 + 3 * 34, 5, 34, 34,
+				 4 * kPadding + 3 * kButtonSize, kPadding, kButtonSize, kButtonSize,
 				 g_gr->images().get("pics/but0.png"),
 				 g_gr->images().get("pics/messages_warfare.png"),
 				 "",
@@ -108,7 +125,7 @@
 	m_scenariobtn =
 			new UI::Button
 				(this, "filter_scenario_messages",
-				 5 * 5 + 4 * 34, 5, 34, 34,
+				 5 * kPadding + 4 * kButtonSize, kPadding, kButtonSize, kButtonSize,
 				 g_gr->images().get("pics/but0.png"),
 				 g_gr->images().get("pics/menu_objectives.png"),
 				 "",
@@ -120,43 +137,26 @@
 	set_filter_messages_tooltips();
 	// End: Buttons for message types
 
-	UI::Button * clearselectionbtn =
-		new UI::Button
-			(this, "clear_selection",
-			 5 * 5 + 6 * 34 + 17, 5, 34, 34,
-			 g_gr->images().get("pics/but2.png"),
-			 g_gr->images().get("pics/message_clear_selection.png"),
-			 _("Clear selection"));
-	clearselectionbtn->sigclicked.connect
-		(boost::bind(&GameMessageMenu::do_clear_selection, this));
-
-	UI::Button * invertselectionbtn =
-		new UI::Button
-			(this, "invert_selection",
-			 6 * 5 + 7 * 34 + 17, 5, 34, 34,
-			 g_gr->images().get("pics/but2.png"),
-			 g_gr->images().get("pics/message_selection_invert.png"),
-			 _("Invert selection"));
-	invertselectionbtn->sigclicked.connect
-		(boost::bind(&GameMessageMenu::do_invert_selection, this));
-
 	m_archivebtn =
 		new UI::Button
 			(this, "archive_or_restore_selected_messages",
-			 6 * 5 + 9 * 34 + 34, 5, 34, 34,
+			 kPadding, kWindowHeight - kPadding - kButtonSize, kButtonSize, kButtonSize,
 			 g_gr->images().get("pics/but2.png"),
 			 g_gr->images().get("pics/message_archive.png"),
 			 /** TRANSLATORS: %s is a tooltip, Del is the corresponding hotkey */
 			 (boost::format(_("Del: %s"))
 			  /** TRANSLATORS: Tooltip in the messages window */
-			  % _("Archive selected messages")).str());
+			  % _("Archive selected message")).str());
 	m_archivebtn->sigclicked.connect
 		(boost::bind(&GameMessageMenu::archive_or_restore, this));
 
 	m_togglemodebtn =
 		new UI::Button
 			(this, "toggle_between_inbox_or_archive",
-			 7 * 5 + 10 * 34 + 34, 5, 34, 34,
+			 m_archivebtn->get_x() + m_archivebtn->get_w() + kPadding,
+			 m_archivebtn->get_y(),
+			 kButtonSize,
+			 kButtonSize,
 			 g_gr->images().get("pics/but2.png"),
 			 g_gr->images().get("pics/message_archived.png"),
 			 _("Show Archive"));
@@ -166,7 +166,7 @@
 	m_centerviewbtn =
 		new UI::Button
 			(this, "center_main_mapview_on_location",
-			 580 - 5 - 34, 5, 34, 34,
+			 kWindowWidth - kPadding - kButtonSize, m_archivebtn->get_y(), kButtonSize, kButtonSize,
 			 g_gr->images().get("pics/but2.png"),
 			 g_gr->images().get("pics/menu_goto.png"),
 			 /** TRANSLATORS: %s is a tooltip, G is the corresponding hotkey */
@@ -176,41 +176,101 @@
 			 false);
 	m_centerviewbtn->sigclicked.connect(boost::bind(&GameMessageMenu::center_view, this));
 
-
-	m_display_message_type_label =
-		new UI::MultilineTextarea
-			(this,
-			 5, 375 - 5 - 34, 5 * 34, 40,
-			 "<rt image=pics/message_new.png></rt>",
-			 UI::Align::Align_BottomLeft, false);
-
 	if (get_usedefaultpos())
 		center_to_parent();
 
 	list->set_column_compare
-		(ColStatus, boost::bind(&GameMessageMenu::status_compare, this, _1, _2));
+		(ColTitle, boost::bind(&GameMessageMenu::compare_title, this, _1, _2));
+	list->set_column_compare
+		(ColStatus, boost::bind(&GameMessageMenu::compare_status, this, _1, _2));
+	list->set_column_compare
+		(ColType,
+		 boost::bind(&GameMessageMenu::compare_type, this, _1, _2));
+	list->set_column_compare
+		(ColTimeSent,
+		 boost::bind(&GameMessageMenu::compare_time_sent, this, _1, _2));
+
 	list->set_sort_column(ColTimeSent);
-	list->set_sort_descending(true);
 
 	set_can_focus(true);
 	focus();
 }
 
 /**
+ * When comparing messages by title, order is alphabetical.
+ * If both are identical, sort by time sent.
+ */
+bool GameMessageMenu::compare_title(uint32_t a, uint32_t b)
+{
+	MessageQueue & mq = iplayer().player().messages();
+	const Message * msga = mq[MessageId((*list)[a])];
+	const Message * msgb = mq[MessageId((*list)[b])];
+
+	if (msga && msgb) {
+		if (msga->title() == msgb->title()) {
+			return compare_time_sent(a, b);
+		}
+		return msga->title() < msgb->title();
+	}
+	return false; // shouldn't happen
+}
+
+/**
  * When comparing messages by status, new messages come before others.
+ * If both are identical, sort by time sent.
  */
-bool GameMessageMenu::status_compare(uint32_t a, uint32_t b)
+bool GameMessageMenu::compare_status(uint32_t a, uint32_t b)
 {
 	MessageQueue & mq = iplayer().player().messages();
 	const Message * msga = mq[MessageId((*list)[a])];
 	const Message * msgb = mq[MessageId((*list)[b])];
 
 	if (msga && msgb) {
+		if (msga->status() == msgb->status()) {
+			return compare_time_sent(a, b);
+		}
 		return msga->status() == Message::Status::kNew && msgb->status() != Message::Status::kNew;
 	}
 	return false; // shouldn't happen
 }
 
+/**
+ * When comparing messages by type, order is the same as in the enum class.
+ * If both are identical, sort by time sent.
+ */
+bool GameMessageMenu::compare_type(uint32_t a, uint32_t b)
+{
+	MessageQueue & mq = iplayer().player().messages();
+	const Message * msga = mq[MessageId((*list)[a])];
+	const Message * msgb = mq[MessageId((*list)[b])];
+
+	if (msga && msgb) {
+		const Widelands::Message::Type cat_a = msga->message_type_category();
+		const Widelands::Message::Type cat_b = msgb->message_type_category();
+		if (cat_a == cat_b) {
+			return compare_time_sent(a, b);
+		}
+		return static_cast<int>(cat_a) < static_cast<int>(cat_b);
+	}
+	return false; // shouldn't happen
+}
+
+/**
+ * When comparing messages by time sent, older messages come before others.
+ */
+bool GameMessageMenu::compare_time_sent(uint32_t a, uint32_t b)
+{
+	MessageQueue & mq = iplayer().player().messages();
+	const Message * msga = mq[MessageId((*list)[a])];
+	const Message * msgb = mq[MessageId((*list)[b])];
+
+	if (msga && msgb) {
+		return msga->sent() > msgb->sent();
+	}
+	return false; // shouldn't happen
+}
+
+
 static char const * const status_picture_filename[] = {
 	"pics/message_new.png",
 	"pics/message_read.png",
@@ -227,6 +287,7 @@
 		toggle_mode();
 	UI::Table<uintptr_t>::EntryRecord & te = list->add(id.value(), true);
 	update_record(te, message);
+	list->sort();
 }
 
 void GameMessageMenu::think()
@@ -264,7 +325,6 @@
 
 	// Filter message type
 	if (m_message_filter != Message::Type::kAllMessages) {
-		set_display_message_type_label(m_message_filter);
 		for (uint32_t j = list->size(); j; --j) {
 			MessageId m_id((*list)[j - 1]);
 			if (Message const * const message = mq[m_id]) {
@@ -284,21 +344,19 @@
 	} else {
 		m_centerviewbtn->set_enabled(false);
 		message_body.set_text(std::string());
-		set_display_message_type_label(Widelands::Message::Type::kNoMessages);
 	}
 }
 
-void GameMessageMenu::update_record
-	(UI::Table<uintptr_t>::EntryRecord & er,
-	 const Widelands::Message & message)
+void GameMessageMenu::update_record(UI::Table<uintptr_t>::EntryRecord& er, const Widelands::Message& message)
 {
+	er.set_picture(ColType, g_gr->images().get(display_message_type_icon(message)));
 	er.set_picture
 		(ColStatus,
 		 g_gr->images().get(status_picture_filename[static_cast<int>(message.status())]));
-	er.set_string(ColTitle, message.title());
+	er.set_picture(ColTitle, message.icon(), message.title());
 
 	const uint32_t time = message.sent();
-	er.set_string(ColTimeSent, gamestring_with_leading_zeros(time));
+	er.set_string(ColTimeSent, gametimestring(time));
 }
 
 /*
@@ -318,8 +376,12 @@
 					 	(game.get_gametime(), player.player_number(), id));
 			}
 			m_centerviewbtn->set_enabled(message->position());
-			message_body.set_text(message->body    ());
-			set_display_message_type_label(message->message_type_category());
+
+			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());
 			return;
 		}
 	}
@@ -390,17 +452,7 @@
 
 	switch (mode) {
 	case Inbox:
-		//archive selected messages
-		for (size_t i = 0; i < list->size(); ++i)
-			if (list->get_record(i).is_checked(ColSelect))
-			{
-				work_done = true;
-				game.send_player_command
-					(*new Widelands::CmdMessageSetStatusArchived
-					 	(gametime, plnum, MessageId((*list)[i])));
-			}
-
-		//archive highlighted message, if nothing was selected
+		//archive highlighted message
 		if (!work_done) {
 			if (!list->has_selection()) return;
 
@@ -410,17 +462,7 @@
 		}
 		break;
 	case Archive:
-		//restore selected messages
-		for (size_t i = 0; i < list->size(); ++i)
-			if (list->get_record(i).is_checked(ColSelect))
-			{
-				work_done = true;
-				game.send_player_command
-					(*new Widelands::CmdMessageSetStatusRead
-					 	(gametime, plnum, MessageId((*list)[i])));
-			}
-
-		//restore highlighted message, if nothing was selected
+		//restore highlighted message
 		if (!work_done) {
 			if (!list->has_selection()) return;
 
@@ -530,73 +572,29 @@
 										 % "5").str());
 }
 
+
 /**
- * Update image and tooltip for message category label
+ * Get the filename for a message category's icon
  */
-void GameMessageMenu::set_display_message_type_label(Widelands::Message::Type msgtype) {
-	std::string message_type_tooltip = "";
-	std::string message_type_image = "";
-
-	switch (msgtype) {
+std::string GameMessageMenu::display_message_type_icon(Widelands::Message message) {
+	switch (message.message_type_category()) {
 		case Widelands::Message::Type::kGeologists:
-			/** TRANSLATORS: This is a message's type */
-			message_type_tooltip =  _("Geologists");
-			message_type_image =  "<rt image=pics/menu_geologist.png></rt>";
-			break;
+			return "pics/menu_geologist.png";
 		case Widelands::Message::Type::kEconomy:
-			/** TRANSLATORS: This is a message's type */
-			message_type_tooltip =  _("Economy");
-			message_type_image =  "<rt image=pics/menu_build_flag.png></rt>";
-			break;
+			return "pics/genstats_nrwares.png";
 		case Widelands::Message::Type::kSeafaring:
-			/** TRANSLATORS: This is a message's type */
-			message_type_tooltip =  _("Seafaring");
-			message_type_image =  "<rt image=pics/start_expedition.png></rt>";
-			break;
+			return "pics/start_expedition.png";
 		case Widelands::Message::Type::kWarfare:
-			/** TRANSLATORS: This is a message's type */
-			message_type_tooltip =  _("Warfare");
-			message_type_image =  "<rt image=pics/messages_warfare.png></rt>";
-			break;
+			return "pics/messages_warfare.png";
 		case Widelands::Message::Type::kScenario:
-			/** TRANSLATORS: This is a message's type */
-			message_type_tooltip =  _("Scenario");
-			message_type_image =  "<rt image=pics/menu_objectives.png></rt>";
-			break;
-		case Widelands::Message::Type::kNoMessages:
-			/** TRANSLATORS: This show up instead of a message's type when there are no messages found */
-			message_type_tooltip =  _("No message found");
-			break;
+			return "pics/menu_objectives.png";
+		case Widelands::Message::Type::kGameLogic:
+			return "pics/menu_help.png";
 		default:
-			/** TRANSLATORS: This is the default message type */
-			message_type_tooltip = _("General");
-			message_type_image =  "<rt image=pics/message_new.png></rt>";
+			return "pics/message_new.png";
 	}
-
-	m_display_message_type_label->set_tooltip(
-				 /** TRANSLATORS: %s is a message's type */
-				 (boost::format(_("Type of this message: %s"))
-				  /** TRANSLATORS: Tooltip in the messages window */
-				  % message_type_tooltip).str());
-	m_display_message_type_label->set_text(message_type_image);
-}
-
-
-/**
- * Clear the current selection of messages.
- */
-void GameMessageMenu::do_clear_selection()
-{
-	for (size_t i = 0; i < list->size(); ++i)
-		list->get_record(i).set_checked
-			(ColSelect, false);
-}
-
-void GameMessageMenu::do_invert_selection()
-{
-	for (size_t i = 0; i < list->size(); ++i)
-		list->get_record(i).toggle(ColSelect);
-}
+}
+
 
 void GameMessageMenu::toggle_mode()
 {
@@ -609,7 +607,7 @@
 		/** TRANSLATORS: %s is a tooltip, Del is the corresponding hotkey */
 		m_archivebtn->set_tooltip((boost::format(_("Del: %s"))
 											/** TRANSLATORS: Tooltip in the messages window */
-											% _("Restore selected messages")).str());
+											% _("Restore selected message")).str());
 		m_togglemodebtn->set_pic(g_gr->images().get("pics/message_new.png"));
 		m_togglemodebtn->set_tooltip(_("Show Inbox"));
 		break;
@@ -620,7 +618,7 @@
 		/** TRANSLATORS: %s is a tooltip, Del is the corresponding hotkey */
 		m_archivebtn->set_tooltip((boost::format(_("Del: %s"))
 											/** TRANSLATORS: Tooltip in the messages window */
-											% _("Archive selected messages")).str());
+											% _("Archive selected message")).str());
 		m_togglemodebtn->set_pic(g_gr->images().get("pics/message_archived.png"));
 		m_togglemodebtn->set_tooltip(_("Show Archive"));
 		break;

=== modified file 'src/wui/game_message_menu.h'
--- src/wui/game_message_menu.h	2014-12-08 11:08:38 +0000
+++ src/wui/game_message_menu.h	2015-09-24 16:48:57 +0000
@@ -48,23 +48,24 @@
 	bool handle_key(bool down, SDL_Keysym code) override;
 
 private:
-	enum Cols {ColSelect, ColStatus, ColTitle, ColTimeSent};
+	enum Cols {ColTitle, ColType, ColStatus, ColTimeSent};
 	enum class ReadUnread: uint8_t {allMessages, readMessages, newMessages};
 
 	InteractivePlayer & iplayer() const;
 	void selected(uint32_t);
 	void double_clicked(uint32_t);
 
-	bool status_compare(uint32_t a, uint32_t b);
-	void do_clear_selection();
-	void do_invert_selection();
+	bool compare_title(uint32_t a, uint32_t b);
+	bool compare_status(uint32_t a, uint32_t b);
+	bool compare_type(uint32_t a, uint32_t b);
+	bool compare_time_sent(uint32_t a, uint32_t b);
 	void archive_or_restore();
 	void toggle_mode();
 	void center_view();
 	void filter_messages(Widelands::Message::Type);
 	void toggle_filter_messages_button(UI::Button &, Widelands::Message::Type);
 	void set_filter_messages_tooltips();
-	void set_display_message_type_label(Widelands::Message::Type);
+	std::string display_message_type_icon(Widelands::Message);
 	void update_record(UI::Table<uintptr_t>::EntryRecord & er, const Widelands::Message &);
 
 	UI::Table<uintptr_t> * list;
@@ -80,7 +81,6 @@
 	UI::Button * m_warfarebtn;
 	UI::Button * m_scenariobtn;
 	Widelands::Message::Type m_message_filter;
-	UI::MultilineTextarea * m_display_message_type_label;
 };
 
 #endif  // end of include guard: WL_WUI_GAME_MESSAGE_MENU_H

=== modified file 'src/wui/interactive_base.cc'
--- src/wui/interactive_base.cc	2015-02-09 05:57:08 +0000
+++ src/wui/interactive_base.cc	2015-09-24 16:48:57 +0000
@@ -357,7 +357,7 @@
 	if (get_display_flag(dfDebug) || !is_game) {
 		std::string node_text;
 		if (is_game) {
-			const std::string gametime(gametimestring(egbase().get_gametime()));
+			const std::string gametime(gametimestring(egbase().get_gametime(), true));
 			const std::string gametime_text = as_uifont(gametime, UI_FONT_SIZE_SMALL);
 			dst.blit(Point(5, 5), UI::g_fh1->render(gametime_text), BlendMode::UseAlpha, UI::Align_TopLeft);
 

=== modified file 'test/maps/expedition.wmf/scripting/init.lua'
--- test/maps/expedition.wmf/scripting/init.lua	2015-07-31 20:57:45 +0000
+++ test/maps/expedition.wmf/scripting/init.lua	2015-09-24 16:48:57 +0000
@@ -111,7 +111,7 @@
 	--else
 		--assert(false)
 		--end
-		
+
    --click_on_ship(ship_to_click)
    --if click_button("cancel_expedition") then
 		--sleep(100)
@@ -127,9 +127,9 @@
 		--assert_true(click_button("ok"))
 		--sleep(100)
 		--close_windows()
-		--sleep(100) 
+		--sleep(100)
 		--print (" DEBUG ship sunk")
-   --end   
+   --end
 --end
 
 
@@ -196,13 +196,13 @@
 
    -- Start a new expedition.
    port:start_expedition()
-   wait_for_message("Expedition Ready")
-   
+   wait_for_message("Expedition")
+
    --if current test requires second ship...
    if needs_second_ship then
       create_second_ship()
    end
-   
+
    game.desired_speed = 10 * 1000
    sleep(10000)
 
@@ -233,7 +233,7 @@
 
    -- Start a new expedition.
    port:start_expedition()
-   wait_for_message("Expedition Ready")
+   wait_for_message("Expedition")
    game.desired_speed = 10 * 1000
    sleep(10000)
 
@@ -272,14 +272,14 @@
 
    -- Send expedition to port space.
    port:start_expedition()
-   wait_for_message("Expedition Ready")
+   wait_for_message("Expedition")
    assert_equal(1, p1:get_workers("builder"))
    sleep(500)
 
    first_ship.island_explore_direction="ccw"
    sleep(2000)
    assert_equal("ccw",first_ship.island_explore_direction)
-   wait_for_message("Port Space Found")
+   wait_for_message("Port Space")
    sleep(500)
    assert_equal(1, p1:get_workers("builder"))
 
@@ -310,20 +310,20 @@
 
 
    port:start_expedition()
-   wait_for_message("Expedition Ready")
-   
+   wait_for_message("Expedition")
+
    if first_ship.state=="exp_waiting" then
       expedition_ship=first_ship
    elseif second_ship.state=="exp_waiting" then
       expedition_ship=second_ship
    else
       assert(false)
-   end   
-   
+   end
+
    expedition_ship.island_explore_direction="ccw"
    sleep(2000)
    assert_equal("ccw",expedition_ship.island_explore_direction)
-   wait_for_message("Port Space Found")
+   wait_for_message("Port Space")
    expedition_ship:build_colonization_port()
    sleep(500)
    assert_equal(1, p1:get_workers("builder"))

=== modified file 'test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua'
--- test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua	2015-07-31 20:29:35 +0000
+++ test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua	2015-09-24 16:48:57 +0000
@@ -7,7 +7,7 @@
 
    -- Send expedition to port space.
    port:start_expedition()
-   wait_for_message("Expedition Ready")
+   wait_for_message("Expedition")
    assert_equal(1, p1:get_workers("builder"))
    sleep(500)
 
@@ -23,7 +23,7 @@
    expedition_ship.island_explore_direction="ccw"
    sleep(2000)
    assert_equal("ccw",expedition_ship.island_explore_direction)
-   wait_for_message("Port Space Found")
+   wait_for_message("Port Space")
    sleep(500)
    assert_equal(1, p1:get_workers("builder"))
 

=== modified file 'test/maps/expedition.wmf/scripting/test_ship_movement_controls.lua'
--- test/maps/expedition.wmf/scripting/test_ship_movement_controls.lua	2015-04-07 13:33:16 +0000
+++ test/maps/expedition.wmf/scripting/test_ship_movement_controls.lua	2015-09-24 16:48:57 +0000
@@ -90,7 +90,7 @@
 	assert_equal("cw", ships[1].island_explore_direction)
 
 	-- wait till it finds a port
-	wait_for_message("Port Space Found")
+	wait_for_message("Port Space")
 	sleep(500)
 	assert_equal("exp_found_port_space", ships[1].state)
 

=== modified file 'test/maps/lua_testsuite.wmf/scripting/messages.lua'
--- test/maps/lua_testsuite.wmf/scripting/messages.lua	2014-09-11 11:18:41 +0000
+++ test/maps/lua_testsuite.wmf/scripting/messages.lua	2015-09-24 16:48:57 +0000
@@ -31,6 +31,15 @@
       player1:send_message("Hallo", "World!", {status="nono"})
    end)
 end
+function messages_tests:test_heading()
+   local m = player1:send_message("Hallo", "World!", {heading="long heading"})
+   assert_equal("long heading", m.heading)
+end
+function messages_tests:test_icon_name()
+   local ware_description = game:get_ware_description("barbarians", "log")
+   local m = player1:send_message("Hallo", "World!", {icon=ware_description.icon_name})
+   assert_equal(ware_description.icon_name, m.icon_name)
+end
 function messages_tests:test_field()
    local f = map:get_field(23,28)
    local m = player1:send_message("Hallo", "World!", {field = f})

=== modified file 'test/maps/lua_testsuite.wmf/scripting/ui.lua'
--- test/maps/lua_testsuite.wmf/scripting/ui.lua	2014-01-12 19:06:22 +0000
+++ test/maps/lua_testsuite.wmf/scripting/ui.lua	2015-09-24 16:48:57 +0000
@@ -64,7 +64,7 @@
 function ui_tests:test_descendant_position()
    self.mv.buttons.messages:click()
    local w = self.mv.windows.messages
-   local b = w.buttons.invert_selection
+   local b = w.buttons.toggle_between_inbox_or_archive
 
    w.position_x = 50
    w.position_y = 50

=== modified file 'tribes/atlanteans/blackroot_farm/conf'
--- tribes/atlanteans/blackroot_farm/conf	2015-07-31 07:26:49 +0000
+++ tribes/atlanteans/blackroot_farm/conf	2015-09-24 16:48:57 +0000
@@ -40,7 +40,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Fields
+# Translators: Short for "Out of ..." for a resource
+title=_No Fields
+heading=_Out of Fields
 message=_The blackroot farmer working at this blackroot farm has no cleared soil to plant his seeds.
 productivity_threshold=30
 

=== modified file 'tribes/atlanteans/coalmine/conf'
--- tribes/atlanteans/coalmine/conf	2014-08-02 19:55:23 +0000
+++ tribes/atlanteans/coalmine/conf	2015-09-24 16:48:57 +0000
@@ -41,7 +41,9 @@
 produce=coal:3
 
 [out_of_resource_notification]
-title=_Main Coal Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Coal
+heading=_Main Coal Vein Exhausted
 message=_This coal mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider dismantling or destroying it.
 
 [idle]

=== added file 'tribes/atlanteans/constructionsite/menu.png'
Binary files tribes/atlanteans/constructionsite/menu.png	1970-01-01 00:00:00 +0000 and tribes/atlanteans/constructionsite/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/atlanteans/crystalmine/conf'
--- tribes/atlanteans/crystalmine/conf	2014-08-02 19:55:23 +0000
+++ tribes/atlanteans/crystalmine/conf	2015-09-24 16:48:57 +0000
@@ -86,7 +86,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Main Crystal Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Crystal
+heading=_Main Crystal Vein Exhausted
 message=_This crystal mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider dismantling or destroying it.
 
 [idle]

=== added file 'tribes/atlanteans/destroyed_building/menu.png'
Binary files tribes/atlanteans/destroyed_building/menu.png	1970-01-01 00:00:00 +0000 and tribes/atlanteans/destroyed_building/menu.png	2015-09-24 16:48:57 +0000 differ
=== added file 'tribes/atlanteans/dismantlesite/menu.png'
Binary files tribes/atlanteans/dismantlesite/menu.png	1970-01-01 00:00:00 +0000 and tribes/atlanteans/dismantlesite/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/atlanteans/farm/conf'
--- tribes/atlanteans/farm/conf	2015-06-10 07:00:10 +0000
+++ tribes/atlanteans/farm/conf	2015-09-24 16:48:57 +0000
@@ -44,7 +44,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Fields
+# Translators: Short for "Out of ..." for a resource
+title=_No Fields
+heading=_Out of Fields
 message=_The farmer working at this farm has no cleared soil to plant his seeds.
 productivity_threshold=30
 

=== modified file 'tribes/atlanteans/fishers_house/conf'
--- tribes/atlanteans/fishers_house/conf	2015-07-26 10:59:28 +0000
+++ tribes/atlanteans/fishers_house/conf	2015-09-24 16:48:57 +0000
@@ -24,7 +24,9 @@
 worker=fish
 
 [out_of_resource_notification]
-title=_Out of Fish
+# Translators: Short for "Out of ..." for a resource
+title=_No Fish
+heading=_Out of Fish
 message=_The fisher working out of this fisher’s house can’t find any fish in his work area. Remember that you can increase the number of existing fish by building a fish breeder’s house.
 
 [idle]

=== modified file 'tribes/atlanteans/goldmine/conf'
--- tribes/atlanteans/goldmine/conf	2014-08-02 19:55:23 +0000
+++ tribes/atlanteans/goldmine/conf	2015-09-24 16:48:57 +0000
@@ -41,7 +41,9 @@
 produce=goldore
 
 [out_of_resource_notification]
-title=_Main Gold Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Gold
+heading=_Main Gold Vein Exhausted
 message=_This gold mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider dismantling or destroying it.
 
 [idle]

=== added file 'tribes/atlanteans/headquarters/menu.png'
Binary files tribes/atlanteans/headquarters/menu.png	1970-01-01 00:00:00 +0000 and tribes/atlanteans/headquarters/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/atlanteans/hunters_house/conf'
--- tribes/atlanteans/hunters_house/conf	2015-07-26 10:59:28 +0000
+++ tribes/atlanteans/hunters_house/conf	2015-09-24 16:48:57 +0000
@@ -24,8 +24,10 @@
 worker=hunt
 
 [out_of_resource_notification]
+# Translators: Short for "Out of Game" for a resource
+title=_No Game
 # TRANSLATORS: "Game" means animals that you can hunt
-title=_Out of Game
+heading=_Out of Game
 message=_The hunter working out of this hunter’s house can’t find any game in his work area.
 productivity_threshold=0
 

=== modified file 'tribes/atlanteans/ironmine/conf'
--- tribes/atlanteans/ironmine/conf	2014-08-02 19:55:23 +0000
+++ tribes/atlanteans/ironmine/conf	2015-09-24 16:48:57 +0000
@@ -41,7 +41,9 @@
 produce=ironore:2
 
 [out_of_resource_notification]
-title=_Main Iron Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Iron
+heading=_Main Iron Vein Exhausted
 message=_This iron mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/atlanteans/quarry/conf'
--- tribes/atlanteans/quarry/conf	2015-07-26 10:59:28 +0000
+++ tribes/atlanteans/quarry/conf	2015-09-24 16:48:57 +0000
@@ -30,7 +30,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Rocks
+# Translators: Short for "Out of ..." for a resource
+title=_No Rocks
+heading=_Out of Rocks
 message=_The stonecutter working at this quarry can’t find any rocks in his work area.
 
 [idle]

=== modified file 'tribes/atlanteans/scripting/sc01_fortified_village.lua'
--- tribes/atlanteans/scripting/sc01_fortified_village.lua	2014-08-26 17:25:00 +0000
+++ tribes/atlanteans/scripting/sc01_fortified_village.lua	2015-09-24 16:48:57 +0000
@@ -98,10 +98,11 @@
          wares = { log = 1 }
       })
    end) then
-      plr:send_message(_"Not enough space", _(
-[[Some of your starting buildings didn’t have enough room and ]] ..
-[[weren’t built. You are at a disadvantage with this; consider restarting ]] ..
-[[this map with a fair starting condition.]]), {popup=true}
+      plr:send_message(
+			-- TRANSLATORS: Short for "Not enough space"
+			_"Space",
+			rt(p(_([[Some of your starting buildings didn’t have enough room and weren’t built. You are at a disadvantage with this; consider restarting this map with a fair starting condition.]]))),
+			{popup=true, heading=_"Not enough space"}
       )
    end
 

=== modified file 'tribes/atlanteans/well/conf'
--- tribes/atlanteans/well/conf	2015-07-26 10:59:28 +0000
+++ tribes/atlanteans/well/conf	2015-09-24 16:48:57 +0000
@@ -29,7 +29,9 @@
 produce=water
 
 [out_of_resource_notification]
-title=_Out of Water
+# Translators: Short for "Out of ..." for a resource
+title=_No Water
+heading=_Out of Water
 message=_The carrier working at this well can’t find any water in his work area.
 productivity_threshold=33
 

=== modified file 'tribes/atlanteans/woodcutters_house/conf'
--- tribes/atlanteans/woodcutters_house/conf	2015-07-26 10:59:28 +0000
+++ tribes/atlanteans/woodcutters_house/conf	2015-09-24 16:48:57 +0000
@@ -25,7 +25,9 @@
 worker=harvest
 
 [out_of_resource_notification]
-title=_Out of Trees
+# Translators: Short for "Out of ..." for a resource
+title=_No Trees
+heading=_Out of Trees
 message=_The woodcutter working at this woodcutter’s house can’t find any trees in his work area. You should consider dismantling or destroying the building or building a forester’s house.
 productivity_threshold=66
 

=== modified file 'tribes/barbarians/coalmine/conf'
--- tribes/barbarians/coalmine/conf	2014-08-02 19:55:23 +0000
+++ tribes/barbarians/coalmine/conf	2015-09-24 16:48:57 +0000
@@ -34,7 +34,9 @@
 produce=coal:2
 
 [out_of_resource_notification]
-title=_Main Coal Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Coal
+heading=_Main Coal Vein Exhausted
 message=_This coal mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== added file 'tribes/barbarians/constructionsite/menu.png'
Binary files tribes/barbarians/constructionsite/menu.png	1970-01-01 00:00:00 +0000 and tribes/barbarians/constructionsite/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/barbarians/deep_coalmine/conf'
--- tribes/barbarians/deep_coalmine/conf	2014-07-29 09:27:08 +0000
+++ tribes/barbarians/deep_coalmine/conf	2015-09-24 16:48:57 +0000
@@ -39,7 +39,9 @@
 produce=coal:2
 
 [out_of_resource_notification]
-title=_Main Coal Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Coal
+heading=_Main Coal Vein Exhausted
 message=_This coal mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/barbarians/deep_goldmine/conf'
--- tribes/barbarians/deep_goldmine/conf	2014-07-29 09:27:08 +0000
+++ tribes/barbarians/deep_goldmine/conf	2015-09-24 16:48:57 +0000
@@ -39,7 +39,9 @@
 produce=goldore:2
 
 [out_of_resource_notification]
-title=_Main Gold Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Gold
+heading=_Main Gold Vein Exhausted
 message=_This gold mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/barbarians/deep_oremine/conf'
--- tribes/barbarians/deep_oremine/conf	2014-07-29 09:27:08 +0000
+++ tribes/barbarians/deep_oremine/conf	2015-09-24 16:48:57 +0000
@@ -40,7 +40,9 @@
 produce=ironore:1
 
 [out_of_resource_notification]
-title=_Main Iron Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Iron
+heading=_Main Iron Vein Exhausted
 message=_This iron mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/barbarians/deeper_coalmine/conf'
--- tribes/barbarians/deeper_coalmine/conf	2014-07-29 09:27:08 +0000
+++ tribes/barbarians/deeper_coalmine/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 produce=coal:3
 
 [out_of_resource_notification]
-title=_Main Coal Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Coal
+heading=_Main Coal Vein Exhausted
 message=_This coal mine’s main vein is exhausted. Expect strongly diminished returns on investment. This mine can’t be enhanced any further, so you should consider dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/barbarians/deeper_goldmine/conf'
--- tribes/barbarians/deeper_goldmine/conf	2014-07-29 09:27:08 +0000
+++ tribes/barbarians/deeper_goldmine/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 produce=goldore:2
 
 [out_of_resource_notification]
-title=_Main Gold Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Gold
+heading=_Main Gold Vein Exhausted
 message=_This gold mine’s main vein is exhausted. Expect strongly diminished returns on investment. This mine can’t be enhanced any further, so you should consider dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/barbarians/deeper_oremine/conf'
--- tribes/barbarians/deeper_oremine/conf	2014-07-29 09:27:08 +0000
+++ tribes/barbarians/deeper_oremine/conf	2015-09-24 16:48:57 +0000
@@ -41,7 +41,9 @@
 produce=ironore:2
 
 [out_of_resource_notification]
-title=_Main Iron Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Iron
+heading=_Main Iron Vein Exhausted
 message=_This iron mine’s main vein is exhausted. Expect strongly diminished returns on investment. This mine can’t be enhanced any further, so you should consider dismantling or destroying it.
 
 [idle]

=== added file 'tribes/barbarians/destroyed_building/menu.png'
Binary files tribes/barbarians/destroyed_building/menu.png	1970-01-01 00:00:00 +0000 and tribes/barbarians/destroyed_building/menu.png	2015-09-24 16:48:57 +0000 differ
=== added file 'tribes/barbarians/dismantlesite/menu.png'
Binary files tribes/barbarians/dismantlesite/menu.png	1970-01-01 00:00:00 +0000 and tribes/barbarians/dismantlesite/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/barbarians/farm/conf'
--- tribes/barbarians/farm/conf	2015-06-28 17:41:39 +0000
+++ tribes/barbarians/farm/conf	2015-09-24 16:48:57 +0000
@@ -43,7 +43,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Fields
+# Translators: Short for "Out of ..." for a resource
+title=_No Fields
+heading=_Out of Fields
 message=_The farmer working at this farm has no cleared soil to plant his seeds.
 productivity_threshold=30
 

=== modified file 'tribes/barbarians/fishers_hut/conf'
--- tribes/barbarians/fishers_hut/conf	2015-07-26 10:59:28 +0000
+++ tribes/barbarians/fishers_hut/conf	2015-09-24 16:48:57 +0000
@@ -23,7 +23,9 @@
 worker=fish
 
 [out_of_resource_notification]
-title=_Out of Fish
+# Translators: Short for "Out of ..." for a resource
+title=_No Fish
+heading=_Out of Fish
 message=_The fisher working out of this fisher’s hut can’t find any fish in his work area.
 
 [build]

=== modified file 'tribes/barbarians/goldmine/conf'
--- tribes/barbarians/goldmine/conf	2014-08-02 19:55:23 +0000
+++ tribes/barbarians/goldmine/conf	2015-09-24 16:48:57 +0000
@@ -34,7 +34,9 @@
 produce=goldore
 
 [out_of_resource_notification]
-title=_Main Gold Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Gold
+heading=_Main Gold Vein Exhausted
 message=_This gold mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/barbarians/granitemine/conf'
--- tribes/barbarians/granitemine/conf	2014-08-02 19:55:23 +0000
+++ tribes/barbarians/granitemine/conf	2015-09-24 16:48:57 +0000
@@ -32,7 +32,9 @@
 produce=raw_stone:2
 
 [out_of_resource_notification]
-title=_Main Granite Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Granite
+heading=_Main Granite Vein Exhausted
 message=_This granite mine’s main vein is exhausted. Expect strongly diminished returns on investment. This mine can’t be enhanced any further, so you should consider dismantling or destroying it.
 
 [idle]

=== added file 'tribes/barbarians/headquarters/menu.png'
Binary files tribes/barbarians/headquarters/menu.png	1970-01-01 00:00:00 +0000 and tribes/barbarians/headquarters/menu.png	2015-09-24 16:48:57 +0000 differ
=== added file 'tribes/barbarians/headquarters_interim/menu.png'
Binary files tribes/barbarians/headquarters_interim/menu.png	1970-01-01 00:00:00 +0000 and tribes/barbarians/headquarters_interim/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/barbarians/hunters_hut/conf'
--- tribes/barbarians/hunters_hut/conf	2015-07-26 10:59:28 +0000
+++ tribes/barbarians/hunters_hut/conf	2015-09-24 16:48:57 +0000
@@ -24,8 +24,10 @@
 worker=hunt
 
 [out_of_resource_notification]
+# Translators: Short for "Out of Game" for a resource
+title=_No Game
 # TRANSLATORS: "Game" means animals that you can hunt
-title=_Out of Game
+heading=_Out of Game
 message=_The hunter working out of this hunter’s hut can’t find any game in his work area. Remember that you can build a gamekeeper’s hut to release more game into the wild.
 productivity_threshold=33
 

=== modified file 'tribes/barbarians/lumberjacks_hut/conf'
--- tribes/barbarians/lumberjacks_hut/conf	2015-07-26 10:59:28 +0000
+++ tribes/barbarians/lumberjacks_hut/conf	2015-09-24 16:48:57 +0000
@@ -23,7 +23,9 @@
 worker=chop
 
 [out_of_resource_notification]
-title=_Out of Trees
+# Translators: Short for "Out of ..." for a resource
+title=_No Trees
+heading=_Out of Trees
 message=_The lumberjack working at this lumberjack’s hut can’t find any trees in his work area. You should consider dismantling or destroying the building or building a rangers’s hut.
 productivity_threshold=66
 

=== modified file 'tribes/barbarians/oremine/conf'
--- tribes/barbarians/oremine/conf	2014-10-07 20:01:26 +0000
+++ tribes/barbarians/oremine/conf	2015-09-24 16:48:57 +0000
@@ -34,7 +34,9 @@
 produce=ironore
 
 [out_of_resource_notification]
-title=_Main Iron Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Iron
+heading=_Main Iron Vein Exhausted
 message=_This iron mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/barbarians/quarry/conf'
--- tribes/barbarians/quarry/conf	2015-07-26 10:59:28 +0000
+++ tribes/barbarians/quarry/conf	2015-09-24 16:48:57 +0000
@@ -29,7 +29,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Rocks
+# Translators: Short for "Out of ..." for a resource
+title=_No Rocks
+heading=_Out of Rocks
 message=_The stonemason working at this quarry can’t find any rocks in his work area.
 
 [idle]

=== modified file 'tribes/barbarians/reed_yard/conf'
--- tribes/barbarians/reed_yard/conf	2015-06-09 08:45:20 +0000
+++ tribes/barbarians/reed_yard/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Fields
+# Translators: Short for "Out of ..." for a resource
+title=_NO Fields
+heading=_Out of Fields
 message=_The gardener working at this reed yard has no cleared soil to plant his seeds.
 productivity_threshold=20
 

=== modified file 'tribes/barbarians/scripting/sc01_fortified_village.lua'
--- tribes/barbarians/scripting/sc01_fortified_village.lua	2014-08-26 17:25:00 +0000
+++ tribes/barbarians/scripting/sc01_fortified_village.lua	2015-09-24 16:48:57 +0000
@@ -91,10 +91,11 @@
          wares = { raw_stone = 6, coal = 3 },
       })
    end) then
-      plr:send_message(_"Not enough space", _(
-[[Some of your starting buildings didn’t have enough room and ]] ..
-[[weren’t built. You are at a disadvantage with this; consider restarting ]] ..
-[[this map with a fair starting condition.]]), {popup=true}
+      plr:send_message(
+			-- TRANSLATORS: Short for "Not enough space"
+			_"Space",
+			rt(p(_([[Some of your starting buildings didn’t have enough room and weren’t built. You are at a disadvantage with this; consider restarting this map with a fair starting condition.]]))),
+			{popup=true, heading=_"Not enough space"}
       )
    end
 end,

=== modified file 'tribes/barbarians/well/conf'
--- tribes/barbarians/well/conf	2015-07-26 10:59:28 +0000
+++ tribes/barbarians/well/conf	2015-09-24 16:48:57 +0000
@@ -25,7 +25,9 @@
 produce=water
 
 [out_of_resource_notification]
-title=_Out of Water
+# Translators: Short for "Out of ..." for a resource
+title=_No Water
+heading=_Out of Water
 message=_The carrier working at this well can’t find any water in his work area.
 productivity_threshold=33
 

=== modified file 'tribes/empire/coalmine/conf'
--- tribes/empire/coalmine/conf	2014-08-02 19:55:23 +0000
+++ tribes/empire/coalmine/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 produce=coal
 
 [out_of_resource_notification]
-title=_Main Coal Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Coal
+heading=_Main Coal Vein Exhausted
 message=_This coal mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== added file 'tribes/empire/constructionsite/menu.png'
Binary files tribes/empire/constructionsite/menu.png	1970-01-01 00:00:00 +0000 and tribes/empire/constructionsite/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/empire/deep_coalmine/conf'
--- tribes/empire/deep_coalmine/conf	2014-07-29 09:27:08 +0000
+++ tribes/empire/deep_coalmine/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 produce=coal:3
 
 [out_of_resource_notification]
-title=_Main Coal Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Coal
+heading=_Main Coal Vein Exhausted
 message=_This coal mine’s main vein is exhausted. Expect strongly diminished returns on investment. This mine can’t be enhanced any further, so you should consider dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/empire/deep_goldmine/conf'
--- tribes/empire/deep_goldmine/conf	2014-07-29 09:27:08 +0000
+++ tribes/empire/deep_goldmine/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 produce=goldore:2
 
 [out_of_resource_notification]
-title=_Main Gold Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Gold
+heading=_Main Gold Vein Exhausted
 message=_This gold mine’s main vein is exhausted. Expect strongly diminished returns on investment. This mine can’t be enhanced any further, so you should consider dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/empire/deep_marblemine/conf'
--- tribes/empire/deep_marblemine/conf	2014-07-29 09:27:08 +0000
+++ tribes/empire/deep_marblemine/conf	2015-09-24 16:48:57 +0000
@@ -39,7 +39,9 @@
 produce=marble stone:2
 
 [out_of_resource_notification]
-title=_Main Marble Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Marble
+heading=_Main Marble Vein Exhausted
 message=_This marble mine’s main vein is exhausted. Expect strongly diminished returns on investment. This mine can’t be enhanced any further, so you should consider dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/empire/deep_oremine/conf'
--- tribes/empire/deep_oremine/conf	2014-07-29 09:27:08 +0000
+++ tribes/empire/deep_oremine/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 produce=ironore:2
 
 [out_of_resource_notification]
-title=_Main Iron Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Iron
+heading=_Main Iron Vein Exhausted
 message=_This iron mine’s main vein is exhausted. Expect strongly diminished returns on investment. This mine can’t be enhanced any further, so you should consider dismantling or destroying it.
 
 [idle]

=== added file 'tribes/empire/destroyed_building/menu.png'
Binary files tribes/empire/destroyed_building/menu.png	1970-01-01 00:00:00 +0000 and tribes/empire/destroyed_building/menu.png	2015-09-24 16:48:57 +0000 differ
=== added file 'tribes/empire/dismantlesite/menu.png'
Binary files tribes/empire/dismantlesite/menu.png	1970-01-01 00:00:00 +0000 and tribes/empire/dismantlesite/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/empire/farm/conf'
--- tribes/empire/farm/conf	2015-06-10 07:00:10 +0000
+++ tribes/empire/farm/conf	2015-09-24 16:48:57 +0000
@@ -43,7 +43,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Fields
+# Translators: Short for "Out of ..." for a resource
+title=_No Fields
+heading=_Out of Fields
 message=_The farmer working at this farm has no cleared soil to plant his seeds.
 productivity_threshold=30
 

=== modified file 'tribes/empire/fishers_house/conf'
--- tribes/empire/fishers_house/conf	2015-07-26 10:59:28 +0000
+++ tribes/empire/fishers_house/conf	2015-09-24 16:48:57 +0000
@@ -25,7 +25,9 @@
 worker=fish
 
 [out_of_resource_notification]
-title=_Out of Fish
+# Translators: Short for "Out of ..." for a resource
+title=_No Fish
+heading=_Out of Fish
 message=_The fisher working in this fisher’s house can’t find any fish in his work area.
 
 [idle]

=== modified file 'tribes/empire/goldmine/conf'
--- tribes/empire/goldmine/conf	2014-08-02 19:55:23 +0000
+++ tribes/empire/goldmine/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 produce=goldore
 
 [out_of_resource_notification]
-title=_Main Gold Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Gold
+heading=_Main Gold Vein Exhausted
 message=_This gold mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== added file 'tribes/empire/headquarters/menu.png'
Binary files tribes/empire/headquarters/menu.png	1970-01-01 00:00:00 +0000 and tribes/empire/headquarters/menu.png	2015-09-24 16:48:57 +0000 differ
=== added file 'tribes/empire/headquarters_shipwreck/menu.png'
Binary files tribes/empire/headquarters_shipwreck/menu.png	1970-01-01 00:00:00 +0000 and tribes/empire/headquarters_shipwreck/menu.png	2015-09-24 16:48:57 +0000 differ
=== modified file 'tribes/empire/hunters_house/conf'
--- tribes/empire/hunters_house/conf	2015-07-26 10:59:28 +0000
+++ tribes/empire/hunters_house/conf	2015-09-24 16:48:57 +0000
@@ -23,8 +23,10 @@
 worker=hunt
 
 [out_of_resource_notification]
+# Translators: Short for "Out of Game" for a resource
+title=_No Game
 # TRANSLATORS: "Game" means animals that you can hunt
-title=_Out of Game
+heading=_Out of Game
 message=_The hunter working out of this hunter’s house can’t find any game in his work area.
 productivity_threshold=0
 

=== modified file 'tribes/empire/lumberjacks_house/conf'
--- tribes/empire/lumberjacks_house/conf	2015-07-26 10:59:28 +0000
+++ tribes/empire/lumberjacks_house/conf	2015-09-24 16:48:57 +0000
@@ -25,7 +25,9 @@
 worker=chop
 
 [out_of_resource_notification]
-title=_Out of Trees
+# Translators: Short for "Out of ..." for a resource
+title=_No Trees
+heading=_Out of Trees
 message=_The lumberjack working at this lumberjack’s house can’t find any trees in his work area. You should consider dismantling or destroying the building or building a forester’s house.
 productivity_threshold=66
 

=== modified file 'tribes/empire/marblemine/conf'
--- tribes/empire/marblemine/conf	2014-08-02 19:55:23 +0000
+++ tribes/empire/marblemine/conf	2015-09-24 16:48:57 +0000
@@ -54,7 +54,9 @@
 produce=stone:2
 
 [out_of_resource_notification]
-title=_Main Marble Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Marble
+heading=_Main Marble Vein Exhausted
 message=_This marble mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [work]

=== modified file 'tribes/empire/oremine/conf'
--- tribes/empire/oremine/conf	2014-10-07 20:01:26 +0000
+++ tribes/empire/oremine/conf	2015-09-24 16:48:57 +0000
@@ -38,7 +38,9 @@
 produce=ironore:2
 
 [out_of_resource_notification]
-title=_Main Iron Vein Exhausted
+# Translators: Short for "Out of ..." for a resource
+title=_No Iron
+heading=_Main Iron Vein Exhausted
 message=_This iron mine’s main vein is exhausted. Expect strongly diminished returns on investment. You should consider enhancing, dismantling or destroying it.
 
 [idle]

=== modified file 'tribes/empire/quarry/conf'
--- tribes/empire/quarry/conf	2015-07-26 10:59:28 +0000
+++ tribes/empire/quarry/conf	2015-09-24 16:48:57 +0000
@@ -43,7 +43,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Rocks
+# Translators: Short for "Out of ..." for a resource
+title=_No Rocks
+heading=_Out of Rocks
 message=_The stonemason working at this quarry can’t find any rocks in his work area.
 
 [idle]

=== modified file 'tribes/empire/scripting/sc01_fortified_village.lua'
--- tribes/empire/scripting/sc01_fortified_village.lua	2014-08-26 17:25:00 +0000
+++ tribes/empire/scripting/sc01_fortified_village.lua	2015-09-24 16:48:57 +0000
@@ -116,10 +116,11 @@
 
       place_building_in_region(plr, "stonemasons_house", sf:region(11))
    end) then
-      plr:send_message(_"Not enough space", _(
-[[Some of your starting buildings didn’t have enough room and ]] ..
-[[weren’t built. You are at a disadvantage with this; consider restarting ]] ..
-[[this map with a fair starting condition.]]), {popup=true}
+      plr:send_message(
+			-- TRANSLATORS: Short for "Not enough space"
+			_"Space",
+			rt(p(_([[Some of your starting buildings didn’t have enough room and weren’t built. You are at a disadvantage with this; consider restarting this map with a fair starting condition.]]))),
+			{popup=true, heading=_"Not enough space"}
       )
    end
 end

=== modified file 'tribes/empire/vineyard/conf'
--- tribes/empire/vineyard/conf	2015-07-31 07:26:49 +0000
+++ tribes/empire/vineyard/conf	2015-09-24 16:48:57 +0000
@@ -40,7 +40,9 @@
 return=skipped
 
 [out_of_resource_notification]
-title=_Out of Fields
+# Translators: Short for "Out of ..." for a resource
+title=_No Fields
+heading=_Out of Fields
 message=_The vine farmer working at this vineyard has no cleared soil to plant his grapevines.
 productivity_threshold=30
 

=== modified file 'tribes/empire/well/conf'
--- tribes/empire/well/conf	2015-07-26 10:59:28 +0000
+++ tribes/empire/well/conf	2015-09-24 16:48:57 +0000
@@ -28,7 +28,9 @@
 produce=water
 
 [out_of_resource_notification]
-title=_Out of Water
+# Translators: Short for "Out of ..." for a resource
+title=_No Water
+heading=_Out of Water
 message=_The carrier working at this well can’t find any water in his work area.
 productivity_threshold=33
 


Follow ups