← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/oars_appdata into lp:widelands/build19

 

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

Commit message:
Added age rating to Appdata.

https://odrs.gnome.org/oars

Requested reviews:
  Widelands Developers (widelands-dev)

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

Since this doesn't affect and runnable code, I'm in favor of merging this into Build 19.
-- 
The attached diff has been truncated due to its size.
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/oars_appdata into lp:widelands/build19.
=== removed file 'data/images/logos/wl-logo-64.png'
Binary files data/images/logos/wl-logo-64.png	2016-09-22 08:25:05 +0000 and data/images/logos/wl-logo-64.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/editor_player_01_starting_pos.png'
Binary files data/images/players/editor_player_01_starting_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/editor_player_01_starting_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/editor_player_02_starting_pos.png'
Binary files data/images/players/editor_player_02_starting_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/editor_player_02_starting_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/editor_player_03_starting_pos.png'
Binary files data/images/players/editor_player_03_starting_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/editor_player_03_starting_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/editor_player_04_starting_pos.png'
Binary files data/images/players/editor_player_04_starting_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/editor_player_04_starting_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/editor_player_05_starting_pos.png'
Binary files data/images/players/editor_player_05_starting_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/editor_player_05_starting_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/editor_player_06_starting_pos.png'
Binary files data/images/players/editor_player_06_starting_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/editor_player_06_starting_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/editor_player_07_starting_pos.png'
Binary files data/images/players/editor_player_07_starting_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/editor_player_07_starting_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/fsel_editor_set_player_01_pos.png'
Binary files data/images/players/fsel_editor_set_player_01_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/fsel_editor_set_player_01_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/fsel_editor_set_player_02_pos.png'
Binary files data/images/players/fsel_editor_set_player_02_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/fsel_editor_set_player_02_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/fsel_editor_set_player_03_pos.png'
Binary files data/images/players/fsel_editor_set_player_03_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/fsel_editor_set_player_03_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/fsel_editor_set_player_04_pos.png'
Binary files data/images/players/fsel_editor_set_player_04_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/fsel_editor_set_player_04_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/fsel_editor_set_player_05_pos.png'
Binary files data/images/players/fsel_editor_set_player_05_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/fsel_editor_set_player_05_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/fsel_editor_set_player_06_pos.png'
Binary files data/images/players/fsel_editor_set_player_06_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/fsel_editor_set_player_06_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/fsel_editor_set_player_07_pos.png'
Binary files data/images/players/fsel_editor_set_player_07_pos.png	2014-12-02 21:50:09 +0000 and data/images/players/fsel_editor_set_player_07_pos.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/genstats_enable_plr_01.png'
Binary files data/images/players/genstats_enable_plr_01.png	2014-12-02 21:50:09 +0000 and data/images/players/genstats_enable_plr_01.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/genstats_enable_plr_02.png'
Binary files data/images/players/genstats_enable_plr_02.png	2014-12-02 21:50:09 +0000 and data/images/players/genstats_enable_plr_02.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/genstats_enable_plr_03.png'
Binary files data/images/players/genstats_enable_plr_03.png	2014-12-02 21:50:09 +0000 and data/images/players/genstats_enable_plr_03.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/genstats_enable_plr_04.png'
Binary files data/images/players/genstats_enable_plr_04.png	2014-12-02 21:50:09 +0000 and data/images/players/genstats_enable_plr_04.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/genstats_enable_plr_05.png'
Binary files data/images/players/genstats_enable_plr_05.png	2014-12-02 21:50:09 +0000 and data/images/players/genstats_enable_plr_05.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/genstats_enable_plr_06.png'
Binary files data/images/players/genstats_enable_plr_06.png	2014-12-02 21:50:09 +0000 and data/images/players/genstats_enable_plr_06.png	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/images/players/genstats_enable_plr_07.png'
Binary files data/images/players/genstats_enable_plr_07.png	2014-12-02 21:50:09 +0000 and data/images/players/genstats_enable_plr_07.png	1970-01-01 00:00:00 +0000 differ
=== renamed file 'data/images/players/genstats_enable_plr_08.png' => 'data/images/players/genstats_player.png'
=== added file 'data/images/players/genstats_player_pc.png'
Binary files data/images/players/genstats_player_pc.png	1970-01-01 00:00:00 +0000 and data/images/players/genstats_player_pc.png	2016-10-28 17:51:15 +0000 differ
=== renamed file 'data/images/players/editor_player_08_starting_pos.png' => 'data/images/players/player_position.png'
=== renamed file 'data/images/players/fsel_editor_set_player_08_pos.png' => 'data/images/players/player_position_menu.png'
=== added file 'data/images/players/player_position_menu_pc.png'
Binary files data/images/players/player_position_menu_pc.png	1970-01-01 00:00:00 +0000 and data/images/players/player_position_menu_pc.png	2016-10-28 17:51:15 +0000 differ
=== added file 'data/images/players/player_position_pc.png'
Binary files data/images/players/player_position_pc.png	1970-01-01 00:00:00 +0000 and data/images/players/player_position_pc.png	2016-10-28 17:51:15 +0000 differ
=== added file 'data/images/wui/menus/menu_reset_zoom.png'
Binary files data/images/wui/menus/menu_reset_zoom.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/menu_reset_zoom.png	2016-10-28 17:51:15 +0000 differ
=== added directory 'data/sound/barbarians/taverns'
=== added file 'data/sound/barbarians/taverns/biginn_01.ogg'
Binary files data/sound/barbarians/taverns/biginn_01.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/biginn_01.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/barbarians/taverns/biginn_02.ogg'
Binary files data/sound/barbarians/taverns/biginn_02.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/biginn_02.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/barbarians/taverns/biginn_10.ogg'
Binary files data/sound/barbarians/taverns/biginn_10.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/biginn_10.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/barbarians/taverns/inn_01.ogg'
Binary files data/sound/barbarians/taverns/inn_01.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/inn_01.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/barbarians/taverns/inn_02.ogg'
Binary files data/sound/barbarians/taverns/inn_02.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/inn_02.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/barbarians/taverns/inn_10.ogg'
Binary files data/sound/barbarians/taverns/inn_10.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/inn_10.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/barbarians/taverns/tavern_01.ogg'
Binary files data/sound/barbarians/taverns/tavern_01.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/tavern_01.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/barbarians/taverns/tavern_02.ogg'
Binary files data/sound/barbarians/taverns/tavern_02.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/tavern_02.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/barbarians/taverns/tavern_10.ogg'
Binary files data/sound/barbarians/taverns/tavern_10.ogg	1970-01-01 00:00:00 +0000 and data/sound/barbarians/taverns/tavern_10.ogg	2016-10-28 17:51:15 +0000 differ
=== added directory 'data/sound/empire/taverns'
=== added file 'data/sound/empire/taverns/meal_01.ogg'
Binary files data/sound/empire/taverns/meal_01.ogg	1970-01-01 00:00:00 +0000 and data/sound/empire/taverns/meal_01.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/empire/taverns/meal_02.ogg'
Binary files data/sound/empire/taverns/meal_02.ogg	1970-01-01 00:00:00 +0000 and data/sound/empire/taverns/meal_02.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/empire/taverns/meal_10.ogg'
Binary files data/sound/empire/taverns/meal_10.ogg	1970-01-01 00:00:00 +0000 and data/sound/empire/taverns/meal_10.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/empire/taverns/ration_01.ogg'
Binary files data/sound/empire/taverns/ration_01.ogg	1970-01-01 00:00:00 +0000 and data/sound/empire/taverns/ration_01.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/empire/taverns/ration_02.ogg'
Binary files data/sound/empire/taverns/ration_02.ogg	1970-01-01 00:00:00 +0000 and data/sound/empire/taverns/ration_02.ogg	2016-10-28 17:51:15 +0000 differ
=== added file 'data/sound/empire/taverns/ration_10.ogg'
Binary files data/sound/empire/taverns/ration_10.ogg	1970-01-01 00:00:00 +0000 and data/sound/empire/taverns/ration_10.ogg	2016-10-28 17:51:15 +0000 differ
=== removed directory 'data/sound/taverns'
=== removed file 'data/sound/taverns/dishes_01.ogg'
Binary files data/sound/taverns/dishes_01.ogg	2016-07-07 09:58:30 +0000 and data/sound/taverns/dishes_01.ogg	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/sound/taverns/dishes_02.ogg'
Binary files data/sound/taverns/dishes_02.ogg	2016-07-07 09:58:30 +0000 and data/sound/taverns/dishes_02.ogg	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/sound/taverns/dishes_10.ogg'
Binary files data/sound/taverns/dishes_10.ogg	2016-07-07 09:58:30 +0000 and data/sound/taverns/dishes_10.ogg	1970-01-01 00:00:00 +0000 differ
=== modified file 'data/tribes/buildings/productionsites/atlanteans/armorsmithy/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/armorsmithy/init.lua	2016-09-22 16:45:02 +0000
+++ data/tribes/buildings/productionsites/atlanteans/armorsmithy/init.lua	2016-10-28 17:51:15 +0000
@@ -144,8 +144,8 @@
          descname = _"forging an advanced shield",
          actions = {
             "return=skipped unless economy needs shield_advanced",
-            "sleep=32000",
             "consume=iron:2 coal:2 gold",
+            "sleep=32000",
             "animate=working 45000",
             "produce=shield_advanced"
          }

=== modified file 'data/tribes/buildings/productionsites/atlanteans/mill/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/mill/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/atlanteans/mill/init.lua	2016-10-28 17:51:15 +0000
@@ -67,6 +67,7 @@
             "return=skipped unless economy needs cornmeal",
             "sleep=3500",
             "consume=corn",
+            "play_sound=sound/mill mill_turning 240",
             "animate=working 15000",
             "produce=cornmeal"
          }
@@ -79,6 +80,7 @@
             "return=skipped when site has corn and economy needs cornmeal and not economy needs blackroot_flour",
             "sleep=3500",
             "consume=blackroot",
+            "play_sound=sound/mill mill_turning 240",
             "animate=working 15000",
             "produce=blackroot_flour"
          }

=== modified file 'data/tribes/buildings/productionsites/atlanteans/smelting_works/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/smelting_works/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/atlanteans/smelting_works/init.lua	2016-10-28 17:51:15 +0000
@@ -66,9 +66,12 @@
          descname = _"smelting iron",
          actions = {
             "return=skipped unless economy needs iron",
-            "sleep=25000",
+            "sleep=5000",  -- penalty for unavailable iron_ore (2x)
             "consume=iron_ore coal",
+            "sleep=20000",
+            "play_sound=sound/metal fizzle 150",
             "animate=working 35000",
+            "play_sound=sound/metal ironping 80",
             "produce=iron"
          }
       },
@@ -77,9 +80,12 @@
          descname = _"smelting gold",
          actions = {
             "return=skipped unless economy needs gold",
-            "sleep=25000",
+            "sleep=10000",  -- penalty for unavailable gold_ore
             "consume=gold_ore coal",
+            "sleep=15000",
+            "play_sound=sound/metal fizzle 150",
             "animate=working 35000",
+            "play_sound=sound/metal goldping 80",
             "produce=gold"
          }
       },

=== modified file 'data/tribes/buildings/productionsites/atlanteans/smokery/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/smokery/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/atlanteans/smokery/init.lua	2016-10-28 17:51:15 +0000
@@ -67,11 +67,13 @@
          -- TRANSLATORS: Completed/Skipped/Did not start smoking meat because ...
          descname = _"smoking meat",
          actions = {
+            -- time total: 60
             "return=skipped when site has fish and economy needs smoked_fish and not economy needs smoked_meat",
             "return=skipped unless economy needs smoked_meat",
-            "sleep=30000",
+            "sleep=10000",
             "consume=meat:2 log",
             "animate=working 30000",
+            "sleep=20000",
             "produce=smoked_meat:2"
          }
       },
@@ -79,11 +81,13 @@
          -- TRANSLATORS: Completed/Skipped/Did not start smoking fish because ...
          descname = _"smoking fish",
          actions = {
+            -- time total: 60
             "return=skipped when site has meat and economy needs smoked_meat and not economy needs smoked_fish",
             "return=skipped unless economy needs smoked_fish",
-            "sleep=30000",
+            "sleep=10000",
             "consume=fish:2 log",
             "animate=working 30000",
+            "sleep=20000",
             "produce=smoked_fish:2"
          }
       },

=== modified file 'data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua	2016-10-28 17:51:15 +0000
@@ -85,8 +85,10 @@
          descname = _"making a bread paddle",
          actions = {
             "return=skipped unless economy needs bread_paddle",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=bread_paddle"
          }
@@ -96,8 +98,10 @@
          descname = _"making a pair of buckets",
          actions = {
             "return=skipped unless economy needs buckets",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=buckets"
          }
@@ -107,8 +111,10 @@
          descname = _"making fire tongs",
          actions = {
             "return=skipped unless economy needs fire_tongs",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=fire_tongs"
          }
@@ -118,8 +124,10 @@
          descname = _"making a fishing net",
          actions = {
             "return=skipped unless economy needs fishing_net",
-            "sleep=32000",
+            "sleep=5000",
             "consume=spidercloth:2",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=fishing_net"
          }
@@ -129,8 +137,10 @@
          descname = _"making a hammer",
          actions = {
             "return=skipped unless economy needs hammer",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=hammer"
          }
@@ -140,8 +150,10 @@
          descname = _"making a hook pole",
          actions = {
             "return=skipped unless economy needs hook_pole",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=hook_pole"
          }
@@ -151,8 +163,10 @@
          descname = _"making a hunting bow",
          actions = {
             "return=skipped unless economy needs hunting_bow",
-            "sleep=32000",
+            "sleep=5000",
             "consume=log spidercloth",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=hunting_bow"
          }
@@ -162,8 +176,10 @@
          descname = _"making milking tongs",
          actions = {
             "return=skipped unless economy needs milking_tongs",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=milking_tongs"
          }
@@ -173,8 +189,10 @@
          descname = _"making a pick",
          actions = {
             "return=skipped unless economy needs pick",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=pick"
          }
@@ -184,8 +202,10 @@
          descname = _"making a saw",
          actions = {
             "return=skipped unless economy needs saw",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=saw"
          }
@@ -195,8 +215,10 @@
          descname = _"making a scythe",
          actions = {
             "return=skipped unless economy needs scythe",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=scythe"
          }
@@ -206,8 +228,10 @@
          descname = _"making a shovel",
          actions = {
             "return=skipped unless economy needs shovel",
-            "sleep=32000",
+            "sleep=5000",
             "consume=iron log",
+            "sleep=27000",
+            "play_sound=sound/smiths toolsmith 192",
             "animate=working 35000",
             "produce=shovel"
          }

=== modified file 'data/tribes/buildings/productionsites/atlanteans/weaponsmithy/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/weaponsmithy/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/atlanteans/weaponsmithy/init.lua	2016-10-28 17:51:15 +0000
@@ -87,8 +87,8 @@
          descname = _"forging a long trident",
          actions = {
             "return=skipped unless economy needs trident_long",
-            "sleep=32000",
             "consume=iron coal planks",
+            "sleep=32000",
             "play_sound=sound/smiths smith 192",
             "animate=working 36000",
             "play_sound=sound/smiths sharpening 120",
@@ -101,8 +101,8 @@
          descname = _"forging a steel trident",
          actions = {
             "return=skipped unless economy needs trident_steel",
-            "sleep=32000",
             "consume=iron:2 coal planks",
+            "sleep=32000",
             "play_sound=sound/smiths smith 192",
             "animate=working 36000",
             "play_sound=sound/smiths sharpening 120",
@@ -115,8 +115,8 @@
          descname = _"forging a double trident",
          actions = {
             "return=skipped unless economy needs trident_double",
-            "sleep=32000",
             "consume=iron coal:2 planks gold",
+            "sleep=32000",
             "play_sound=sound/smiths smith 192",
             "animate=working 36000",
             "play_sound=sound/smiths sharpening 120",
@@ -129,8 +129,8 @@
          descname = _"forging a heavy double trident",
          actions = {
             "return=skipped unless economy needs trident_heavy_double",
-            "sleep=32000",
             "consume=iron:2 coal:2 planks gold",
+            "sleep=32000",
             "play_sound=sound/smiths smith 192",
             "animate=working 36000",
             "play_sound=sound/smiths sharpening 120",

=== modified file 'data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua	2016-10-28 17:51:15 +0000
@@ -68,9 +68,10 @@
          descname = _"weaving spidercloth",
          actions = {
             "return=skipped unless economy needs spidercloth",
-            "sleep=20000",
+            "sleep=10000",
             "consume=spider_silk",
             "animate=working 20000",
+            "sleep=10000",
             "produce=spidercloth"
          }
       },
@@ -79,9 +80,10 @@
          descname = _"tailoring a tabard",
          actions = {
             "return=skipped unless economy needs tabard",
-            "sleep=20000",
+            "sleep=10000",
             "consume=spider_silk",
-            "animate=working 20000",
+            "animate=working 25000",
+            "sleep=5000",
             "produce=tabard"
          }
       },
@@ -90,9 +92,11 @@
          descname = _"tailoring a golden tabard",
          actions = {
             "return=skipped unless economy needs tabard_golden",
-            "sleep=20000",
+            "sleep=2000",
             "consume=spider_silk gold_thread",
-            "animate=working 20000",
+            "sleep=3000",
+            "animate=working 30000",
+            "sleep=5000",
             "produce=tabard_golden"
          }
       },

=== modified file 'data/tribes/buildings/productionsites/barbarians/ax_workshop/init.lua'
--- data/tribes/buildings/productionsites/barbarians/ax_workshop/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/ax_workshop/init.lua	2016-10-28 17:51:15 +0000
@@ -89,8 +89,8 @@
          descname = _"forging a sharp ax",
          actions = {
             "return=skipped unless economy needs ax_sharp",
-            "sleep=26000",
             "consume=coal iron:2",
+            "sleep=26000",
             "play_sound=sound/smiths smith 192",
             "animate=working 22000",
             "play_sound=sound/smiths sharpening 120",
@@ -103,8 +103,8 @@
          descname = _"forging a broad ax",
          actions = {
             "return=skipped unless economy needs ax_broad",
-            "sleep=26000",
             "consume=coal:2 iron:2",
+            "sleep=26000",
             "play_sound=sound/smiths smith 192",
             "animate=working 22000",
             "play_sound=sound/smiths sharpening 120",

=== modified file 'data/tribes/buildings/productionsites/barbarians/big_inn/init.lua'
--- data/tribes/buildings/productionsites/barbarians/big_inn/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/big_inn/init.lua	2016-10-28 17:51:15 +0000
@@ -69,9 +69,12 @@
          -- TRANSLATORS: Completed/Skipped/Did not start preparing a ration because ...
          descname = _"preparing a ration",
          actions = {
+            -- time total: 33
             "return=skipped unless economy needs ration",
-            "sleep=33000",
+            "sleep=23000",
             "consume=barbarians_bread,fish,meat",
+            "play_sound=sound/barbarians/taverns tavern 100",
+            "sleep=10000",
             "produce=ration"
          }
       },
@@ -79,9 +82,12 @@
          -- TRANSLATORS: Completed/Skipped/Did not start preparing a snack because ...
          descname = _"preparing a snack",
          actions = {
+            -- time total: 37
             "return=skipped unless economy needs snack",
-            "sleep=35000",
+            "sleep=5000",
             "consume=barbarians_bread fish,meat beer",
+            "play_sound=sound/barbarians/taverns biginn 100",
+            "sleep=32000",
             "produce=snack"
          }
       },
@@ -89,9 +95,12 @@
          -- TRANSLATORS: Completed/Skipped/Did not start preparing a meal because ...
          descname = _"preparing a meal",
          actions = {
+            -- time total: 40
             "return=skipped unless economy needs meal",
-            "sleep=37000",
+            "sleep=5000",
             "consume=barbarians_bread fish,meat beer_strong",
+            "play_sound=sound/barbarians/taverns biginn 100",
+            "sleep=35000",
             "produce=meal"
          }
       },

=== modified file 'data/tribes/buildings/productionsites/barbarians/helmsmithy/init.lua'
--- data/tribes/buildings/productionsites/barbarians/helmsmithy/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/helmsmithy/init.lua	2016-10-28 17:51:15 +0000
@@ -89,8 +89,8 @@
          descname = _"forging a mask",
          actions = {
             "return=skipped unless economy needs helmet_mask",
-            "sleep=32000",
             "consume=coal iron:2",
+            "sleep=32000",
             "animate=working 45000",
             "produce=helmet_mask"
          }
@@ -100,8 +100,8 @@
          descname = _"forging a warhelm",
          actions = {
             "return=skipped unless economy needs helmet_warhelm",
-            "sleep=32000",
             "consume=coal gold iron:2",
+            "sleep=32000",
             "animate=working 55000",
             "produce=helmet_warhelm"
          }

=== modified file 'data/tribes/buildings/productionsites/barbarians/inn/init.lua'
--- data/tribes/buildings/productionsites/barbarians/inn/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/inn/init.lua	2016-10-28 17:51:15 +0000
@@ -66,10 +66,13 @@
          -- TRANSLATORS: Completed/Skipped/Did not start preparing a ration because ...
          descname = _"preparing a ration",
          actions = {
+            -- time total: 33
             "return=skipped unless economy needs ration",
-            "sleep=14000",
+            "sleep=5000",
             "consume=barbarians_bread,fish,meat",
-            "animate=working 19000",
+            "play_sound=sound/barbarians/taverns inn 100",
+            "animate=working 18000",
+            "sleep=10000",
             "produce=ration"
          }
       },
@@ -77,10 +80,13 @@
          -- TRANSLATORS: Completed/Skipped/Did not start preparing a snack because ...
          descname = _"preparing a snack",
          actions = {
+            -- time total: 37
             "return=skipped unless economy needs snack",
-            "sleep=15000",
+            "sleep=5000",
             "consume=barbarians_bread fish,meat beer",
-            "animate=working 20000",
+            "play_sound=sound/barbarians/taverns inn 100",
+            "animate=working 22000",
+            "sleep=10000",
             "produce=snack"
          }
       },

=== modified file 'data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua'
--- data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua	2016-10-28 17:51:15 +0000
@@ -69,8 +69,9 @@
          descname = _"smelting iron",
          actions = {
             "return=skipped unless economy needs iron",
-            "sleep=32000",
+            "sleep=5000",  -- penalty for unavailable iron_ore (2x)
             "consume=coal iron_ore",
+            "sleep=27000",
             "play_sound=sound/metal furnace 192",
             "animate=working 35000",
             "play_sound=sound/metal ironping 80",
@@ -82,8 +83,9 @@
          descname = _"smelting gold",
          actions = {
             "return=skipped unless economy needs gold",
-            "sleep=32000",
+            "sleep=10000",  -- penalty for unavailable gold_ore
             "consume=coal gold_ore",
+            "sleep=22000",
             "play_sound=sound/metal furnace 192",
             "animate=working 35000",
             "play_sound=sound/metal goldping 80",

=== modified file 'data/tribes/buildings/productionsites/barbarians/tavern/init.lua'
--- data/tribes/buildings/productionsites/barbarians/tavern/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/tavern/init.lua	2016-10-28 17:51:15 +0000
@@ -62,7 +62,7 @@
             "sleep=14000",
             "return=skipped unless economy needs ration",
             "consume=barbarians_bread,fish,meat",
-            "play_sound=sound/taverns dishes 100",
+            "play_sound=sound/barbarians/taverns tavern 100",
             "animate=working 19000",
             "produce=ration"
          },

=== modified file 'data/tribes/buildings/productionsites/barbarians/warmill/init.lua'
--- data/tribes/buildings/productionsites/barbarians/warmill/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/warmill/init.lua	2016-10-28 17:51:15 +0000
@@ -96,8 +96,8 @@
          descname = _"forging a sharp ax",
          actions = {
             "return=skipped unless economy needs ax_sharp",
-            "sleep=26000",
             "consume=coal iron:2",
+            "sleep=26000",
             "play_sound=sound/smiths smith 192",
             "animate=working 22000",
             "play_sound=sound/smiths sharpening 120",
@@ -110,8 +110,8 @@
          descname = _"forging a broad ax",
          actions = {
             "return=skipped unless economy needs ax_broad",
+            "consume=coal:2 iron:2",
             "sleep=26000",
-            "consume=coal:2 iron:2",
             "play_sound=sound/smiths smith 192",
             "animate=working 22000",
             "play_sound=sound/smiths sharpening 120",
@@ -124,8 +124,8 @@
          descname = _"forging a bronze ax",
          actions = {
             "return=skipped unless economy needs ax_bronze",
+            "consume=coal:2 iron:2",
             "sleep=26000",
-            "consume=coal:2 iron:2",
             "play_sound=sound/smiths smith 192",
             "animate=working 22000",
             "play_sound=sound/smiths sharpening 120",
@@ -138,8 +138,8 @@
          descname = _"forging a battle ax",
          actions = {
             "return=skipped unless economy needs ax_battle",
-            "sleep=26000",
             "consume=coal gold iron:2",
+            "sleep=26000",
             "play_sound=sound/smiths smith 192",
             "animate=working 22000",
             "play_sound=sound/smiths sharpening 120",
@@ -152,8 +152,8 @@
          descname = _"forging a warrior’s ax",
          actions = {
             "return=skipped unless economy needs ax_warriors",
-            "sleep=26000",
             "consume=coal:2 gold:2 iron:2",
+            "sleep=26000",
             "play_sound=sound/smiths smith 192",
             "animate=working 22000",
             "play_sound=sound/smiths sharpening 120",

=== modified file 'data/tribes/buildings/productionsites/empire/armorsmithy/init.lua'
--- data/tribes/buildings/productionsites/empire/armorsmithy/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/armorsmithy/init.lua	2016-10-28 17:51:15 +0000
@@ -91,8 +91,8 @@
          descname = _"forging a suit of armor",
          actions = {
             "return=skipped unless economy needs armor",
-            "sleep=32000",
             "consume=iron coal cloth",
+            "sleep=32000",
             "animate=working 45000",
             "produce=armor"
          }
@@ -102,8 +102,8 @@
          descname = _"forging a suit of chain armor",
          actions = {
             "return=skipped unless economy needs armor_chain",
-            "sleep=32000",
             "consume=iron:2 coal cloth",
+            "sleep=32000",
             "animate=working 45000",
             "produce=armor_chain"
          }
@@ -113,8 +113,8 @@
          descname = _"forging a suit of gilded armor",
          actions = {
             "return=skipped unless economy needs armor_gilded",
-            "sleep=32000",
             "consume=iron:2 coal:2 cloth gold",
+            "sleep=32000",
             "animate=working 45000",
             "produce=armor_gilded"
          }

=== modified file 'data/tribes/buildings/productionsites/empire/inn/init.lua'
--- data/tribes/buildings/productionsites/empire/inn/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/inn/init.lua	2016-10-28 17:51:15 +0000
@@ -63,10 +63,13 @@
          -- TRANSLATORS: Completed/Skipped/Did not start preparing a ration because ...
          descname = _"preparing a ration",
          actions = {
+            -- time total: 33
             "return=skipped unless economy needs ration",
-            "sleep=14000",
+            "sleep=10000",
             "consume=empire_bread,fish,meat",
+            "play_sound=sound/empire/taverns ration 100",
             "animate=working 19000",
+            "sleep=4000",
             "produce=ration"
          }
       },
@@ -74,10 +77,13 @@
          -- TRANSLATORS: Completed/Skipped/Did not start preparing a meal because ...
          descname = _"preparing a meal",
          actions = {
+            -- time total: 40
             "return=skipped unless economy needs meal",
-            "sleep=15000",
+            "sleep=10000",
             "consume=empire_bread fish,meat",
-            "animate=working 20000",
+            "play_sound=sound/empire/taverns meal 100",
+            "animate=working 25000",
+            "sleep=5000",
             "produce=meal"
          }
       },

=== modified file 'data/tribes/buildings/productionsites/empire/smelting_works/init.lua'
--- data/tribes/buildings/productionsites/empire/smelting_works/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/smelting_works/init.lua	2016-10-28 17:51:15 +0000
@@ -71,8 +71,9 @@
          descname = _"smelting iron",
          actions = {
             "return=skipped unless economy needs iron",
-            "sleep=25000",
+            "sleep=5000",  -- penalty for unavailable iron_ore (2x)
             "consume=iron_ore coal",
+            "sleep=20000",
             "play_sound=sound/metal fizzle 150",
             "animate=working 35000",
             "play_sound=sound/metal ironping 80",
@@ -84,8 +85,9 @@
          descname = _"smelting gold",
          actions = {
             "return=skipped unless economy needs gold",
-            "sleep=25000",
+            "sleep=10000",  -- penalty for unavailable gold_ore
             "consume=gold_ore coal",
+            "sleep=15000",
             "play_sound=sound/metal fizzle 150",
             "animate=working 35000",
             "play_sound=sound/metal goldping 80",

=== modified file 'data/tribes/buildings/productionsites/empire/tavern/init.lua'
--- data/tribes/buildings/productionsites/empire/tavern/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/tavern/init.lua	2016-10-28 17:51:15 +0000
@@ -55,10 +55,11 @@
          -- TRANSLATORS: Completed/Skipped/Did not start preparing a ration because ...
          descname = _"preparing a ration",
          actions = {
+            -- time total: 33
             "sleep=14000",
             "return=skipped unless economy needs ration",
             "consume=empire_bread,fish,meat",
-            "play_sound=sound/taverns dishes 100",
+            "play_sound=sound/empire/taverns ration 100",
             "animate=working 19000",
             "produce=ration"
          }

=== modified file 'data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua'
--- data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua	2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua	2016-10-28 17:51:15 +0000
@@ -92,8 +92,8 @@
          descname = _"forging a spear",
          actions = {
             "return=skipped unless economy needs spear",
-            "sleep=32000",
             "consume=coal iron planks",
+            "sleep=32000",
             "play_sound=sound/smiths smith 192",
             "animate=working 36000",
             "play_sound=sound/smiths sharpening 120",
@@ -106,8 +106,8 @@
          descname = _"forging an advanced spear",
          actions = {
             "return=skipped unless economy needs spear_advanced",
-            "sleep=32000",
             "consume=coal iron:2 planks",
+            "sleep=32000",
             "play_sound=sound/smiths smith 192",
             "animate=working 36000",
             "play_sound=sound/smiths sharpening 120",
@@ -120,8 +120,8 @@
          descname = _"forging a heavy spear",
          actions = {
             "return=skipped unless economy needs spear_heavy",
-            "sleep=32000",
             "consume=coal:2 gold iron planks",
+            "sleep=32000",
             "play_sound=sound/smiths smith 192",
             "animate=working 36000",
             "play_sound=sound/smiths sharpening 120",
@@ -134,8 +134,8 @@
          descname = _"forging a war spear",
          actions = {
             "return=skipped unless economy needs spear_war",
-            "sleep=32000",
             "consume=coal:2 gold iron:2 planks",
+            "sleep=32000",
             "play_sound=sound/smiths smith 192",
             "animate=working 36000",
             "play_sound=sound/smiths sharpening 120",

=== modified file 'data/tribes/scripting/help/controls.lua'
--- data/tribes/scripting/help/controls.lua	2016-09-11 16:29:59 +0000
+++ data/tribes/scripting/help/controls.lua	2016-10-28 17:51:15 +0000
@@ -56,7 +56,13 @@
                -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
                dl(help_format_hotkey(pgettext("hotkey", "Home")), _"Center main mapview on starting location") ..
                -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
-               dl(help_format_hotkey(pgettext("hotkey", "(Ctrl +) 0-9")), _"Remember and go to previously remembered locations") ..
+               dl(help_format_hotkey(pgettext("hotkey", "(Ctrl +) 1-9")), _"Remember and go to previously remembered locations") ..
+               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+               dl(help_format_hotkey(pgettext("hotkey", "(Ctrl +) +")), _"Increase zoom") ..
+               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+               dl(help_format_hotkey(pgettext("hotkey", "(Ctrl +) -")), _"Decrease zoom") ..
+               -- TRANSLATORS: This is an access key combination. Localize, but do not change the key.
+               dl(help_format_hotkey(pgettext("hotkey", "(Ctrl +) 0")), _"Reset zoom") ..
                -- TRANSLATORS: This is an access key combination.
                dl(help_format_hotkey(","), _"Go to the previous location") ..
                -- TRANSLATORS: This is an access key combination.

=== modified file 'data/txts/developers.json'
--- data/txts/developers.json	2016-10-05 04:24:26 +0000
+++ data/txts/developers.json	2016-10-28 17:51:15 +0000
@@ -2,7 +2,7 @@
 	"developers":[
 		{
 			"heading": "Chieftain",
-			"image": "images/players/genstats_enable_plr_01.png",
+			"image": "images/players/genstats_player.png",
 			"entries":[
 				{
 					"members":[
@@ -13,7 +13,7 @@
 		},
 		{
 			"heading": "Elders",
-			"image": "images/players/genstats_enable_plr_04.png",
+			"image": "images/players/genstats_player.png",
 			"entries":[
 				{
 					"subheading": "Graphics",
@@ -329,7 +329,7 @@
 		},
 		{
 			"heading": "Former Elders",
-			"image": "images/players/genstats_enable_plr_04.png",
+			"image": "images/players/genstats_player.png",
 			"entries":[
 				{
 					"subheading": "Graphics",

=== modified file 'data/txts/developers.lua'
--- data/txts/developers.lua	2016-10-07 07:05:09 +0000
+++ data/txts/developers.lua	2016-10-28 17:51:15 +0000
@@ -1,3 +1,3 @@
 -- Do not edit this file - it is automatically generated
 -- by utils/update_authors.py from developers.json.
-function developers() return {{heading = _"Chieftain",image = "images/players/genstats_enable_plr_01.png",entries = {{members = {"Holger Rapp (SirVer)",},},},},{heading = _"Elders",image = "images/players/genstats_enable_plr_04.png",entries = {{subheading = _"Graphics",members = {"Chuck Wilder (chuckw)",},},{subheading = _"Homepage",members = {"Markus Pfitzner (janus)",},},{subheading = _"Sound",members = {"Jan Bruns (solatis)",},},{subheading = _"Tongues",members = {"GunChleoc",},},},},{heading = _"Coders",image = "images/wui/stats/genstats_nrwares.png",entries = {{members = {"Holger Rapp (SirVer)","Nicolai Hähnle (ixprefect)","Florian Bluemel","Florian Falkner (foldrian)","Florian Weber (Bedouin)","Philipp Engelhard","Stefan Boettner","Tron","Martin Quinson","Raul Ferriz","Willem Jan Palenstijn","Josef Spillner","Christof Petig","Erik Sigra (sigra)","Nanne Wams","Surgery","Andrius R. (knutux)","Jari Hautio (jarih)","Peter Schwanemann (Nasenbaer)","Victor Pelt (Dwarik)","Axel Gehlert (dunkelbrauer)","András Eisenberger (Kiscsirke)","Andi","Timo","Hannes","TimoW","Jens Beyer (Qcumber-some)","Andreas Breitschopp (ab-tools)","Joachim Breitner (nomeata)","Nizamov Shawkat","Carl-Philip Hänsch (carli)","Martin Prussak (martin)","David Allwicher (aber)","Nathan Peters (nathanpeters)","Leif Sandstede (lcsand)","Matthias Horne (shevonar)","Borim (borim)","Angelo Locritani (alocritani)","Gabriel Margiani (gamag)","Anthony J. Bentley (anthonyjbentley)","Peter Waller (iri)","Johannes Ebke (sirius-in4matiker)","Andreas Eriksson","Mark Scott","Teppo Mäenpää","Steven De Herdt (stdh)","Charly Ghislain (cghislai)","Tino Miegel (TinoM)","Tibor Bamhor (tiborb95)","GunChleoc","Ferdinand Thiessen (f-thiessen)","Willy Scheibel (willyscheibel)","Martin Schmidt (mars)","Simon Eilting","Alexander Kartzow (daAlx1)","Łukasz Majcher","Paul Mehrer (meitis)","Miroslav Remák (MiroslavR)","Janosch Peters","Hasi50 (Klaus Halfmann)","Philipp Klaus Krause (PkK)","Notabilis",},},},},{heading = _"Graphicians",image = "images/wui/stats/genstats_nrbuildings.png",entries = {{members = {"Albert Jasiowka","Holger Rapp (SirVer)","Marz","Philipp Engelhard","Yannick Warnier","Delia","Florian Neuerburg","Jerome Rosinski","Mats Olsson","Odin Omdal","Wolfgang Weidner","Andreas Baier","Juri Chomé","Toralf Bethke (bithunter32)","Peter Schwanemann (Nasenbaer)","Alexia Death","Repsa Jih","Geoffroy Schmitlin (Trimard)","Benedikt Freisen (Objpaswriter)","Stefano Guidoni (Ilguido)","Samith Sandanayake (samithdisal)","Chuck Wilder (chuckw)","Astuur","Gerrit Familiegrosskopf (kingcreole)","Florian Angermeier (fraang)",},},},},{heading = _"Musicians",image = "images/wui/overlays/workarea123.png",entries = {{members = {"Kristian","MiddleFinger","Valerio Orlandini (Symbiosis)","Barry van Oudtshoorn (barryvan)","Jan Bruns (Solatis)","Nikola Whallon (Saturn)","Joshua O'Leary (Joshun)",},},},},{heading = _"Sound Effects",image = "images/wui/overlays/workarea123.png",entries = {{members = {"Stefan de Konik","Peter Schwanemann (Nasenbaer)","Stephan","Adam Piggott (_aD)","Stanisław Gackowski (Soeb)",},},},},{heading = _"Maps and Missions",image = "images/wui/stats/genstats_landsize.png",entries = {{members = {"Michal Szopa (Winterwind)","Jan-Henrik Kluth (Isch)","Peter Schwanemann (Nasenbaer)","Sven (deviant)","Tuxlands","Kamil Wilczek (Another Barbarian)","Tarvo Reim (Tarrei)","Manuel Holzmeier (Quappo)","ivh","Hanna Podewski (kristin)","Teppo Mäenpää","fk","Einstein13","Jenia","Robnick","wl-zocker","king of nowhere","kaputtnik",},},},},{heading = _"Campaign Story",image = "images/ui_basic/ls_wlmap.png",entries = {{subheading = _"Barbarian",members = {"Bastian Rapp","Alexander Kahl (wolfpac)","Peter Schwanemann (Nasenbaer)",},},{subheading = _"Empire",members = {"Peter Schwanemann (Nasenbaer)",},},{subheading = _"Atlantean",members = {"Holger Rapp (SirVer)","Peter Schwanemann (Nasenbaer)",},},},},{heading = _"Packagers",image = "images/wui/stats/genstats_productivity.png",entries = {{subheading = _"Debian Linux",members = {"Martin Quinson",},},{subheading = _"Fedora Linux",members = {"Karol Trzcionka","Jochen Wiedmann",},},{subheading = _"Mandriva Linux",members = {"Emmanuel Andry (eandry)",},},{subheading = _"FreeBSD",members = {"Bartosz Fabianowski",},},{subheading = _"Mac OS X",members = {"Philipp Engelhard","Pierre Salagnac (Tarou)","Wolf St. Kappesser","David Allwicher (aber)",},},{subheading = _"Windows",members = {"Tino Miegel (TinoM)","Alexander Kahl (Wolfpac)","Geodomus","Jari Hautio",},},{subheading = _"ZetaOS",members = {"BeSman",},},},},{heading = _"Homepage",image = "images/logos/WL-Editor-16.png",entries = {{subheading = _"Homepage Coders",members = {"Holger Rapp (SirVer)","Stanislaw Gackowski (Soeb)","Markus Pfitzner (janus)","Tobi","kaputtnik",},},{subheading = _"Documentation, Help and Wiki",members = {"Erik Sigra (sigra)","Florian Falkner (foldrian)","Florian Weber (bedouin)","Nicolai Haehnle","Holger Rapp (SirVer)","Johannes (nuefke)","Alexander Kahl (wolfpac)","Stanislaw Gackowski (Soeb)","Hanna Podewski (kristin)","king of nowhere","GunChleoc",},},},},{heading = _"Former Elders",image = "images/players/genstats_enable_plr_04.png",entries = {{subheading = _"Graphics",members = {"Salamander","Alexia Death (death)",},},{subheading = _"Homepage",members = {"holymoly","Stuart Eglington (DaaL1973)","Jon Harris (jonsjava)",},},{subheading = _"Sound",members = {"Yannick Warnier",},},{subheading = _"Translation",members = {"Peter Schwanemann (Nasenbaer)","Philipp Niemann (Azagtoth)",},},},},{heading = _"Other",image = "images/wui/stats/genstats_landsize.png",entries = {{members = {"Matt Howe (mdhowe)","Samuel Tilly (eldamar)","and many, many more (thank you for everything you've done)",},},},},} end
\ No newline at end of file
+function developers() return {{heading = _"Chieftain",image = "images/players/genstats_player.png",entries = {{members = {"Holger Rapp (SirVer)",},},},},{heading = _"Elders",image = "images/players/genstats_player.png",entries = {{subheading = _"Graphics",members = {"Chuck Wilder (chuckw)",},},{subheading = _"Homepage",members = {"Markus Pfitzner (janus)",},},{subheading = _"Sound",members = {"Jan Bruns (solatis)",},},{subheading = _"Tongues",members = {"GunChleoc",},},},},{heading = _"Coders",image = "images/wui/stats/genstats_nrwares.png",entries = {{members = {"Holger Rapp (SirVer)","Nicolai Hähnle (ixprefect)","Florian Bluemel","Florian Falkner (foldrian)","Florian Weber (Bedouin)","Philipp Engelhard","Stefan Boettner","Tron","Martin Quinson","Raul Ferriz","Willem Jan Palenstijn","Josef Spillner","Christof Petig","Erik Sigra (sigra)","Nanne Wams","Surgery","Andrius R. (knutux)","Jari Hautio (jarih)","Peter Schwanemann (Nasenbaer)","Victor Pelt (Dwarik)","Axel Gehlert (dunkelbrauer)","András Eisenberger (Kiscsirke)","Andi","Timo","Hannes","TimoW","Jens Beyer (Qcumber-some)","Andreas Breitschopp (ab-tools)","Joachim Breitner (nomeata)","Nizamov Shawkat","Carl-Philip Hänsch (carli)","Martin Prussak (martin)","David Allwicher (aber)","Nathan Peters (nathanpeters)","Leif Sandstede (lcsand)","Matthias Horne (shevonar)","Borim (borim)","Angelo Locritani (alocritani)","Gabriel Margiani (gamag)","Anthony J. Bentley (anthonyjbentley)","Peter Waller (iri)","Johannes Ebke (sirius-in4matiker)","Andreas Eriksson","Mark Scott","Teppo Mäenpää","Steven De Herdt (stdh)","Charly Ghislain (cghislai)","Tino Miegel (TinoM)","Tibor Bamhor (tiborb95)","GunChleoc","Ferdinand Thiessen (f-thiessen)","Willy Scheibel (willyscheibel)","Martin Schmidt (mars)","Simon Eilting","Alexander Kartzow (daAlx1)","Łukasz Majcher","Paul Mehrer (meitis)","Miroslav Remák (MiroslavR)","Janosch Peters","Hasi50 (Klaus Halfmann)","Philipp Klaus Krause (PkK)","Notabilis",},},},},{heading = _"Graphicians",image = "images/wui/stats/genstats_nrbuildings.png",entries = {{members = {"Albert Jasiowka","Holger Rapp (SirVer)","Marz","Philipp Engelhard","Yannick Warnier","Delia","Florian Neuerburg","Jerome Rosinski","Mats Olsson","Odin Omdal","Wolfgang Weidner","Andreas Baier","Juri Chomé","Toralf Bethke (bithunter32)","Peter Schwanemann (Nasenbaer)","Alexia Death","Repsa Jih","Geoffroy Schmitlin (Trimard)","Benedikt Freisen (Objpaswriter)","Stefano Guidoni (Ilguido)","Samith Sandanayake (samithdisal)","Chuck Wilder (chuckw)","Astuur","Gerrit Familiegrosskopf (kingcreole)","Florian Angermeier (fraang)",},},},},{heading = _"Musicians",image = "images/wui/overlays/workarea123.png",entries = {{members = {"Kristian","MiddleFinger","Valerio Orlandini (Symbiosis)","Barry van Oudtshoorn (barryvan)","Jan Bruns (Solatis)","Nikola Whallon (Saturn)","Joshua O'Leary (Joshun)",},},},},{heading = _"Sound Effects",image = "images/wui/overlays/workarea123.png",entries = {{members = {"Stefan de Konik","Peter Schwanemann (Nasenbaer)","Stephan","Adam Piggott (_aD)","Stanisław Gackowski (Soeb)",},},},},{heading = _"Maps and Missions",image = "images/wui/stats/genstats_landsize.png",entries = {{members = {"Michal Szopa (Winterwind)","Jan-Henrik Kluth (Isch)","Peter Schwanemann (Nasenbaer)","Sven (deviant)","Tuxlands","Kamil Wilczek (Another Barbarian)","Tarvo Reim (Tarrei)","Manuel Holzmeier (Quappo)","ivh","Hanna Podewski (kristin)","Teppo Mäenpää","fk","Einstein13","Jenia","Robnick","wl-zocker","king of nowhere","kaputtnik",},},},},{heading = _"Campaign Story",image = "images/ui_basic/ls_wlmap.png",entries = {{subheading = _"Barbarian",members = {"Bastian Rapp","Alexander Kahl (wolfpac)","Peter Schwanemann (Nasenbaer)",},},{subheading = _"Empire",members = {"Peter Schwanemann (Nasenbaer)",},},{subheading = _"Atlantean",members = {"Holger Rapp (SirVer)","Peter Schwanemann (Nasenbaer)",},},},},{heading = _"Packagers",image = "images/wui/stats/genstats_productivity.png",entries = {{subheading = _"Debian Linux",members = {"Martin Quinson",},},{subheading = _"Fedora Linux",members = {"Karol Trzcionka","Jochen Wiedmann",},},{subheading = _"Mandriva Linux",members = {"Emmanuel Andry (eandry)",},},{subheading = _"FreeBSD",members = {"Bartosz Fabianowski",},},{subheading = _"Mac OS X",members = {"Philipp Engelhard","Pierre Salagnac (Tarou)","Wolf St. Kappesser","David Allwicher (aber)",},},{subheading = _"Windows",members = {"Tino Miegel (TinoM)","Alexander Kahl (Wolfpac)","Geodomus","Jari Hautio",},},{subheading = _"ZetaOS",members = {"BeSman",},},},},{heading = _"Homepage",image = "images/logos/WL-Editor-16.png",entries = {{subheading = _"Homepage Coders",members = {"Holger Rapp (SirVer)","Stanislaw Gackowski (Soeb)","Markus Pfitzner (janus)","Tobi","kaputtnik",},},{subheading = _"Documentation, Help and Wiki",members = {"Erik Sigra (sigra)","Florian Falkner (foldrian)","Florian Weber (bedouin)","Nicolai Haehnle","Holger Rapp (SirVer)","Johannes (nuefke)","Alexander Kahl (wolfpac)","Stanislaw Gackowski (Soeb)","Hanna Podewski (kristin)","king of nowhere","GunChleoc",},},},},{heading = _"Former Elders",image = "images/players/genstats_player.png",entries = {{subheading = _"Graphics",members = {"Salamander","Alexia Death (death)",},},{subheading = _"Homepage",members = {"holymoly","Stuart Eglington (DaaL1973)","Jon Harris (jonsjava)",},},{subheading = _"Sound",members = {"Yannick Warnier",},},{subheading = _"Translation",members = {"Peter Schwanemann (Nasenbaer)","Philipp Niemann (Azagtoth)",},},},},{heading = _"Other",image = "images/wui/stats/genstats_landsize.png",entries = {{members = {"Matt Howe (mdhowe)","Samuel Tilly (eldamar)","and many, many more (thank you for everything you've done)",},},},},} end
\ No newline at end of file

=== modified file 'data/txts/help/multiplayer_help.lua'
--- data/txts/help/multiplayer_help.lua	2016-03-14 11:37:49 +0000
+++ data/txts/help/multiplayer_help.lua	2016-10-28 17:51:15 +0000
@@ -12,7 +12,7 @@
 
       result = result .. rt(h2(_"Client settings"))
       result = result .. rt(p(_"On the left side is a list of all clients including you. You can set your role with the button following your nickname. Available roles are:"))
-      result = result .. picture_li("images/players/genstats_enable_plr_08.png", _"The player with the color of the flag. If more than one client selected the same color, these share control over the player (‘shared kingdom mode’).")
+      result = result .. picture_li("images/players/genstats_player.png", _"The player with the color of the flag. If more than one client selected the same color, these share control over the player (‘shared kingdom mode’).")
       result = result .. picture_li("images/wui/fieldaction/menu_tab_watch.png", _"Spectator mode, meaning you can see everything, but cannot control any player")
 
       result = result .. rt(h2(_"Player settings"))

=== modified file 'debian/widelands.appdata.xml'
--- debian/widelands.appdata.xml	2016-10-25 06:07:19 +0000
+++ debian/widelands.appdata.xml	2016-10-28 17:51:15 +0000
@@ -237,3 +237,25 @@
   <url type="help">https://wl.widelands.org/wiki/Game%20Manual/</url>
   <developer_name>The Widelands Development Team</developer_name>
 </component>
+<content_rating type="oars-1.0">
+  <content_attribute id="violence-cartoon">moderate</content_attribute>
+  <content_attribute id="violence-fantasy">none</content_attribute>
+  <content_attribute id="violence-realistic">none</content_attribute>
+  <content_attribute id="violence-bloodshed">none</content_attribute>
+  <content_attribute id="violence-sexual">none</content_attribute>
+  <content_attribute id="drugs-alcohol">mild</content_attribute>
+  <content_attribute id="drugs-narcotics">none</content_attribute>
+  <content_attribute id="drugs-tobacco">none</content_attribute>
+  <content_attribute id="sex-nudity">none</content_attribute>
+  <content_attribute id="sex-themes">none</content_attribute>
+  <content_attribute id="language-profanity">none</content_attribute>
+  <content_attribute id="language-humor">none</content_attribute>
+  <content_attribute id="language-discrimination">none</content_attribute>
+  <content_attribute id="social-chat">intense</content_attribute>
+  <content_attribute id="social-info">none</content_attribute>
+  <content_attribute id="social-audio">none</content_attribute>
+  <content_attribute id="social-location">none</content_attribute>
+  <content_attribute id="social-contacts">none</content_attribute>
+  <content_attribute id="money-purchasing">none</content_attribute>
+  <content_attribute id="money-gambling">none</content_attribute>
+</content_rating>

=== modified file 'debian/widelands.appdata.xml.stub'
--- debian/widelands.appdata.xml.stub	2016-10-25 06:07:19 +0000
+++ debian/widelands.appdata.xml.stub	2016-10-28 17:51:15 +0000
@@ -57,3 +57,25 @@
   <url type="help">https://wl.widelands.org/wiki/Game%20Manual/</url>
   <developer_name>The Widelands Development Team</developer_name>
 </component>
+<content_rating type="oars-1.0">
+  <content_attribute id="violence-cartoon">moderate</content_attribute>
+  <content_attribute id="violence-fantasy">none</content_attribute>
+  <content_attribute id="violence-realistic">none</content_attribute>
+  <content_attribute id="violence-bloodshed">none</content_attribute>
+  <content_attribute id="violence-sexual">none</content_attribute>
+  <content_attribute id="drugs-alcohol">mild</content_attribute>
+  <content_attribute id="drugs-narcotics">none</content_attribute>
+  <content_attribute id="drugs-tobacco">none</content_attribute>
+  <content_attribute id="sex-nudity">none</content_attribute>
+  <content_attribute id="sex-themes">none</content_attribute>
+  <content_attribute id="language-profanity">none</content_attribute>
+  <content_attribute id="language-humor">none</content_attribute>
+  <content_attribute id="language-discrimination">none</content_attribute>
+  <content_attribute id="social-chat">intense</content_attribute>
+  <content_attribute id="social-info">none</content_attribute>
+  <content_attribute id="social-audio">none</content_attribute>
+  <content_attribute id="social-location">none</content_attribute>
+  <content_attribute id="social-contacts">none</content_attribute>
+  <content_attribute id="money-purchasing">none</content_attribute>
+  <content_attribute id="money-gambling">none</content_attribute>
+</content_rating>

=== modified file 'src/base/CMakeLists.txt'
--- src/base/CMakeLists.txt	2016-08-15 10:43:23 +0000
+++ src/base/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -37,9 +37,9 @@
 
 wl_library(base_geometry
   SRCS
-    point.h
-    point.cc
     rect.h
+    vector.h
+    vector.cc
 )
 
 wl_library(base_md5
@@ -50,7 +50,6 @@
     base_macros
 )
 
-
 wl_library(base_scoped_timer
   SRCS
     scoped_timer.h
@@ -68,3 +67,11 @@
   DEPENDS
     base_i18n
 )
+
+wl_library(base_math
+  SRCS
+    math.h
+    math.cc
+  DEPENDS
+    base_macros
+)

=== added file 'src/base/math.cc'
--- src/base/math.cc	1970-01-01 00:00:00 +0000
+++ src/base/math.cc	2016-10-28 17:51:15 +0000
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2006-2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+// Dummy file as cmake cannot handle header only libraries :(.

=== added file 'src/base/math.h'
--- src/base/math.h	1970-01-01 00:00:00 +0000
+++ src/base/math.h	2016-10-28 17:51:15 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006-2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_BASE_MATH_H
+#define WL_BASE_MATH_H
+
+#include "base/macros.h"
+
+namespace math {
+
+// Returns 1 for positive and -1 for negative numbers.
+template <typename T>
+T sign(const T& val) {
+	return val < T(0.) ? T(-1.) : T(1.);
+}
+
+// Clamps 'val' to 'min' and 'max'.
+template <typename T>
+T clamp(const T& val, const T& low, const T& high) {
+	if (val < low) { return low; }
+	if (val > high) { return high; }
+	return val;
+}
+
+}  // namespace math
+
+#endif  // end of include guard: WL_BASE_MATH_H

=== removed file 'src/base/point.h'
--- src/base/point.h	2016-08-04 15:49:05 +0000
+++ src/base/point.h	1970-01-01 00:00:00 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2002-2004, 2006-2013 by the Widelands Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#ifndef WL_BASE_POINT_H
-#define WL_BASE_POINT_H
-
-#include <limits>
-
-#include <stdint.h>
-
-template <typename T> struct GenericPoint {
-	GenericPoint(const T& px, const T& py) : x(px), y(py) {
-	}
-	GenericPoint() : GenericPoint(T(0), T(0)) {
-	}
-
-	// Returns an invalid point.
-	static GenericPoint invalid() {
-		return GenericPoint(std::numeric_limits<T>::max(), std::numeric_limits<T>::max());
-	}
-
-	bool operator==(const GenericPoint& other) const {
-		return x == other.x && y == other.y;
-	}
-	bool operator!=(const GenericPoint& other) const {
-		return !(*this == other);
-	}
-
-	GenericPoint operator+(const GenericPoint& other) const {
-		return GenericPoint(x + other.x, y + other.y);
-	}
-
-	GenericPoint operator-() const {
-		return GenericPoint(-x, -y);
-	}
-
-	GenericPoint operator-(const GenericPoint& other) const {
-		return GenericPoint(x - other.x, y - other.y);
-	}
-
-	GenericPoint& operator+=(const GenericPoint& other) {
-		x += other.x;
-		y += other.y;
-		return *this;
-	}
-
-	GenericPoint& operator-=(const GenericPoint& other) {
-		x -= other.x;
-		y -= other.y;
-		return *this;
-	}
-
-	T x, y;
-};
-
-using Point = GenericPoint<int>;
-using FloatPoint = GenericPoint<float>;
-
-/// Returns the point in the middle between a and b (rounded to integer
-/// values).
-Point middle(const Point& a, const Point& b);
-
-#endif  // end of include guard: WL_BASE_POINT_H

=== modified file 'src/base/rect.h'
--- src/base/rect.h	2016-08-04 15:49:05 +0000
+++ src/base/rect.h	2016-10-28 17:51:15 +0000
@@ -20,41 +20,51 @@
 #ifndef WL_BASE_RECT_H
 #define WL_BASE_RECT_H
 
-#include "base/point.h"
+#include "base/vector.h"
 
-template <typename T> struct GenericRect {
-	/// Generates a degenerate Rect at (0, 0) with no height or width.
-	GenericRect() : GenericRect(T(0), T(0), T(0), T(0)) {
+template <typename T> struct Rect {
+	/// Generates a degenerate Recti at (0, 0) with no height or width.
+	Rect() : Rect(T(0), T(0), T(0), T(0)) {
 	}
 
-	GenericRect(const T& gx, const T& gy, const T& W, const T& H) : x(gx), y(gy), w(W), h(H) {
+	Rect(const T& gx, const T& gy, const T& W, const T& H) : x(gx), y(gy), w(W), h(H) {
 	}
 
 	template <typename PointType>
-	GenericRect(const GenericPoint<PointType>& p, const T& width, const T& height)
-	   : GenericRect(T(p.x), T(p.y), width, height) {
+	Rect(const Vector2<PointType>& p, const T& width, const T& height)
+	   : Rect(T(p.x), T(p.y), width, height) {
 	}
 
-	/// The Point (x, y).
-	GenericPoint<T> origin() const {
-		return GenericPoint<T>(x, y);
+	/// The Vector2i (x, y).
+	Vector2<T> origin() const {
+		return Vector2<T>(x, y);
 	}
 
 	/// The point (x + w, y + h).
-	GenericPoint<T> opposite_of_origin() const {
-		return GenericPoint<T>(x + w, y + h);
+	Vector2<T> opposite_of_origin() const {
+		return Vector2<T>(x + w, y + h);
 	}
 
 	/// Returns true if this rectangle contains the given point.
 	/// The bottom and right borders of the rectangle are considered to be excluded.
-	template <typename PointType> bool contains(const GenericPoint<PointType>& pt) const {
+	template <typename PointType> bool contains(const Vector2<PointType>& pt) const {
 		return T(pt.x) >= x && T(pt.x) < x + w && T(pt.y) >= y && T(pt.y) < y + h;
 	}
 
+	// The center point of 'r'.
+	Vector2f center() const {
+		return Vector2f(x + w / 2.f, y + h / 2.f);
+	}
+
+	template<typename Type>
+	Rect<Type> cast() const {
+		return Rect<Type>(Type(x), Type(y), Type(w), Type(h));
+	}
+
 	T x, y, w, h;
 };
 
-using Rect = GenericRect<int>;
-using FloatRect = GenericRect<float>;
+using Recti = Rect<int>;
+using Rectf = Rect<float>;
 
 #endif  // end of include guard: WL_BASE_RECT_H

=== renamed file 'src/base/point.cc' => 'src/base/vector.cc'
--- src/base/point.cc	2015-03-01 09:21:20 +0000
+++ src/base/vector.cc	2016-10-28 17:51:15 +0000
@@ -17,8 +17,14 @@
  *
  */
 
-#include "base/point.h"
-
-Point middle(const Point& a, const Point& b) {
-	return Point((a.x + b.x) / 2, (a.y + b.y) / 2);
+#include "base/vector.h"
+
+#include <cmath>
+
+Vector2f middle(const Vector2f& a, const Vector2f& b) {
+	return Vector2f((a.x + b.x) / 2.f, (a.y + b.y) / 2.f);
+}
+
+Vector2i round(const Vector2f& a) {
+	return Vector2i(std::lround(a.x), std::lround(a.y));
 }

=== renamed file 'src/wui/vector.h' => 'src/base/vector.h'
--- src/wui/vector.h	2016-08-04 15:49:05 +0000
+++ src/base/vector.h	2016-10-28 17:51:15 +0000
@@ -17,23 +17,88 @@
  *
  */
 
-#ifndef WL_WUI_VECTOR_H
-#define WL_WUI_VECTOR_H
+#ifndef WL_BASE_VECTOR_H
+#define WL_BASE_VECTOR_H
 
 #include <cmath>
-
-// hm, floats...
-// tried to be faster with fixed point arithmetics
-// it was, but i'll try to find other opts first
-struct Vector {
-	Vector() : x(0), y(0), z(0) {
-	}
-	Vector(const float X, const float Y, const float Z) : x(X), y(Y), z(Z) {
+#include <limits>
+
+#include <stdint.h>
+
+template <typename T> struct Vector2 {
+	Vector2(const T& px, const T& py) : x(px), y(py) {
+	}
+	Vector2() : Vector2(T(0), T(0)) {
+	}
+
+	// Returns an invalid point.
+	static Vector2 invalid() {
+		return Vector2(std::numeric_limits<T>::max(), std::numeric_limits<T>::max());
+	}
+
+	bool operator==(const Vector2& other) const {
+		return x == other.x && y == other.y;
+	}
+	bool operator!=(const Vector2& other) const {
+		return !(*this == other);
+	}
+
+	Vector2 operator+(const Vector2& other) const {
+		return Vector2(x + other.x, y + other.y);
+	}
+
+	Vector2 operator*(const float a) const {
+		return Vector2(a * x, a * y);
+	}
+
+	Vector2 operator/(const float a) const {
+		return Vector2(x / a, y / a);
+	}
+
+	Vector2 operator-() const {
+		return Vector2(-x, -y);
+	}
+
+	Vector2 operator-(const Vector2& other) const {
+		return Vector2(x - other.x, y - other.y);
+	}
+
+	Vector2& operator+=(const Vector2& other) {
+		x += other.x;
+		y += other.y;
+		return *this;
+	}
+
+	Vector2& operator-=(const Vector2& other) {
+		x -= other.x;
+		y -= other.y;
+		return *this;
+	}
+
+	template<typename Type>
+	Vector2<Type> cast() const {
+		return Vector2<Type>(Type(x), Type(y));
+	}
+
+	T x, y;
+};
+
+using Vector2i = Vector2<int>;
+using Vector2f = Vector2<float>;
+
+/// Returns the point in the middle between a and b.
+Vector2f middle(const Vector2f& a, const Vector2f& b);
+
+// Returns an point rounded to the closest integer.
+Vector2i round(const Vector2f& a);
+
+struct Vector3f {
+	Vector3f(const float X, const float Y, const float Z) : x(X), y(Y), z(Z) {
 	}
 
 	void normalize() {
-		const float f = static_cast<float>(sqrt(x * x + y * y + z * z));
-		if (fabs(f) < 0.00001)  // check for ==0
+		const float f = static_cast<float>(std::sqrt(x * x + y * y + z * z));
+		if (std::fabs(f) < 0.00001f)  // check for ==0
 			return;
 		x /= f;
 		y /= f;
@@ -41,16 +106,16 @@
 	}
 
 	// vector addition
-	Vector operator+(const Vector& other) const {
-		return Vector(x + other.x, y + other.y, z + other.z);
+	Vector3f operator+(const Vector3f& other) const {
+		return Vector3f(x + other.x, y + other.y, z + other.z);
 	}
 
 	// inner product
-	float operator*(const Vector& other) const {
+	float dot(const Vector3f& other) const {
 		return x * other.x + y * other.y + z * other.z;
 	}
 
 	float x, y, z;
 };
 
-#endif  // end of include guard: WL_WUI_VECTOR_H
+#endif  // end of include guard: WL_BASE_VECTOR_H

=== modified file 'src/economy/flag.h'
--- src/economy/flag.h	2016-08-04 15:49:05 +0000
+++ src/economy/flag.h	2016-10-28 17:51:15 +0000
@@ -25,6 +25,7 @@
 
 #include "base/macros.h"
 #include "economy/routing_node.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/map_objects/immovable.h"
 
 namespace Widelands {
@@ -144,7 +145,11 @@
 	void init(EditorGameBase&) override;
 	void cleanup(EditorGameBase&) override;
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          TextToDraw draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 
 	void wake_up_capacity_queue(Game&);
 

=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc	2016-08-04 15:49:05 +0000
+++ src/economy/portdock.cc	2016-10-28 17:51:15 +0000
@@ -141,7 +141,7 @@
 		expedition_bootstrap_->set_economy(e);
 }
 
-void PortDock::draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) {
+void PortDock::draw(uint32_t, const TextToDraw, const Vector2f&, float, RenderTarget*) {
 	// do nothing
 }
 
@@ -337,8 +337,7 @@
 			// The expedition goods are now on the ship, so from now on it is independent from the port
 			// and thus we switch the port to normal, so we could even start a new expedition,
 			cancel_expedition(game);
-			if (upcast(InteractiveGameBase, igb, game.get_ibase()))
-				ship.refresh_window(*igb);
+			Notifications::publish(NoteShipWindow(ship.serial(), NoteShipWindow::Action::kRefresh));
 			return fleet_->update(game);
 		}
 	}

=== modified file 'src/economy/portdock.h'
--- src/economy/portdock.h	2016-08-04 15:49:05 +0000
+++ src/economy/portdock.h	2016-10-28 17:51:15 +0000
@@ -96,7 +96,11 @@
 
 	Flag& base_flag() override;
 	PositionList get_positions(const EditorGameBase&) const override;
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          TextToDraw draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 
 	void init(EditorGameBase&) override;
 	void cleanup(EditorGameBase&) override;

=== modified file 'src/economy/road.h'
--- src/economy/road.h	2016-08-04 15:49:05 +0000
+++ src/economy/road.h	2016-10-28 17:51:15 +0000
@@ -118,7 +118,11 @@
 	void init(EditorGameBase&) override;
 	void cleanup(EditorGameBase&) override;
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          TextToDraw draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 
 private:
 	void set_path(EditorGameBase&, const Path&);

=== modified file 'src/editor/CMakeLists.txt'
--- src/editor/CMakeLists.txt	2016-05-11 19:05:05 +0000
+++ src/editor/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -93,6 +93,7 @@
     base_macros
     base_scoped_timer
     graphic
+    graphic_playercolor
     graphic_surface
     io_filesystem
     logic

=== modified file 'src/editor/editorinteractive.cc'
--- src/editor/editorinteractive.cc	2016-09-25 18:46:29 +0000
+++ src/editor/editorinteractive.cc	2016-10-28 17:51:15 +0000
@@ -38,6 +38,7 @@
 #include "editor/ui_menus/tool_menu.h"
 #include "editor/ui_menus/toolsize_menu.h"
 #include "graphic/graphic.h"
+#include "graphic/playercolor.h"
 #include "logic/map.h"
 #include "logic/map_objects/tribes/tribes.h"
 #include "logic/map_objects/world/resource_description.h"
@@ -55,16 +56,6 @@
 #include "wui/interactive_base.h"
 
 namespace {
-
-static char const* const player_pictures[] = {"images/players/editor_player_01_starting_pos.png",
-                                              "images/players/editor_player_02_starting_pos.png",
-                                              "images/players/editor_player_03_starting_pos.png",
-                                              "images/players/editor_player_04_starting_pos.png",
-                                              "images/players/editor_player_05_starting_pos.png",
-                                              "images/players/editor_player_06_starting_pos.png",
-                                              "images/players/editor_player_07_starting_pos.png",
-                                              "images/players/editor_player_08_starting_pos.png"};
-
 using Widelands::Building;
 
 // Load all tribes from disk.
@@ -118,6 +109,9 @@
      toggle_buildhelp_(INIT_BUTTON("images/wui/menus/menu_toggle_buildhelp.png",
                                    "buildhelp",
                                    _("Show Building Spaces (on/off)"))),
+     reset_zoom_(INIT_BUTTON("images/wui/menus/menu_reset_zoom.png",
+                                   "reset_zoom",
+                                   _("Reset zoom"))),
      toggle_player_menu_(
         INIT_BUTTON("images/wui/editor/editor_menu_player_menu.png", "players", _("Players"))),
      undo_(INIT_BUTTON("images/wui/editor/editor_undo.png", "undo", _("Undo"))),
@@ -129,6 +123,8 @@
 	   boost::bind(&EditorInteractive::toolsize_menu_btn, this));
 	toggle_minimap_.sigclicked.connect(boost::bind(&EditorInteractive::toggle_minimap, this));
 	toggle_buildhelp_.sigclicked.connect(boost::bind(&EditorInteractive::toggle_buildhelp, this));
+	reset_zoom_.sigclicked.connect(
+	   [this] { zoom_around(1.f, Vector2f(get_w() / 2.f, get_h() / 2.f)); });
 	toggle_player_menu_.sigclicked.connect(boost::bind(&EditorInteractive::toggle_playermenu, this));
 	undo_.sigclicked.connect([this] { history_->undo_action(egbase().world()); });
 	redo_.sigclicked.connect([this] { history_->redo_action(egbase().world()); });
@@ -138,11 +134,15 @@
 	toolbar_.add(&toggle_main_menu_, UI::Align::kLeft);
 	toolbar_.add(&toggle_tool_menu_, UI::Align::kLeft);
 	toolbar_.add(&toggle_toolsize_menu_, UI::Align::kLeft);
+	toolbar_.add(&toggle_player_menu_, UI::Align::kLeft);
+	toolbar_.add_space(15);
 	toolbar_.add(&toggle_minimap_, UI::Align::kLeft);
 	toolbar_.add(&toggle_buildhelp_, UI::Align::kLeft);
-	toolbar_.add(&toggle_player_menu_, UI::Align::kLeft);
+	toolbar_.add(&reset_zoom_, UI::Align::kLeft);
+	toolbar_.add_space(15);
 	toolbar_.add(&undo_, UI::Align::kLeft);
 	toolbar_.add(&redo_, UI::Align::kLeft);
+	toolbar_.add_space(15);
 	toolbar_.add(&toggle_help_, UI::Align::kLeft);
 	adjust_toolbar_position();
 
@@ -160,6 +160,8 @@
 	      [this](const Widelands::NoteFieldResourceChanged& note) {
 		      update_resource_overlay(note, egbase().world(), mutable_field_overlay_manager());
 		   });
+
+	minimap_registry().minimap_type = MiniMapType::kStaticMap;
 }
 
 void EditorInteractive::register_overlays() {
@@ -167,13 +169,10 @@
 
 	//  Starting locations
 	Widelands::PlayerNumber const nr_players = map.get_nrplayers();
-	assert(nr_players <= MAX_PLAYERS);
+	assert(nr_players <= kMaxPlayers);
 	iterate_player_numbers(p, nr_players) {
 		if (Widelands::Coords const sp = map.get_starting_pos(p)) {
-			const Image* player_image = g_gr->images().get(player_pictures[p - 1]);
-			assert(player_image);
-			mutable_field_overlay_manager()->register_overlay(
-			   sp, player_image, 8, Point(player_image->width() / 2, STARTING_POS_HOTSPOT_Y));
+			tools_->set_starting_pos.set_starting_pos(*this, p, sp, &map);
 		}
 	}
 
@@ -543,10 +542,11 @@
 	tools_->current_pointer = &primary;
 	tools_->use_tool = which;
 
-	if (char const* const sel_pic = primary.get_sel(which))
+	if (const Image* sel_pic = primary.get_sel(which)) {
 		set_sel_picture(sel_pic);
-	else
+	} else {
 		unset_sel_picture();
+	}
 	set_sel_triangles(primary.operates_on_triangles());
 }
 
@@ -669,7 +669,7 @@
 		}
 
 		// Make sure that we will start at coordinates (0,0).
-		set_viewpoint(Point(0, 0), true);
+		set_viewpoint(Vector2f(0, 0), true);
 		set_sel_pos(Widelands::NodeAndTriangle<>(
 		   Widelands::Coords(0, 0),
 		   Widelands::TCoords<>(Widelands::Coords(0, 0), Widelands::TCoords<>::D)));

=== modified file 'src/editor/editorinteractive.h'
--- src/editor/editorinteractive.h	2016-09-25 18:46:29 +0000
+++ src/editor/editorinteractive.h	2016-10-28 17:51:15 +0000
@@ -189,6 +189,7 @@
 	UI::Button toggle_toolsize_menu_;
 	UI::Button toggle_minimap_;
 	UI::Button toggle_buildhelp_;
+	UI::Button reset_zoom_;
 	UI::Button toggle_player_menu_;
 	UI::Button undo_;
 	UI::Button redo_;

=== modified file 'src/editor/tools/decrease_height_tool.h'
--- src/editor/tools/decrease_height_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/decrease_height_tool.h	2016-10-28 17:51:15 +0000
@@ -41,8 +41,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor//fsel_editor_decrease_height.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor//fsel_editor_decrease_height.png");
 	}
 
 	int32_t get_change_by() const {

=== modified file 'src/editor/tools/decrease_resources_tool.h'
--- src/editor/tools/decrease_resources_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/decrease_resources_tool.h	2016-10-28 17:51:15 +0000
@@ -41,8 +41,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_decrease_resources.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_decrease_resources.png");
 	}
 
 	int32_t get_change_by() const {

=== modified file 'src/editor/tools/delete_bob_tool.h'
--- src/editor/tools/delete_bob_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/delete_bob_tool.h	2016-10-28 17:51:15 +0000
@@ -41,8 +41,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_delete.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_delete.png");
 	}
 };
 

=== modified file 'src/editor/tools/delete_immovable_tool.h'
--- src/editor/tools/delete_immovable_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/delete_immovable_tool.h	2016-10-28 17:51:15 +0000
@@ -41,8 +41,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_delete.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_delete.png");
 	}
 };
 

=== modified file 'src/editor/tools/draw_tool.h'
--- src/editor/tools/draw_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/draw_tool.h	2016-10-28 17:51:15 +0000
@@ -43,8 +43,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "EDITOR_DRAW_TOOL";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/novalue.png");
 	}
 
 	void add_action(EditorToolAction ac, EditorActionArgs& args);

=== modified file 'src/editor/tools/history.cc'
--- src/editor/tools/history.cc	2016-08-04 15:49:05 +0000
+++ src/editor/tools/history.cc	2016-10-28 17:51:15 +0000
@@ -94,7 +94,7 @@
 	   tool, static_cast<uint32_t>(ind), map, center, parent, tool.format_args(ind, parent));
 	if (draw && tool.is_undoable()) {
 		if (undo_stack_.empty() ||
-		    undo_stack_.front().tool.get_sel_impl() != std::string(draw_tool_.get_sel_impl())) {
+		    undo_stack_.front().tool.get_sel_impl() != draw_tool_.get_sel_impl()) {
 			EditorToolAction da(draw_tool_, EditorTool::First, map, center, parent,
 			                    draw_tool_.format_args(EditorTool::First, parent));
 

=== modified file 'src/editor/tools/increase_height_tool.h'
--- src/editor/tools/increase_height_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/increase_height_tool.h	2016-10-28 17:51:15 +0000
@@ -47,8 +47,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_increase_height.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_increase_height.png");
 	}
 
 	int32_t get_change_by() const {

=== modified file 'src/editor/tools/increase_resources_tool.h'
--- src/editor/tools/increase_resources_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/increase_resources_tool.h	2016-10-28 17:51:15 +0000
@@ -53,8 +53,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_increase_resources.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_increase_resources.png");
 	}
 
 	int32_t get_change_by() const {

=== modified file 'src/editor/tools/info_tool.h'
--- src/editor/tools/info_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/info_tool.h	2016-10-28 17:51:15 +0000
@@ -33,8 +33,8 @@
 	                          EditorActionArgs* args,
 	                          Widelands::Map* map) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_info.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_info.png");
 	}
 
 	bool has_size_one() const override {

=== modified file 'src/editor/tools/make_infrastructure_tool.h'
--- src/editor/tools/make_infrastructure_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/make_infrastructure_tool.h	2016-10-28 17:51:15 +0000
@@ -48,8 +48,8 @@
 	                          EditorActionArgs* args,
 	                          Widelands::Map* map) override;
 
-	const char* get_sel_impl() const override {
-		return "images/ui_basic/fsel.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/ui_basic/fsel.png");
 	}  //  Standard sel icon, most complex tool of all
 
 private:

=== modified file 'src/editor/tools/noise_height_tool.h'
--- src/editor/tools/noise_height_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/noise_height_tool.h	2016-10-28 17:51:15 +0000
@@ -44,8 +44,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_noise_height.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_noise_height.png");
 	}
 
 	Widelands::HeightInterval get_interval() const {

=== modified file 'src/editor/tools/place_bob_tool.h'
--- src/editor/tools/place_bob_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/place_bob_tool.h	2016-10-28 17:51:15 +0000
@@ -42,8 +42,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_place_bob.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_place_bob.png");
 	}
 };
 

=== modified file 'src/editor/tools/place_immovable_tool.h'
--- src/editor/tools/place_immovable_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/place_immovable_tool.h	2016-10-28 17:51:15 +0000
@@ -44,8 +44,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_place_immovable.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_place_immovable.png");
 	}
 };
 

=== modified file 'src/editor/tools/set_height_tool.h'
--- src/editor/tools/set_height_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_height_tool.h	2016-10-28 17:51:15 +0000
@@ -43,8 +43,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_set_height.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_set_height.png");
 	}
 
 	Widelands::HeightInterval get_interval() const {

=== modified file 'src/editor/tools/set_origin_tool.cc'
--- src/editor/tools/set_origin_tool.cc	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_origin_tool.cc	2016-10-28 17:51:15 +0000
@@ -30,9 +30,7 @@
                                                Widelands::Map* map) {
 	map->set_origin(center.node);
 	eia.map_changed(EditorInteractive::MapWas::kGloballyMutated);
-	eia.set_rel_viewpoint(Point(-(center.node.x * 2 + (center.node.y & 1)) * (kTriangleWidth / 2),
-	                            -center.node.y * kTriangleHeight),
-	                      true);
+	eia.center_view_on_coords(Widelands::Coords(0, 0));
 	return 0;
 }
 
@@ -46,8 +44,7 @@
 	   map->get_width() - 1 - center.node.x, map->get_height() - 1 - center.node.y);
 	map->set_origin(nc);
 	eia.map_changed(EditorInteractive::MapWas::kGloballyMutated);
-	eia.set_rel_viewpoint(
-	   Point(-(nc.x * 2 + (nc.y & 1)) * (kTriangleWidth / 2), -nc.y * kTriangleHeight), true);
+	eia.center_view_on_coords(Widelands::Coords(0, 0));
 	return 0;
 }
 

=== modified file 'src/editor/tools/set_origin_tool.h'
--- src/editor/tools/set_origin_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_origin_tool.h	2016-10-28 17:51:15 +0000
@@ -42,8 +42,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/ui_basic/fsel.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/ui_basic/fsel.png");
 	}
 
 	bool has_size_one() const override {

=== modified file 'src/editor/tools/set_port_space_tool.h'
--- src/editor/tools/set_port_space_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_port_space_tool.h	2016-10-28 17:51:15 +0000
@@ -43,8 +43,8 @@
 	                         EditorActionArgs* args,
 	                         Widelands::Map* map) override;
 
-	char const* get_sel_impl() const override {
-		return FSEL_EUPS_FILENAME;
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get(FSEL_EUPS_FILENAME);
 	}
 };
 
@@ -65,8 +65,8 @@
 	                         EditorActionArgs* args,
 	                         Widelands::Map* map) override;
 
-	char const* get_sel_impl() const override {
-		return FSEL_ESPS_FILENAME;
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get(FSEL_ESPS_FILENAME);
 	}
 };
 

=== modified file 'src/editor/tools/set_resources_tool.h'
--- src/editor/tools/set_resources_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_resources_tool.h	2016-10-28 17:51:15 +0000
@@ -46,8 +46,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/wui/editor/fsel_editor_set_resources.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/wui/editor/fsel_editor_set_resources.png");
 	}
 
 	Widelands::ResourceAmount get_set_to() const {

=== modified file 'src/editor/tools/set_starting_pos_tool.cc'
--- src/editor/tools/set_starting_pos_tool.cc	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_starting_pos_tool.cc	2016-10-28 17:51:15 +0000
@@ -22,28 +22,8 @@
 #include "editor/editorinteractive.h"
 #include "editor/tools/tool.h"
 #include "graphic/graphic.h"
+#include "graphic/playercolor.h"
 #include "logic/map.h"
-#include "wui/field_overlay_manager.h"
-
-namespace {
-static char const* const player_pictures[] = {"images/players/editor_player_01_starting_pos.png",
-                                              "images/players/editor_player_02_starting_pos.png",
-                                              "images/players/editor_player_03_starting_pos.png",
-                                              "images/players/editor_player_04_starting_pos.png",
-                                              "images/players/editor_player_05_starting_pos.png",
-                                              "images/players/editor_player_06_starting_pos.png",
-                                              "images/players/editor_player_07_starting_pos.png",
-                                              "images/players/editor_player_08_starting_pos.png"};
-static char const* const player_pictures_small[] = {
-   "images/players/fsel_editor_set_player_01_pos.png",
-   "images/players/fsel_editor_set_player_02_pos.png",
-   "images/players/fsel_editor_set_player_03_pos.png",
-   "images/players/fsel_editor_set_player_04_pos.png",
-   "images/players/fsel_editor_set_player_05_pos.png",
-   "images/players/fsel_editor_set_player_06_pos.png",
-   "images/players/fsel_editor_set_player_07_pos.png",
-   "images/players/fsel_editor_set_player_08_pos.png"};
-}  // namespace
 
 // global variable to pass data from callback to class
 static int32_t current_player_;
@@ -77,9 +57,8 @@
 }
 
 EditorSetStartingPosTool::EditorSetStartingPosTool()
-   : EditorTool(*this, *this, false), current_sel_pic_(nullptr) {
+   : EditorTool(*this, *this, false), overlay_ids_(kMaxPlayers, 0) {
 	current_player_ = 1;
-	fsel_picsname_ = "images/players/fsel_editor_set_player_01_pos.png";
 }
 
 int32_t EditorSetStartingPosTool::handle_click_impl(const Widelands::World&,
@@ -100,34 +79,42 @@
 			current_player_ = 1;
 		}
 
-		Widelands::Coords const old_sp = map->get_starting_pos(current_player_);
-
-		const Image* player_image = g_gr->images().get(player_pictures[current_player_ - 1]);
-		assert(player_image);
-
 		//  check if field is valid
 		if (editor_tool_set_starting_pos_callback(map->get_fcoords(center.node), *map)) {
-			FieldOverlayManager* overlay_manager = eia.mutable_field_overlay_manager();
-			//  remove old overlay if any
-			overlay_manager->remove_overlay(old_sp, player_image);
-
-			//  add new overlay
-			overlay_manager->register_overlay(
-			   center.node, player_image, 4, Point(player_image->width() / 2, STARTING_POS_HOTSPOT_Y));
-
-			//  set new player pos
-			map->set_starting_pos(current_player_, center.node);
+			set_starting_pos(eia, current_player_, center.node, map);
 		}
 	}
 	return 1;
 }
 
+void EditorSetStartingPosTool::set_starting_pos(EditorInteractive& eia,
+                                                Widelands::PlayerNumber plnum,
+                                                const Widelands::Coords& c,
+                                                Widelands::Map* map) {
+	FieldOverlayManager* overlay_manager = eia.mutable_field_overlay_manager();
+	//  remove old overlay if any
+	overlay_manager->remove_overlay(overlay_ids_.at(plnum - 1));
+
+	//  add new overlay
+	FieldOverlayManager::OverlayId overlay_id = overlay_manager->next_overlay_id();
+	overlay_ids_[plnum - 1] = overlay_id;
+
+	const Image* player_image =
+	   playercolor_image(plnum - 1, g_gr->images().get("images/players/player_position.png"),
+	                     g_gr->images().get("images/players/player_position_pc.png"));
+	assert(player_image);
+
+	overlay_manager->register_overlay(
+	   c, player_image, 8, Vector2i(player_image->width() / 2, STARTING_POS_HOTSPOT_Y), overlay_id);
+
+	//  set new player pos
+	map->set_starting_pos(plnum, c);
+}
+
 Widelands::PlayerNumber EditorSetStartingPosTool::get_current_player() const {
 	return current_player_;
 }
 
 void EditorSetStartingPosTool::set_current_player(int32_t const i) {
 	current_player_ = i;
-	fsel_picsname_ = player_pictures_small[current_player_ - 1];
-	current_sel_pic_ = fsel_picsname_;
 }

=== modified file 'src/editor/tools/set_starting_pos_tool.h'
--- src/editor/tools/set_starting_pos_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_starting_pos_tool.h	2016-10-28 17:51:15 +0000
@@ -20,8 +20,12 @@
 #ifndef WL_EDITOR_TOOLS_SET_STARTING_POS_TOOL_H
 #define WL_EDITOR_TOOLS_SET_STARTING_POS_TOOL_H
 
+#include <vector>
+
 #include "editor/tools/tool.h"
+#include "graphic/playercolor.h"
 #include "logic/widelands.h"
+#include "wui/field_overlay_manager.h"
 
 // How much place should be left around a player position
 // where no other player can start
@@ -37,8 +41,10 @@
 	                          EditorInteractive&,
 	                          EditorActionArgs*,
 	                          Widelands::Map*) override;
-	char const* get_sel_impl() const override {
-		return current_sel_pic_;
+	const Image* get_sel_impl() const override {
+		return playercolor_image(get_current_player() - 1,
+		                         g_gr->images().get("images/players/player_position_menu.png"),
+		                         g_gr->images().get("images/players/player_position_menu_pc.png"));
 	}
 
 	Widelands::PlayerNumber get_current_player() const;
@@ -46,10 +52,13 @@
 	bool has_size_one() const override {
 		return true;
 	}
+	void set_starting_pos(EditorInteractive& eia,
+	                      Widelands::PlayerNumber plnum,
+	                      const Widelands::Coords& c,
+	                      Widelands::Map* map);
 
 private:
-	char const* fsel_picsname_;
-	char const* current_sel_pic_;
+	std::vector<FieldOverlayManager::OverlayId> overlay_ids_;
 };
 
 int32_t editor_tool_set_starting_pos_callback(const Widelands::TCoords<Widelands::FCoords>& c,

=== modified file 'src/editor/tools/set_terrain_tool.h'
--- src/editor/tools/set_terrain_tool.h	2016-08-04 15:49:05 +0000
+++ src/editor/tools/set_terrain_tool.h	2016-10-28 17:51:15 +0000
@@ -41,8 +41,8 @@
 
 	EditorActionArgs format_args_impl(EditorInteractive& parent) override;
 
-	char const* get_sel_impl() const override {
-		return "images/ui_basic/fsel.png";
+	const Image* get_sel_impl() const override {
+		return g_gr->images().get("images/ui_basic/fsel.png");
 	}
 	bool operates_on_triangles() const override {
 		return true;

=== modified file 'src/editor/tools/tool.h'
--- src/editor/tools/tool.h	2016-09-10 16:50:51 +0000
+++ src/editor/tools/tool.h	2016-10-28 17:51:15 +0000
@@ -23,6 +23,8 @@
 #define MAX_TOOL_AREA 9
 
 #include "base/macros.h"
+#include "graphic/graphic.h"
+#include "graphic/image.h"
 #include "editor/tools/action_args.h"
 #include "logic/widelands_geometry.h"
 
@@ -67,7 +69,7 @@
 		   .handle_undo_impl(world, center, parent, args, map);
 	}
 
-	const char* get_sel(const ToolIndex i) {
+	const Image* get_sel(const ToolIndex i) {
 		return (i == First ? *this : i == Second ? second_ : third_).get_sel_impl();
 	}
 
@@ -96,7 +98,7 @@
 	                                 Widelands::Map*) {
 		return 0;
 	}  // non unduable tools don't need to implement this.
-	virtual const char* get_sel_impl() const = 0;
+	virtual const Image* get_sel_impl() const = 0;
 	virtual bool operates_on_triangles() const {
 		return false;
 	}

=== modified file 'src/editor/ui_menus/main_menu_load_or_save_map.cc'
--- src/editor/ui_menus/main_menu_load_or_save_map.cc	2016-08-04 18:09:55 +0000
+++ src/editor/ui_menus/main_menu_load_or_save_map.cc	2016-10-28 17:51:15 +0000
@@ -89,7 +89,7 @@
 	vbox->add(show_mapnames_, UI::Align::kLeft, true);
 
 	/** TRANSLATORS: Checkbox title. If this checkbox is enabled, map names aren't translated. */
-	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Point(0, 0), _("Show original map names"));
+	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Vector2i(0, 0), _("Show original map names"));
 	cb_dont_localize_mapnames_->set_state(false);
 	vbox->add_space(2 * padding_);
 	vbox->add(cb_dont_localize_mapnames_, UI::Align::kLeft, true);

=== modified file 'src/editor/ui_menus/main_menu_map_options.cc'
--- src/editor/ui_menus/main_menu_map_options.cc	2016-08-07 10:10:18 +0000
+++ src/editor/ui_menus/main_menu_map_options.cc	2016-10-28 17:51:15 +0000
@@ -227,7 +227,7 @@
                                           std::string tag,
                                           std::string displ_name) {
 	UI::Box* box = new UI::Box(parent, 0, 0, UI::Box::Horizontal, max_w_, checkbox_space_, 0);
-	UI::Checkbox* cb = new UI::Checkbox(box, Point(0, 0), displ_name);
+	UI::Checkbox* cb = new UI::Checkbox(box, Vector2i(0, 0), displ_name);
 	box->add(cb, UI::Align::kLeft, true);
 	box->add_space(checkbox_space_);
 	parent->add(box, UI::Align::kLeft);

=== modified file 'src/editor/ui_menus/main_menu_random_map.cc'
--- src/editor/ui_menus/main_menu_random_map.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/main_menu_random_map.cc	2016-10-28 17:51:15 +0000
@@ -33,7 +33,6 @@
 #include "editor/map_generator.h"
 #include "graphic/font_handler1.h"
 #include "graphic/graphic.h"
-#include "logic/constants.h"
 #include "logic/editor_game_base.h"
 #include "logic/map.h"
 #include "logic/map_objects/world/world.h"
@@ -41,6 +40,11 @@
 #include "ui_basic/messagebox.h"
 #include "ui_basic/progresswindow.h"
 
+namespace {
+// The map generator can't find starting positions for too many players
+constexpr uint8_t kMaxMapgenPlayers = 8;
+} // namespace
+
 using namespace Widelands;
 
 MainMenuNewRandomMap::MainMenuNewRandomMap(EditorInteractive& parent)
@@ -184,7 +188,7 @@
                 resources_label_.get_h(),
                 (boost::format(_("%i %%")) % mountainsval_).str(),
                 UI::Align::kHCenter),
-     island_mode_(&box_, Point(0, 0), _("Island mode")),
+     island_mode_(&box_, Vector2i(0, 0), _("Island mode")),
      // Geeky stuff
      map_number_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_),
      map_number_label_(&map_number_box_, 0, 0, _("Random Number:")),
@@ -406,7 +410,7 @@
 	case ButtonId::kMapSize:
 		// Restrict maximum players according to map size, but allow at least 2 players.
 		max_players_ = std::min(
-		   static_cast<size_t>(MAX_PLAYERS),
+			static_cast<size_t>(kMaxMapgenPlayers),
 		   (find_dimension_index(width_.get_value()) + find_dimension_index(height_.get_value())) /
 		         2 +
 		      2);
@@ -442,7 +446,7 @@
 	case ButtonId::kNone:
 		// Make sure that all conditions are met
 		max_players_ = std::min(
-		   static_cast<size_t>(MAX_PLAYERS),
+			static_cast<size_t>(kMaxMapgenPlayers),
 		   (find_dimension_index(width_.get_value()) + find_dimension_index(height_.get_value())) /
 		         2 +
 		      2);

=== modified file 'src/editor/ui_menus/main_menu_save_map.h'
--- src/editor/ui_menus/main_menu_save_map.h	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/main_menu_save_map.h	2016-10-28 17:51:15 +0000
@@ -40,7 +40,7 @@
 
 private:
 	EditorInteractive& eia();
-	void clicked_ok();
+	void clicked_ok() override;
 	void clicked_make_directory();
 	void clicked_edit_options();
 	void clicked_item();

=== modified file 'src/editor/ui_menus/player_menu.cc'
--- src/editor/ui_menus/player_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/player_menu.cc	2016-10-28 17:51:15 +0000
@@ -26,7 +26,6 @@
 #include "editor/editorinteractive.h"
 #include "editor/tools/set_starting_pos_tool.h"
 #include "graphic/graphic.h"
-#include "logic/constants.h"
 #include "logic/map.h"
 #include "logic/map_objects/tribes/tribes.h"
 #include "logic/map_objects/tribes/warehouse.h"
@@ -36,26 +35,6 @@
 #include "ui_basic/textarea.h"
 #include "wui/field_overlay_manager.h"
 
-namespace {
-static char const* const player_pictures[] = {"images/players/editor_player_01_starting_pos.png",
-                                              "images/players/editor_player_02_starting_pos.png",
-                                              "images/players/editor_player_03_starting_pos.png",
-                                              "images/players/editor_player_04_starting_pos.png",
-                                              "images/players/editor_player_05_starting_pos.png",
-                                              "images/players/editor_player_06_starting_pos.png",
-                                              "images/players/editor_player_07_starting_pos.png",
-                                              "images/players/editor_player_08_starting_pos.png"};
-static char const* const player_pictures_small[] = {
-   "images/players/fsel_editor_set_player_01_pos.png",
-   "images/players/fsel_editor_set_player_02_pos.png",
-   "images/players/fsel_editor_set_player_03_pos.png",
-   "images/players/fsel_editor_set_player_04_pos.png",
-   "images/players/fsel_editor_set_player_05_pos.png",
-   "images/players/fsel_editor_set_player_06_pos.png",
-   "images/players/fsel_editor_set_player_07_pos.png",
-   "images/players/fsel_editor_set_player_08_pos.png"};
-}  // namespace
-
 #define UNDEFINED_TRIBE_NAME "<undefined>"
 
 inline EditorInteractive& EditorPlayerMenu::eia() {
@@ -72,8 +51,7 @@
                  20,
                  g_gr->images().get("images/ui_basic/but1.png"),
                  g_gr->images().get("images/ui_basic/scrollbar_up.png"),
-                 _("Add player"),
-                 parent.egbase().map().get_nrplayers() < MAX_PLAYERS),
+                 _("Add player")),
      remove_last_player_(this,
                          "remove_last_player",
                          5,
@@ -82,9 +60,9 @@
                          20,
                          g_gr->images().get("images/ui_basic/but1.png"),
                          g_gr->images().get("images/ui_basic/scrollbar_down.png"),
-                         _("Remove last player"),
-                         1 < parent.egbase().map().get_nrplayers()),
+                         _("Remove last player")),
      tribenames_(eia().egbase().tribes().get_all_tribenames()) {
+	add_player_.set_enabled(parent.egbase().map().get_nrplayers() < kMaxPlayers);
 	add_player_.sigclicked.connect(
 	   boost::bind(&EditorPlayerMenu::clicked_add_player, boost::ref(*this)));
 	remove_last_player_.sigclicked.connect(
@@ -97,17 +75,17 @@
 	set_inner_size(375, 135);
 
 	UI::Textarea* ta = new UI::Textarea(this, 0, 0, _("Number of Players"));
-	ta->set_pos(Point((get_inner_w() - ta->get_w()) / 2, posy + 5));
+	ta->set_pos(Vector2i((get_inner_w() - ta->get_w()) / 2, posy + 5));
 	posy += spacing + width;
 
 	nr_of_players_ta_ = new UI::Textarea(this, 0, 0, "5");
-	nr_of_players_ta_->set_pos(Point((get_inner_w() - nr_of_players_ta_->get_w()) / 2, posy + 5));
+	nr_of_players_ta_->set_pos(Vector2i((get_inner_w() - nr_of_players_ta_->get_w()) / 2, posy + 5));
 
 	posy += width + spacing + spacing;
 
 	posy_ = posy;
 
-	for (Widelands::PlayerNumber i = 0; i < MAX_PLAYERS; ++i) {
+	for (Widelands::PlayerNumber i = 0; i < kMaxPlayers; ++i) {
 		plr_names_[i] = nullptr;
 		plr_set_pos_buts_[i] = nullptr;
 		plr_set_tribes_buts_[i] = nullptr;
@@ -150,7 +128,7 @@
 	}
 
 	//  Now remove all the unneeded stuff.
-	for (Widelands::PlayerNumber i = nr_players; i < MAX_PLAYERS; ++i) {
+	for (Widelands::PlayerNumber i = nr_players; i < kMaxPlayers; ++i) {
 		delete plr_names_[i];
 		plr_names_[i] = nullptr;
 		delete plr_set_pos_buts_[i];
@@ -205,19 +183,23 @@
 			plr_set_pos_buts_[p - 1]->sigclicked.connect(
 			   boost::bind(&EditorPlayerMenu::set_starting_pos_clicked, boost::ref(*this), p));
 		}
-		const Image* player_image = g_gr->images().get(player_pictures_small[p - 1]);
+		const Image* player_image =
+		   playercolor_image(p - 1, g_gr->images().get("images/players/player_position_menu.png"),
+		                     g_gr->images().get("images/players/player_position_menu_pc.png"));
 		assert(player_image);
 
 		plr_set_pos_buts_[p - 1]->set_pic(player_image);
 		posy += size + spacing;
 	}
+	add_player_.set_enabled(nr_players < kMaxPlayers);
+	remove_last_player_.set_enabled(1 < nr_players);
 	set_inner_size(get_inner_w(), posy + spacing);
 }
 
 void EditorPlayerMenu::clicked_add_player() {
 	Widelands::Map& map = eia().egbase().map();
 	Widelands::PlayerNumber const nr_players = map.get_nrplayers() + 1;
-	assert(nr_players <= MAX_PLAYERS);
+	assert(nr_players <= kMaxPlayers);
 	map.set_nrplayers(nr_players);
 	{                             //  register new default name for this players
 		assert(nr_players <= 99);  //  2 decimal digits
@@ -228,7 +210,7 @@
 	}
 	map.set_scenario_player_tribe(nr_players, tribenames_[0]);
 	eia().set_need_save(true);
-	add_player_.set_enabled(nr_players < MAX_PLAYERS);
+	add_player_.set_enabled(nr_players < kMaxPlayers);
 	remove_last_player_.set_enabled(true);
 	update();
 }
@@ -243,7 +225,9 @@
 	if (!menu.is_player_tribe_referenced(old_nr_players)) {
 		if (const Widelands::Coords sp = map.get_starting_pos(old_nr_players)) {
 			//  Remove starting position marker.
-			const Image* player_image = g_gr->images().get(player_pictures[old_nr_players - 1]);
+			const Image* player_image = playercolor_image(
+			   old_nr_players - 1, g_gr->images().get("images/players/player_position.png"),
+			   g_gr->images().get("images/players/player_position_pc.png"));
 			assert(player_image);
 			menu.mutable_field_overlay_manager()->remove_overlay(sp, player_image);
 		}
@@ -252,9 +236,8 @@
 			set_starting_pos_clicked(nr_players);
 	}
 	map.set_nrplayers(nr_players);
-	add_player_.set_enabled(nr_players < MAX_PLAYERS);
+	add_player_.set_enabled(nr_players < kMaxPlayers);
 	remove_last_player_.set_enabled(1 < nr_players);
-
 	update();
 	// TODO(SirVer): Take steps when the player is referenced someplace. Not
 	// TODO(SirVer): currently possible in the editor though.
@@ -297,7 +280,7 @@
 	//  jump to the current node
 	Widelands::Map& map = menu.egbase().map();
 	if (Widelands::Coords const sp = map.get_starting_pos(n))
-		menu.move_view_to(sp);
+		menu.center_view_on_coords(sp);
 
 	//  select tool set mplayer
 	menu.select_tool(menu.tools()->set_starting_pos, EditorTool::First);
@@ -375,7 +358,9 @@
 
 		// Remove the player overlay from this starting pos.
 		// A HQ is overlay enough
-		const Image* player_image = g_gr->images().get(player_pictures[n - 1]);
+		const Image* player_image =
+		   playercolor_image(n - 1, g_gr->images().get("images/players/player_position.png"),
+		                     g_gr->images().get("images/players/player_position_pc.png"));
 		assert(player_image);
 		overlay_manager->remove_overlay(start_pos, player_image);
 	}

=== modified file 'src/editor/ui_menus/player_menu.h'
--- src/editor/ui_menus/player_menu.h	2016-09-10 16:50:51 +0000
+++ src/editor/ui_menus/player_menu.h	2016-10-28 17:51:15 +0000
@@ -25,7 +25,7 @@
 #include <string>
 #include <vector>
 
-#include "logic/constants.h"
+#include "graphic/playercolor.h"
 #include "logic/widelands.h"
 #include "ui_basic/button.h"
 #include "ui_basic/unique_window.h"
@@ -47,15 +47,15 @@
 	EditorInteractive& eia();
 	UI::UniqueWindow::Registry allow_buildings_menu_;
 	UI::Textarea* nr_of_players_ta_;
-	UI::EditBox* plr_names_[MAX_PLAYERS];
+	UI::EditBox* plr_names_[kMaxPlayers];
 	UI::Button add_player_, remove_last_player_;
-	UI::Button* plr_make_infrastructure_buts_[MAX_PLAYERS], *plr_set_pos_buts_[MAX_PLAYERS],
-	   *plr_set_tribes_buts_[MAX_PLAYERS];
+	UI::Button* plr_make_infrastructure_buts_[kMaxPlayers], *plr_set_pos_buts_[kMaxPlayers],
+	   *plr_set_tribes_buts_[kMaxPlayers];
 
 	std::vector<std::string> tribenames_;
 
 	/// List of the tribes currently selected for all players
-	std::string selected_tribes_[MAX_PLAYERS];
+	std::string selected_tribes_[kMaxPlayers];
 
 	int32_t posy_;
 

=== modified file 'src/editor/ui_menus/tool_change_resources_options_menu.cc'
--- src/editor/ui_menus/tool_change_resources_options_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_change_resources_options_menu.cc	2016-10-28 17:51:15 +0000
@@ -100,7 +100,7 @@
 
 	for (Widelands::DescriptionIndex i = 0; i < nr_resources; ++i) {
 		const Widelands::ResourceDescription& resource = *world.get_resource(i);
-		radiogroup_.add_button(&resources_box_, Point(0, 0),
+		radiogroup_.add_button(&resources_box_, Vector2i(0, 0),
 		                       g_gr->images().get(resource.representative_image()),
 		                       resource.descname());
 		resources_box_.add(radiogroup_.get_first_button(), UI::Align::kLeft, false, true);

=== modified file 'src/editor/ui_menus/tool_menu.cc'
--- src/editor/ui_menus/tool_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_menu.cc	2016-10-28 17:51:15 +0000
@@ -45,8 +45,8 @@
    : UI::UniqueWindow(&parent, "tool_menu", &registry, 350, 400, _("Tools")) {
 
 #define spacing 5
-	Point const offs(spacing, spacing);
-	Point pos = offs;
+	Vector2i const offs(spacing, spacing);
+	Vector2i pos = offs;
 	int32_t const width = 34;
 	int32_t const height = 34;
 

=== modified file 'src/editor/ui_menus/tool_place_bob_options_menu.cc'
--- src/editor/ui_menus/tool_place_bob_options_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_place_bob_options_menu.cc	2016-10-28 17:51:15 +0000
@@ -64,14 +64,14 @@
 	}
 
 	const Image* tab_icon = g_gr->images().get("images/ui_basic/list_first_entry.png");
-	Point pos;
+	Vector2i pos;
 	uint32_t cur_x = bobs_in_row;
 	int32_t i = 0;
 	UI::Box* box = nullptr;
 	while (i < nr_bobs) {
 		if (cur_x == bobs_in_row) {
 			cur_x = 0;
-			pos = Point(5, 15);
+			pos = Vector2i(5, 15);
 			box = new UI::Box(&tabpanel_, 0, 0, UI::Box::Horizontal);
 			tabpanel_.add("icons", tab_icon, box);
 		}

=== modified file 'src/editor/ui_menus/tool_place_immovable_options_menu.cc'
--- src/editor/ui_menus/tool_place_immovable_options_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_place_immovable_options_menu.cc	2016-10-28 17:51:15 +0000
@@ -39,7 +39,7 @@
 
 UI::Checkbox* create_immovable_checkbox(UI::Panel* parent, const ImmovableDescr& immovable_descr) {
 	const Image* pic = immovable_descr.representative_image();
-	UI::Checkbox* cb = new UI::Checkbox(parent, Point(0, 0), pic, immovable_descr.descname());
+	UI::Checkbox* cb = new UI::Checkbox(parent, Vector2i(0, 0), pic, immovable_descr.descname());
 	const int kMinClickableArea = 24;
 	cb->set_desired_size(std::max<int>(pic->width(), kMinClickableArea),
 	                     std::max<int>(pic->height(), kMinClickableArea));

=== modified file 'src/editor/ui_menus/tool_set_terrain_options_menu.cc'
--- src/editor/ui_menus/tool_set_terrain_options_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/tool_set_terrain_options_menu.cc	2016-10-28 17:51:15 +0000
@@ -53,10 +53,10 @@
 	// Blit the main terrain image
 	const Image& terrain_texture = terrain_descr.get_texture(0);
 	Texture* texture = new Texture(terrain_texture.width(), terrain_texture.height());
-	texture->blit(Rect(0, 0, terrain_texture.width(), terrain_texture.height()), terrain_texture,
-	              Rect(0, 0, terrain_texture.width(), terrain_texture.height()), 1.,
+	texture->blit(Rectf(0, 0, terrain_texture.width(), terrain_texture.height()), terrain_texture,
+	              Rectf(0, 0, terrain_texture.width(), terrain_texture.height()), 1.,
 	              BlendMode::UseAlpha);
-	Point pt(1, terrain_texture.height() - kSmallPicSize - 1);
+	Vector2i pt(1, terrain_texture.height() - kSmallPicSize - 1);
 
 	// Collect tooltips and blit small icons representing "is" values
 	for (const TerrainDescription::Type& terrain_type : terrain_descr.get_types()) {
@@ -64,9 +64,9 @@
 		                terrain_descr.custom_tooltips().end());
 		tooltips.push_back(terrain_type.descname);
 
-		texture->blit(Rect(pt.x, pt.y, terrain_type.icon->width(), terrain_type.icon->height()),
+		texture->blit(Rectf(pt.x, pt.y, terrain_type.icon->width(), terrain_type.icon->height()),
 		              *terrain_type.icon,
-		              Rect(0, 0, terrain_type.icon->width(), terrain_type.icon->height()), 1.,
+		              Rectf(0, 0, terrain_type.icon->width(), terrain_type.icon->height()), 1.,
 		              BlendMode::UseAlpha);
 		pt.x += kSmallPicSize + 1;
 	}
@@ -79,7 +79,7 @@
 	                               .str();
 
 	std::unique_ptr<const Image>& image = offscreen_images->back();
-	UI::Checkbox* cb = new UI::Checkbox(parent, Point(0, 0), image.get(), tooltip);
+	UI::Checkbox* cb = new UI::Checkbox(parent, Vector2i(0, 0), image.get(), tooltip);
 	cb->set_desired_size(image->width() + 1, image->height() + 1);
 	return cb;
 }

=== modified file 'src/editor/ui_menus/toolsize_menu.cc'
--- src/editor/ui_menus/toolsize_menu.cc	2016-08-04 15:49:05 +0000
+++ src/editor/ui_menus/toolsize_menu.cc	2016-10-28 17:51:15 +0000
@@ -46,9 +46,7 @@
                20,
                20,
                g_gr->images().get("images/ui_basic/but0.png"),
-               g_gr->images().get("images/ui_basic/scrollbar_up.png"),
-               std::string(),
-               parent.get_sel_radius() < MAX_TOOL_AREA),
+               g_gr->images().get("images/ui_basic/scrollbar_up.png")),
      decrease_(this,
                "decr",
                get_inner_w() / 2 + 10,
@@ -56,9 +54,7 @@
                20,
                20,
                g_gr->images().get("images/ui_basic/but0.png"),
-               g_gr->images().get("images/ui_basic/scrollbar_down.png"),
-               std::string(),
-               0 < parent.get_sel_radius()),
+               g_gr->images().get("images/ui_basic/scrollbar_down.png")),
      value_(0) {
 	increase_.sigclicked.connect(
 	   boost::bind(&EditorToolsizeMenu::increase_radius, boost::ref(*this)));

=== modified file 'src/game_io/CMakeLists.txt'
--- src/game_io/CMakeLists.txt	2016-01-20 20:12:00 +0000
+++ src/game_io/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -30,6 +30,7 @@
     build_info
     economy
     graphic
+    graphic_image_io
     graphic_minimap_renderer
     io_fileread
     io_filesystem
@@ -42,4 +43,5 @@
     scripting_lua_table
     wui
     wui_mapview_pixelfunctions
+    wui_mapview
 )

=== modified file 'src/game_io/game_interactive_player_packet.cc'
--- src/game_io/game_interactive_player_packet.cc	2016-08-04 15:49:05 +0000
+++ src/game_io/game_interactive_player_packet.cc	2016-10-28 17:51:15 +0000
@@ -30,7 +30,22 @@
 
 namespace Widelands {
 
-constexpr uint16_t kCurrentPacketVersion = 3;
+namespace {
+
+constexpr uint16_t kCurrentPacketVersion = 4;
+
+void load_landmarks_pre_zoom(FileRead* fr, InteractiveBase* ibase) {
+	size_t no_of_landmarks = fr->unsigned_8();
+	for (size_t i = 0; i < no_of_landmarks; ++i) {
+		uint8_t set = fr->unsigned_8();
+		QuickNavigation::View view = {Vector2f(fr->signed_32(), fr->signed_32()), 1.f};
+		if (set > 0) {
+			ibase->set_landmark(i, view);
+		}
+	}
+}
+
+}  // namespace
 
 void GameInteractivePlayerPacket::read(FileSystem& fs, Game& game, MapObjectLoader*) {
 	try {
@@ -55,12 +70,19 @@
 				if (player_number > max)
 					throw GameDataError("The game has no players!");
 			}
-			int32_t const x = fr.unsigned_16();
-			int32_t const y = fr.unsigned_16();
+			float viewpoint_x, viewpoint_y;
+			if (packet_version <= 3) {
+				viewpoint_x = fr.unsigned_16();
+				viewpoint_y = fr.unsigned_16();
+			} else {
+				viewpoint_x = fr.float_32();
+				viewpoint_y = fr.float_32();
+			}
+
 			uint32_t const display_flags = fr.unsigned_32();
 
 			if (InteractiveBase* const ibase = game.get_ibase()) {
-				ibase->set_viewpoint(Point(x, y), true);
+				ibase->set_viewpoint(Vector2f(viewpoint_x, viewpoint_y), true);
 
 				uint32_t const loaded_df =
 				   InteractiveBase::dfShowCensus | InteractiveBase::dfShowStatistics;
@@ -73,14 +95,19 @@
 			}
 
 			// Map landmarks
-			if (packet_version >= 3) {
-				if (InteractiveBase* const ibase = game.get_ibase()) {
+			if (InteractiveBase* const ibase = game.get_ibase()) {
+				if (packet_version == 3) {
+					load_landmarks_pre_zoom(&fr, ibase);
+				} else if (packet_version >= 4) {
 					size_t no_of_landmarks = fr.unsigned_8();
 					for (size_t i = 0; i < no_of_landmarks; ++i) {
 						uint8_t set = fr.unsigned_8();
-						Point landmark(fr.signed_32(), fr.signed_32());
+						const float x = fr.float_32();
+						const float y = fr.float_32();
+						const float zoom = fr.float_32();
+						QuickNavigation::View view = {Vector2f(x, y), zoom};
 						if (set > 0) {
-							ibase->set_landmark(i, landmark);
+							ibase->set_landmark(i, view);
 						}
 					}
 				}
@@ -109,12 +136,14 @@
 	fw.unsigned_8(iplayer ? iplayer->player_number() : 1);
 
 	// Map Position
+#ifndef NDEBUG
 	if (ibase) {
 		assert(0 <= ibase->get_viewpoint().x);
 		assert(0 <= ibase->get_viewpoint().y);
 	}
-	fw.unsigned_16(ibase ? ibase->get_viewpoint().x : 0);
-	fw.unsigned_16(ibase ? ibase->get_viewpoint().y : 0);
+#endif
+	fw.float_32(ibase ? ibase->get_viewpoint().x : 0.f);
+	fw.float_32(ibase ? ibase->get_viewpoint().y : 0.f);
 
 	// Display flags
 	fw.unsigned_32(ibase ? ibase->get_display_flags() : 0);
@@ -124,8 +153,9 @@
 	fw.unsigned_8(landmarks.size());
 	for (const QuickNavigation::Landmark& landmark : landmarks) {
 		fw.unsigned_8(landmark.set ? 1 : 0);
-		fw.signed_32(landmark.point.x);
-		fw.signed_32(landmark.point.y);
+		fw.float_32(landmark.view.viewpoint.x);
+		fw.float_32(landmark.view.viewpoint.y);
+		fw.float_32(landmark.view.zoom);
 	}
 
 	fw.write(fs, "binary/interactive_player");

=== modified file 'src/game_io/game_player_info_packet.cc'
--- src/game_io/game_player_info_packet.cc	2016-08-04 15:49:05 +0000
+++ src/game_io/game_player_info_packet.cc	2016-10-28 17:51:15 +0000
@@ -21,7 +21,6 @@
 
 #include "io/fileread.h"
 #include "io/filewrite.h"
-#include "logic/constants.h"
 #include "logic/game.h"
 #include "logic/game_data_error.h"
 #include "logic/map_objects/tribes/tribe_descr.h"
@@ -46,9 +45,9 @@
 					bool const see_all = fr.unsigned_8();
 
 					int32_t const plnum = fr.unsigned_8();
-					if (plnum < 1 || MAX_PLAYERS < plnum)
+					if (plnum < 1 || kMaxPlayers < plnum)
 						throw GameDataError(
-						   "player number (%i) is out of range (1 .. %u)", plnum, MAX_PLAYERS);
+						   "player number (%i) is out of range (1 .. %u)", plnum, kMaxPlayers);
 
 					Widelands::TeamNumber team = fr.unsigned_8();
 					char const* const tribe_name = fr.c_string();

=== modified file 'src/game_io/game_preload_packet.cc'
--- src/game_io/game_preload_packet.cc	2016-08-05 12:32:08 +0000
+++ src/game_io/game_preload_packet.cc	2016-10-28 17:51:15 +0000
@@ -27,6 +27,7 @@
 #include "base/time_string.h"
 #include "build_info.h"
 #include "graphic/graphic.h"
+#include "graphic/image_io.h"
 #include "graphic/minimap_renderer.h"
 #include "logic/game.h"
 #include "logic/game_data_error.h"
@@ -120,13 +121,17 @@
 
 	std::unique_ptr<::StreamWrite> sw(fs.open_stream_write(kMinimapFilename));
 	if (sw.get() != nullptr) {
-		const MiniMapLayer flags =
+		const MiniMapLayer layers =
 		   MiniMapLayer::Owner | MiniMapLayer::Building | MiniMapLayer::Terrain;
+		std::unique_ptr<Texture> texture;
 		if (ipl != nullptr) {  // Player
-			write_minimap_image(game, &ipl->player(), ipl->get_viewpoint(), flags, sw.get());
+			texture = draw_minimap(
+			   game, &ipl->player(), ipl->get_view_area(), MiniMapType::kStaticViewWindow, layers);
 		} else {  // Observer
-			write_minimap_image(game, nullptr, Point(0, 0), flags, sw.get());
+			texture = draw_minimap(game, nullptr, Rectf(), MiniMapType::kStaticMap, layers);
 		}
+		assert(texture != nullptr);
+		save_to_png(texture.get(), sw.get(), ColorType::RGBA);
 		sw->flush();
 	}
 }

=== modified file 'src/graphic/CMakeLists.txt'
--- src/graphic/CMakeLists.txt	2016-02-19 19:10:44 +0000
+++ src/graphic/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -22,6 +22,15 @@
   USES_SDL2
 )
 
+wl_library(graphic_playercolor
+  SRCS
+    playercolor.cc
+    playercolor.h
+  DEPENDS
+    graphic_color
+    graphic_surface
+)
+
 wl_library(graphic_render_queue
   SRCS
     render_queue.cc
@@ -124,6 +133,7 @@
     graphic_surface
     io_filesystem
     logic
+    logic_widelands_geometry
 )
 
 wl_library(graphic_draw_programs
@@ -209,7 +219,6 @@
     base_macros
     economy
     graphic
-    graphic_image_io
     graphic_surface
     logic
     wui_mapview_pixelfunctions
@@ -255,6 +264,7 @@
     graphic_gl_utils
     graphic_image_cache
     graphic_image_io
+    graphic_playercolor
     graphic_render_queue
     graphic_surface
     graphic_text

=== modified file 'src/graphic/align.cc'
--- src/graphic/align.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/align.cc	2016-10-28 17:51:15 +0000
@@ -53,7 +53,12 @@
 	return alignment;
 }
 
-void correct_for_align(Align align, uint32_t w, uint32_t h, Point* pt) {
+void correct_for_align(Align align, uint32_t w, uint32_t h, Vector2f* pt) {
+	// When correcting for align, we never move from pixel boundaries to
+	// sub-pixels, because this might lead from pixel-perfect rendering to
+	// subsampled rendering - this can lead to blurry texts. That is why we
+	// never do float divisions in this function.
+
 	// Vertical Align
 	if (static_cast<int>(align & (Align::kVCenter | Align::kBottom))) {
 		if (static_cast<int>(align & Align::kVCenter))

=== modified file 'src/graphic/align.h'
--- src/graphic/align.h	2016-08-04 15:49:05 +0000
+++ src/graphic/align.h	2016-10-28 17:51:15 +0000
@@ -20,7 +20,7 @@
 #ifndef WL_GRAPHIC_ALIGN_H
 #define WL_GRAPHIC_ALIGN_H
 
-#include "base/point.h"
+#include "base/vector.h"
 
 namespace UI {
 
@@ -58,6 +58,6 @@
 }
 
 Align mirror_alignment(Align alignment);
-void correct_for_align(Align, uint32_t w, uint32_t h, Point* pt);
+void correct_for_align(Align, uint32_t w, uint32_t h, Vector2f* pt);
 }
 #endif  // end of include guard: WL_GRAPHIC_ALIGN_H

=== modified file 'src/graphic/animation.cc'
--- src/graphic/animation.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/animation.cc	2016-10-28 17:51:15 +0000
@@ -34,6 +34,7 @@
 #include "graphic/graphic.h"
 #include "graphic/image.h"
 #include "graphic/image_cache.h"
+#include "graphic/playercolor.h"
 #include "graphic/surface.h"
 #include "graphic/texture.h"
 #include "io/filesystem/layered_filesystem.h"
@@ -44,7 +45,7 @@
 
 namespace {
 // Parses an array { 12, 23 } into a point.
-void get_point(const LuaTable& table, Point* p) {
+void get_point(const LuaTable& table, Vector2i* p) {
 	std::vector<int> pts = table.array_entries<int>();
 	if (pts.size() != 2) {
 		throw wexception("Expected 2 entries, but got %" PRIuS ".", pts.size());
@@ -68,11 +69,14 @@
 	uint16_t height() const override;
 	uint16_t nr_frames() const override;
 	uint32_t frametime() const override;
-	const Point& hotspot() const override;
+	const Vector2i& hotspot() const override;
 	Image* representative_image(const RGBColor* clr) const override;
 	const std::string& representative_image_filename() const override;
-	virtual void blit(
-	   uint32_t time, const Point&, const Rect& srcrc, const RGBColor* clr, Surface*) const override;
+	virtual void blit(uint32_t time,
+	                  const Rectf& dstrc,
+	                  const Rectf& srcrc,
+	                  const RGBColor* clr,
+	                  Surface*) const override;
 	void trigger_sound(uint32_t framenumber, uint32_t stereo_position) const override;
 
 private:
@@ -85,7 +89,7 @@
 	uint32_t current_frame(uint32_t time) const;
 
 	uint32_t frametime_;
-	Point hotspot_;
+	Vector2i hotspot_;
 	bool hasplrclrs_;
 	std::vector<std::string> image_files_;
 	std::vector<std::string> pc_mask_image_files_;
@@ -207,27 +211,24 @@
 	return frametime_;
 }
 
-const Point& NonPackedAnimation::hotspot() const {
+const Vector2i& NonPackedAnimation::hotspot() const {
 	return hotspot_;
 }
 
 Image* NonPackedAnimation::representative_image(const RGBColor* clr) const {
 	assert(!image_files_.empty());
-
 	const Image* image = g_gr->images().get(image_files_[0]);
-	int w = image->width();
-	int h = image->height();
 
-	Texture* rv = new Texture(w, h);
 	if (!hasplrclrs_ || clr == nullptr) {
 		// No player color means we simply want an exact copy of the original image.
-		rv->blit(Rect(Point(0, 0), w, h), *image, Rect(Point(0, 0), w, h), 1., BlendMode::Copy);
+		const int w = image->width();
+		const int h = image->height();
+		Texture* rv = new Texture(w, h);
+		rv->blit(Rectf(0, 0, w, h), *image, Rectf(0, 0, w, h), 1., BlendMode::Copy);
+		return rv;
 	} else {
-		rv->fill_rect(Rect(Point(0, 0), w, h), RGBAColor(0, 0, 0, 0));
-		rv->blit_blended(Rect(Point(0, 0), w, h), *image,
-		                 *g_gr->images().get(pc_mask_image_files_[0]), Rect(Point(0, 0), w, h), *clr);
+		return playercolor_image(clr, image, g_gr->images().get(pc_mask_image_files_[0]));
 	}
-	return rv;
 }
 
 const std::string& NonPackedAnimation::representative_image_filename() const {
@@ -255,19 +256,20 @@
 	}
 }
 
-void NonPackedAnimation::blit(
-   uint32_t time, const Point& dst, const Rect& srcrc, const RGBColor* clr, Surface* target) const {
+void NonPackedAnimation::blit(uint32_t time,
+                              const Rectf& dstrc,
+                              const Rectf& srcrc,
+                              const RGBColor* clr,
+                              Surface* target) const {
 	assert(target);
 
 	const uint32_t idx = current_frame(time);
 	assert(idx < nr_frames());
 
 	if (!hasplrclrs_ || clr == nullptr) {
-		target->blit(
-		   Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), srcrc, 1., BlendMode::UseAlpha);
+		target->blit(dstrc, *frames_.at(idx), srcrc, 1., BlendMode::UseAlpha);
 	} else {
-		target->blit_blended(
-		   Rect(dst.x, dst.y, srcrc.w, srcrc.h), *frames_.at(idx), *pcmasks_.at(idx), srcrc, *clr);
+		target->blit_blended(dstrc, *frames_.at(idx), *pcmasks_.at(idx), srcrc, *clr);
 	}
 }
 

=== modified file 'src/graphic/animation.h'
--- src/graphic/animation.h	2016-08-04 15:49:05 +0000
+++ src/graphic/animation.h	2016-10-28 17:51:15 +0000
@@ -29,8 +29,8 @@
 #include <boost/utility.hpp>
 
 #include "base/macros.h"
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 
 class Image;
 class LuaTable;
@@ -68,7 +68,7 @@
 
 	/// The hotspot of this animation. Note that this is ignored when blitting,
 	/// so the caller has to adjust for the hotspot himself.
-	virtual const Point& hotspot() const = 0;
+	virtual const Vector2i& hotspot() const = 0;
 
 	/// An image of the first frame, blended with the given player color.
 	/// The 'clr' is the player color used for blending - the parameter can be
@@ -83,8 +83,11 @@
 	/// color used for blitting - the parameter can be 'nullptr', in which case the
 	/// neutral image will be blitted. The Surface is the target for the blit
 	/// operation and must be non-null.
-	virtual void
-	blit(uint32_t time, const Point&, const Rect& srcrc, const RGBColor* clr, Surface*) const = 0;
+	virtual void blit(uint32_t time,
+	                  const Rectf& dstrc,
+	                  const Rectf& srcrc,
+	                  const RGBColor* clr,
+	                  Surface*) const = 0;
 
 	/// Play the sound effect associated with this animation at the given time.
 	virtual void trigger_sound(uint32_t time, uint32_t stereo_position) const = 0;

=== modified file 'src/graphic/font_handler.cc'
--- src/graphic/font_handler.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/font_handler.cc	2016-10-28 17:51:15 +0000
@@ -46,16 +46,15 @@
  */
 void draw_caret(RenderTarget& dst,
                 const TextStyle& style,
-                const Point& dstpoint,
+                const Vector2f& dstpoint,
                 const std::string& text,
                 uint32_t caret_offset) {
 	int caret_x = style.calc_bare_width(text.substr(0, caret_offset));
 
 	const Image* caret_image = g_gr->images().get("images/ui_basic/caret.png");
-	Point caretpt;
+	Vector2f caretpt;
 	caretpt.x = dstpoint.x + caret_x + LINE_MARGIN - caret_image->width();
-	caretpt.y = dstpoint.y + (style.font->height() - caret_image->height()) / 2;
-
+	caretpt.y = dstpoint.y + (style.font->height() - caret_image->height()) / 2.f;
 	dst.blit(caretpt, caret_image);
 }
 
@@ -202,7 +201,7 @@
  */
 void FontHandler::draw_text(RenderTarget& dst,
                             const TextStyle& style,
-                            Point dstpoint,
+                            Vector2i dstpoint_i,
                             const std::string& text,
                             Align align,
                             uint32_t caret) {
@@ -212,10 +211,11 @@
 	copytext = i18n::make_ligatures(copytext.c_str());
 	const LineCacheEntry& lce = d->get_line(style, copytext);
 
+	Vector2f dstpoint = dstpoint_i.cast<float>();
 	UI::correct_for_align(align, lce.width + 2 * LINE_MARGIN, lce.height, &dstpoint);
 
 	if (lce.image)
-		dst.blit(Point(dstpoint.x + LINE_MARGIN, dstpoint.y), lce.image.get());
+		dst.blit(Vector2f(dstpoint.x + LINE_MARGIN, dstpoint.y), lce.image.get());
 
 	if (caret <= copytext.size())
 		draw_caret(dst, style, dstpoint, copytext, caret);
@@ -226,12 +226,13 @@
  */
 uint32_t FontHandler::draw_text_raw(RenderTarget& dst,
                                     const UI::TextStyle& style,
-                                    Point dstpoint,
+                                    Vector2i dstpoint,
                                     const std::string& text) {
 	const LineCacheEntry& lce = d->get_line(style, text);
 
-	if (lce.image)
-		dst.blit(dstpoint, lce.image.get());
+	if (lce.image) {
+		dst.blit(dstpoint.cast<float>(), lce.image.get());
+	}
 
 	return lce.width;
 }

=== modified file 'src/graphic/font_handler.h'
--- src/graphic/font_handler.h	2016-08-04 15:49:05 +0000
+++ src/graphic/font_handler.h	2016-10-28 17:51:15 +0000
@@ -24,7 +24,7 @@
 #include <memory>
 #include <string>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/align.h"
 
 class RenderTarget;
@@ -42,11 +42,11 @@
 
 	void draw_text(RenderTarget&,
 	               const TextStyle&,
-	               Point dstpoint,
+	               Vector2i dstpoint,
 	               const std::string& text,
 	               Align align = UI::Align::kCenterLeft,
 	               uint32_t caret = std::numeric_limits<uint32_t>::max());
-	uint32_t draw_text_raw(RenderTarget&, const TextStyle&, Point dstpoint, const std::string& text);
+	uint32_t draw_text_raw(RenderTarget&, const TextStyle&, Vector2i dstpoint, const std::string& text);
 
 	void get_size(const TextStyle&,
 	              const std::string& text,

=== modified file 'src/graphic/font_handler1.h'
--- src/graphic/font_handler1.h	2016-08-04 15:49:05 +0000
+++ src/graphic/font_handler1.h	2016-10-28 17:51:15 +0000
@@ -25,7 +25,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/align.h"
 #include "graphic/text/font_set.h"
 

=== modified file 'src/graphic/game_renderer.cc'
--- src/graphic/game_renderer.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/game_renderer.cc	2016-10-28 17:51:15 +0000
@@ -97,23 +97,214 @@
 	return brightness / 255.;
 }
 
-// Returns the road that should be rendered here. The format is like in field,
-// but this is not the physically present road, but the one that should be
-// drawn (i.e. taking into account if there is fog of war involved or road
-// building overlays enabled).
-uint8_t field_roads(const FCoords& coords,
-                    const Map& map,
-                    const EdgeOverlayManager& edge_overlay_manager,
-                    const Player* const player) {
-	uint8_t roads;
-	if (player && !player->see_all()) {
-		const Player::Field& pf = player->fields()[Map::get_index(coords, map.get_width())];
-		roads = pf.roads | edge_overlay_manager.get_overlay(coords);
-	} else {
-		roads = coords.field->get_roads();
-	}
-	roads |= edge_overlay_manager.get_overlay(coords);
-	return roads;
+void draw_objects_for_visible_field(const EditorGameBase& egbase,
+                                    const FieldsToDraw::Field& field,
+                                    const float zoom,
+                                    const TextToDraw draw_text,
+                                    const Player* player,
+                                    RenderTarget* dst) {
+	BaseImmovable* const imm = field.fcoords.field->get_immovable();
+	if (imm != nullptr && imm->get_positions(egbase).front() == field.fcoords) {
+		TextToDraw draw_text_for_this_immovable = draw_text;
+		const Player* owner = imm->get_owner();
+		if (player != nullptr && owner != nullptr && !player->see_all() &&
+		    player->is_hostile(*owner)) {
+			draw_text_for_this_immovable =
+			   static_cast<TextToDraw>(draw_text_for_this_immovable & ~TextToDraw::kStatistics);
+		}
+
+		imm->draw(
+		   egbase.get_gametime(), draw_text_for_this_immovable, field.rendertarget_pixel, zoom, dst);
+	}
+	for (Bob* bob = field.fcoords.field->get_first_bob(); bob; bob = bob->get_next_bob()) {
+		TextToDraw draw_text_for_this_bob = draw_text;
+		const Player* owner = bob->get_owner();
+		if (player != nullptr && owner != nullptr && !player->see_all() &&
+		    player->is_hostile(*owner)) {
+			draw_text_for_this_bob =
+			   static_cast<TextToDraw>(draw_text_for_this_bob & ~TextToDraw::kStatistics);
+		}
+		bob->draw(egbase, draw_text_for_this_bob, field.rendertarget_pixel, zoom, dst);
+	}
+}
+
+void draw_objets_for_formerly_visible_field(const FieldsToDraw::Field& field,
+                                            const Player::Field& player_field,
+                                            const float zoom,
+                                            RenderTarget* dst) {
+	if (const MapObjectDescr* const map_object_descr =
+	       player_field.map_object_descr[TCoords<>::None]) {
+		if (player_field.constructionsite.becomes) {
+			assert(field.owner != nullptr);
+			const ConstructionsiteInformation& csinf = player_field.constructionsite;
+			// draw the partly finished constructionsite
+			uint32_t anim_idx;
+			try {
+				anim_idx = csinf.becomes->get_animation("build");
+			} catch (MapObjectDescr::AnimationNonexistent&) {
+				try {
+					anim_idx = csinf.becomes->get_animation("unoccupied");
+				} catch (MapObjectDescr::AnimationNonexistent) {
+					anim_idx = csinf.becomes->get_animation("idle");
+				}
+			}
+			const Animation& anim = g_gr->animations().get_animation(anim_idx);
+			const size_t nr_frames = anim.nr_frames();
+			uint32_t cur_frame =
+			   csinf.totaltime ? csinf.completedtime * nr_frames / csinf.totaltime : 0;
+			uint32_t tanim = cur_frame * FRAME_LENGTH;
+
+			const uint16_t w = anim.width();
+			const uint16_t h = anim.height();
+			uint32_t lines = h * csinf.completedtime * nr_frames;
+			if (csinf.totaltime)
+				lines /= csinf.totaltime;
+			assert(h * cur_frame <= lines);
+			lines -= h * cur_frame;
+
+			if (cur_frame) {  // not the first frame
+				// draw the prev frame from top to where next image will be drawing
+				dst->blit_animation(field.rendertarget_pixel, zoom, anim_idx, tanim - FRAME_LENGTH,
+				                    field.owner->get_playercolor(),
+				                    Recti(Vector2i(0, 0), w, h - lines));
+			} else if (csinf.was) {
+				// Is the first frame, but there was another building here before,
+				// get its last build picture and draw it instead.
+				uint32_t a;
+				try {
+					a = csinf.was->get_animation("unoccupied");
+				} catch (MapObjectDescr::AnimationNonexistent&) {
+					a = csinf.was->get_animation("idle");
+				}
+				dst->blit_animation(field.rendertarget_pixel, zoom, a, tanim - FRAME_LENGTH,
+				                    field.owner->get_playercolor(),
+				                    Recti(Vector2i(0, 0), w, h - lines));
+			}
+			assert(lines <= h);
+			dst->blit_animation(field.rendertarget_pixel, zoom, anim_idx, tanim,
+			                    field.owner->get_playercolor(),
+			                    Recti(Vector2i(0, h - lines), w, lines));
+		} else if (upcast(const BuildingDescr, building, map_object_descr)) {
+			assert(field.owner != nullptr);
+			// this is a building therefore we either draw unoccupied or idle animation
+			uint32_t pic;
+			try {
+				pic = building->get_animation("unoccupied");
+			} catch (MapObjectDescr::AnimationNonexistent&) {
+				pic = building->get_animation("idle");
+			}
+			dst->blit_animation(
+			   field.rendertarget_pixel, zoom, pic, 0, field.owner->get_playercolor());
+		} else if (map_object_descr->type() == MapObjectType::FLAG) {
+			assert(field.owner != nullptr);
+			dst->blit_animation(field.rendertarget_pixel, zoom, field.owner->tribe().flag_animation(),
+			                    0, field.owner->get_playercolor());
+		} else if (const uint32_t pic = map_object_descr->main_animation()) {
+			if (field.owner != nullptr) {
+				dst->blit_animation(
+				   field.rendertarget_pixel, zoom, pic, 0, field.owner->get_playercolor());
+			} else {
+				dst->blit_animation(field.rendertarget_pixel, zoom, pic, 0);
+			}
+		}
+	}
+}
+
+// Draws the objects (animations & overlays).
+void draw_objects(const EditorGameBase& egbase,
+                  const float zoom,
+                  const FieldsToDraw& fields_to_draw,
+                  const Player* player,
+                  const TextToDraw draw_text,
+                  RenderTarget* dst) {
+	std::vector<FieldOverlayManager::OverlayInfo> overlay_info;
+	for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
+		const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
+		if (!field.all_neighbors_valid()) {
+			continue;
+		}
+
+		const FieldsToDraw::Field& rn = fields_to_draw.at(field.rn_index);
+		const FieldsToDraw::Field& bln = fields_to_draw.at(field.bln_index);
+		const FieldsToDraw::Field& brn = fields_to_draw.at(field.brn_index);
+
+		if (field.is_border) {
+			assert(field.owner != nullptr);
+			uint32_t const anim_idx = field.owner->tribe().frontier_animation();
+			if (field.vision) {
+				dst->blit_animation(
+				   field.rendertarget_pixel, zoom, anim_idx, 0, field.owner->get_playercolor());
+			}
+			for (const auto& nf : {rn, bln, brn}) {
+				if ((field.vision || nf.vision) && nf.is_border &&
+				    (field.owner == nf.owner || nf.owner == nullptr)) {
+					dst->blit_animation(middle(field.rendertarget_pixel, nf.rendertarget_pixel), zoom,
+					                    anim_idx, 0, field.owner->get_playercolor());
+				}
+			}
+		}
+
+		if (1 < field.vision) {  // Render stuff that belongs to the node.
+			draw_objects_for_visible_field(egbase, field, zoom, draw_text, player, dst);
+		} else if (field.vision == 1) {
+			// We never show census or statistics for objects in the fog.
+			assert(player != nullptr);
+			const Map& map = egbase.map();
+			const Player::Field& player_field =
+			   player->fields()[map.get_index(field.fcoords, map.get_width())];
+			draw_objets_for_formerly_visible_field(field, player_field, zoom, dst);
+		}
+
+		const FieldOverlayManager& overlay_manager = egbase.get_ibase()->field_overlay_manager();
+		{
+			overlay_info.clear();
+			overlay_manager.get_overlays(field.fcoords, &overlay_info);
+			for (const auto& overlay : overlay_info) {
+				dst->blitrect_scale(
+				   Rectf(field.rendertarget_pixel - overlay.hotspot.cast<float>() * zoom,
+				         overlay.pic->width() * zoom, overlay.pic->height() * zoom),
+				   overlay.pic, Recti(0, 0, overlay.pic->width(), overlay.pic->height()), 1.f,
+				   BlendMode::UseAlpha);
+			}
+		}
+
+		{
+			// Render overlays on the right triangle
+			overlay_info.clear();
+			overlay_manager.get_overlays(TCoords<>(field.fcoords, TCoords<>::R), &overlay_info);
+
+			Vector2f tripos(
+			   (field.rendertarget_pixel.x + rn.rendertarget_pixel.x + brn.rendertarget_pixel.x) / 3.f,
+			   (field.rendertarget_pixel.y + rn.rendertarget_pixel.y + brn.rendertarget_pixel.y) /
+			      3.f);
+			for (const auto& overlay : overlay_info) {
+				dst->blitrect_scale(Rectf(tripos - overlay.hotspot.cast<float>() * zoom,
+				                          overlay.pic->width() * zoom, overlay.pic->height() * zoom),
+				                    overlay.pic,
+				                    Recti(0, 0, overlay.pic->width(), overlay.pic->height()), 1.f,
+				                    BlendMode::UseAlpha);
+			}
+		}
+
+		{
+			// Render overlays on the D triangle
+			overlay_info.clear();
+			overlay_manager.get_overlays(TCoords<>(field.fcoords, TCoords<>::D), &overlay_info);
+
+			Vector2f tripos(
+			   (field.rendertarget_pixel.x + bln.rendertarget_pixel.x + brn.rendertarget_pixel.x) /
+			      3.f,
+			   (field.rendertarget_pixel.y + bln.rendertarget_pixel.y + brn.rendertarget_pixel.y) /
+			      3.f);
+			for (const auto& overlay : overlay_info) {
+				dst->blitrect_scale(Rectf(tripos - overlay.hotspot.cast<float>() * zoom,
+				                          overlay.pic->width() * zoom, overlay.pic->height() * zoom),
+				                    overlay.pic,
+				                    Recti(0, 0, overlay.pic->width(), overlay.pic->height()), 1.f,
+				                    BlendMode::UseAlpha);
+			}
+		}
+	}
 }
 
 }  // namespace
@@ -124,46 +315,60 @@
 GameRenderer::~GameRenderer() {
 }
 
-void GameRenderer::rendermap(RenderTarget& dst,
-                             const Widelands::EditorGameBase& egbase,
-                             const Point& view_offset,
-
-                             const Widelands::Player& player) {
-	draw(dst, egbase, view_offset, &player);
-}
-
-void GameRenderer::rendermap(RenderTarget& dst,
-                             const Widelands::EditorGameBase& egbase,
-                             const Point& view_offset) {
-	draw(dst, egbase, view_offset, nullptr);
-}
-
-void GameRenderer::draw(RenderTarget& dst,
-                        const EditorGameBase& egbase,
-                        const Point& view_offset,
-                        const Player* player) {
-	Point tl_map = dst.get_offset() + view_offset;
-
-	assert(tl_map.x >= 0);  // divisions involving negative numbers are bad
-	assert(tl_map.y >= 0);
-
-	int minfx = tl_map.x / kTriangleWidth - 1;
-	int minfy = tl_map.y / kTriangleHeight - 1;
-	int maxfx = (tl_map.x + dst.get_rect().w + (kTriangleWidth / 2)) / kTriangleWidth;
-	int maxfy = (tl_map.y + dst.get_rect().h) / kTriangleHeight;
-
-	// fudge for triangle boundary effects and for height differences
-	minfx -= 1;
-	minfy -= 1;
-	maxfx += 1;
+void GameRenderer::rendermap(const Widelands::EditorGameBase& egbase,
+                             const Vector2f& viewpoint,
+                             const float zoom,
+                             const Widelands::Player& player,
+                             const TextToDraw draw_text,
+                             RenderTarget* dst) {
+	draw(egbase, viewpoint, zoom, draw_text, &player, dst);
+}
+
+void GameRenderer::rendermap(const Widelands::EditorGameBase& egbase,
+                             const Vector2f& viewpoint,
+                             const float zoom,
+                             const TextToDraw draw_text,
+                             RenderTarget* dst) {
+	draw(egbase, viewpoint, zoom, draw_text, nullptr, dst);
+}
+
+void GameRenderer::draw(const EditorGameBase& egbase,
+                        const Vector2f& viewpoint,
+                        const float zoom,
+                        const TextToDraw draw_text,
+                        const Player* player,
+                        RenderTarget* dst) {
+	assert(viewpoint.x >= 0);  // divisions involving negative numbers are bad
+	assert(viewpoint.y >= 0);
+	assert(dst->get_offset().x <= 0);
+	assert(dst->get_offset().y <= 0);
+
+	int minfx = std::floor(viewpoint.x / kTriangleWidth);
+	int minfy = std::floor(viewpoint.y / kTriangleHeight);
+
+	// If a view window is partially moved outside of the display, its 'rect' is
+	// adjusted to be fully contained on the screen - i.e. x = 0 and width is
+	// made smaller. Its offset is made negative to account for this change.
+	// To figure out which fields we need to draw, we have to add the absolute
+	// value of 'offset' to the actual dimension of the 'rect' to get to desired
+	// dimension of the 'rect'
+	const Vector2f br_map = MapviewPixelFunctions::panel_to_map(
+	   viewpoint, zoom, Vector2f(dst->get_rect().w + std::abs(dst->get_offset().x),
+	                             dst->get_rect().h + std::abs(dst->get_offset().y)));
+	int maxfx = std::ceil(br_map.x / kTriangleWidth);
+	int maxfy = std::ceil(br_map.y / kTriangleHeight);
+
+	// Adjust for triangle boundary effects and for height differences.
+	minfx -= 2;
+	maxfx += 2;
+	minfy -= 2;
 	maxfy += 10;
 
-	Surface* surface = dst.get_surface();
+	Surface* surface = dst->get_surface();
 	if (!surface)
 		return;
 
-	const Rect& bounding_rect = dst.get_rect();
-	const Point surface_offset = bounding_rect.origin() + dst.get_offset() - view_offset;
+	const Recti& bounding_rect = dst->get_rect();
 	const int surface_width = surface->width();
 	const int surface_height = surface->height();
 
@@ -171,46 +376,60 @@
 	const EdgeOverlayManager& edge_overlay_manager = egbase.get_ibase()->edge_overlay_manager();
 	const uint32_t gametime = egbase.get_gametime();
 
+	const float scale = 1.f / zoom;
 	fields_to_draw_.reset(minfx, maxfx, minfy, maxfy);
 	for (int32_t fy = minfy; fy <= maxfy; ++fy) {
 		for (int32_t fx = minfx; fx <= maxfx; ++fx) {
 			FieldsToDraw::Field& f =
 			   *fields_to_draw_.mutable_field(fields_to_draw_.calculate_index(fx, fy));
 
-			f.fx = fx;
-			f.fy = fy;
-
-			Coords coords(fx, fy);
-			int x, y;
-			MapviewPixelFunctions::get_basepix(coords, x, y);
-
-			map.normalize_coords(coords);
-			const FCoords& fcoords = map.get_fcoords(coords);
+			f.geometric_coords = Coords(fx, fy);
+
+			f.ln_index = fields_to_draw_.calculate_index(fx - 1, fy);
+			f.rn_index = fields_to_draw_.calculate_index(fx + 1, fy);
+			f.trn_index = fields_to_draw_.calculate_index(fx + (fy & 1), fy - 1);
+			f.bln_index = fields_to_draw_.calculate_index(fx + (fy & 1) - 1, fy + 1);
+			f.brn_index = fields_to_draw_.calculate_index(fx + (fy & 1), fy + 1);
 
 			// Texture coordinates for pseudo random tiling of terrain and road
 			// graphics. Since screen space X increases top-to-bottom and OpenGL
 			// increases bottom-to-top we flip the y coordinate to not have
 			// terrains and road graphics vertically mirrorerd.
-			f.texture_x = float(x) / kTextureSideLength;
-			f.texture_y = -float(y) / kTextureSideLength;
-
-			f.gl_x = f.pixel_x = x + surface_offset.x;
-			f.gl_y = f.pixel_y = y + surface_offset.y - fcoords.field->get_height() * kHeightFactor;
-			pixel_to_gl_renderbuffer(surface_width, surface_height, &f.gl_x, &f.gl_y);
-
-			f.ter_d = fcoords.field->terrain_d();
-			f.ter_r = fcoords.field->terrain_r();
-
-			f.brightness = field_brightness(fcoords, gametime, map, player);
-
-			PlayerNumber owner_number = fcoords.field->get_owned_by();
-			if (owner_number > 0) {
-				f.road_textures = &egbase.player(owner_number).tribe().road_textures();
-			} else {
-				f.road_textures = nullptr;
+			Vector2f map_pixel =
+			   MapviewPixelFunctions::to_map_pixel_ignoring_height(f.geometric_coords);
+			f.texture_coords.x = map_pixel.x / kTextureSideLength;
+			f.texture_coords.y = -map_pixel.y / kTextureSideLength;
+
+			Coords normalized = f.geometric_coords;
+			map.normalize_coords(normalized);
+			f.fcoords = map.get_fcoords(normalized);
+
+			map_pixel.y -= f.fcoords.field->get_height() * kHeightFactor;
+
+			f.rendertarget_pixel = MapviewPixelFunctions::map_to_panel(viewpoint, zoom, map_pixel);
+			f.gl_position = f.surface_pixel = f.rendertarget_pixel +
+			                                  dst->get_rect().origin().cast<float>() +
+			                                  dst->get_offset().cast<float>();
+			pixel_to_gl_renderbuffer(
+			   surface_width, surface_height, &f.gl_position.x, &f.gl_position.y);
+
+			f.brightness = field_brightness(f.fcoords, gametime, map, player);
+
+			PlayerNumber owned_by = f.fcoords.field->get_owned_by();
+			f.owner = owned_by != 0 ? &egbase.player(owned_by) : nullptr;
+			f.is_border = f.fcoords.field->is_border();
+			f.vision = 2;
+			f.roads = f.fcoords.field->get_roads();
+			if (player && !player->see_all()) {
+				const Player::Field& pf = player->fields()[map.get_index(f.fcoords, map.get_width())];
+				f.roads = pf.roads;
+				f.vision = pf.vision;
+				if (pf.vision == 1) {
+					f.owner = pf.owner != 0 ? &egbase.player(owned_by) : nullptr;
+					f.is_border = pf.border;
+				}
 			}
-
-			f.roads = field_roads(fcoords, map, edge_overlay_manager, player);
+			f.roads |= edge_overlay_manager.get_overlay(f.fcoords);
 		}
 	}
 
@@ -219,13 +438,14 @@
 	i.program_id = RenderQueue::Program::kTerrainBase;
 	i.blend_mode = BlendMode::Copy;
 	i.terrain_arguments.destination_rect =
-	   FloatRect(bounding_rect.x, surface_height - bounding_rect.y - bounding_rect.h,
-	             bounding_rect.w, bounding_rect.h);
+	   Rectf(bounding_rect.x, surface_height - bounding_rect.y - bounding_rect.h, bounding_rect.w,
+	         bounding_rect.h);
 	i.terrain_arguments.gametime = gametime;
 	i.terrain_arguments.renderbuffer_width = surface_width;
 	i.terrain_arguments.renderbuffer_height = surface_height;
 	i.terrain_arguments.terrains = &egbase.world().terrains();
 	i.terrain_arguments.fields_to_draw = &fields_to_draw_;
+	i.terrain_arguments.scale = scale;
 	RenderQueue::instance().enqueue(i);
 
 	// Enqueue the drawing of the dither layer.
@@ -237,191 +457,5 @@
 	i.program_id = RenderQueue::Program::kTerrainRoad;
 	RenderQueue::instance().enqueue(i);
 
-	draw_objects(dst, egbase, view_offset, player, minfx, maxfx, minfy, maxfy);
-}
-
-void GameRenderer::draw_objects(RenderTarget& dst,
-                                const EditorGameBase& egbase,
-                                const Point& view_offset,
-                                const Player* player,
-                                int minfx,
-                                int maxfx,
-                                int minfy,
-                                int maxfy) {
-	// TODO(sirver): this should use FieldsToDraw. Would simplify this function a lot.
-	static const uint32_t F = 0;
-	static const uint32_t R = 1;
-	static const uint32_t BL = 2;
-	static const uint32_t BR = 3;
-	const Map& map = egbase.map();
-
-	std::vector<FieldOverlayManager::OverlayInfo> overlay_info;
-	for (int32_t fy = minfy; fy <= maxfy; ++fy) {
-		for (int32_t fx = minfx; fx <= maxfx; ++fx) {
-			Coords ncoords(fx, fy);
-			map.normalize_coords(ncoords);
-			FCoords coords[4];
-			coords[F] = map.get_fcoords(ncoords);
-			coords[R] = map.r_n(coords[F]);
-			coords[BL] = map.bl_n(coords[F]);
-			coords[BR] = map.br_n(coords[F]);
-			Point pos[4];
-			MapviewPixelFunctions::get_basepix(Coords(fx, fy), pos[F].x, pos[F].y);
-			MapviewPixelFunctions::get_basepix(Coords(fx + 1, fy), pos[R].x, pos[R].y);
-			MapviewPixelFunctions::get_basepix(
-			   Coords(fx + (fy & 1) - 1, fy + 1), pos[BL].x, pos[BL].y);
-			MapviewPixelFunctions::get_basepix(Coords(fx + (fy & 1), fy + 1), pos[BR].x, pos[BR].y);
-			for (uint32_t d = 0; d < 4; ++d) {
-				pos[d].y -= coords[d].field->get_height() * kHeightFactor;
-				pos[d] -= view_offset;
-			}
-
-			PlayerNumber owner_number[4];
-			bool isborder[4];
-			Vision vision[4] = {2, 2, 2, 2};
-			for (uint32_t d = 0; d < 4; ++d)
-				owner_number[d] = coords[d].field->get_owned_by();
-			for (uint32_t d = 0; d < 4; ++d)
-				isborder[d] = coords[d].field->is_border();
-
-			if (player && !player->see_all()) {
-				for (uint32_t d = 0; d < 4; ++d) {
-					const Player::Field& pf =
-					   player->fields()[map.get_index(coords[d], map.get_width())];
-					vision[d] = pf.vision;
-					if (pf.vision == 1) {
-						owner_number[d] = pf.owner;
-						isborder[d] = pf.border;
-					}
-				}
-			}
-
-			if (isborder[F]) {
-				const Player& owner = egbase.player(owner_number[F]);
-				uint32_t const anim_idx = owner.tribe().frontier_animation();
-				if (vision[F])
-					dst.blit_animation(pos[F], anim_idx, 0, owner.get_playercolor());
-				for (uint32_t d = 1; d < 4; ++d) {
-					if ((vision[F] || vision[d]) && isborder[d] &&
-					    (owner_number[d] == owner_number[F] || !owner_number[d])) {
-						dst.blit_animation(middle(pos[F], pos[d]), anim_idx, 0, owner.get_playercolor());
-					}
-				}
-			}
-
-			if (1 < vision[F]) {  // Render stuff that belongs to the node.
-				if (BaseImmovable* const imm = coords[F].field->get_immovable())
-					imm->draw(egbase, dst, coords[F], pos[F]);
-				for (Bob* bob = coords[F].field->get_first_bob(); bob; bob = bob->get_next_bob())
-					bob->draw(egbase, dst, pos[F]);
-			} else if (vision[F] == 1) {
-				const Player::Field& f_pl = player->fields()[map.get_index(coords[F], map.get_width())];
-				const Player* owner = owner_number[F] ? egbase.get_player(owner_number[F]) : nullptr;
-				if (const MapObjectDescr* const map_object_descr =
-				       f_pl.map_object_descr[TCoords<>::None]) {
-					if (f_pl.constructionsite.becomes) {
-						assert(owner != nullptr);
-						const ConstructionsiteInformation& csinf = f_pl.constructionsite;
-						// draw the partly finished constructionsite
-						uint32_t anim_idx;
-						try {
-							anim_idx = csinf.becomes->get_animation("build");
-						} catch (MapObjectDescr::AnimationNonexistent&) {
-							try {
-								anim_idx = csinf.becomes->get_animation("unoccupied");
-							} catch (MapObjectDescr::AnimationNonexistent) {
-								anim_idx = csinf.becomes->get_animation("idle");
-							}
-						}
-						const Animation& anim = g_gr->animations().get_animation(anim_idx);
-						const size_t nr_frames = anim.nr_frames();
-						uint32_t cur_frame =
-						   csinf.totaltime ? csinf.completedtime * nr_frames / csinf.totaltime : 0;
-						uint32_t tanim = cur_frame * FRAME_LENGTH;
-
-						const uint16_t w = anim.width();
-						const uint16_t h = anim.height();
-						uint32_t lines = h * csinf.completedtime * nr_frames;
-						if (csinf.totaltime)
-							lines /= csinf.totaltime;
-						assert(h * cur_frame <= lines);
-						lines -= h * cur_frame;
-
-						if (cur_frame) {  // not the first frame
-							// draw the prev frame from top to where next image will be drawing
-							dst.blit_animation(pos[F], anim_idx, tanim - FRAME_LENGTH,
-							                   owner->get_playercolor(), Rect(Point(0, 0), w, h - lines));
-						} else if (csinf.was) {
-							// Is the first frame, but there was another building here before,
-							// get its last build picture and draw it instead.
-							uint32_t a;
-							try {
-								a = csinf.was->get_animation("unoccupied");
-							} catch (MapObjectDescr::AnimationNonexistent&) {
-								a = csinf.was->get_animation("idle");
-							}
-							dst.blit_animation(pos[F], a, tanim - FRAME_LENGTH, owner->get_playercolor(),
-							                   Rect(Point(0, 0), w, h - lines));
-						}
-						assert(lines <= h);
-						dst.blit_animation(pos[F], anim_idx, tanim, owner->get_playercolor(),
-						                   Rect(Point(0, h - lines), w, lines));
-					} else if (upcast(const BuildingDescr, building, map_object_descr)) {
-						assert(owner != nullptr);
-						// this is a building therefore we either draw unoccupied or idle animation
-						uint32_t pic;
-						try {
-							pic = building->get_animation("unoccupied");
-						} catch (MapObjectDescr::AnimationNonexistent&) {
-							pic = building->get_animation("idle");
-						}
-						dst.blit_animation(pos[F], pic, 0, owner->get_playercolor());
-					} else if (map_object_descr->type() == MapObjectType::FLAG) {
-						assert(owner != nullptr);
-						dst.blit_animation(
-						   pos[F], owner->tribe().flag_animation(), 0, owner->get_playercolor());
-					} else if (const uint32_t pic = map_object_descr->main_animation()) {
-						if (owner != nullptr) {
-							dst.blit_animation(pos[F], pic, 0, owner->get_playercolor());
-						} else {
-							dst.blit_animation(pos[F], pic, 0);
-						}
-					}
-				}
-			}
-
-			const FieldOverlayManager& overlay_manager = egbase.get_ibase()->field_overlay_manager();
-			{
-				overlay_info.clear();
-				overlay_manager.get_overlays(coords[F], &overlay_info);
-				for (const auto& overlay : overlay_info) {
-					dst.blit(pos[F] - overlay.hotspot, overlay.pic);
-				}
-			}
-
-			{
-				// Render overlays on the R triangle
-				overlay_info.clear();
-				overlay_manager.get_overlays(TCoords<>(coords[F], TCoords<>::R), &overlay_info);
-
-				Point tripos(
-				   (pos[F].x + pos[R].x + pos[BR].x) / 3, (pos[F].y + pos[R].y + pos[BR].y) / 3);
-				for (const auto& overlay : overlay_info) {
-					dst.blit(tripos - overlay.hotspot, overlay.pic);
-				}
-			}
-
-			{
-				// Render overlays on the D triangle
-				overlay_info.clear();
-				overlay_manager.get_overlays(TCoords<>(coords[F], TCoords<>::D), &overlay_info);
-
-				Point tripos(
-				   (pos[F].x + pos[BL].x + pos[BR].x) / 3, (pos[F].y + pos[BL].y + pos[BR].y) / 3);
-				for (const auto& overlay : overlay_info) {
-					dst.blit(tripos - overlay.hotspot, overlay.pic);
-				}
-			}
-		}
-	}
+	draw_objects(egbase, scale, fields_to_draw_, player, draw_text, dst);
 }

=== modified file 'src/graphic/game_renderer.h'
--- src/graphic/game_renderer.h	2016-08-04 15:49:05 +0000
+++ src/graphic/game_renderer.h	2016-10-28 17:51:15 +0000
@@ -23,8 +23,9 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/gl/fields_to_draw.h"
+#include "logic/map_objects/draw_text.h"
 
 namespace Widelands {
 class Player;
@@ -33,51 +34,39 @@
 
 class RenderTarget;
 
-/**
- * This abstract base class renders the main game view into an
- * arbitrary @ref RenderTarget.
- *
- * Specializations exist for SDL software rendering and for OpenGL rendering.
- *
- * Users of this class should keep instances alive for as long as possible,
- * so that target-specific optimizations (such as caching data) can
- * be effective.
- */
+// Renders the MapView on screen.
 class GameRenderer {
 public:
 	GameRenderer();
 	~GameRenderer();
 
-	// Renders the map from a player's point of view into the given
-	// drawing window. 'view_offset' is the offset of the upper left
-	// corner of the window into the map, in pixels.
-	void rendermap(RenderTarget& dst,
-	               const Widelands::EditorGameBase& egbase,
-	               const Point& view_offset,
-	               const Widelands::Player& player);
+	// Renders the map from a player's point of view into the given drawing
+	// window. The 'viewpoint' is the top left screens pixel map pixel and
+	// 'scale' is the magnification of the view.
+	void rendermap(const Widelands::EditorGameBase& egbase,
+	               const Vector2f& viewpoint,
+	               float scale,
+	               const Widelands::Player& player,
+	               TextToDraw draw_text,
+	               RenderTarget* dst);
 
 	// Renders the map from an omniscient perspective. This is used
 	// for spectators, players that see all, and in the editor.
-	void
-	rendermap(RenderTarget& dst, const Widelands::EditorGameBase& egbase, const Point& view_offset);
+	void rendermap(const Widelands::EditorGameBase& egbase,
+	               const Vector2f& viewpoint,
+	               float scale,
+	               TextToDraw draw_text,
+	               RenderTarget* dst);
 
 private:
 	// Draw the map for the given parameters (see rendermap). 'player'
 	// can be nullptr in which case the whole map is drawn.
-	void draw(RenderTarget& dst,
-	          const Widelands::EditorGameBase& egbase,
-	          const Point& view_offset,
-	          const Widelands::Player* player);
-
-	// Draws the objects (animations & overlays).
-	void draw_objects(RenderTarget& dst,
-	                  const Widelands::EditorGameBase& egbase,
-	                  const Point& view_offset,
-	                  const Widelands::Player* player,
-	                  int minfx,
-	                  int maxfx,
-	                  int minfy,
-	                  int maxfy);
+	void draw(const Widelands::EditorGameBase& egbase,
+	          const Vector2f& viewpoint,
+	          float scale,
+	          TextToDraw draw_text,
+	          const Widelands::Player* player,
+	          RenderTarget* dst);
 
 	// This is owned and handled by us, but handed to the RenderQueue, so we
 	// basically promise that this stays valid for one frame.

=== modified file 'src/graphic/gl/blit_data.h'
--- src/graphic/gl/blit_data.h	2016-01-04 20:54:08 +0000
+++ src/graphic/gl/blit_data.h	2016-10-28 17:51:15 +0000
@@ -38,7 +38,7 @@
 	int parent_height;
 
 	// The subrect in the parent texture.
-	Rect rect;
+	Rectf rect;
 };
 
 #endif  // end of include guard: WL_GRAPHIC_GL_BLIT_DATA_H

=== modified file 'src/graphic/gl/blit_program.cc'
--- src/graphic/gl/blit_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/blit_program.cc	2016-10-28 17:51:15 +0000
@@ -108,8 +108,8 @@
 			const float blend_b = current_args.blend.b / 255.;
 			const float blend_a = current_args.blend.a / 255.;
 
-			const FloatRect texture_rect = to_gl_texture(current_args.texture);
-			const FloatRect mask_rect = to_gl_texture(current_args.mask);
+			const Rectf texture_rect = to_gl_texture(current_args.texture);
+			const Rectf mask_rect = to_gl_texture(current_args.mask);
 			float program_flavor = 0;
 			switch (current_args.blit_mode) {
 			case BlitMode::kDirect:
@@ -176,7 +176,7 @@
 	}
 }
 
-void BlitProgram::draw(const FloatRect& gl_dest_rect,
+void BlitProgram::draw(const Rectf& gl_dest_rect,
                        const float z_value,
                        const BlitData& texture,
                        const BlitData& mask,
@@ -186,11 +186,11 @@
 	                mask.texture_id != 0 ? BlitMode::kBlendedWithMask : BlitMode::kDirect}});
 }
 
-void BlitProgram::draw_monochrome(const FloatRect& dest_rect,
+void BlitProgram::draw_monochrome(const Rectf& dest_rect,
                                   const float z_value,
                                   const BlitData& texture,
                                   const RGBAColor& blend) {
-	draw({Arguments{dest_rect, z_value, texture, BlitData{0, 0, 0, Rect()}, blend,
+	draw({Arguments{dest_rect, z_value, texture, BlitData{0, 0, 0, Rectf()}, blend,
 	                BlendMode::UseAlpha, BlitMode::kMonochrome}});
 }
 

=== modified file 'src/graphic/gl/blit_program.h'
--- src/graphic/gl/blit_program.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/blit_program.h	2016-10-28 17:51:15 +0000
@@ -36,7 +36,7 @@
 class BlitProgram {
 public:
 	struct Arguments {
-		FloatRect destination_rect;
+		Rectf destination_rect;
 		float z_value;
 		BlitData texture;
 		BlitData mask;
@@ -53,7 +53,7 @@
 	// 'gl_texture_image' to 'gl_dest_rect' in the currently bound framebuffer. All
 	// coordinates are in the OpenGL frame. The 'texture_mask' is used to selectively apply
 	// the 'blend'. This is used for blitting player colored images.
-	void draw(const FloatRect& gl_dest_rect,
+	void draw(const Rectf& gl_dest_rect,
 	          const float z_value,
 	          const BlitData& texture,
 	          const BlitData& mask,
@@ -64,7 +64,7 @@
 	// 'texture' to 'gl_dest_rect' in the currently bound framebuffer. All
 	// coordinates are in the OpenGL frame. The image is first converted to
 	// luminance, then all values are multiplied with blend.
-	void draw_monochrome(const FloatRect& gl_dest_rect,
+	void draw_monochrome(const Rectf& gl_dest_rect,
 	                     const float z_value,
 	                     const BlitData& blit_source,
 	                     const RGBAColor& blend);

=== modified file 'src/graphic/gl/coordinate_conversion.h'
--- src/graphic/gl/coordinate_conversion.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/coordinate_conversion.h	2016-10-28 17:51:15 +0000
@@ -38,34 +38,34 @@
 // Converts 'rect' given on a screen of 'width' x 'height' pixels into a rect
 // in opengl coordinates in a renderbuffer, i.e. in [-1, 1]. The returned
 // rectangle has positive width and height.
-inline FloatRect rect_to_gl_renderbuffer(const int width, const int height, const Rect& rect) {
+inline Rectf rect_to_gl_renderbuffer(const int width, const int height, const Rectf& rect) {
 	float left = rect.x;
 	float top = rect.y;
 	float right = rect.x + rect.w;
 	float bottom = rect.y + rect.h;
 	pixel_to_gl_renderbuffer(width, height, &left, &top);
 	pixel_to_gl_renderbuffer(width, height, &right, &bottom);
-	return FloatRect(left, bottom, right - left, top - bottom);
+	return Rectf(left, bottom, right - left, top - bottom);
 }
 
 // Converts 'rect' given on a texture of 'width' x 'height' pixels into a rect
 // in opengl coordinates in a texture, i.e. in [0, 1]. Texture pixels are sampled in their center.
 // The returned rectangle has positive width and height.
-inline FloatRect rect_to_gl_texture(const int width, const int height, const FloatRect& rect) {
+inline Rectf rect_to_gl_texture(const int width, const int height, const Rectf& rect) {
 	float left = rect.x;
 	float top = rect.y;
 	float right = rect.x + rect.w;
 	float bottom = rect.y + rect.h;
 	pixel_to_gl_texture(width, height, &left, &top);
 	pixel_to_gl_texture(width, height, &right, &bottom);
-	return FloatRect(left, bottom, right - left, top - bottom);
+	return Rectf(left, bottom, right - left, top - bottom);
 }
 
 // Convert 'blit_data' from pixel space into opengl space.
-inline FloatRect to_gl_texture(const BlitData& blit_data) {
+inline Rectf to_gl_texture(const BlitData& blit_data) {
 	return rect_to_gl_texture(
 	   blit_data.parent_width, blit_data.parent_height,
-	   FloatRect(blit_data.rect.x, blit_data.rect.y, blit_data.rect.w, blit_data.rect.h));
+	   Rectf(blit_data.rect.x, blit_data.rect.y, blit_data.rect.w, blit_data.rect.h));
 }
 
 #endif  // end of include guard: WL_GRAPHIC_GL_COORDINATE_CONVERSION_H

=== modified file 'src/graphic/gl/dither_program.cc'
--- src/graphic/gl/dither_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/dither_program.cc	2016-10-28 17:51:15 +0000
@@ -56,14 +56,14 @@
 
 void DitherProgram::add_vertex(const FieldsToDraw::Field& field,
                                const TrianglePoint triangle_point,
-                               const FloatPoint& texture_offset) {
+                               const Vector2f& texture_offset) {
 	vertices_.emplace_back();
 	PerVertexData& back = vertices_.back();
 
-	back.gl_x = field.gl_x;
-	back.gl_y = field.gl_y;
-	back.texture_x = field.texture_x;
-	back.texture_y = field.texture_y;
+	back.gl_x = field.gl_position.x;
+	back.gl_y = field.gl_position.y;
+	back.texture_x = field.texture_coords.x;
+	back.texture_y = field.texture_coords.y;
 	back.brightness = field.brightness;
 	back.texture_offset_x = texture_offset.x;
 	back.texture_offset_y = texture_offset.y;
@@ -98,7 +98,7 @@
 	}
 	const Widelands::TerrainDescription& other_terrain_description = terrains.get(other_terrain);
 	if (terrains.get(my_terrain).dither_layer() < other_terrain_description.dither_layer()) {
-		const FloatPoint texture_offset =
+		const Vector2f texture_offset =
 		   to_gl_texture(other_terrain_description.get_texture(gametime).blit_data()).origin();
 		add_vertex(fields_to_draw.at(idx1), TrianglePoint::kTopRight, texture_offset);
 		add_vertex(fields_to_draw.at(idx2), TrianglePoint::kTopLeft, texture_offset);
@@ -156,50 +156,49 @@
 		// The bottom right neighbor fields_to_draw is needed for both triangles
 		// associated with this field. If it is not in fields_to_draw, there is no need to
 		// draw any triangles.
-		const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
-		if (brn_index == -1) {
+		if (field.brn_index == FieldsToDraw::kInvalidIndex) {
 			continue;
 		}
 
 		// Dithering triangles for Down triangle.
-		const int bln_index =
-		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
-		if (bln_index != -1) {
-			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, brn_index, current_index,
-			                             bln_index, field.ter_d, field.ter_r);
-
-			const int terrain_dd = fields_to_draw.at(bln_index).ter_r;
-			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, bln_index, brn_index,
-			                             current_index, field.ter_d, terrain_dd);
-
-			const int ln_index = fields_to_draw.calculate_index(field.fx - 1, field.fy);
-			if (ln_index != -1) {
-				const int terrain_l = fields_to_draw.at(ln_index).ter_r;
+		if (field.bln_index != FieldsToDraw::kInvalidIndex) {
+			maybe_add_dithering_triangle(
+			   gametime, terrains, fields_to_draw, field.brn_index, current_index, field.bln_index,
+			   field.fcoords.field->terrain_d(), field.fcoords.field->terrain_r());
+
+			const int terrain_dd = fields_to_draw.at(field.bln_index).fcoords.field->terrain_r();
+			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, field.bln_index,
+			                             field.brn_index, current_index,
+			                             field.fcoords.field->terrain_d(), terrain_dd);
+
+			if (field.ln_index != FieldsToDraw::kInvalidIndex) {
+				const int terrain_l = fields_to_draw.at(field.ln_index).fcoords.field->terrain_r();
 				maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, current_index,
-				                             bln_index, brn_index, field.ter_d, terrain_l);
+				                             field.bln_index, field.brn_index,
+				                             field.fcoords.field->terrain_d(), terrain_l);
 			}
 		}
 
 		// Dithering for right triangle.
-		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
-		if (rn_index != -1) {
-			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, current_index, brn_index,
-			                             rn_index, field.ter_r, field.ter_d);
-			int terrain_rr = fields_to_draw.at(rn_index).ter_d;
-			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, brn_index, rn_index,
-			                             current_index, field.ter_r, terrain_rr);
+		if (field.rn_index != FieldsToDraw::kInvalidIndex) {
+			maybe_add_dithering_triangle(
+			   gametime, terrains, fields_to_draw, current_index, field.brn_index, field.rn_index,
+			   field.fcoords.field->terrain_r(), field.fcoords.field->terrain_d());
+			int terrain_rr = fields_to_draw.at(field.rn_index).fcoords.field->terrain_d();
+			maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, field.brn_index,
+			                             field.rn_index, current_index,
+			                             field.fcoords.field->terrain_r(), terrain_rr);
 
-			const int trn_index =
-			   fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy - 1);
-			if (trn_index != -1) {
-				const int terrain_u = fields_to_draw.at(trn_index).ter_d;
-				maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, rn_index,
-				                             current_index, brn_index, field.ter_r, terrain_u);
+			if (field.trn_index != FieldsToDraw::kInvalidIndex) {
+				const int terrain_u = fields_to_draw.at(field.trn_index).fcoords.field->terrain_d();
+				maybe_add_dithering_triangle(gametime, terrains, fields_to_draw, field.rn_index,
+				                             current_index, field.brn_index,
+				                             field.fcoords.field->terrain_r(), terrain_u);
 			}
 		}
 	}
 
 	const BlitData& blit_data = terrains.get(0).get_texture(0).blit_data();
-	const FloatRect texture_coordinates = to_gl_texture(blit_data);
+	const Rectf texture_coordinates = to_gl_texture(blit_data);
 	gl_draw(blit_data.texture_id, texture_coordinates.w, texture_coordinates.h, z_value);
 }

=== modified file 'src/graphic/gl/dither_program.h'
--- src/graphic/gl/dither_program.h	2016-01-08 21:00:39 +0000
+++ src/graphic/gl/dither_program.h	2016-10-28 17:51:15 +0000
@@ -22,7 +22,7 @@
 
 #include <memory>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/gl/fields_to_draw.h"
 #include "graphic/gl/utils.h"
 #include "logic/description_maintainer.h"
@@ -66,7 +66,7 @@
 	// this vertex.
 	void add_vertex(const FieldsToDraw::Field& field,
 	                TrianglePoint triangle_point,
-	                const FloatPoint& texture_offset);
+	                const Vector2f& texture_offset);
 
 	struct PerVertexData {
 		float gl_x;

=== modified file 'src/graphic/gl/draw_line_program.h'
--- src/graphic/gl/draw_line_program.h	2016-02-02 09:02:53 +0000
+++ src/graphic/gl/draw_line_program.h	2016-10-28 17:51:15 +0000
@@ -22,8 +22,8 @@
 
 #include <vector>
 
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 #include "graphic/blend_mode.h"
 #include "graphic/color.h"
 #include "graphic/gl/utils.h"

=== modified file 'src/graphic/gl/fields_to_draw.h'
--- src/graphic/gl/fields_to_draw.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/fields_to_draw.h	2016-10-28 17:51:15 +0000
@@ -21,29 +21,64 @@
 #define WL_GRAPHIC_GL_FIELDS_TO_DRAW_H
 
 #include <cstddef>
+#include <limits>
 #include <string>
 #include <vector>
 
 #include <stdint.h>
 
+#include "base/vector.h"
 #include "logic/map_objects/tribes/road_textures.h"
+#include "logic/player.h"
+#include "logic/widelands.h"
+#include "logic/widelands_geometry.h"
 
 // Helper struct that contains the data needed for drawing all fields. All
 // methods are inlined for performance reasons.
 class FieldsToDraw {
 public:
+	static constexpr int kInvalidIndex = std::numeric_limits<int>::min();
+
 	struct Field {
-		int fx, fy;        // geometric coordinates (i.e. map coordinates that can be out of bounds).
-		float gl_x, gl_y;  // GL Position of this field.
-		float pixel_x, pixel_y;             // Pixel position relative to top left.
-		float texture_x, texture_y;         // Texture coordinates.
-		float brightness;                   // brightness of the pixel
-		uint8_t ter_r, ter_d;               // Texture index of the right and down triangle.
-		uint8_t roads;                      // Bitmask of roads to render, see logic/roadtype.h.
-		const RoadTextures* road_textures;  // Road Textures to use for drawing.
+		Widelands::Coords geometric_coords;  // geometric coordinates (i.e. map coordinates that can
+		                                     // be out of bounds).
+		Widelands::FCoords fcoords;  // The normalized coords and the field this is refering to.
+		Vector2f gl_position;        // GL Position of this field.
+
+		// Surface pixel this will be plotted on.
+		Vector2f surface_pixel;
+
+		// Rendertarget pixel this will be plotted on. This is only different by
+		// the Rendertarget::get_rect().origin() of the view window.
+		Vector2f rendertarget_pixel;
+		Vector2f texture_coords;  // Texture coordinates.
+		float brightness;         // brightness of the pixel
+
+		// The next values are not necessarily the true data of this field, but
+		// what the player should see. For example in fog of war we always draw
+		// what we saw last.
+		uint8_t roads;  // Bitmask of roads to render, see logic/roadtype.h.
+		bool is_border;
+		Widelands::Vision vision;
+		Widelands::Player* owner;  // can be nullptr.
+
+		// Index of neighbors in this 'FieldsToDraw'. kInvalidIndex if this
+		// neighbor is not contained.
+		int ln_index;
+		int rn_index;
+		int trn_index;
+		int bln_index;
+		int brn_index;
+
+		inline bool all_neighbors_valid() const {
+			return ln_index != kInvalidIndex && rn_index != kInvalidIndex &&
+			       trn_index != kInvalidIndex && bln_index != kInvalidIndex &&
+			       brn_index != kInvalidIndex;
+		}
 	};
 
-	FieldsToDraw() = default;
+	FieldsToDraw() {
+	}
 
 	// Resize this fields to draw for reuse.
 	void reset(int minfx, int maxfx, int minfy, int maxfy) {
@@ -60,15 +95,16 @@
 	}
 
 	// Calculates the index of the given field with ('fx', 'fy') being geometric
-	// coordinates in the map. Returns -1 if this field is not in the fields_to_draw.
+	// coordinates in the map. Returns kInvalidIndex if this field is not in the
+	// fields_to_draw.
 	inline int calculate_index(int fx, int fy) const {
 		uint16_t xidx = fx - min_fx_;
 		if (xidx >= w_) {
-			return -1;
+			return kInvalidIndex;
 		}
 		uint16_t yidx = fy - min_fy_;
 		if (yidx >= h_) {
-			return -1;
+			return kInvalidIndex;
 		}
 		return yidx * w_ + xidx;
 	}

=== modified file 'src/graphic/gl/fill_rect_program.cc'
--- src/graphic/gl/fill_rect_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/fill_rect_program.cc	2016-10-28 17:51:15 +0000
@@ -37,7 +37,7 @@
 	attr_color_ = glGetAttribLocation(gl_program_.object(), "attr_color");
 }
 
-void FillRectProgram::draw(const FloatRect& destination_rect,
+void FillRectProgram::draw(const Rectf& destination_rect,
                            const float z_value,
                            const RGBAColor& color,
                            const BlendMode blend_mode) {

=== modified file 'src/graphic/gl/fill_rect_program.h'
--- src/graphic/gl/fill_rect_program.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/fill_rect_program.h	2016-10-28 17:51:15 +0000
@@ -30,7 +30,7 @@
 class FillRectProgram {
 public:
 	struct Arguments {
-		FloatRect destination_rect;
+		Rectf destination_rect;
 		float z_value;
 		RGBAColor color;
 		BlendMode blend_mode;
@@ -41,7 +41,7 @@
 
 	// Fills a solid rect in 'color'. If blend_mode is BlendMode::UseAlpha, this
 	// will brighten the rect, if it is BlendMode::Subtract it darkens it.
-	void draw(const FloatRect& destination_rect,
+	void draw(const Rectf& destination_rect,
 	          float z_value,
 	          const RGBAColor& color,
 	          BlendMode blend_mode);

=== modified file 'src/graphic/gl/road_program.cc'
--- src/graphic/gl/road_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/road_program.cc	2016-10-28 17:51:15 +0000
@@ -50,6 +50,7 @@
                            const int renderbuffer_height,
                            const FieldsToDraw::Field& start,
                            const FieldsToDraw::Field& end,
+                           const float scale,
                            const Widelands::RoadType road_type,
                            const Direction direction,
                            uint32_t* gl_texture) {
@@ -59,8 +60,8 @@
 	// The overshot of the road in either direction in percent.
 	static constexpr float kRoadElongationInPercent = .1;
 
-	const float delta_x = end.pixel_x - start.pixel_x;
-	const float delta_y = end.pixel_y - start.pixel_y;
+	const float delta_x = end.surface_pixel.x - start.surface_pixel.x;
+	const float delta_y = end.surface_pixel.y - start.surface_pixel.y;
 	const float vector_length = std::hypot(delta_x, delta_y);
 
 	const float road_overshoot_x = delta_x * kRoadElongationInPercent;
@@ -68,13 +69,15 @@
 
 	// Find the reciprocal unit vector, so that we can calculate start and end
 	// points for the quad that will make the road.
-	const float road_thickness_x = (-delta_y / vector_length) * kRoadThicknessInPixels;
-	const float road_thickness_y = (delta_x / vector_length) * kRoadThicknessInPixels;
+	const float road_thickness_x = (-delta_y / vector_length) * kRoadThicknessInPixels * scale;
+	const float road_thickness_y = (delta_x / vector_length) * kRoadThicknessInPixels * scale;
 
+	assert(start.owner != nullptr);
 	const Image& texture =
 	   road_type == Widelands::RoadType::kNormal ?
-	      start.road_textures->get_normal_texture(start.fx, start.fy, direction) :
-	      start.road_textures->get_busy_texture(start.fx, start.fy, direction);
+	      start.owner->tribe().road_textures().get_normal_texture(
+	         start.geometric_coords, direction) :
+	      start.owner->tribe().road_textures().get_busy_texture(start.geometric_coords, direction);
 	if (*gl_texture == 0) {
 		*gl_texture = texture.blit_data().texture_id;
 	}
@@ -82,27 +85,27 @@
 	// one texture atlas.
 	assert(*gl_texture == texture.blit_data().texture_id);
 
-	const FloatRect texture_rect = to_gl_texture(texture.blit_data());
+	const Rectf texture_rect = to_gl_texture(texture.blit_data());
 
 	vertices_.emplace_back(PerVertexData{
-	   start.pixel_x - road_overshoot_x + road_thickness_x,
-	   start.pixel_y - road_overshoot_y + road_thickness_y, texture_rect.x, texture_rect.y,
+	   start.surface_pixel.x - road_overshoot_x + road_thickness_x,
+	   start.surface_pixel.y - road_overshoot_y + road_thickness_y, texture_rect.x, texture_rect.y,
 	   start.brightness,
 	});
 	pixel_to_gl_renderbuffer(
 	   renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
 
 	vertices_.emplace_back(PerVertexData{
-	   start.pixel_x - road_overshoot_x - road_thickness_x,
-	   start.pixel_y - road_overshoot_y - road_thickness_y, texture_rect.x,
+	   start.surface_pixel.x - road_overshoot_x - road_thickness_x,
+	   start.surface_pixel.y - road_overshoot_y - road_thickness_y, texture_rect.x,
 	   texture_rect.y + texture_rect.h, start.brightness,
 	});
 	pixel_to_gl_renderbuffer(
 	   renderbuffer_width, renderbuffer_height, &vertices_.back().gl_x, &vertices_.back().gl_y);
 
 	vertices_.emplace_back(PerVertexData{
-	   end.pixel_x + road_overshoot_x + road_thickness_x,
-	   end.pixel_y + road_overshoot_y + road_thickness_y, texture_rect.x + texture_rect.w,
+	   end.surface_pixel.x + road_overshoot_x + road_thickness_x,
+	   end.surface_pixel.y + road_overshoot_y + road_thickness_y, texture_rect.x + texture_rect.w,
 	   texture_rect.y, end.brightness,
 	});
 	pixel_to_gl_renderbuffer(
@@ -116,8 +119,8 @@
 	vertices_.emplace_back(vertices_.at(vertices_.size() - 2));
 
 	vertices_.emplace_back(PerVertexData{
-	   end.pixel_x + road_overshoot_x - road_thickness_x,
-	   end.pixel_y + road_overshoot_y - road_thickness_y, texture_rect.x + texture_rect.w,
+	   end.surface_pixel.x + road_overshoot_x - road_thickness_x,
+	   end.surface_pixel.y + road_overshoot_y - road_thickness_y, texture_rect.x + texture_rect.w,
 	   texture_rect.y + texture_rect.h, end.brightness,
 	});
 	pixel_to_gl_renderbuffer(
@@ -127,7 +130,8 @@
 void RoadProgram::draw(const int renderbuffer_width,
                        const int renderbuffer_height,
                        const FieldsToDraw& fields_to_draw,
-                       float z_value) {
+                       const float scale,
+                       const float z_value) {
 	vertices_.clear();
 
 	uint32_t gl_texture = 0;
@@ -135,36 +139,32 @@
 		const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
 
 		// Road to right neighbor.
-		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
-		if (rn_index != -1) {
+		if (field.rn_index != FieldsToDraw::kInvalidIndex) {
 			const Widelands::RoadType road =
 			   static_cast<Widelands::RoadType>(field.roads & Widelands::RoadType::kMask);
 			if (road != Widelands::RoadType::kNone) {
-				add_road(renderbuffer_width, renderbuffer_height, field, fields_to_draw.at(rn_index),
-				         road, kEast, &gl_texture);
+				add_road(renderbuffer_width, renderbuffer_height, field,
+				         fields_to_draw.at(field.rn_index), scale, road, kEast, &gl_texture);
 			}
 		}
 
 		// Road to bottom right neighbor.
-		const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
-		if (brn_index != -1) {
+		if (field.brn_index != FieldsToDraw::kInvalidIndex) {
 			const Widelands::RoadType road =
 			   static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::RoadType::kMask);
 			if (road != Widelands::RoadType::kNone) {
-				add_road(renderbuffer_width, renderbuffer_height, field, fields_to_draw.at(brn_index),
-				         road, kSouthEast, &gl_texture);
+				add_road(renderbuffer_width, renderbuffer_height, field,
+				         fields_to_draw.at(field.brn_index), scale, road, kSouthEast, &gl_texture);
 			}
 		}
 
 		// Road to bottom right neighbor.
-		const int bln_index =
-		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
-		if (bln_index != -1) {
+		if (field.bln_index != FieldsToDraw::kInvalidIndex) {
 			const Widelands::RoadType road =
 			   static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::RoadType::kMask);
 			if (road != Widelands::RoadType::kNone) {
-				add_road(renderbuffer_width, renderbuffer_height, field, fields_to_draw.at(bln_index),
-				         road, kSouthWest, &gl_texture);
+				add_road(renderbuffer_width, renderbuffer_height, field,
+				         fields_to_draw.at(field.bln_index), scale, road, kSouthWest, &gl_texture);
 			}
 		}
 	}

=== modified file 'src/graphic/gl/road_program.h'
--- src/graphic/gl/road_program.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/road_program.h	2016-10-28 17:51:15 +0000
@@ -42,6 +42,7 @@
 	void draw(int renderbuffer_width,
 	          int renderbuffer_height,
 	          const FieldsToDraw& fields_to_draw,
+				 float scale,
 	          float z_value);
 
 private:
@@ -61,6 +62,7 @@
 	              int renderbuffer_height,
 	              const FieldsToDraw::Field& start,
 	              const FieldsToDraw::Field& end,
+					  float scale,
 	              const Widelands::RoadType road_type,
 	              const Direction direction,
 	              uint32_t* gl_texture);

=== modified file 'src/graphic/gl/terrain_program.cc'
--- src/graphic/gl/terrain_program.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/terrain_program.cc	2016-10-28 17:51:15 +0000
@@ -71,15 +71,15 @@
 }
 
 void TerrainProgram::add_vertex(const FieldsToDraw::Field& field,
-                                const FloatPoint& texture_offset) {
+                                const Vector2f& texture_offset) {
 	vertices_.emplace_back();
 	PerVertexData& back = vertices_.back();
 
-	back.gl_x = field.gl_x;
-	back.gl_y = field.gl_y;
+	back.gl_x = field.gl_position.x;
+	back.gl_y = field.gl_position.y;
 	back.brightness = field.brightness;
-	back.texture_x = field.texture_x;
-	back.texture_y = field.texture_y;
+	back.texture_x = field.texture_coords.x;
+	back.texture_y = field.texture_coords.y;
 	back.texture_offset_x = texture_offset.x;
 	back.texture_offset_y = texture_offset.y;
 }
@@ -101,34 +101,34 @@
 		// The bottom right neighbor fields_to_draw is needed for both triangles
 		// associated with this field. If it is not in fields_to_draw, there is no need to
 		// draw any triangles.
-		const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
-		if (brn_index == -1) {
+		if (field.brn_index == FieldsToDraw::kInvalidIndex) {
 			continue;
 		}
 
 		// Down triangle.
-		const int bln_index =
-		   fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
-		if (bln_index != -1) {
-			const FloatPoint texture_offset =
-			   to_gl_texture(terrains.get(field.ter_d).get_texture(gametime).blit_data()).origin();
+		if (field.bln_index != FieldsToDraw::kInvalidIndex) {
+			const Vector2f texture_offset =
+			   to_gl_texture(
+			      terrains.get(field.fcoords.field->terrain_d()).get_texture(gametime).blit_data())
+			      .origin();
 			add_vertex(fields_to_draw.at(current_index), texture_offset);
-			add_vertex(fields_to_draw.at(bln_index), texture_offset);
-			add_vertex(fields_to_draw.at(brn_index), texture_offset);
+			add_vertex(fields_to_draw.at(field.bln_index), texture_offset);
+			add_vertex(fields_to_draw.at(field.brn_index), texture_offset);
 		}
 
 		// Right triangle.
-		const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
-		if (rn_index != -1) {
-			const FloatPoint texture_offset =
-			   to_gl_texture(terrains.get(field.ter_r).get_texture(gametime).blit_data()).origin();
+		if (field.rn_index != FieldsToDraw::kInvalidIndex) {
+			const Vector2f texture_offset =
+			   to_gl_texture(
+			      terrains.get(field.fcoords.field->terrain_r()).get_texture(gametime).blit_data())
+			      .origin();
 			add_vertex(fields_to_draw.at(current_index), texture_offset);
-			add_vertex(fields_to_draw.at(brn_index), texture_offset);
-			add_vertex(fields_to_draw.at(rn_index), texture_offset);
+			add_vertex(fields_to_draw.at(field.brn_index), texture_offset);
+			add_vertex(fields_to_draw.at(field.rn_index), texture_offset);
 		}
 	}
 
 	const BlitData& blit_data = terrains.get(0).get_texture(0).blit_data();
-	const FloatRect texture_coordinates = to_gl_texture(blit_data);
+	const Rectf texture_coordinates = to_gl_texture(blit_data);
 	gl_draw(blit_data.texture_id, texture_coordinates.w, texture_coordinates.h, z_value);
 }

=== modified file 'src/graphic/gl/terrain_program.h'
--- src/graphic/gl/terrain_program.h	2016-08-04 15:49:05 +0000
+++ src/graphic/gl/terrain_program.h	2016-10-28 17:51:15 +0000
@@ -22,7 +22,7 @@
 
 #include <vector>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/gl/fields_to_draw.h"
 #include "graphic/gl/utils.h"
 #include "logic/description_maintainer.h"
@@ -54,7 +54,7 @@
 	void gl_draw(int gl_texture, float texture_w, float texture_h, float z_value);
 
 	// Adds a vertex to the end of vertices with data from 'field' and 'texture_coordinates'.
-	void add_vertex(const FieldsToDraw::Field& field, const FloatPoint& texture_coordinates);
+	void add_vertex(const FieldsToDraw::Field& field, const Vector2f& texture_coordinates);
 
 	// The program used for drawing the terrain.
 	Gl::Program gl_program_;

=== modified file 'src/graphic/minimap_renderer.cc'
--- src/graphic/minimap_renderer.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/minimap_renderer.cc	2016-10-28 17:51:15 +0000
@@ -25,13 +25,9 @@
 #include "economy/flag.h"
 #include "economy/road.h"
 #include "graphic/graphic.h"
-#include "graphic/image_io.h"
-#include "graphic/texture.h"
 #include "logic/field.h"
-#include "logic/map.h"
 #include "logic/map_objects/world/terrain_description.h"
 #include "logic/map_objects/world/world.h"
-#include "logic/player.h"
 #include "wui/mapviewpixelconstants.h"
 #include "wui/mapviewpixelfunctions.h"
 
@@ -40,12 +36,17 @@
 namespace {
 
 const RGBColor kWhite(255, 255, 255);
+const RGBColor kRed(255, 0, 0);
 
 // Blend two colors.
 inline RGBColor blend_color(const RGBColor& c1, const RGBColor& c2) {
 	return RGBColor((c1.r + c2.r) / 2, (c1.g + c2.g) / 2, (c1.b + c2.b) / 2);
 }
 
+int round_up_to_nearest_even(int number) {
+	return number % 2 == 0 ? number : number + 1;
+}
+
 // Returns the color to be used in the minimap for the given field.
 inline RGBColor calc_minimap_color(const Widelands::EditorGameBase& egbase,
                                    const Widelands::FCoords& f,
@@ -85,83 +86,83 @@
 	return color;
 }
 
-// Draws the dotted frame border onto the minimap.
-bool is_minimap_frameborder(const Widelands::FCoords& f,
-                            const Point& ptopleft,
-                            const Point& pbottomright,
-                            int32_t mapwidth,
-                            int32_t mapheight,
-                            int32_t modx,
-                            int32_t mody) {
-	bool isframepixel = false;
-
-	if (ptopleft.x <= pbottomright.x) {
-		if (f.x >= ptopleft.x && f.x <= pbottomright.x &&
-		    (f.y == ptopleft.y || f.y == pbottomright.y) && f.x % 2 == modx)
-			isframepixel = true;
-	} else {
-		if (((f.x >= ptopleft.x && f.x <= mapwidth) || (f.x >= 0 && f.x <= pbottomright.x)) &&
-		    (f.y == ptopleft.y || f.y == pbottomright.y) && (f.x % 2) == modx)
-			isframepixel = true;
-	}
-
-	if (ptopleft.y <= pbottomright.y) {
-		if (f.y >= ptopleft.y && f.y <= pbottomright.y &&
-		    (f.x == ptopleft.x || f.x == pbottomright.x) && f.y % 2 == mody)
-			isframepixel = true;
-	} else {
-		if (((f.y >= ptopleft.y && f.y <= mapheight) || (f.y >= 0 && f.y <= pbottomright.y)) &&
-		    (f.x == ptopleft.x || f.x == pbottomright.x) && f.y % 2 == mody)
-			isframepixel = true;
-	}
-
-	return isframepixel;
+void draw_view_window(const Map& map,
+                      const Rectf& view_area,
+                      const MiniMapType minimap_type,
+                      const bool zoom,
+                      Texture* texture) {
+	const float divider = zoom ? 1.f : 2.f;
+	const int half_width =
+	   round_up_to_nearest_even(std::ceil(view_area.w / kTriangleWidth / divider));
+	const int half_height =
+	   round_up_to_nearest_even(std::ceil(view_area.h / kTriangleHeight / divider));
+
+	Vector2i center_pixel;
+	switch (minimap_type) {
+	case MiniMapType::kStaticViewWindow:
+		center_pixel = Vector2i(texture->width() / 2, texture->height() / 2);
+		break;
+
+	case MiniMapType::kStaticMap: {
+		Vector2f origin = view_area.center();
+		MapviewPixelFunctions::normalize_pix(map, &origin);
+		center_pixel =
+		   Vector2i(origin.x / kTriangleWidth, origin.y / kTriangleHeight) * (zoom ? 2 : 1);
+		break;
+	}
+	}
+
+	const int width = zoom ? map.get_width() * 2 : map.get_width();
+	const int height = zoom ? map.get_height() * 2 : map.get_height();
+	const auto make_red = [width, height, &texture](int x, int y) {
+		if (x < 0) {
+			x += width;
+		}
+		if (x >= width) {
+			x -= width;
+		}
+		if (y < 0) {
+			y += height;
+		}
+		if (y >= height) {
+			y -= height;
+		}
+		texture->set_pixel(x, y, kRed);
+	};
+
+	bool draw = true;
+	for (int y = -half_height; y <= half_height; ++y) {
+		if (draw) {
+			make_red(-half_width + center_pixel.x, y + center_pixel.y);
+			make_red(half_width + center_pixel.x, y + center_pixel.y);
+		}
+		draw = !draw;
+	}
+
+	draw = true;
+	for (int x = -half_width; x <= half_width; ++x) {
+		if (draw) {
+			make_red(x + center_pixel.x, -half_height + center_pixel.y);
+			make_red(x + center_pixel.x, half_height + center_pixel.y);
+		}
+		draw = !draw;
+	}
 }
 
 // Does the actual work of drawing the minimap.
-void draw_minimap_int(Texture* texture,
-                      const Widelands::EditorGameBase& egbase,
-                      const Widelands::Player* player,
-                      const Point& viewpoint,
-                      MiniMapLayer layers) {
+void do_draw_minimap(Texture* texture,
+                     const Widelands::EditorGameBase& egbase,
+                     const Widelands::Player* player,
+                     const Vector2i& top_left,
+                     MiniMapLayer layers) {
 	const Widelands::Map& map = egbase.map();
-
 	const uint16_t surface_h = texture->height();
 	const uint16_t surface_w = texture->width();
-
-	// size of the display frame
-	int32_t xsize = g_gr->get_xres() / kTriangleWidth / 2;
-	int32_t ysize = g_gr->get_yres() / kTriangleHeight / 2;
-
 	const int32_t mapwidth = egbase.get_map().get_width();
-	const int32_t mapheight = map.get_height();
-
-	Point ptopleft;  // top left point of the current display frame
-	ptopleft.x = viewpoint.x + mapwidth / 2 - xsize;
-	if (ptopleft.x < 0) {
-		ptopleft.x += mapwidth;
-	}
-	ptopleft.y = viewpoint.y + mapheight / 2 - ysize;
-	if (ptopleft.y < 0) {
-		ptopleft.y += mapheight;
-	}
-
-	Point pbottomright;  // bottom right point of the current display frame
-	pbottomright.x = viewpoint.x + mapwidth / 2 + xsize;
-	if (pbottomright.x >= mapwidth) {
-		pbottomright.x -= mapwidth;
-	}
-	pbottomright.y = viewpoint.y + mapheight / 2 + ysize;
-	if (pbottomright.y >= mapheight) {
-		pbottomright.y -= mapheight;
-	}
-
-	uint32_t modx = pbottomright.x % 2;
-	uint32_t mody = pbottomright.y % 2;
 
 	for (uint32_t y = 0; y < surface_h; ++y) {
 		Widelands::FCoords f(
-		   Widelands::Coords(viewpoint.x, viewpoint.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
+		   Widelands::Coords(top_left.x, top_left.y + (layers & MiniMapLayer::Zoom2 ? y / 2 : y)));
 		map.normalize_coords(f);
 		f.field = &map[f];
 		Widelands::MapIndex i = Widelands::Map::get_index(f, mapwidth);
@@ -170,30 +171,26 @@
 				move_r(mapwidth, f, i);
 			}
 
-			RGBColor pixel_color;
-			if ((layers & MiniMapLayer::ViewWindow) &&
-			    is_minimap_frameborder(f, ptopleft, pbottomright, mapwidth, mapheight, modx, mody)) {
-				pixel_color = RGBColor(255, 0, 0);
-			} else {
-				uint16_t vision =
-				   0;  // See Player::Field::Vision: 1 if seen once, > 1 if seen right now.
-				Widelands::PlayerNumber owner = 0;
-				if (player == nullptr || player->see_all()) {
-					vision = 2;  // Seen right now.
-					owner = f.field->get_owned_by();
-				} else if (player != nullptr) {
-					const auto& field = player->fields()[i];
-					vision = field.vision;
-					owner = field.owner;
-				}
-
-				if (vision > 0) {
-					pixel_color = calc_minimap_color(egbase, f, layers, owner, vision > 1);
-				}
+			uint16_t vision = 0;  // See Player::Field::Vision: 1 if seen once, > 1 if seen right now.
+			Widelands::PlayerNumber owner = 0;
+			if (player == nullptr || player->see_all()) {
+				// This player has omnivision - show the field like it is in reality.
+				vision = 2;  // Seen right now.
+				owner = f.field->get_owned_by();
+			} else if (player != nullptr) {
+				// This player might be affected by fog of war - instead of the
+				// reality, we show her what she last saw on this field. If she has
+				// vision of this field, this will be the same as reality -
+				// otherwise this shows reality as it was the last time she had
+				// vision on the field.
+				// If she never had vision, field.vision will be 0.
+				const auto& field = player->fields()[i];
+				vision = field.vision;
+				owner = field.owner;
 			}
 
-			if (pixel_color.r != 0 || pixel_color.g != 0 || pixel_color.b != 0) {
-				texture->set_pixel(x, y, pixel_color);
+			if (vision > 0) {
+				texture->set_pixel(x, y, calc_minimap_color(egbase, f, layers, owner, vision > 1));
 			}
 		}
 	}
@@ -201,12 +198,38 @@
 
 }  // namespace
 
+Vector2f minimap_pixel_to_mappixel(const Widelands::Map& map,
+                                   const Vector2i& minimap_pixel,
+                                   const Rectf& view_area,
+                                   MiniMapType minimap_type,
+                                   const bool zoom) {
+	Vector2f top_left;
+	switch (minimap_type) {
+	case MiniMapType::kStaticViewWindow:
+		top_left =
+		   view_area.center() -
+		   Vector2f(map.get_width() * kTriangleWidth, map.get_height() * kTriangleHeight) / 2.f;
+		break;
+
+	case MiniMapType::kStaticMap:
+		top_left = Vector2f(0., 0.);
+		break;
+	}
+
+	const float multiplier = zoom ? 2.f : 1.f;
+	Vector2f map_pixel = top_left + Vector2f(minimap_pixel.x / multiplier * kTriangleWidth,
+	                                         minimap_pixel.y / multiplier * kTriangleHeight);
+	MapviewPixelFunctions::normalize_pix(map, &map_pixel);
+	return map_pixel;
+}
+
 std::unique_ptr<Texture> draw_minimap(const EditorGameBase& egbase,
                                       const Player* player,
-                                      const Point& viewpoint,
+                                      const Rectf& view_area,
+                                      const MiniMapType& minimap_type,
                                       MiniMapLayer layers) {
-	// TODO(unknown): Currently the minimap is redrawn every frame. That is not really
-	//       necesary. The created texture could be cached and only redrawn two
+	// TODO(sirver): Currently the minimap is redrawn every frame. That is not really
+	//       necessary. The created texture could be cached and only redrawn two
 	//       or three times per second
 	const Map& map = egbase.map();
 	const int16_t map_w = (layers & MiniMapLayer::Zoom2) ? map.get_width() * 2 : map.get_width();
@@ -214,44 +237,22 @@
 
 	std::unique_ptr<Texture> texture(new Texture(map_w, map_h));
 
-	texture->fill_rect(Rect(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255));
+	texture->fill_rect(Rectf(0, 0, texture->width(), texture->height()), RGBAColor(0, 0, 0, 255));
+
+	// Center the view on the middle of the 'view_area'.
+	const bool zoom = layers & MiniMapLayer::Zoom2;
+	Vector2f top_left =
+	   minimap_pixel_to_mappixel(map, Vector2i(0, 0), view_area, minimap_type, zoom);
+	const Coords node =
+	   MapviewPixelFunctions::calc_node_and_triangle(map, top_left.x, top_left.y).node;
 
 	texture->lock();
-	draw_minimap_int(texture.get(), egbase, player, viewpoint, layers);
+	do_draw_minimap(texture.get(), egbase, player, Vector2i(node.x, node.y), layers);
+
+	if (layers & MiniMapLayer::ViewWindow) {
+		draw_view_window(map, view_area, minimap_type, zoom, texture.get());
+	}
 	texture->unlock(Texture::Unlock_Update);
 
 	return texture;
 }
-
-void write_minimap_image(const EditorGameBase& egbase,
-                         const Player* player,
-                         const Point& gviewpoint,
-                         MiniMapLayer layers,
-                         ::StreamWrite* const streamwrite) {
-	assert(streamwrite != nullptr);
-
-	Point viewpoint(gviewpoint);
-
-	// map dimension
-	const int16_t map_w = egbase.get_map().get_width();
-	const int16_t map_h = egbase.get_map().get_height();
-	const int32_t maxx = MapviewPixelFunctions::get_map_end_screen_x(egbase.get_map());
-	const int32_t maxy = MapviewPixelFunctions::get_map_end_screen_y(egbase.get_map());
-	// adjust the viewpoint top topleft in map coords
-	viewpoint.x += g_gr->get_xres() / 2;
-	if (viewpoint.x >= maxx) {
-		viewpoint.x -= maxx;
-	}
-	viewpoint.y += g_gr->get_yres() / 2;
-	if (viewpoint.y >= maxy) {
-		viewpoint.y -= maxy;
-	}
-	viewpoint.x /= kTriangleWidth;
-	viewpoint.y /= kTriangleHeight;
-	viewpoint.x -= map_w / 2;
-	viewpoint.y -= map_h / 2;
-
-	// Render minimap
-	std::unique_ptr<Texture> texture(draw_minimap(egbase, player, viewpoint, layers));
-	save_to_png(texture.get(), streamwrite, ColorType::RGBA);
-}

=== modified file 'src/graphic/minimap_renderer.h'
--- src/graphic/minimap_renderer.h	2016-08-04 15:49:05 +0000
+++ src/graphic/minimap_renderer.h	2016-10-28 17:51:15 +0000
@@ -22,15 +22,12 @@
 
 #include <memory>
 
-#include "base/point.h"
-
-class StreamWrite;
-class Texture;
-
-namespace Widelands {
-class Player;
-class EditorGameBase;
-}
+#include "base/rect.h"
+#include "base/vector.h"
+#include "graphic/texture.h"
+#include "logic/editor_game_base.h"
+#include "logic/map.h"
+#include "logic/player.h"
 
 // Layers for selecting what do display on the minimap.
 enum class MiniMapLayer {
@@ -54,20 +51,31 @@
 	return MiniMapLayer(static_cast<int>(left) ^ static_cast<int>(right));
 }
 
-/// Render the minimap. If player is not nullptr, it renders from that player's
-/// point of view.
-/// \param viewpoint top left corner in map coordinates
+enum class MiniMapType {
+	// Keep the view window always in the center of the minimap and pan the underlying map.
+	kStaticViewWindow,
+
+	// Always align the map at (0, 0) and move the view window instead.
+	kStaticMap,
+};
+
+// Converts between minimap pixel and map pixel.
+// Remember to call 'normalize_pix' after applying the transformation.
+Vector2f minimap_pixel_to_mappixel(const Widelands::Map& map,
+                                   const Vector2i& minimap_pixel,
+                                   const Rectf& view_area,
+                                   MiniMapType minimap_type,
+                                   const bool zoom);
+
+// Render the minimap. If player is not nullptr, it renders from that player's
+// point of view. The 'view_area' designates the currently visible area in the
+// main view in map pixel coordinates and is used to draw the wire frame view
+// window. The 'view_point' is map pixel that will be drawn as the top-left
+// point in the resulting minimap.
 std::unique_ptr<Texture> draw_minimap(const Widelands::EditorGameBase& egbase,
                                       const Widelands::Player* player,
-                                      const Point& viewpoint,
+                                      const Rectf& view_area,
+                                      const MiniMapType& map_draw_type,
                                       MiniMapLayer layers);
 
-/// Render the minimap to a file. 1 pixel will be used for each fields.
-/// \param viewpoint : The game point of view as returned by interactive_base.get_viewpoint();
-void write_minimap_image(const Widelands::EditorGameBase& egbase,
-                         Widelands::Player const* player,
-                         const Point& viewpoint,
-                         MiniMapLayer layers,
-                         StreamWrite* const streamwrite);
-
 #endif  // end of include guard: WL_GRAPHIC_MINIMAP_RENDERER_H

=== added file 'src/graphic/playercolor.cc'
--- src/graphic/playercolor.cc	1970-01-01 00:00:00 +0000
+++ src/graphic/playercolor.cc	2016-10-28 17:51:15 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "graphic/playercolor.h"
+
+#include "graphic/texture.h"
+
+Image* playercolor_image(const RGBColor* clr, const Image* image, const Image* color_mask) {
+	int w = image->width();
+	int h = image->height();
+	Texture* rv = new Texture(w, h);
+	rv->fill_rect(Rectf(0, 0, w, h), RGBAColor(0, 0, 0, 0));
+	rv->blit_blended(Rectf(0, 0, w, h), *image, *color_mask, Rectf(0, 0, w, h), *clr);
+	return rv;
+}
+
+Image* playercolor_image(int player_number, const Image* image, const Image* color_mask) {
+	return playercolor_image(&kPlayerColors[player_number], image, color_mask);
+}

=== added file 'src/graphic/playercolor.h'
--- src/graphic/playercolor.h	1970-01-01 00:00:00 +0000
+++ src/graphic/playercolor.h	2016-10-28 17:51:15 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_PLAYERCOLOR_H
+#define WL_GRAPHIC_PLAYERCOLOR_H
+
+#include "graphic/color.h"
+#include "graphic/image.h"
+
+/// Maximum numbers of players in a game. The game logic code reserves 5 bits
+/// for player numbers, so it can keep track of 32 different player numbers, of
+/// which the value 0 means neutral and the values 1 .. 31 can be used as the
+/// numbers for actual players. So the upper limit of this value is 31.
+constexpr uint8_t kMaxPlayers = 16;
+
+// Hard coded player colors
+const RGBColor kPlayerColors[kMaxPlayers] = {
+   RGBColor(2, 2, 198),      // blue
+   RGBColor(255, 41, 0),     // red
+   RGBColor(255, 232, 0),    // yellow
+   RGBColor(59, 223, 3),     // green
+   RGBColor(57, 57, 57),     // black/dark gray
+   RGBColor(255, 172, 0),    // orange
+   RGBColor(215, 0, 218),    // purple
+   RGBColor(255, 255, 255),  // white
+   RGBColor(0, 120, 255),    // sky blue
+   RGBColor(104, 0, 40),     // dark red
+   RGBColor(120, 108, 0),    // dark yellow
+   RGBColor(0, 112, 0),      // dark green
+   RGBColor(255, 120, 160),  // rose
+   RGBColor(148, 56, 0),     // brown
+   RGBColor(96, 0, 84),      // dark purple
+   RGBColor(144, 144, 144),  // light gray
+};
+
+Image* playercolor_image(const RGBColor* clr, const Image* image, const Image* color_mask);
+Image* playercolor_image(int player_number, const Image* image, const Image* color_mask);
+
+#endif  // end of include guard: WL_GRAPHIC_PLAYERCOLOR_H

=== modified file 'src/graphic/render_queue.cc'
--- src/graphic/render_queue.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/render_queue.cc	2016-10-28 17:51:15 +0000
@@ -120,14 +120,14 @@
 // creation. Disables GL_SCISSOR_TEST at desctruction again.
 class ScopedScissor {
 public:
-	ScopedScissor(const FloatRect& rect);
+	ScopedScissor(const Rectf& rect);
 	~ScopedScissor();
 
 private:
 	DISALLOW_COPY_AND_ASSIGN(ScopedScissor);
 };
 
-ScopedScissor::ScopedScissor(const FloatRect& rect) {
+ScopedScissor::ScopedScissor(const Rectf& rect) {
 	glScissor(rect.x, rect.y, rect.w, rect.h);
 	glEnable(GL_SCISSOR_TEST);
 }
@@ -249,9 +249,10 @@
 
 		case Program::kTerrainRoad: {
 			ScopedScissor scoped_scissor(item.terrain_arguments.destination_rect);
-			road_program_->draw(
-			   item.terrain_arguments.renderbuffer_width, item.terrain_arguments.renderbuffer_height,
-			   *item.terrain_arguments.fields_to_draw, item.z_value + 2 * kOpenGlZDelta);
+			road_program_->draw(item.terrain_arguments.renderbuffer_width,
+			                    item.terrain_arguments.renderbuffer_height,
+			                    *item.terrain_arguments.fields_to_draw, item.terrain_arguments.scale,
+			                    item.z_value + 2 * kOpenGlZDelta);
 			++i;
 		} break;
 

=== modified file 'src/graphic/render_queue.h'
--- src/graphic/render_queue.h	2016-08-04 15:49:05 +0000
+++ src/graphic/render_queue.h	2016-10-28 17:51:15 +0000
@@ -99,12 +99,12 @@
 		BlitData texture;
 		BlitData mask;
 		RGBAColor blend;
-		FloatRect destination_rect;
+		Rectf destination_rect;
 	};
 
 	struct RectArguments {
 		RGBAColor color;
-		FloatRect destination_rect;
+		Rectf destination_rect;
 	};
 
 	// TODO(sirver): these are really triangle arguments.
@@ -121,7 +121,8 @@
 		int renderbuffer_height;
 		const DescriptionMaintainer<Widelands::TerrainDescription>* terrains;
 		FieldsToDraw* fields_to_draw;
-		FloatRect destination_rect;
+		float scale;
+		Rectf destination_rect;
 	};
 
 	// The union of all possible program arguments represents an Item that is

=== modified file 'src/graphic/rendertarget.cc'
--- src/graphic/rendertarget.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/rendertarget.cc	2016-10-28 17:51:15 +0000
@@ -35,7 +35,7 @@
 /**
  * Sets an arbitrary drawing window.
  */
-void RenderTarget::set_window(const Rect& rc, const Point& ofs) {
+void RenderTarget::set_window(const Recti& rc, const Vector2i& ofs) {
 	rect_ = rc;
 	offset_ = ofs;
 
@@ -69,15 +69,15 @@
  * Returns false if the subwindow is invisible. In that case, the window state
  * is not changed at all. Otherwise, the function returns true.
  */
-bool RenderTarget::enter_window(const Rect& rc, Rect* previous, Point* prevofs) {
-	Rect newrect = rc;
-
-	if (clip(newrect)) {
+bool RenderTarget::enter_window(const Recti& rc, Recti* previous, Vector2i* prevofs) {
+	Rectf newrect_f = rc.cast<float>();
+	if (clip(newrect_f)) {
 		if (previous)
 			*previous = rect_;
 		if (prevofs)
 			*prevofs = offset_;
 
+		const Recti newrect = newrect_f.cast<int>();
 		// Apply the changes
 		offset_ = rc.origin() - (newrect.origin() - rect_.origin() - offset_);
 		rect_ = newrect;
@@ -104,10 +104,10 @@
 /**
  * This functions draws a line in the target
  */
-void RenderTarget::draw_line_strip(const std::vector<FloatPoint>& points,
+void RenderTarget::draw_line_strip(const std::vector<Vector2f>& points,
                                    const RGBColor& color,
                                    float line_width) {
-	std::vector<FloatPoint> adjusted_points;
+	std::vector<Vector2f> adjusted_points;
 	adjusted_points.reserve(points.size());
 	for (const auto& p : points) {
 		adjusted_points.emplace_back(p.x + offset_.x + rect_.x, p.y + offset_.y + rect_.y);
@@ -118,21 +118,21 @@
 /**
  * Clip against window and pass those primitives along to the bitmap.
  */
-void RenderTarget::draw_rect(const Rect& rect, const RGBColor& clr) {
-	Rect r(rect);
+void RenderTarget::draw_rect(const Rectf& rect, const RGBColor& clr) {
+	Rectf r(rect);
 	if (clip(r)) {
 		::draw_rect(r, clr, surface_);
 	}
 }
 
-void RenderTarget::fill_rect(const Rect& rect, const RGBAColor& clr, BlendMode blend_mode) {
-	Rect r(rect);
+void RenderTarget::fill_rect(const Rectf& rect, const RGBAColor& clr, BlendMode blend_mode) {
+	Rectf r(rect);
 	if (clip(r))
 		surface_->fill_rect(r, clr, blend_mode);
 }
 
-void RenderTarget::brighten_rect(const Rect& rect, int32_t factor) {
-	Rect r(rect);
+void RenderTarget::brighten_rect(const Rectf& rect, int32_t factor) {
+	Rectf r(rect);
 	if (clip(r))
 		surface_->brighten_rect(r, factor);
 }
@@ -142,30 +142,32 @@
  *
  * This blit function copies the pixels to the destination surface.
  */
-void RenderTarget::blit(const Point& dst,
+void RenderTarget::blit(const Vector2f& dst,
                         const Image* image,
                         BlendMode blend_mode,
                         UI::Align align) {
-	Point destination_point(dst);
+	Vector2f destination_point(dst);
 	UI::correct_for_align(align, image->width(), image->height(), &destination_point);
 
-	Rect source_rect(Point(0, 0), image->width(), image->height());
-	Rect destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
+	Rectf source_rect(Vector2i(0, 0), image->width(), image->height());
+	Rectf destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
 
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
-		surface_->blit(destination_rect, *image, source_rect, 1., blend_mode);
+		// I seem to remember seeing 1. a lot in blitting calls.
+		constexpr float kFullyOpaque = 1.f;
+		surface_->blit(destination_rect, *image, source_rect, kFullyOpaque, blend_mode);
 	}
 }
 
-void RenderTarget::blit_monochrome(const Point& dst,
+void RenderTarget::blit_monochrome(const Vector2f& dst,
                                    const Image* image,
                                    const RGBAColor& blend_mode,
                                    UI::Align align) {
-	Point destination_point(dst);
+	Vector2f destination_point(dst);
 	UI::correct_for_align(align, image->width(), image->height(), &destination_point);
 
-	Rect source_rect(Point(0, 0), image->width(), image->height());
-	Rect destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
+	Rectf source_rect(Vector2i(0, 0), image->width(), image->height());
+	Rectf destination_rect(destination_point.x, destination_point.y, source_rect.w, source_rect.h);
 
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
 		surface_->blit_monochrome(destination_rect, *image, source_rect, blend_mode);
@@ -175,38 +177,40 @@
 /**
  * Like \ref blit, but use only a sub-rectangle of the source image.
  */
-void RenderTarget::blitrect(const Point& dst,
+void RenderTarget::blitrect(const Vector2f& dst,
                             const Image* image,
-                            const Rect& gsrcrc,
+                            const Recti& gsrcrc,
                             BlendMode blend_mode) {
 	assert(0 <= gsrcrc.x);
 	assert(0 <= gsrcrc.y);
 
 	// We want to use the given srcrc, but we must make sure that we are not
 	// blitting outside of the boundaries of 'image'.
-	Rect source_rect(gsrcrc.x, gsrcrc.y, std::min<int32_t>(image->width() - gsrcrc.x, gsrcrc.w),
-	                 std::min<int32_t>(image->height() - gsrcrc.y, gsrcrc.h));
-	Rect destination_rect(dst.x, dst.y, source_rect.w, source_rect.h);
+	Rectf source_rect(gsrcrc.x, gsrcrc.y, std::min<int32_t>(image->width() - gsrcrc.x, gsrcrc.w),
+	                  std::min<int32_t>(image->height() - gsrcrc.y, gsrcrc.h));
+	Rectf destination_rect(dst.x, dst.y, source_rect.w, source_rect.h);
 
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
 		surface_->blit(destination_rect, *image, source_rect, 1., blend_mode);
 	}
 }
 
-void RenderTarget::blitrect_scale(Rect destination_rect,
+void RenderTarget::blitrect_scale(Rectf destination_rect,
                                   const Image* image,
-                                  Rect source_rect,
+                                  Recti source_rect_i,
                                   const float opacity,
                                   const BlendMode blend_mode) {
+	Rectf source_rect = source_rect_i.cast<float>();
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
 		surface_->blit(destination_rect, *image, source_rect, opacity, blend_mode);
 	}
 }
 
-void RenderTarget::blitrect_scale_monochrome(Rect destination_rect,
+void RenderTarget::blitrect_scale_monochrome(Rectf destination_rect,
                                              const Image* image,
-                                             Rect source_rect,
+                                             Recti source_rect_i,
                                              const RGBAColor& blend) {
+	Rectf source_rect = source_rect_i.cast<float>();
 	if (to_surface_geometry(&destination_rect, &source_rect)) {
 		surface_->blit_monochrome(destination_rect, *image, source_rect, blend);
 	}
@@ -218,15 +222,15 @@
  * The pixel from ofs inside image is placed at the top-left corner of
  * the filled rectangle.
  */
-void RenderTarget::tile(const Rect& rect,
+void RenderTarget::tile(const Recti& rect,
                         const Image* image,
-                        const Point& gofs,
+                        const Vector2i& gofs,
                         BlendMode blend_mode) {
 	int32_t srcw = image->width();
 	int32_t srch = image->height();
 
-	Rect r(rect);
-	Point ofs(gofs);
+	Rectf r = rect.cast<float>();
+	Vector2i ofs(gofs);
 	if (clip(r)) {
 		if (offset_.x < 0)
 			ofs.x -= offset_.x;
@@ -251,7 +255,7 @@
 		while (ty < r.h) {
 			int tx = 0;
 			int32_t tofsx = ofs.x;
-			Rect srcrc;
+			Rectf srcrc;
 
 			srcrc.y = ofs.y;
 			srcrc.h = srch - ofs.y;
@@ -266,7 +270,7 @@
 				if (tx + srcrc.w > r.w)
 					srcrc.w = r.w - tx;
 
-				const Rect dst_rect(r.x + tx, r.y + ty, srcrc.w, srcrc.h);
+				const Rectf dst_rect(r.x + tx, r.y + ty, srcrc.w, srcrc.h);
 				surface_->blit(dst_rect, *image, srcrc, 1., blend_mode);
 
 				tx += srcrc.w;
@@ -280,54 +284,50 @@
 	}
 }
 
-/**
- * Draws a frame of an animation at the given location
- * Plays sound effect that is registered with this frame (the SoundHandler
- * decides if the sound really does get played)
- *
- * \param dstx, dsty the on-screen location of the animation hot spot
- * \param animation the animation ID
- * \param time the time, in milliseconds, in the animation
- * \param player the player this object belongs to, for player colour
- * purposes. May be 0 (for example, for world objects).
- */
-// TODO(unknown): Correctly calculate the stereo position for sound effects
-// TODO(unknown): The chosen semantics of animation sound effects is problematic:
-// What if the game runs very slowly or very quickly?
-void RenderTarget::blit_animation(const Point& dst, uint32_t animation, uint32_t time) {
+void RenderTarget::blit_animation(const Vector2f& dst,
+                                  const float scale,
+                                  uint32_t animation,
+                                  uint32_t time) {
+	// TODO(unknown): Correctly calculate the stereo position for sound effects
+	// TODO(unknown): The chosen semantics of animation sound effects is problematic:
+	// What if the game runs very slowly or very quickly?
 	const Animation& anim = g_gr->animations().get_animation(animation);
-	do_blit_animation(dst, anim, time, nullptr, Rect(Point(0, 0), anim.width(), anim.height()));
+	do_blit_animation(
+	   dst, scale, anim, time, nullptr, Recti(Vector2i(0, 0), anim.width(), anim.height()));
 }
 
-void RenderTarget::blit_animation(const Point& dst,
+void RenderTarget::blit_animation(const Vector2f& dst,
+                                  const float scale,
                                   uint32_t animation,
                                   uint32_t time,
                                   const RGBColor& player_color) {
 	const Animation& anim = g_gr->animations().get_animation(animation);
 	do_blit_animation(
-	   dst, anim, time, &player_color, Rect(Point(0, 0), anim.width(), anim.height()));
+	   dst, scale, anim, time, &player_color, Recti(Vector2i(0, 0), anim.width(), anim.height()));
 }
 
-void RenderTarget::blit_animation(const Point& dst,
+void RenderTarget::blit_animation(const Vector2f& dst,
+                                  const float scale,
                                   uint32_t animation,
                                   uint32_t time,
                                   const RGBColor& player_color,
-                                  const Rect& source_rect) {
+                                  const Recti& source_rect) {
 	do_blit_animation(
-	   dst, g_gr->animations().get_animation(animation), time, &player_color, source_rect);
+	   dst, scale, g_gr->animations().get_animation(animation), time, &player_color, source_rect);
 }
 
-void RenderTarget::do_blit_animation(const Point& dst,
+void RenderTarget::do_blit_animation(const Vector2f& dst,
+                                     const float scale,
                                      const Animation& animation,
                                      uint32_t time,
                                      const RGBColor* player_color,
-                                     const Rect& source_rect) {
-	Rect destination_rect(dst.x - animation.hotspot().x + source_rect.x,
-	                      dst.y - animation.hotspot().y + source_rect.y, source_rect.w,
-	                      source_rect.h);
-	Rect srcrc(source_rect);
-	if (to_surface_geometry(&destination_rect, &srcrc)) {
-		animation.blit(time, destination_rect.origin(), srcrc, player_color, surface_);
+                                     const Recti& source_rect_i) {
+	Rectf source_rect = source_rect_i.cast<float>();
+	Rectf destination_rect(dst.x - (animation.hotspot().x - source_rect.x) * scale,
+	                       dst.y - (animation.hotspot().y - source_rect.y) * scale,
+	                       source_rect.w * scale, source_rect.h * scale);
+	if (to_surface_geometry(&destination_rect, &source_rect)) {
+		animation.blit(time, destination_rect, source_rect, player_color, surface_);
 	}
 
 	// Look if there is a sound effect registered for this frame and trigger the
@@ -355,7 +355,7 @@
  * If true is returned, r a valid rectangle that can be used.
  * If false is returned, r may not be used and may be partially modified.
  */
-bool RenderTarget::clip(Rect& r) const {
+bool RenderTarget::clip(Rectf& r) const {
 	r.x += offset_.x;
 	r.y += offset_.y;
 
@@ -397,7 +397,7 @@
  * Clip against window and source bitmap, returns false if blitting is
  * unnecessary because image is not inside the target surface.
  */
-bool RenderTarget::to_surface_geometry(Rect* destination_rect, Rect* source_rect) const {
+bool RenderTarget::to_surface_geometry(Rectf* destination_rect, Rectf* source_rect) const {
 	assert(0 <= source_rect->x);
 	assert(0 <= source_rect->y);
 	destination_rect->x += offset_.x;
@@ -409,17 +409,16 @@
 	// destination_rect, we do this by making the proportional change.
 
 	// Clipping, from the left.
-	if (destination_rect->x < 0) {
+	if (destination_rect->x < 0.f) {
 		if (destination_rect->w <= -destination_rect->x) {
 			return false;
 		}
-		// Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
-		const int source_rect_pixel_change =
-		   0.5 + -static_cast<double>(destination_rect->x) / destination_rect->w * source_rect->w;
+		const float source_rect_pixel_change =
+		   -destination_rect->x / destination_rect->w * source_rect->w;
 		source_rect->x += source_rect_pixel_change;
 		source_rect->w -= source_rect_pixel_change;
 		destination_rect->w += destination_rect->x;
-		destination_rect->x = 0;
+		destination_rect->x = 0.f;
 	}
 
 	// Clipping, from the right.
@@ -427,25 +426,22 @@
 		if (rect_.w <= destination_rect->x) {
 			return false;
 		}
-		const int new_destination_w = rect_.w - destination_rect->x;
-		// Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
-		source_rect->w =
-		   0.5 + static_cast<double>(new_destination_w) / destination_rect->w * source_rect->w;
+		const float new_destination_w = rect_.w - destination_rect->x;
+		source_rect->w = new_destination_w / destination_rect->w * source_rect->w;
 		destination_rect->w = new_destination_w;
 	}
 
 	// Clipping, from the top.
-	if (destination_rect->y < 0) {
+	if (destination_rect->y < 0.f) {
 		if (destination_rect->h <= -destination_rect->y) {
 			return false;
 		}
-		// Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
-		const int source_rect_pixel_change =
-		   0.5 + -static_cast<double>(destination_rect->y) / destination_rect->h * source_rect->h;
+		const float source_rect_pixel_change =
+		   -destination_rect->y / destination_rect->h * source_rect->h;
 		source_rect->y += source_rect_pixel_change;
 		source_rect->h -= source_rect_pixel_change;
 		destination_rect->h += destination_rect->y;
-		destination_rect->y = 0;
+		destination_rect->y = 0.f;
 	}
 
 	// Clipping, from the bottom.
@@ -453,13 +449,10 @@
 		if (rect_.h <= destination_rect->y) {
 			return false;
 		}
-		const int new_destination_h = rect_.h - destination_rect->y;
-		// Adding 0.5 is a cheap way of turning integer truncation into a rounded value.
-		source_rect->h =
-		   0.5 + static_cast<double>(new_destination_h) / destination_rect->h * source_rect->h;
+		const float new_destination_h = rect_.h - destination_rect->y;
+		source_rect->h = new_destination_h / destination_rect->h * source_rect->h;
 		destination_rect->h = new_destination_h;
 	}
-
 	destination_rect->x += rect_.x;
 	destination_rect->y += rect_.y;
 	return true;

=== modified file 'src/graphic/rendertarget.h'
--- src/graphic/rendertarget.h	2016-08-04 15:49:05 +0000
+++ src/graphic/rendertarget.h	2016-10-28 17:51:15 +0000
@@ -51,31 +51,31 @@
 class RenderTarget {
 public:
 	RenderTarget(Surface*);
-	void set_window(const Rect& rc, const Point& ofs);
-	bool enter_window(const Rect& rc, Rect* previous, Point* prevofs);
+	void set_window(const Recti& rc, const Vector2i& ofs);
+	bool enter_window(const Recti& rc, Recti* previous, Vector2i* prevofs);
 
 	int32_t width() const;
 	int32_t height() const;
 
-	void draw_line_strip(const std::vector<FloatPoint>& points, const RGBColor& color, float width);
-	void draw_rect(const Rect&, const RGBColor&);
-	void fill_rect(const Rect&, const RGBAColor&, BlendMode blend_mode = BlendMode::Copy);
-	void brighten_rect(const Rect&, int32_t factor);
+	void draw_line_strip(const std::vector<Vector2f>& points, const RGBColor& color, float width);
+	void draw_rect(const Rectf&, const RGBColor&);
+	void fill_rect(const Rectf&, const RGBAColor&, BlendMode blend_mode = BlendMode::Copy);
+	void brighten_rect(const Rectf&, int32_t factor);
 
-	void blit(const Point& dst,
+	void blit(const Vector2f& dst,
 	          const Image* image,
 	          BlendMode blend_mode = BlendMode::UseAlpha,
 	          UI::Align = UI::Align::kTopLeft);
 
 	// Like blit. See MonochromeBlitProgram for details.
-	void blit_monochrome(const Point& dst,
+	void blit_monochrome(const Vector2f& dst,
 	                     const Image* image,
 	                     const RGBAColor& blend_mode,
 	                     UI::Align = UI::Align::kTopLeft);
 
-	void blitrect(const Point& dst,
+	void blitrect(const Vector2f& dst,
 	              const Image* image,
-	              const Rect& src,
+	              const Recti& src,
 	              BlendMode blend_mode = BlendMode::UseAlpha);
 
 	// Blits the 'source_rect' from 'image' into the
@@ -83,68 +83,71 @@
 	// multiplied with 'opacity' before blitting. The 'blend_mode'
 	// defines if values are blended with whats already there or just
 	// copied over.
-	// Rect's are taken by value on purpose.
-	void blitrect_scale(Rect destination_rect,
+	// Takes by value on purpose.
+	void blitrect_scale(Rectf destination_rect,
 	                    const Image* image,
-	                    Rect source_rect,
+	                    Recti source_rect,
 	                    float opacity,
 	                    BlendMode blend_mode);
 
-	// Like blitrect_scale. See MonochromeBlitProgram for details. Rect's are
-	// taken by value on purpose.
-	void blitrect_scale_monochrome(Rect destination_rect,
+	// Like blitrect_scale. See MonochromeBlitProgram for details. Takes by
+	// value on purpose.
+	void blitrect_scale_monochrome(Rectf destination_rect,
 	                               const Image* image,
-	                               Rect source_rect,
+	                               Recti source_rect,
 	                               const RGBAColor& blend);
 
-	void tile(const Rect&,
+	void tile(const Recti&,
 	          const Image* image,
-	          const Point& ofs,
+	          const Vector2i& ofs,
 	          BlendMode blend_mode = BlendMode::UseAlpha);
 
-	// Draw the 'animation' as it should appear at 'time' in this target at 'dst'. Optionally, the
-	// animation is
-	// tinted with 'player_color' and cropped to 'source_rect'.
-	void blit_animation(const Point& dst, uint32_t animation, uint32_t time);
-	void blit_animation(const Point& dst,
+	// Draw the 'animation' as it should appear at 'time' in this target at
+	// 'dst'. Optionally, the animation is tinted with 'player_color' and
+	// cropped to 'source_rect'.
+	void blit_animation(const Vector2f& dst, float scale, uint32_t animation, uint32_t time);
+	void blit_animation(const Vector2f& dst,
+	                    float scale,
 	                    uint32_t animation,
 	                    uint32_t time,
 	                    const RGBColor& player_color);
-	void blit_animation(const Point& dst,
+	void blit_animation(const Vector2f& dst,
+	                    float scale,
 	                    uint32_t animation,
 	                    uint32_t time,
 	                    const RGBColor& player_color,
-	                    const Rect& source_rect);
+	                    const Recti& source_rect);
 
 	void reset();
 
 	Surface* get_surface() const {
 		return surface_;
 	}
-	const Rect& get_rect() const {
+	const Recti& get_rect() const {
 		return rect_;
 	}
-	const Point& get_offset() const {
+	const Vector2i& get_offset() const {
 		return offset_;
 	}
 
 protected:
-	bool clip(Rect& r) const;
-	bool to_surface_geometry(Rect* destination_rect, Rect* source_rect) const;
+	bool clip(Rectf& r) const;
+	bool to_surface_geometry(Rectf* destination_rect, Rectf* source_rect) const;
 
 	// Does the actual blitting.
-	void do_blit_animation(const Point& dst,
+	void do_blit_animation(const Vector2f& dst,
+	                       const float scale,
 	                       const Animation& animation,
 	                       uint32_t time,
 	                       const RGBColor* player_color,
-	                       const Rect& source_rect);
+	                       const Recti& source_rect);
 
 	/// The target surface
 	Surface* surface_;
 	/// The current clip rectangle
-	Rect rect_;
+	Recti rect_;
 	/// Drawing offset
-	Point offset_;
+	Vector2i offset_;
 };
 
 #endif  // end of include guard: WL_GRAPHIC_RENDERTARGET_H

=== modified file 'src/graphic/richtext.cc'
--- src/graphic/richtext.cc	2016-08-04 16:24:09 +0000
+++ src/graphic/richtext.cc	2016-10-28 17:51:15 +0000
@@ -41,7 +41,7 @@
  * rectangular bounding box.
  */
 struct Element {
-	explicit Element(const Rect& bounding_box) : bbox(bounding_box) {
+	explicit Element(const Recti& bounding_box) : bbox(bounding_box) {
 	}
 	virtual ~Element() {
 	}
@@ -52,23 +52,23 @@
 	 */
 	virtual void draw(RenderTarget& dst) = 0;
 
-	Rect bbox;
+	Recti bbox;
 };
 
 struct ImageElement : Element {
-	ImageElement(const Rect& bounding_box, const Image* init_image)
+	ImageElement(const Recti& bounding_box, const Image* init_image)
 	   : Element(bounding_box), image(init_image) {
 	}
 
 	void draw(RenderTarget& dst) override {
-		dst.blit(Point(0, 0), image);
+		dst.blit(Vector2f(0, 0), image);
 	}
 
 	const Image* image;
 };
 
 struct TextlineElement : Element {
-	TextlineElement(const Rect& bounding_box,
+	TextlineElement(const Recti& bounding_box,
 	                const TextStyle& init_style,
 	                std::vector<std::string>::const_iterator words_begin,
 	                std::vector<std::string>::const_iterator words_end)
@@ -107,16 +107,16 @@
 			}
 		}
 		// Now render
-		uint32_t x = g_fh->draw_text_raw(dst, style, Point(0, 0), result_words[0]);
+		uint32_t x = g_fh->draw_text_raw(dst, style, Vector2i(0, 0), result_words[0]);
 
 		it = result_words.begin() + 1;
 		if (it != result_words.end()) {
 			do {
 				if (style.underline)
-					x += g_fh->draw_text_raw(dst, style, Point(x, 0), " ");
+					x += g_fh->draw_text_raw(dst, style, Vector2i(x, 0), " ");
 				else
 					x += spacewidth;
-				x += g_fh->draw_text_raw(dst, style, Point(x, 0), *it++);
+				x += g_fh->draw_text_raw(dst, style, Vector2i(x, 0), *it++);
 			} while (it != result_words.end());
 		}
 	}
@@ -357,7 +357,7 @@
 			if (!image)
 				continue;
 
-			Rect bbox;
+			Recti bbox;
 			bbox.x = text.images_width;
 			bbox.y = m->height;
 			bbox.w = image->width();
@@ -423,7 +423,7 @@
 				TextBuilder::Elt elt;
 				elt.miny = elt.maxy = 0;
 
-				Rect bbox;
+				Recti bbox;
 				bbox.x = text.linewidth ? text.linewidth + text.spacewidth : 0;
 				bbox.y = 0;  // filled in later
 				bbox.w = 0;
@@ -486,16 +486,16 @@
  * @note this function may draw content outside the box given offset
  * and @ref width and @ref height, if there were wrapping problems.
  */
-void RichText::draw(RenderTarget& dst, const Point& offset, bool background) {
+void RichText::draw(RenderTarget& dst, const Vector2i& offset, bool background) {
 	for (std::vector<Element*>::const_iterator elt = m->elements.begin(); elt != m->elements.end();
 	     ++elt) {
-		Rect oldbox;
-		Point oldofs;
-		Rect bbox((*elt)->bbox.origin() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
+		Recti oldbox;
+		Vector2i oldofs;
+		Recti bbox((*elt)->bbox.origin() + offset, (*elt)->bbox.w, (*elt)->bbox.h);
 
 		if (dst.enter_window(bbox, &oldbox, &oldofs)) {
 			if (background)
-				dst.fill_rect(Rect(Point(0, 0), bbox.w, bbox.h), m->background_color);
+				dst.fill_rect(Rectf(0.f, 0.f, bbox.w, bbox.h), m->background_color);
 			(*elt)->draw(dst);
 			dst.set_window(oldbox, oldofs);
 		}

=== modified file 'src/graphic/richtext.h'
--- src/graphic/richtext.h	2016-08-04 15:49:05 +0000
+++ src/graphic/richtext.h	2016-10-28 17:51:15 +0000
@@ -24,7 +24,7 @@
 #include <memory>
 #include <string>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/color.h"
 
 class RenderTarget;
@@ -50,7 +50,7 @@
 	uint32_t height();
 
 	void parse(const std::string& text);
-	void draw(RenderTarget& dst, const Point& offset, bool background = false);
+	void draw(RenderTarget& dst, const Vector2i& offset, bool background = false);
 
 private:
 	std::unique_ptr<RichTextImpl> m;

=== modified file 'src/graphic/screen.cc'
--- src/graphic/screen.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/screen.cc	2016-10-28 17:51:15 +0000
@@ -53,7 +53,7 @@
 	return std::unique_ptr<Texture>(new Texture(surface));
 }
 
-void Screen::do_blit(const FloatRect& dst_rect,
+void Screen::do_blit(const Rectf& dst_rect,
                      const BlitData& texture,
                      float opacity,
                      BlendMode blend_mode) {
@@ -68,7 +68,7 @@
 	RenderQueue::instance().enqueue(i);
 }
 
-void Screen::do_blit_blended(const FloatRect& dst_rect,
+void Screen::do_blit_blended(const Rectf& dst_rect,
                              const BlitData& texture,
                              const BlitData& mask,
                              const RGBColor& blend) {
@@ -83,7 +83,7 @@
 	RenderQueue::instance().enqueue(i);
 }
 
-void Screen::do_blit_monochrome(const FloatRect& dst_rect,
+void Screen::do_blit_monochrome(const Rectf& dst_rect,
                                 const BlitData& texture,
                                 const RGBAColor& blend) {
 	RenderQueue::Item i;
@@ -105,7 +105,7 @@
 	RenderQueue::instance().enqueue(i);
 }
 
-void Screen::do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
+void Screen::do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
 	RenderQueue::Item i;
 	i.blend_mode = blend_mode;
 	i.program_id = RenderQueue::Program::kRect;

=== modified file 'src/graphic/screen.h'
--- src/graphic/screen.h	2016-08-04 15:49:05 +0000
+++ src/graphic/screen.h	2016-10-28 17:51:15 +0000
@@ -43,20 +43,20 @@
 	std::unique_ptr<Texture> to_texture() const;
 
 private:
-	void do_blit(const FloatRect& dst_rect,
+	void do_blit(const Rectf& dst_rect,
 	             const BlitData& texture,
 	             float opacity,
 	             BlendMode blend_mode) override;
-	void do_blit_blended(const FloatRect& dst_rect,
+	void do_blit_blended(const Rectf& dst_rect,
 	                     const BlitData& texture,
 	                     const BlitData& mask,
 	                     const RGBColor& blend) override;
-	void do_blit_monochrome(const FloatRect& dst_rect,
+	void do_blit_monochrome(const Rectf& dst_rect,
 	                        const BlitData& texture,
 	                        const RGBAColor& blend) override;
 	void do_draw_line_strip(std::vector<DrawLineProgram::PerVertexData> vertices) override;
 	void
-	do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
+	do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
 
 	const int w_, h_;
 

=== modified file 'src/graphic/surface.cc'
--- src/graphic/surface.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/surface.cc	2016-10-28 17:51:15 +0000
@@ -26,15 +26,15 @@
 #include <SDL.h>
 
 #include "base/macros.h"
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 #include "graphic/gl/coordinate_conversion.h"
 #include "graphic/gl/utils.h"
 
 namespace {
 
 // Adjust 'original' so that only 'src_rect' is actually blitted.
-BlitData adjust_for_src(BlitData blit_data, const Rect& src_rect) {
+BlitData adjust_for_src(BlitData blit_data, const Rectf& src_rect) {
 	blit_data.rect.x += src_rect.x;
 	blit_data.rect.y += src_rect.y;
 	blit_data.rect.w = src_rect.w;
@@ -44,11 +44,11 @@
 
 // Get the normal of the line between 'start' and 'end'.
 template <typename PointType>
-FloatPoint calculate_line_normal(const PointType& start, const PointType& end) {
+Vector2f calculate_line_normal(const PointType& start, const PointType& end) {
 	const float dx = end.x - start.x;
 	const float dy = end.y - start.y;
 	const float len = std::hypot(dx, dy);
-	return FloatPoint(-dy / len, dx / len);
+	return Vector2f(-dy / len, dx / len);
 }
 
 // Tesselates the line made up of 'points' ino triangles and converts them into
@@ -60,7 +60,7 @@
                           int h,
                           const RGBColor& color,
                           float line_width,
-                          const std::vector<FloatPoint>& points,
+                          const std::vector<Vector2f>& points,
                           std::vector<DrawLineProgram::PerVertexData>* vertices) {
 	const float r = color.r / 255.;
 	const float g = color.g / 255.;
@@ -69,27 +69,27 @@
 	// Iterate over each line segment, i.e. all points but the last, convert
 	// them from pixel space to gl space and draw them.
 	for (size_t i = 0; i < points.size() - 1; ++i) {
-		const FloatPoint p1 = FloatPoint(points[i].x, points[i].y);
-		const FloatPoint p2 = FloatPoint(points[i + 1].x, points[i + 1].y);
+		const Vector2f p1 = Vector2f(points[i].x, points[i].y);
+		const Vector2f p2 = Vector2f(points[i + 1].x, points[i + 1].y);
 
-		const FloatPoint normal = calculate_line_normal(p1, p2);
-		const FloatPoint scaled_normal(0.5f * line_width * normal.x, 0.5f * line_width * normal.y);
+		const Vector2f normal = calculate_line_normal(p1, p2);
+		const Vector2f scaled_normal(0.5f * line_width * normal.x, 0.5f * line_width * normal.y);
 
 		// Quad points are created in rendering order for OpenGL.
 		{
-			FloatPoint p = p1 - scaled_normal;
-			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
-			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, 1.});
-		}
-
-		{
-			FloatPoint p = p2 - scaled_normal;
-			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
-			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, 1.});
-		}
-
-		{
-			FloatPoint p = p1 + scaled_normal;
+			Vector2f p = p1 - scaled_normal;
+			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
+			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, 1.});
+		}
+
+		{
+			Vector2f p = p2 - scaled_normal;
+			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
+			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, 1.});
+		}
+
+		{
+			Vector2f p = p1 + scaled_normal;
 			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
 			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, -1.});
 		}
@@ -98,7 +98,7 @@
 		vertices->push_back(vertices->at(vertices->size() - 2));
 
 		{
-			FloatPoint p = p2 + scaled_normal;
+			Vector2f p = p2 + scaled_normal;
 			pixel_to_gl_renderbuffer(w, h, &p.x, &p.y);
 			vertices->emplace_back(DrawLineProgram::PerVertexData{p.x, p.y, 0.f, r, g, b, -1.});
 		}
@@ -107,12 +107,12 @@
 
 }  // namespace
 
-void Surface::fill_rect(const Rect& rc, const RGBAColor& clr, BlendMode blend_mode) {
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
+void Surface::fill_rect(const Rectf& rc, const RGBAColor& clr, BlendMode blend_mode) {
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), rc);
 	do_fill_rect(rect, clr, blend_mode);
 }
 
-void Surface::brighten_rect(const Rect& rc, const int32_t factor) {
+void Surface::brighten_rect(const Rectf& rc, const int32_t factor) {
 	if (!factor) {
 		return;
 	}
@@ -120,11 +120,11 @@
 	const BlendMode blend_mode = factor < 0 ? BlendMode::Subtract : BlendMode::UseAlpha;
 	const int abs_factor = std::abs(factor);
 	const RGBAColor color(abs_factor, abs_factor, abs_factor, 0);
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), rc);
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), rc);
 	do_fill_rect(rect, color, blend_mode);
 }
 
-void Surface::draw_line_strip(std::vector<FloatPoint> points,
+void Surface::draw_line_strip(std::vector<Vector2f> points,
                               const RGBColor& color,
                               float line_width) {
 	if (points.size() < 2) {
@@ -138,41 +138,41 @@
 	do_draw_line_strip(std::move(vertices));
 }
 
-void Surface::blit_monochrome(const Rect& dst_rect,
+void Surface::blit_monochrome(const Rectf& dst_rect,
                               const Image& image,
-                              const Rect& src_rect,
+                              const Rectf& src_rect,
                               const RGBAColor& blend) {
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
 	do_blit_monochrome(rect, adjust_for_src(image.blit_data(), src_rect), blend);
 }
 
-void Surface::blit_blended(const Rect& dst_rect,
+void Surface::blit_blended(const Rectf& dst_rect,
                            const Image& image,
                            const Image& texture_mask,
-                           const Rect& src_rect,
+                           const Rectf& src_rect,
                            const RGBColor& blend) {
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
 	do_blit_blended(rect, adjust_for_src(image.blit_data(), src_rect),
 	                adjust_for_src(texture_mask.blit_data(), src_rect), blend);
 }
 
-void Surface::blit(const Rect& dst_rect,
+void Surface::blit(const Rectf& dst_rect,
                    const Image& image,
-                   const Rect& src_rect,
+                   const Rectf& src_rect,
                    float opacity,
                    BlendMode blend_mode) {
-	const FloatRect rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
+	const Rectf rect = rect_to_gl_renderbuffer(width(), height(), dst_rect);
 	do_blit(rect, adjust_for_src(image.blit_data(), src_rect), opacity, blend_mode);
 }
 
-void draw_rect(const Rect& rc, const RGBColor& clr, Surface* surface) {
-	const FloatPoint top_left = FloatPoint(rc.x + 0.5f, rc.y + 0.5f);
-	const FloatPoint top_right = FloatPoint(rc.x + rc.w - 0.5f, rc.y + 0.5f);
-	const FloatPoint bottom_right = FloatPoint(rc.x + rc.w - 0.5f, rc.y + rc.h - 0.5f);
-	const FloatPoint bottom_left = FloatPoint(rc.x + 0.5f, rc.y + rc.h - 0.5f);
+void draw_rect(const Rectf& rc, const RGBColor& clr, Surface* surface) {
+	const Vector2f top_left = Vector2f(rc.x + 0.5f, rc.y + 0.5f);
+	const Vector2f top_right = Vector2f(rc.x + rc.w - 0.5f, rc.y + 0.5f);
+	const Vector2f bottom_right = Vector2f(rc.x + rc.w - 0.5f, rc.y + rc.h - 0.5f);
+	const Vector2f bottom_left = Vector2f(rc.x + 0.5f, rc.y + rc.h - 0.5f);
 
 	surface->draw_line_strip({top_left, top_right, bottom_right}, clr, 1);
 	// We need to split this up in order not to miss a pixel on the bottom right corner.
 	surface->draw_line_strip(
-	   {FloatPoint(bottom_right.x + 1, bottom_right.y), bottom_left, top_left}, clr, 1);
+	   {Vector2f(bottom_right.x + 1, bottom_right.y), bottom_left, top_left}, clr, 1);
 }

=== modified file 'src/graphic/surface.h'
--- src/graphic/surface.h	2016-08-04 15:49:05 +0000
+++ src/graphic/surface.h	2016-10-28 17:51:15 +0000
@@ -46,42 +46,42 @@
 
 	/// This draws a part of 'texture'.
 	void blit(
-	   const Rect& dst, const Image&, const Rect& srcrc, const float opacity, BlendMode blend_mode);
+	   const Rectf& dst, const Image&, const Rectf& srcrc, const float opacity, BlendMode blend_mode);
 
 	/// This draws a playercolor blended image.
-	void blit_blended(const Rect& dst,
+	void blit_blended(const Rectf& dst,
 	                  const Image& image,
 	                  const Image& texture_mask,
-	                  const Rect& srcrc,
+	                  const Rectf& srcrc,
 	                  const RGBColor& blend);
 
 	/// This draws a grayed out version.
 	void
-	blit_monochrome(const Rect& dst, const Image&, const Rect& srcrc, const RGBAColor& multiplier);
+	blit_monochrome(const Rectf& dst, const Image&, const Rectf& srcrc, const RGBAColor& multiplier);
 
 	/// Draws a filled rect to the destination.
-	void fill_rect(const Rect&, const RGBAColor&, BlendMode blend_mode = BlendMode::Copy);
+	void fill_rect(const Rectf& dst, const RGBAColor&, BlendMode blend_mode = BlendMode::Copy);
 
 	// Draw a 'width' pixel wide line to the destination. 'points' are taken by
 	// value on purpose.
-	void draw_line_strip(std::vector<FloatPoint> points, const RGBColor& color, float width);
+	void draw_line_strip(std::vector<Vector2f> points, const RGBColor& color, float width);
 
 	/// makes a rectangle on the destination brighter (or darker).
-	void brighten_rect(const Rect&, int factor);
+	void brighten_rect(const Rectf&, int factor);
 
 private:
 	/// The actual implementation of the methods below.
-	virtual void do_blit(const FloatRect& dst_rect,
+	virtual void do_blit(const Rectf& dst_rect,
 	                     const BlitData& texture,
 	                     float opacity,
 	                     BlendMode blend_mode) = 0;
 
-	virtual void do_blit_blended(const FloatRect& dst_rect,
+	virtual void do_blit_blended(const Rectf& dst_rect,
 	                             const BlitData& texture,
 	                             const BlitData& mask,
 	                             const RGBColor& blend) = 0;
 
-	virtual void do_blit_monochrome(const FloatRect& dst_rect,
+	virtual void do_blit_monochrome(const Rectf& dst_rect,
 	                                const BlitData& texture,
 	                                const RGBAColor& blend) = 0;
 
@@ -90,7 +90,7 @@
 	virtual void do_draw_line_strip(std::vector<DrawLineProgram::PerVertexData> vertices) = 0;
 
 	virtual void
-	do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) = 0;
+	do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) = 0;
 
 	DISALLOW_COPY_AND_ASSIGN(Surface);
 };
@@ -98,6 +98,6 @@
 /// Draws a rect (frame only) to the surface. The width of the surrounding line
 /// is 1 pixel, i.e. the transparent inner box of the drawn rectangle starts at
 /// (x+1, y+1) and has dimension (w - 2, h - 2).
-void draw_rect(const Rect& rect, const RGBColor&, Surface* destination);
+void draw_rect(const Rectf& rect, const RGBColor&, Surface* destination);
 
 #endif  // end of include guard: WL_GRAPHIC_SURFACE_H

=== modified file 'src/graphic/text/rt_render.cc'
--- src/graphic/text/rt_render.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/text/rt_render.cc	2016-10-28 17:51:15 +0000
@@ -32,8 +32,8 @@
 #include "base/i18n.h"
 #include "base/log.h"
 #include "base/macros.h"
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 #include "base/wexception.h"
 #include "graphic/align.h"
 #include "graphic/graphic.h"
@@ -173,7 +173,7 @@
 }
 
 struct Reference {
-	Rect dim;
+	Recti dim;
 	string ref;
 };
 
@@ -185,7 +185,7 @@
 		// Should this linear algorithm proof to be too slow (doubtful), the
 		// RefMap could also be efficiently implemented using an R-Tree
 		for (const Reference& c : refs_)
-			if (c.dim.contains(Point(x, y)))
+			if (c.dim.contains(Vector2i(x, y)))
 				return c.ref;
 		return "";
 	}
@@ -469,7 +469,7 @@
 	const vector<Reference> get_references() override {
 		vector<Reference> rv;
 		if (!nodestyle_.reference.empty()) {
-			Reference r = {Rect(0, 0, w_, h_), nodestyle_.reference};
+			Reference r = {Recti(0, 0, w_, h_), nodestyle_.reference};
 			rv.push_back(r);
 		}
 		return rv;
@@ -501,7 +501,7 @@
 	const Texture& img =
 	   font_.render(txt_, nodestyle_.font_color, nodestyle_.font_style, texture_cache);
 	Texture* rv = new Texture(img.width(), img.height());
-	rv->blit(Rect(0, 0, img.width(), img.height()), img, Rect(0, 0, img.width(), img.height()), 1.,
+	rv->blit(Rectf(0, 0, img.width(), img.height()), img, Rectf(0, 0, img.width(), img.height()), 1.,
 	         BlendMode::Copy);
 	return rv;
 }
@@ -536,8 +536,8 @@
 	   font_.render(txt_, nodestyle_.font_color, nodestyle_.font_style, texture_cache);
 	Texture* rv = new Texture(w_, h_);
 	for (uint16_t curx = 0; curx < w_; curx += t.width()) {
-		Rect srcrect(Point(0, 0), min<int>(t.width(), w_ - curx), h_);
-		rv->blit(Rect(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy);
+		Rectf srcrect(0.f, 0.f, min<int>(t.width(), w_ - curx), h_);
+		rv->blit(Rectf(curx, 0, srcrect.w, srcrect.h), t, srcrect, 1., BlendMode::Copy);
 	}
 	return rv;
 }
@@ -557,7 +557,7 @@
 	Texture* render(TextureCache* texture_cache) override {
 		if (show_spaces_) {
 			Texture* rv = new Texture(w_, h_);
-			rv->fill_rect(Rect(0, 0, w_, h_), RGBAColor(0xcc, 0, 0, 0xcc));
+			rv->fill_rect(Rectf(0, 0, w_, h_), RGBAColor(0xcc, 0, 0, 0xcc));
 			return rv;
 		}
 		return TextNode::render(texture_cache);
@@ -619,8 +619,8 @@
 
 		// Draw background image (tiling)
 		if (background_image_) {
-			Rect dst;
-			Rect srcrect(Point(0, 0), 1, 1);
+			Rectf dst;
+			Rectf srcrect(0, 0, 1, 1);
 			for (uint16_t curx = 0; curx < w_; curx += background_image_->width()) {
 				dst.x = curx;
 				dst.y = 0;
@@ -629,7 +629,7 @@
 				rv->blit(dst, *background_image_, srcrect, 1., BlendMode::Copy);
 			}
 		} else {
-			rv->fill_rect(Rect(0, 0, w_, h_), RGBAColor(255, 255, 255, 0));
+			rv->fill_rect(Rectf(0, 0, w_, h_), RGBAColor(255, 255, 255, 0));
 		}
 		return rv;
 	}
@@ -689,19 +689,19 @@
 			throw TextureTooBig(error_message);
 		}
 		Texture* rv = new Texture(width(), height());
-		rv->fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
+		rv->fill_rect(Rectf(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
 
 		// Draw Solid background Color
 		bool set_alpha = true;
 		if (is_background_color_set_) {
-			rv->fill_rect(Rect(Point(margin_.left, margin_.top), w_, h_), background_color_);
+			rv->fill_rect(Rectf(margin_.left, margin_.top, w_, h_), background_color_);
 			set_alpha = false;
 		}
 
 		// Draw background image (tiling)
 		if (background_image_) {
-			Rect dst;
-			Rect src(0, 0, 0, 0);
+			Rectf dst;
+			Rectf src(0, 0, 0, 0);
 
 			for (uint16_t cury = margin_.top; cury < h_ + margin_.top;
 			     cury += background_image_->height()) {
@@ -720,10 +720,9 @@
 		for (RenderNode* n : nodes_to_render_) {
 			Texture* node_texture = n->render(texture_cache);
 			if (node_texture) {
-				Rect dst = Rect(n->x() + margin_.left, n->y() + margin_.top, node_texture->width(),
+				Rectf dst(n->x() + margin_.left, n->y() + margin_.top, node_texture->width(),
 				                node_texture->height());
-				Rect src = Rect(0, 0, node_texture->width(), node_texture->height());
-
+				Rectf src(0, 0, node_texture->width(), node_texture->height());
 				rv->blit(
 				   dst, *node_texture, src, 1., set_alpha ? BlendMode::Copy : BlendMode::UseAlpha);
 				delete node_texture;
@@ -754,7 +753,7 @@
 		nodes_to_render_ = n;
 	}
 	void add_reference(int16_t gx, int16_t gy, uint16_t w, uint16_t h, const string& s) {
-		Reference r = {Rect(gx, gy, w, h), s};
+		Reference r = {Recti(gx, gy, w, h), s};
 		refs_.push_back(r);
 	}
 
@@ -790,8 +789,8 @@
 
 Texture* ImgRenderNode::render(TextureCache* /* texture_cache */) {
 	Texture* rv = new Texture(image_.width(), image_.height());
-	rv->blit(Rect(0, 0, image_.width(), image_.height()), image_,
-	         Rect(0, 0, image_.width(), image_.height()), 1., BlendMode::Copy);
+	rv->blit(Rectf(0, 0, image_.width(), image_.height()), image_,
+	         Rectf(0, 0, image_.width(), image_.height()), 1., BlendMode::Copy);
 	return rv;
 }
 // End: Helper Stuff

=== modified file 'src/graphic/texture.cc'
--- src/graphic/texture.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/texture.cc	2016-10-28 17:51:15 +0000
@@ -144,14 +144,14 @@
 	SDL_FreeSurface(surface);
 }
 
-Texture::Texture(const GLuint texture, const Rect& subrect, int parent_w, int parent_h)
+Texture::Texture(const GLuint texture, const Recti& subrect, int parent_w, int parent_h)
    : owns_texture_(false) {
 	if (parent_w == 0 || parent_h == 0) {
 		throw wexception("Created a sub Texture with zero height and width parent.");
 	}
 
 	blit_data_ = BlitData{
-	   texture, parent_w, parent_h, subrect,
+	   texture, parent_w, parent_h, subrect.cast<float>(),
 	};
 }
 
@@ -172,7 +172,7 @@
 void Texture::init(uint16_t w, uint16_t h) {
 	blit_data_ = {
 	   0,  // initialized below
-	   w, h, Rect(0, 0, w, h),
+	   w, h, Rectf(0, 0, w, h),
 	};
 	if (w * h == 0) {
 		return;
@@ -250,7 +250,7 @@
 	glViewport(0, 0, width(), height());
 }
 
-void Texture::do_blit(const FloatRect& dst_rect,
+void Texture::do_blit(const Rectf& dst_rect,
                       const BlitData& texture,
                       float opacity,
                       BlendMode blend_mode) {
@@ -258,11 +258,11 @@
 		return;
 	}
 	setup_gl();
-	BlitProgram::instance().draw(dst_rect, 0.f, texture, BlitData{0, 0, 0, Rect()},
+	BlitProgram::instance().draw(dst_rect, 0.f, texture, BlitData{0, 0, 0, Rectf()},
 	                             RGBAColor(0, 0, 0, 255 * opacity), blend_mode);
 }
 
-void Texture::do_blit_blended(const FloatRect& dst_rect,
+void Texture::do_blit_blended(const Rectf& dst_rect,
                               const BlitData& texture,
                               const BlitData& mask,
                               const RGBColor& blend) {
@@ -274,7 +274,7 @@
 	BlitProgram::instance().draw(dst_rect, 0.f, texture, mask, blend, BlendMode::UseAlpha);
 }
 
-void Texture::do_blit_monochrome(const FloatRect& dst_rect,
+void Texture::do_blit_monochrome(const Rectf& dst_rect,
                                  const BlitData& texture,
                                  const RGBAColor& blend) {
 	if (blit_data_.texture_id == 0) {
@@ -293,9 +293,7 @@
 	   {DrawLineProgram::Arguments{vertices, 0.f, BlendMode::UseAlpha}});
 }
 
-void Texture::do_fill_rect(const FloatRect& dst_rect,
-                           const RGBAColor& color,
-                           BlendMode blend_mode) {
+void Texture::do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) {
 	if (blit_data_.texture_id == 0) {
 		return;
 	}

=== modified file 'src/graphic/texture.h'
--- src/graphic/texture.h	2016-08-04 15:49:05 +0000
+++ src/graphic/texture.h	2016-10-28 17:51:15 +0000
@@ -39,7 +39,7 @@
 
 	// Create a logical texture that is a 'subrect' (in Pixel) in
 	// another texture. Ownership of 'texture' is not taken.
-	Texture(const GLuint texture, const Rect& subrect, int parent_w, int parent_h);
+	Texture(const GLuint texture, const Recti& subrect, int parent_w, int parent_h);
 
 	virtual ~Texture();
 
@@ -83,20 +83,20 @@
 	void init(uint16_t w, uint16_t h);
 
 	// Implements surface.
-	void do_blit(const FloatRect& dst_rect,
+	void do_blit(const Rectf& dst_rect,
 	             const BlitData& texture,
 	             float opacity,
 	             BlendMode blend_mode) override;
-	void do_blit_blended(const FloatRect& dst_rect,
+	void do_blit_blended(const Rectf& dst_rect,
 	                     const BlitData& texture,
 	                     const BlitData& mask,
 	                     const RGBColor& blend) override;
-	void do_blit_monochrome(const FloatRect& dst_rect,
+	void do_blit_monochrome(const Rectf& dst_rect,
 	                        const BlitData& texture,
 	                        const RGBAColor& blend) override;
 	void do_draw_line_strip(std::vector<DrawLineProgram::PerVertexData> vertices) override;
 	void
-	do_fill_rect(const FloatRect& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
+	do_fill_rect(const Rectf& dst_rect, const RGBAColor& color, BlendMode blend_mode) override;
 
 	// True if we own the texture, i.e. if we need to delete it.
 	bool owns_texture_;

=== modified file 'src/graphic/texture_atlas.cc'
--- src/graphic/texture_atlas.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/texture_atlas.cc	2016-10-28 17:51:15 +0000
@@ -34,14 +34,14 @@
 
 }  // namespace
 
-TextureAtlas::Node::Node(const Rect& init_r) : used(false), r(init_r) {
+TextureAtlas::Node::Node(const Recti& init_r) : used(false), r(init_r) {
 }
 
 void TextureAtlas::Node::split(int item_w, int item_h) {
 	assert(!used);
 
-	down.reset(new Node(Rect(r.x, r.y + item_h, r.w, r.h - item_h)));
-	right.reset(new Node(Rect(r.x + item_w, r.y, r.w - item_w, item_h)));
+	down.reset(new Node(Recti(r.x, r.y + item_h, r.w, r.h - item_h)));
+	right.reset(new Node(Recti(r.x + item_w, r.y, r.w - item_w, item_h)));
 	used = true;
 
 	// Note: we do not change the size of the root. It is not needed
@@ -77,21 +77,21 @@
 std::unique_ptr<Texture> TextureAtlas::pack_as_many_as_possible(
    const int max_dimension, const int texture_atlas_index, std::vector<PackedTexture>* pack_info) {
 
-	std::unique_ptr<Node> root(new Node(Rect(0, 0, blocks_.begin()->texture->width() + kPadding,
-	                                         blocks_.begin()->texture->height() + kPadding)));
+	std::unique_ptr<Node> root(new Node(Recti(0, 0, blocks_.begin()->texture->width() + kPadding,
+	                                          blocks_.begin()->texture->height() + kPadding)));
 
 	const auto grow_right = [&root](int delta_w) {
-		std::unique_ptr<Node> new_root(new Node(Rect(0, 0, root->r.w + delta_w, root->r.h)));
+		std::unique_ptr<Node> new_root(new Node(Recti(0, 0, root->r.w + delta_w, root->r.h)));
 		new_root->used = true;
-		new_root->right.reset(new Node(Rect(root->r.w, 0, delta_w, root->r.h)));
+		new_root->right.reset(new Node(Recti(root->r.w, 0, delta_w, root->r.h)));
 		new_root->down.reset(root.release());
 		root.reset(new_root.release());
 	};
 
 	const auto grow_down = [&root](int delta_h) {
-		std::unique_ptr<Node> new_root(new Node(Rect(0, 0, root->r.w, root->r.h + delta_h)));
+		std::unique_ptr<Node> new_root(new Node(Recti(0, 0, root->r.w, root->r.h + delta_h)));
 		new_root->used = true;
-		new_root->down.reset(new Node(Rect(0, root->r.h, root->r.w, delta_h)));
+		new_root->down.reset(new Node(Recti(0, root->r.h, root->r.w, delta_h)));
 		new_root->right.reset(root.release());
 		root.reset(new_root.release());
 	};
@@ -134,20 +134,20 @@
 	}
 
 	std::unique_ptr<Texture> texture_atlas(new Texture(root->r.w, root->r.h));
-	texture_atlas->fill_rect(Rect(0, 0, root->r.w, root->r.h), RGBAColor(0, 0, 0, 0));
+	texture_atlas->fill_rect(Rectf(0, 0, root->r.w, root->r.h), RGBAColor(0, 0, 0, 0));
 
 	const auto packed_texture_id = texture_atlas->blit_data().texture_id;
 	for (Block& block : packed) {
 		texture_atlas->blit(
-		   Rect(block.node->r.x, block.node->r.y, block.texture->width(), block.texture->height()),
-		   *block.texture, Rect(0, 0, block.texture->width(), block.texture->height()), 1.,
+		   Rectf(block.node->r.x, block.node->r.y, block.texture->width(), block.texture->height()),
+		   *block.texture, Rectf(0, 0, block.texture->width(), block.texture->height()), 1.,
 		   BlendMode::Copy);
 
 		pack_info->emplace_back(PackedTexture(
 		   texture_atlas_index, block.index,
 		   std::unique_ptr<Texture>(new Texture(
 		      packed_texture_id,
-		      Rect(block.node->r.origin(), block.texture->width(), block.texture->height()),
+		      Recti(block.node->r.origin(), block.texture->width(), block.texture->height()),
 		      root->r.w, root->r.h))));
 	}
 	blocks_ = not_packed;

=== modified file 'src/graphic/texture_atlas.h'
--- src/graphic/texture_atlas.h	2016-08-04 15:49:05 +0000
+++ src/graphic/texture_atlas.h	2016-10-28 17:51:15 +0000
@@ -68,11 +68,11 @@
 
 private:
 	struct Node {
-		Node(const Rect& init_r);
+		Node(const Recti& init_r);
 		void split(int w, int h);
 
 		bool used;
-		Rect r;
+		Recti r;
 		std::unique_ptr<Node> right;
 		std::unique_ptr<Node> down;
 

=== modified file 'src/graphic/wordwrap.cc'
--- src/graphic/wordwrap.cc	2016-08-04 15:49:05 +0000
+++ src/graphic/wordwrap.cc	2016-10-28 17:51:15 +0000
@@ -303,7 +303,7 @@
  *
  * \note This also draws the caret, if any.
  */
-void WordWrap::draw(RenderTarget& dst, Point where, Align align, uint32_t caret) {
+void WordWrap::draw(RenderTarget& dst, Vector2i where, Align align, uint32_t caret) {
 	if (lines_.empty())
 		return;
 
@@ -329,7 +329,7 @@
 		if (where.y >= dst.height() || int32_t(where.y + fontheight) <= 0)
 			continue;
 
-		Point point(where.x, where.y);
+		Vector2f point(where.x, where.y);
 
 		if (static_cast<int>(alignment & UI::Align::kRight)) {
 			point.x += wrapwidth_ - LINE_MARGIN;
@@ -346,9 +346,9 @@
 			int caret_x = text_width(line_to_caret, style_.font->size());
 
 			const Image* caret_image = g_gr->images().get("images/ui_basic/caret.png");
-			Point caretpt;
+			Vector2f caretpt;
 			caretpt.x = point.x + caret_x - caret_image->width() + LINE_MARGIN;
-			caretpt.y = point.y + (fontheight - caret_image->height()) / 2;
+			caretpt.y = point.y + (fontheight - caret_image->height()) / 2.f;
 			dst.blit(caretpt, caret_image);
 		}
 	}

=== modified file 'src/graphic/wordwrap.h'
--- src/graphic/wordwrap.h	2016-08-04 15:49:05 +0000
+++ src/graphic/wordwrap.h	2016-10-28 17:51:15 +0000
@@ -21,7 +21,7 @@
 
 #include <string>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "graphic/align.h"
 #include "graphic/text_layout.h"
 
@@ -50,7 +50,7 @@
 	}
 
 	void draw(RenderTarget& dst,
-	          Point where,
+	          Vector2i where,
 	          Align align = UI::Align::kLeft,
 	          uint32_t caret = std::numeric_limits<uint32_t>::max());
 

=== modified file 'src/io/streamread.cc'
--- src/io/streamread.cc	2016-08-04 15:49:05 +0000
+++ src/io/streamread.cc	2016-10-28 17:51:15 +0000
@@ -22,6 +22,7 @@
 #include <cassert>
 #include <cstdarg>
 #include <cstdio>
+#include <cstring>
 
 #include "base/wexception.h"
 
@@ -89,6 +90,15 @@
 	return little_32(x);
 }
 
+float StreamRead::float_32() {
+	uint32_t x;
+	data_complete(&x, 4);
+	x = little_32(x);
+	float rv;
+	memcpy(&rv, &x, 4);
+	return rv;
+}
+
 std::string StreamRead::string() {
 	std::string x;
 	char ch;

=== modified file 'src/io/streamread.h'
--- src/io/streamread.h	2016-08-04 15:49:05 +0000
+++ src/io/streamread.h	2016-10-28 17:51:15 +0000
@@ -67,6 +67,7 @@
 	uint16_t unsigned_16();
 	int32_t signed_32();
 	uint32_t unsigned_32();
+	float float_32();
 	std::string string();
 	virtual char const* c_string() {
 		throw;

=== modified file 'src/io/streamwrite.cc'
--- src/io/streamwrite.cc	2016-08-04 15:49:05 +0000
+++ src/io/streamwrite.cc	2016-10-28 17:51:15 +0000
@@ -20,6 +20,7 @@
 #include "io/streamwrite.h"
 
 #include <cstdarg>
+#include <cstring>
 
 #include "base/wexception.h"
 

=== modified file 'src/io/streamwrite.h'
--- src/io/streamwrite.h	2016-08-04 15:49:05 +0000
+++ src/io/streamwrite.h	2016-10-28 17:51:15 +0000
@@ -82,6 +82,12 @@
 		uint32_t const y = little_32(x);
 		data(&y, 4);
 	}
+	void float_32(const float x) {
+		uint32_t y;
+		memcpy(&y, &x, 4);
+		y = little_32(y);
+		data(&y, 4);
+	}
 	void string(const std::string& str) {
 		data(str.c_str(), str.size() + 1);
 	}

=== modified file 'src/logic/CMakeLists.txt'
--- src/logic/CMakeLists.txt	2016-05-14 07:35:39 +0000
+++ src/logic/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -44,6 +44,12 @@
     profile
 )
 
+wl_library(logic_constants
+  SRCS
+    constants.h
+    constants.cc
+)
+
 wl_library(logic
   SRCS
     backtrace.cc
@@ -60,7 +66,6 @@
     cmd_luascript.h
     cmd_queue.cc
     cmd_queue.h
-    constants.h
     cookie_priority_queue.h
     description_maintainer.h
     editor_game_base.cc
@@ -119,6 +124,7 @@
     widelands_geometry_io.cc
     widelands_geometry_io.h
     widelands.h
+    map_objects/draw_text.h
     map_objects/attackable.h
     map_objects/bob.cc
     map_objects/bob.h
@@ -126,15 +132,13 @@
     map_objects/buildcost.h
     map_objects/checkstep.cc
     map_objects/checkstep.h
-    map_objects/immovable_program.h
     map_objects/immovable.cc
     map_objects/immovable.h
+    map_objects/immovable_program.h
     map_objects/map_object.cc
     map_objects/map_object.h
     map_objects/terrain_affinity.cc
     map_objects/terrain_affinity.h
-    map_objects/walkingdir.cc
-    map_objects/walkingdir.h
     map_objects/tribes/battle.cc
     map_objects/tribes/battle.h
     map_objects/tribes/bill_of_materials.h
@@ -181,15 +185,17 @@
     map_objects/tribes/warelist.h
     map_objects/tribes/wareworker.h
     map_objects/tribes/workarea_info.h
+    map_objects/tribes/worker.cc
+    map_objects/tribes/worker.h
     map_objects/tribes/worker_descr.cc
     map_objects/tribes/worker_descr.h
     map_objects/tribes/worker_program.cc
     map_objects/tribes/worker_program.h
-    map_objects/tribes/worker.cc
-    map_objects/tribes/worker.h
-    map_objects/world/critter_program.h
+    map_objects/walkingdir.cc
+    map_objects/walkingdir.h
     map_objects/world/critter.cc
     map_objects/world/critter.h
+    map_objects/world/critter_program.h
     map_objects/world/editor_category.cc
     map_objects/world/editor_category.h
     map_objects/world/map_gen.cc
@@ -209,6 +215,7 @@
     base_i18n
     base_log
     base_macros
+    base_math
     base_md5
     base_scoped_timer
     base_time_string
@@ -219,12 +226,14 @@
     graphic
     graphic_color
     graphic_image_io
+    graphic_playercolor
     graphic_surface
     graphic_text_layout
     helper
     io_fileread
     io_filesystem
     io_stream
+    logic_constants
     logic_game_controller
     logic_game_settings
     logic_widelands_geometry

=== added file 'src/logic/constants.cc'
--- src/logic/constants.cc	1970-01-01 00:00:00 +0000
+++ src/logic/constants.cc	2016-10-28 17:51:15 +0000
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2006-2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+// Dummy file as cmake cannot handle header only libraries :(.

=== modified file 'src/logic/constants.h'
--- src/logic/constants.h	2016-05-19 07:51:43 +0000
+++ src/logic/constants.h	2016-10-28 17:51:15 +0000
@@ -22,12 +22,6 @@
 
 #include <cstdint>
 
-/// Maximum numbers of players in a game. The game logic code reserves 5 bits
-/// for player numbers, so it can keep track of 32 different player numbers, of
-/// which the value 0 means neutral and the values 1 .. 31 can be used as the
-/// numbers for actual players. So the upper limit of this value is 31.
-#define MAX_PLAYERS 8
-
 /// How often are statistics to be sampled.
 constexpr uint32_t kStatisticsSampleTime = 30000;
 

=== modified file 'src/logic/editor_game_base.cc'
--- src/logic/editor_game_base.cc	2016-08-04 15:49:05 +0000
+++ src/logic/editor_game_base.cc	2016-10-28 17:51:15 +0000
@@ -31,7 +31,6 @@
 #include "economy/road.h"
 #include "graphic/color.h"
 #include "graphic/graphic.h"
-#include "logic/constants.h"
 #include "logic/findimmovable.h"
 #include "logic/game.h"
 #include "logic/game_data_error.h"
@@ -174,7 +173,7 @@
 
 void EditorGameBase::inform_players_about_ownership(MapIndex const i,
                                                     PlayerNumber const new_owner) {
-	iterate_players_existing_const(plnum, MAX_PLAYERS, *this, p) {
+	iterate_players_existing_const(plnum, kMaxPlayers, *this, p) {
 		Player::Field& player_field = p->fields_[i];
 		if (1 < player_field.vision) {
 			player_field.owner = new_owner;
@@ -184,7 +183,7 @@
 void EditorGameBase::inform_players_about_immovable(MapIndex const i,
                                                     MapObjectDescr const* const descr) {
 	if (!Road::is_road_descr(descr))
-		iterate_players_existing_const(plnum, MAX_PLAYERS, *this, p) {
+		iterate_players_existing_const(plnum, kMaxPlayers, *this, p) {
 			Player::Field& player_field = p->fields_[i];
 			if (1 < player_field.vision) {
 				player_field.map_object_descr[TCoords<>::None] = descr;
@@ -206,7 +205,7 @@
 }
 
 void EditorGameBase::allocate_player_maps() {
-	iterate_players_existing(plnum, MAX_PLAYERS, *this, p) {
+	iterate_players_existing(plnum, kMaxPlayers, *this, p) {
 		p->allocate_map();
 	}
 }
@@ -483,7 +482,7 @@
 	uint8_t const road = f.field->get_roads() & mask;
 	MapIndex const i = f.field - &first_field;
 	MapIndex const neighbour_i = neighbour.field - &first_field;
-	iterate_players_existing_const(plnum, MAX_PLAYERS, *this, p) {
+	iterate_players_existing_const(plnum, kMaxPlayers, *this, p) {
 		Player::Field& first_player_field = *p->fields_;
 		Player::Field& player_field = (&first_player_field)[i];
 		if (1 < player_field.vision || 1 < (&first_player_field)[neighbour_i].vision) {

=== modified file 'src/logic/editor_game_base.h'
--- src/logic/editor_game_base.h	2016-08-04 15:49:05 +0000
+++ src/logic/editor_game_base.h	2016-10-28 17:51:15 +0000
@@ -154,6 +154,7 @@
 	uint32_t get_gametime() const {
 		return gametime_;
 	}
+	// TODO(GunChleoc): Get rid.
 	InteractiveBase* get_ibase() const {
 		return ibase_.get();
 	}

=== modified file 'src/logic/field.h'
--- src/logic/field.h	2016-08-04 15:49:05 +0000
+++ src/logic/field.h	2016-10-28 17:51:15 +0000
@@ -23,7 +23,7 @@
 #include <cassert>
 #include <limits>
 
-#include "logic/constants.h"
+#include "graphic/playercolor.h"
 #include "logic/nodecaps.h"
 #include "logic/roadtype.h"
 #include "logic/widelands.h"
@@ -145,12 +145,12 @@
 	 * be done separately.
 	 */
 	void set_owned_by(const PlayerNumber n) {
-		assert(n <= MAX_PLAYERS);
+		assert(n <= kMaxPlayers);
 		owner_info_and_selections = n | (owner_info_and_selections & ~Player_Number_Bitmask);
 	}
 
 	PlayerNumber get_owned_by() const {
-		assert((owner_info_and_selections & Player_Number_Bitmask) <= MAX_PLAYERS);
+		assert((owner_info_and_selections & Player_Number_Bitmask) <= kMaxPlayers);
 		return owner_info_and_selections & Player_Number_Bitmask;
 	}
 	bool is_border() const {
@@ -229,7 +229,7 @@
 	static const OwnerInfoAndSelectionsType Player_Number_Bitmask = Border_Bitmask - 1;
 	static const OwnerInfoAndSelectionsType Owner_Info_Bitmask =
 	   Player_Number_Bitmask + Border_Bitmask;
-	static_assert(MAX_PLAYERS <= Player_Number_Bitmask, "Bitmask is too big.");
+	static_assert(kMaxPlayers <= Player_Number_Bitmask, "Bitmask is too big.");
 
 	// Data Members
 	/** linked list, \sa Bob::linknext_ */

=== modified file 'src/logic/game.cc'
--- src/logic/game.cc	2016-08-04 15:49:05 +0000
+++ src/logic/game.cc	2016-10-28 17:51:15 +0000
@@ -455,7 +455,7 @@
 		}
 
 		if (get_ipl())
-			get_ipl()->move_view_to(map().get_starting_pos(get_ipl()->player_number()));
+			get_ipl()->center_view_on_coords(map().get_starting_pos(get_ipl()->player_number()));
 
 		// Prepare the map, set default textures
 		map().recalc_default_resources(world());

=== modified file 'src/logic/game_controller.h'
--- src/logic/game_controller.h	2016-08-04 15:49:05 +0000
+++ src/logic/game_controller.h	2016-10-28 17:51:15 +0000
@@ -100,9 +100,6 @@
 	/**
 	 * Report a player result once he has left the game. This may be done through lua
 	 * by the win_condition scripts.
-	 * \param player : the player idx;
-	 * \param result : the player result
-	 * \param info : The info string (\see \struct PlayerEndStatus)
 	 */
 	virtual void report_result(uint8_t /* player */,
 	                           Widelands::PlayerEndResult /*result*/,

=== modified file 'src/logic/map_objects/bob.cc'
--- src/logic/map_objects/bob.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/bob.cc	2016-10-28 17:51:15 +0000
@@ -25,6 +25,7 @@
 #include <stdint.h>
 
 #include "base/macros.h"
+#include "base/math.h"
 #include "base/wexception.h"
 #include "economy/route.h"
 #include "economy/transfer.h"
@@ -88,7 +89,6 @@
 
 Bob::Bob(const BobDescr& init_descr)
    : MapObject(&init_descr),
-     owner_(nullptr),
      position_(FCoords(Coords(0, 0), nullptr)),  // not linked anywhere
      linknext_(nullptr),
      linkpprev_(nullptr),
@@ -685,45 +685,51 @@
 		return schedule_act(game, walkend_ - game.get_gametime());
 }
 
-/// Calculates the actual position to draw on from the base node position.
-/// This function takes walking etc. into account.
-///
-/// pos is the location, in pixels, of the node position_ (height is already
-/// taken into account).
-Point Bob::calc_drawpos(const EditorGameBase& game, const Point pos) const {
+// Calculates the actual position to draw on from the base node position. This
+// function takes walking etc. into account.
+//
+// pos is the location, in pixels, of the node position_ on screen with scale
+// and height taken into account.
+Vector2f Bob::calc_drawpos(const EditorGameBase& game,
+                             const Vector2f& field_on_dst,
+                             const float scale) const {
 	const Map& map = game.get_map();
 	const FCoords end = position_;
 	FCoords start;
-	Point spos = pos, epos = pos;
+	Vector2f spos = field_on_dst;
+	Vector2f epos = field_on_dst;
+
+	const float triangle_w = kTriangleWidth * scale;
+	const float triangle_h = kTriangleHeight * scale;
 
 	switch (walking_) {
 	case WALK_NW:
 		map.get_brn(end, &start);
-		spos.x += kTriangleWidth / 2;
-		spos.y += kTriangleHeight;
+		spos.x += triangle_w / 2.f;
+		spos.y += triangle_h;
 		break;
 	case WALK_NE:
 		map.get_bln(end, &start);
-		spos.x -= kTriangleWidth / 2;
-		spos.y += kTriangleHeight;
+		spos.x -= triangle_w / 2.f;
+		spos.y += triangle_h;
 		break;
 	case WALK_W:
 		map.get_rn(end, &start);
-		spos.x += kTriangleWidth;
+		spos.x += triangle_w;
 		break;
 	case WALK_E:
 		map.get_ln(end, &start);
-		spos.x -= kTriangleWidth;
+		spos.x -= triangle_w;
 		break;
 	case WALK_SW:
 		map.get_trn(end, &start);
-		spos.x += kTriangleWidth / 2;
-		spos.y -= kTriangleHeight;
+		spos.x += triangle_w / 2.f;
+		spos.y -= triangle_h;
 		break;
 	case WALK_SE:
 		map.get_tln(end, &start);
-		spos.x -= kTriangleWidth / 2;
-		spos.y -= kTriangleHeight;
+		spos.x -= triangle_w / 2.f;
+		spos.y -= triangle_h;
 		break;
 
 	case IDLE:
@@ -732,37 +738,39 @@
 	}
 
 	if (start.field) {
-		spos.y += end.field->get_height() * kHeightFactor;
-		spos.y -= start.field->get_height() * kHeightFactor;
+		spos.y += end.field->get_height() * kHeightFactor * scale;
+		spos.y -= start.field->get_height() * kHeightFactor * scale;
 
 		assert(static_cast<uint32_t>(walkstart_) <= game.get_gametime());
 		assert(walkstart_ < walkend_);
-		float f = static_cast<float>(game.get_gametime() - walkstart_) / (walkend_ - walkstart_);
-
-		if (f < 0)
-			f = 0;
-		else if (f > 1)
-			f = 1;
-
-		epos.x = static_cast<int32_t>(f * epos.x + (1 - f) * spos.x);
-		epos.y = static_cast<int32_t>(f * epos.y + (1 - f) * spos.y);
+		const float f = math::clamp(
+				static_cast<float>(game.get_gametime() - walkstart_) / (walkend_ - walkstart_),
+				0.f, 1.f);
+		epos.x = f * epos.x + (1.f - f) * spos.x;
+		epos.y = f * epos.y + (1.f - f) * spos.y;
 	}
-
 	return epos;
 }
 
 /// It LERPs between start and end position when we are walking.
 /// Note that the current node is actually the node that we are walking to, not
 /// the the one that we start from.
-void Bob::draw(const EditorGameBase& egbase, RenderTarget& dst, const Point& pos) const {
-	if (anim_) {
-		auto* const owner = get_owner();
-		if (owner != nullptr) {
-			dst.blit_animation(calc_drawpos(egbase, pos), anim_, egbase.get_gametime() - animstart_,
-			                   owner->get_playercolor());
-		} else {
-			dst.blit_animation(calc_drawpos(egbase, pos), anim_, egbase.get_gametime() - animstart_);
-		}
+void Bob::draw(const EditorGameBase& egbase,
+               const TextToDraw&,
+               const Vector2f& field_on_dst,
+               const float scale,
+               RenderTarget* dst) const {
+	if (!anim_) {
+		return;
+	}
+
+	auto* const owner = get_owner();
+	const Vector2f point_on_dst = calc_drawpos(egbase, field_on_dst, scale);
+	if (owner != nullptr) {
+		dst->blit_animation(
+		   point_on_dst, scale, anim_, egbase.get_gametime() - animstart_, owner->get_playercolor());
+	} else {
+		dst->blit_animation(point_on_dst, scale, anim_, egbase.get_gametime() - animstart_);
 	}
 }
 

=== modified file 'src/logic/map_objects/bob.h'
--- src/logic/map_objects/bob.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/bob.h	2016-10-28 17:51:15 +0000
@@ -21,10 +21,11 @@
 #define WL_LOGIC_MAP_OBJECTS_BOB_H
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "economy/route.h"
 #include "graphic/animation.h"
 #include "graphic/diranimations.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/map_objects/map_object.h"
 #include "logic/map_objects/walkingdir.h"
 #include "logic/widelands_geometry.h"
@@ -240,11 +241,9 @@
 	void schedule_destroy(Game&);
 	void schedule_act(Game&, uint32_t tdelta);
 	void skip_act();
-	Point calc_drawpos(const EditorGameBase&, Point) const;
+	Vector2f calc_drawpos(const EditorGameBase&, const Vector2f& field_on_dst, float scale) const;
 	void set_owner(Player*);
-	Player* get_owner() const {
-		return owner_;
-	}
+
 	void set_position(EditorGameBase&, const Coords&);
 	const FCoords& get_position() const {
 		return position_;
@@ -260,7 +259,15 @@
 	///    onto the \p to node if this function allows it to.
 	virtual bool check_node_blocked(Game&, const FCoords&, bool commit);
 
-	virtual void draw(const EditorGameBase&, RenderTarget&, const Point&) const;
+	// Draws the bob onto the screen with 'field_on_dst' being the position of
+	// the field associated with this bob (if it is walking, that is its
+	// starting field) in pixel space of 'dst' (including scale). The 'scale' is
+	// required to draw the bob in the right size.
+	virtual void draw(const EditorGameBase&,
+	                  const TextToDraw& draw_text,
+	                  const Vector2f& field_on_dst,
+	                  float scale,
+	                  RenderTarget* dst) const;
 
 	// For debug
 	void log_general_info(const EditorGameBase&) override;
@@ -366,7 +373,6 @@
 	static Task const taskMovepath;
 	static Task const taskMove;
 
-	Player* owner_;     ///< can be 0
 	FCoords position_;  ///< where are we right now?
 	Bob* linknext_;     ///< next object on this node
 	Bob** linkpprev_;

=== added file 'src/logic/map_objects/draw_text.h'
--- src/logic/map_objects/draw_text.h	1970-01-01 00:00:00 +0000
+++ src/logic/map_objects/draw_text.h	2016-10-28 17:51:15 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006-2016 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_LOGIC_MAP_OBJECTS_DRAW_TEXT_H
+#define WL_LOGIC_MAP_OBJECTS_DRAW_TEXT_H
+
+enum TextToDraw {
+	kNone = 0,
+	kCensus = 1,
+	kStatistics = 2,
+};
+
+inline TextToDraw operator|(TextToDraw a, TextToDraw b) {
+	return static_cast<TextToDraw>(static_cast<int>(a) | static_cast<int>(b));
+}
+
+#endif  // end of include guard: WL_LOGIC_MAP_OBJECTS_DRAW_TEXT_H
+

=== modified file 'src/logic/map_objects/immovable.cc'
--- src/logic/map_objects/immovable.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/immovable.cc	2016-10-28 17:51:15 +0000
@@ -35,7 +35,6 @@
 #include "helper.h"
 #include "io/fileread.h"
 #include "io/filewrite.h"
-#include "logic/constants.h"
 #include "logic/editor_game_base.h"
 #include "logic/field.h"
 #include "logic/game.h"
@@ -324,7 +323,6 @@
  * Create an immovable of this type
 */
 Immovable& ImmovableDescr::create(EditorGameBase& egbase, const Coords& coords) const {
-	assert(this != nullptr);
 	Immovable& result = *new Immovable(*this);
 	result.position_ = coords;
 	result.init(egbase);
@@ -341,7 +339,6 @@
 
 Immovable::Immovable(const ImmovableDescr& imm_descr)
    : BaseImmovable(imm_descr),
-     owner_(nullptr),
      anim_(0),
      animstart_(0),
      program_(nullptr),
@@ -439,19 +436,26 @@
 	}
 }
 
-void Immovable::draw(const EditorGameBase& game,
-                     RenderTarget& dst,
-                     const FCoords&,
-                     const Point& pos) {
-	if (anim_) {
-		if (!anim_construction_total_)
-			dst.blit_animation(pos, anim_, game.get_gametime() - animstart_);
-		else
-			draw_construction(game, dst, pos);
+void Immovable::draw(uint32_t gametime,
+                     const TextToDraw draw_text,
+                     const Vector2f& point_on_dst,
+                     float scale,
+                     RenderTarget* dst) {
+	if (!anim_) {
+		return;
+	}
+	if (!anim_construction_total_) {
+		dst->blit_animation(point_on_dst, scale, anim_, gametime - animstart_);
+	} else {
+		draw_construction(gametime, draw_text, point_on_dst, scale, dst);
 	}
 }
 
-void Immovable::draw_construction(const EditorGameBase& game, RenderTarget& dst, const Point pos) {
+void Immovable::draw_construction(const uint32_t gametime,
+                                  const TextToDraw draw_text,
+                                  const Vector2f& point_on_dst,
+                                  const float scale,
+                                  RenderTarget* dst) {
 	const ImmovableProgram::ActConstruction* constructionact = nullptr;
 	if (program_ptr_ < program_->size())
 		constructionact =
@@ -462,7 +466,7 @@
 	uint32_t done = 0;
 	if (anim_construction_done_ > 0) {
 		done = steptime * (anim_construction_done_ - 1);
-		done += std::min(steptime, game.get_gametime() - animstart_);
+		done += std::min(steptime, gametime - animstart_);
 	}
 
 	uint32_t total = anim_construction_total_ * steptime;
@@ -483,21 +487,19 @@
 	const RGBColor& player_color = get_owner()->get_playercolor();
 	if (current_frame > 0) {
 		// Not the first pic, so draw the previous one in the back
-		dst.blit_animation(pos, anim_, (current_frame - 1) * frametime, player_color);
+		dst->blit_animation(point_on_dst, scale, anim_, (current_frame - 1) * frametime, player_color);
 	}
 
 	assert(lines <= curh);
-	dst.blit_animation(pos, anim_, current_frame * frametime, player_color,
-	                   Rect(Point(0, curh - lines), curw, lines));
+	dst->blit_animation(point_on_dst, scale, anim_, current_frame * frametime, player_color,
+	                   Recti(Vector2i(0, curh - lines), curw, lines));
 
 	// Additionally, if statistics are enabled, draw a progression string
-	uint32_t const display_flags = game.get_ibase()->get_display_flags();
-	do_draw_info(display_flags & InteractiveBase::dfShowCensus, descr().descname(),
-	             display_flags & InteractiveBase::dfShowStatistics,
+	do_draw_info(draw_text, descr().descname(),
 	             (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_DARK.hex_value() %
 	              (boost::format(_("%i%% built")) % (100 * done / total)).str())
 	                .str(),
-	             dst, pos);
+	             point_on_dst, scale, dst);
 }
 
 /**
@@ -527,7 +529,7 @@
 
 	if (packet_version >= 5) {
 		PlayerNumber pn = fr.unsigned_8();
-		if (pn && pn <= MAX_PLAYERS) {
+		if (pn && pn <= kMaxPlayers) {
 			Player* plr = egbase().get_player(pn);
 			if (!plr)
 				throw GameDataError("Immovable::load: player %u does not exist", pn);
@@ -1179,7 +1181,7 @@
  * Zero-initialize
 */
 PlayerImmovable::PlayerImmovable(const MapObjectDescr& mo_descr)
-   : BaseImmovable(mo_descr), owner_(nullptr), economy_(nullptr) {
+   : BaseImmovable(mo_descr), economy_(nullptr) {
 }
 
 /**

=== modified file 'src/logic/map_objects/immovable.h'
--- src/logic/map_objects/immovable.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/immovable.h	2016-10-28 17:51:15 +0000
@@ -26,6 +26,7 @@
 #include "base/macros.h"
 #include "graphic/animation.h"
 #include "logic/map_objects/buildcost.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/map_objects/map_object.h"
 #include "logic/widelands_geometry.h"
 #include "notifications/note_ids.h"
@@ -91,7 +92,18 @@
 	 * if one can be chosen as main.
 	 */
 	virtual PositionList get_positions(const EditorGameBase&) const = 0;
-	virtual void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) = 0;
+
+	// Draw this immovable onto 'dst' choosing the frame appropriate for
+	// 'gametime'. 'draw_text' decides if census and statistics are written too.
+	// The 'coords_to_draw' are passed one to give objects that occupy multiple
+	// fields a way to only draw themselves once. The 'point_on_dst' determines
+	// the point for the hotspot of the animation and 'scale' determines how big
+	// the immovable will be plotted.
+	virtual void draw(uint32_t gametime,
+	          TextToDraw draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) = 0;
 
 	static int32_t string_to_size(const std::string& size);
 	static std::string size_to_string(int32_t size);
@@ -189,10 +201,7 @@
 	Immovable(const ImmovableDescr&);
 	~Immovable();
 
-	Player* get_owner() const {
-		return owner_;
-	}
-	void set_owner(Player* player);
+	void set_owner(Player*);
 
 	Coords get_position() const {
 		return position_;
@@ -212,8 +221,11 @@
 	void init(EditorGameBase&) override;
 	void cleanup(EditorGameBase&) override;
 	void act(Game&, uint32_t data) override;
-
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          TextToDraw draw_text,
+	          const Vector2f& point_on_dst,
+	          float scale,
+	          RenderTarget* dst) override;
 
 	void switch_program(Game& game, const std::string& programname);
 	bool construct_ware(Game& game, DescriptionIndex index);
@@ -230,7 +242,6 @@
 	}
 
 protected:
-	Player* owner_;
 	Coords position_;
 
 	uint32_t anim_;
@@ -289,8 +300,11 @@
 
 private:
 	void increment_program_pointer();
-
-	void draw_construction(const EditorGameBase&, RenderTarget&, Point);
+	void draw_construction(uint32_t gametime,
+	                       TextToDraw draw_text,
+	                       const Vector2f& point_on_dst,
+	                       float scale,
+	                       RenderTarget* dst);
 };
 
 /**
@@ -360,7 +374,6 @@
 	void cleanup(EditorGameBase&) override;
 
 private:
-	Player* owner_;
 	Economy* economy_;
 
 	Workers workers_;

=== modified file 'src/logic/map_objects/map_object.cc'
--- src/logic/map_objects/map_object.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/map_object.cc	2016-10-28 17:51:15 +0000
@@ -393,7 +393,7 @@
  * Zero-initialize a map object
  */
 MapObject::MapObject(const MapObjectDescr* const the_descr)
-   : descr_(the_descr), serial_(0), logsink_(nullptr), reserved_by_worker_(false) {
+   : descr_(the_descr), serial_(0), logsink_(nullptr), owner_(nullptr), reserved_by_worker_(false) {
 }
 
 /**
@@ -445,27 +445,40 @@
 	egbase.objects().remove(*this);
 }
 
-void MapObject::do_draw_info(bool show_census,
+void MapObject::do_draw_info(const TextToDraw& draw_text,
                              const std::string& census,
-                             bool show_statictics,
                              const std::string& statictics,
-                             RenderTarget& dst,
-                             const Point& pos) const {
-	if (show_census || show_statictics) {
-		// We always render this so we can have a stable position for the statistics string.
-		const Image* rendered_census_info =
-		   UI::g_fh1->render(as_condensed(census, UI::Align::kCenter), 120);
-		const Point census_pos(pos - Point(0, 48));
-
-		if (show_census) {
-			dst.blit(census_pos, rendered_census_info, BlendMode::UseAlpha, UI::Align::kCenter);
-		}
-
-		if (show_statictics && !statictics.empty()) {
-			dst.blit(census_pos + Point(0, rendered_census_info->height() / 2 + 10),
-			         UI::g_fh1->render(as_condensed(statictics)), BlendMode::UseAlpha,
-			         UI::Align::kCenter);
-		}
+                             const Vector2f& field_on_dst,
+                             float scale,
+                             RenderTarget* dst) const {
+	if (draw_text == TextToDraw::kNone) {
+		return;
+	}
+
+	// Rendering text is expensive, so let's just do it for only a few sizes.
+	scale = std::round(scale);
+	if (scale == 0.f) {
+		return;
+	}
+	const int font_size = scale * UI_FONT_SIZE_SMALL;
+
+	// We always render this so we can have a stable position for the statistics string.
+	const Image* rendered_census_info =
+	   UI::g_fh1->render(as_condensed(census, UI::Align::kCenter, font_size), 120);
+
+	// Rounding guarantees that text aligns with pixels to avoid subsampling.
+	const Vector2f census_pos = round(field_on_dst - Vector2f(0, 48) * scale).cast<float>();
+	if (draw_text & TextToDraw::kCensus) {
+		dst->blit(census_pos, rendered_census_info, BlendMode::UseAlpha, UI::Align::kCenter);
+	}
+
+	if (draw_text & TextToDraw::kStatistics && !statictics.empty()) {
+		const Vector2f statistics_pos =
+		   round(census_pos + Vector2f(0, rendered_census_info->height() / 2.f + 10 * scale))
+		      .cast<float>();
+		dst->blit(statistics_pos,
+		          UI::g_fh1->render(as_condensed(statictics, UI::Align::kLeft, font_size)),
+		          BlendMode::UseAlpha, UI::Align::kCenter);
 	}
 }
 

=== modified file 'src/logic/map_objects/map_object.h'
--- src/logic/map_objects/map_object.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/map_object.h	2016-10-28 17:51:15 +0000
@@ -35,6 +35,7 @@
 #include "graphic/color.h"
 #include "graphic/image.h"
 #include "logic/cmd_queue.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/map_objects/tribes/training_attribute.h"
 #include "logic/widelands.h"
 #include "scripting/lua_table.h"
@@ -306,6 +307,10 @@
 	/// Called when a new logsink is set. Used to give general information.
 	virtual void log_general_info(const EditorGameBase&);
 
+	Player* get_owner() const {
+		return owner_;
+	}
+
 	// Header bytes to distinguish between data packages for the different
 	// MapObject classes. Be careful in changing those, since they are written
 	// to files.
@@ -401,18 +406,19 @@
 	virtual void cleanup(EditorGameBase&);
 
 	/// Draws census and statistics on screen
-	void do_draw_info(bool show_census,
+	void do_draw_info(const TextToDraw& draw_text,
 	                  const std::string& census,
-	                  bool show_statictics,
 	                  const std::string& statictics,
-	                  RenderTarget& dst,
-	                  const Point& pos) const;
+	                  const Vector2f& field_on_dst,
+	                  const float scale,
+	                  RenderTarget* dst) const;
 
 	void molog(char const* fmt, ...) const __attribute__((format(printf, 2, 3)));
 
 	const MapObjectDescr* descr_;
 	Serial serial_;
 	LogSink* logsink_;
+	Player* owner_;
 
 	/**
 	 * MapObjects like trees are reserved by a worker that is walking

=== modified file 'src/logic/map_objects/tribes/building.cc'
--- src/logic/map_objects/tribes/building.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/building.cc	2016-10-28 17:51:15 +0000
@@ -586,24 +586,19 @@
 	return false;
 }
 
-/*
-===============
-Draw the building.
-===============
-*/
-void Building::draw(const EditorGameBase& game,
-                    RenderTarget& dst,
-                    const FCoords& coords,
-                    const Point& pos) {
-	if (coords == position_) {  // draw big buildings only once
-		dst.blit_animation(
-		   pos, anim_, game.get_gametime() - animstart_, get_owner()->get_playercolor());
-
-		//  door animation?
-
-		//  overlay strings (draw when enabled)
-		draw_info(game, dst, pos);
-	}
+
+void Building::draw(uint32_t gametime,
+                    const TextToDraw draw_text,
+                    const Vector2f& point_on_dst,
+                    const float scale,
+                    RenderTarget* dst) {
+	dst->blit_animation(
+	   point_on_dst, scale, anim_, gametime - animstart_, get_owner()->get_playercolor());
+
+	//  door animation?
+
+	//  overlay strings (draw when enabled)
+	draw_info(draw_text, point_on_dst, scale, dst);
 }
 
 /*
@@ -611,24 +606,14 @@
 Draw overlay help strings when enabled.
 ===============
 */
-void Building::draw_info(const EditorGameBase& game, RenderTarget& dst, const Point& pos) {
-	const InteractiveGameBase& igbase = dynamic_cast<const InteractiveGameBase&>(*game.get_ibase());
-	uint32_t const display_flags = igbase.get_display_flags();
-
-	bool show_statistics_string = display_flags & InteractiveBase::dfShowStatistics;
-	if (show_statistics_string) {
-		if (upcast(InteractivePlayer const, iplayer, &igbase)) {
-			if (!iplayer->player().see_all() && iplayer->player().is_hostile(*get_owner())) {
-				show_statistics_string = false;
-			}
-		}
-	}
+void Building::draw_info(const TextToDraw draw_text,
+                         const Vector2f& point_on_dst,
+								 const float scale,
+                         RenderTarget* dst) {
 	const std::string statistics_string =
-	   show_statistics_string ? info_string(InfoStringFormat::kStatistics) : "";
-
-	do_draw_info(display_flags & InteractiveBase::dfShowCensus,
-	             info_string(InfoStringFormat::kCensus), show_statistics_string, statistics_string,
-	             dst, pos);
+	   (draw_text & TextToDraw::kStatistics) ? info_string(InfoStringFormat::kStatistics) : "";
+	do_draw_info(draw_text, info_string(InfoStringFormat::kCensus), statistics_string, point_on_dst,
+	             scale, dst);
 }
 
 int32_t

=== modified file 'src/logic/map_objects/tribes/building.h'
--- src/logic/map_objects/tribes/building.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/building.h	2016-10-28 17:51:15 +0000
@@ -241,7 +241,7 @@
 	virtual bool burn_on_destroy();
 	void destroy(EditorGameBase&) override;
 
-	void show_options(InteractiveGameBase&, bool avoid_fastclick = false, Point pos = Point(-1, -1));
+	void show_options(InteractiveGameBase&, bool avoid_fastclick = false, Vector2i pos = Vector2i(-1, -1));
 	void hide_options();
 	void refresh_options(InteractiveGameBase&);
 
@@ -311,8 +311,12 @@
 	void cleanup(EditorGameBase&) override;
 	void act(Game&, uint32_t data) override;
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
-	void draw_info(const EditorGameBase&, RenderTarget&, const Point&);
+	void draw(uint32_t gametime,
+	          TextToDraw draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
+	void draw_info(TextToDraw draw_text, const Vector2f& point_on_dst, float scale, RenderTarget* dst);
 
 	virtual void create_options_window(InteractiveGameBase&, UI::Window*& registry) = 0;
 

=== modified file 'src/logic/map_objects/tribes/constructionsite.cc'
--- src/logic/map_objects/tribes/constructionsite.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/constructionsite.cc	2016-10-28 17:51:15 +0000
@@ -153,7 +153,7 @@
 		}
 		// Open the new building window if needed
 		if (optionswindow_) {
-			Point window_position = optionswindow_->get_pos();
+			Vector2i window_position = optionswindow_->get_pos();
 			hide_options();
 			InteractiveGameBase& igbase = dynamic_cast<InteractiveGameBase&>(*egbase.get_ibase());
 			b.show_options(igbase, false, window_position);
@@ -297,19 +297,15 @@
 Draw the construction site.
 ===============
 */
-void ConstructionSite::draw(const EditorGameBase& game,
-                            RenderTarget& dst,
-                            const FCoords& coords,
-                            const Point& pos) {
-	const uint32_t gametime = game.get_gametime();
+void ConstructionSite::draw(uint32_t gametime,
+                            TextToDraw draw_text,
+                            const Vector2f& point_on_dst,
+                            float scale,
+                            RenderTarget* dst) {
 	uint32_t tanim = gametime - animstart_;
-
-	if (coords != position_)
-		return;  // draw big buildings only once
-
 	// Draw the construction site marker
 	const RGBColor& player_color = get_owner()->get_playercolor();
-	dst.blit_animation(pos, anim_, tanim, player_color);
+	dst->blit_animation(point_on_dst, scale, anim_, tanim, player_color);
 
 	// Draw the partially finished building
 
@@ -324,7 +320,6 @@
 	}
 
 	uint32_t anim_idx;
-	uint32_t cur_frame;
 	try {
 		anim_idx = building().get_animation("build");
 	} catch (MapObjectDescr::AnimationNonexistent&) {
@@ -336,23 +331,23 @@
 	}
 	const Animation& anim = g_gr->animations().get_animation(anim_idx);
 	const size_t nr_frames = anim.nr_frames();
-	cur_frame = info_.totaltime ? info_.completedtime * nr_frames / info_.totaltime : 0;
-	// Redefine tanim
+	const uint32_t cur_frame = info_.totaltime ? info_.completedtime * nr_frames / info_.totaltime : 0;
 	tanim = cur_frame * FRAME_LENGTH;
 
 	const uint16_t w = anim.width();
 	const uint16_t h = anim.height();
 
 	uint32_t lines = h * info_.completedtime * nr_frames;
-	if (info_.totaltime)
+	if (info_.totaltime) {
 		lines /= info_.totaltime;
+	}
 	assert(h * cur_frame <= lines);
 	lines -= h * cur_frame;  //  This won't work if pictures have various sizes.
 
 	if (cur_frame) {  //  not the first pic
 		//  draw the prev pic from top to where next image will be drawing
-		dst.blit_animation(
-		   pos, anim_idx, tanim - FRAME_LENGTH, player_color, Rect(Point(0, 0), w, h - lines));
+		dst->blit_animation(point_on_dst, scale, anim_idx, tanim - FRAME_LENGTH, player_color,
+		                    Recti(Vector2i(0, 0), w, h - lines));
 	} else if (!old_buildings_.empty()) {
 		DescriptionIndex prev_idx = old_buildings_.back();
 		const BuildingDescr* prev_building = owner().tribe().get_building_descr(prev_idx);
@@ -366,15 +361,17 @@
 		}
 		const Animation& prev_building_anim =
 		   g_gr->animations().get_animation(prev_building_anim_idx);
-		dst.blit_animation(pos, prev_building_anim_idx, tanim - FRAME_LENGTH, player_color,
-		                   Rect(Point(0, 0), prev_building_anim.width(),
-		                        std::min<int>(prev_building_anim.height(), h - lines)));
+		dst->blit_animation(point_on_dst, scale, prev_building_anim_idx, tanim - FRAME_LENGTH,
+		                    player_color,
+		                    Recti(Vector2i(0, 0), prev_building_anim.width(),
+		                         std::min<int>(prev_building_anim.height(), h - lines)));
 	}
 
 	assert(lines <= h);
-	dst.blit_animation(pos, anim_idx, tanim, player_color, Rect(Point(0, h - lines), w, lines));
+	dst->blit_animation(point_on_dst, scale, anim_idx, tanim,
+	                    player_color, Recti(Vector2i(0, h - lines), w, lines));
 
 	// Draw help strings
-	draw_info(game, dst, pos);
+	draw_info(draw_text, point_on_dst, scale, dst);
 }
 }

=== modified file 'src/logic/map_objects/tribes/constructionsite.h'
--- src/logic/map_objects/tribes/constructionsite.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/constructionsite.h	2016-10-28 17:51:15 +0000
@@ -114,7 +114,11 @@
 
 	static void wares_queue_callback(Game&, WaresQueue*, DescriptionIndex, void* data);
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          TextToDraw draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 
 private:
 	int32_t fetchfromflag_;  // # of wares to fetch from flag

=== modified file 'src/logic/map_objects/tribes/dismantlesite.cc'
--- src/logic/map_objects/tribes/dismantlesite.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/dismantlesite.cc	2016-10-28 17:51:15 +0000
@@ -212,20 +212,16 @@
 Draw it.
 ===============
 */
-void DismantleSite::draw(const EditorGameBase& game,
-                         RenderTarget& dst,
-                         const FCoords& coords,
-                         const Point& pos) {
-	const uint32_t gametime = game.get_gametime();
+void DismantleSite::draw(uint32_t gametime,
+                         const TextToDraw draw_text,
+                         const Vector2f& point_on_dst,
+                         float scale,
+                         RenderTarget* dst) {
 	uint32_t tanim = gametime - animstart_;
-
-	if (coords != position_)
-		return;  // draw big buildings only once
-
 	const RGBColor& player_color = get_owner()->get_playercolor();
 
 	// Draw the construction site marker
-	dst.blit_animation(pos, anim_, tanim, player_color);
+	dst->blit_animation(point_on_dst, scale, anim_, tanim, player_color);
 
 	// Draw the partially dismantled building
 	static_assert(0 <= DISMANTLESITE_STEP_TIME, "assert(0 <= DISMANTLESITE_STEP_TIME) failed.");
@@ -247,9 +243,10 @@
 
 	const uint32_t lines = total_time ? h * completed_time / total_time : 0;
 
-	dst.blit_animation(pos, anim_idx, tanim, player_color, Rect(Point(0, lines), w, h - lines));
+	dst->blit_animation(
+	   point_on_dst, scale, anim_idx, tanim, player_color, Recti(Vector2i(0, lines), w, h - lines));
 
 	// Draw help strings
-	draw_info(game, dst, pos);
+	draw_info(draw_text, point_on_dst, scale, dst);
 }
 }

=== modified file 'src/logic/map_objects/tribes/dismantlesite.h'
--- src/logic/map_objects/tribes/dismantlesite.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/dismantlesite.h	2016-10-28 17:51:15 +0000
@@ -89,7 +89,11 @@
 
 	void create_options_window(InteractiveGameBase&, UI::Window*& registry) override;
 
-	void draw(const EditorGameBase&, RenderTarget&, const FCoords&, const Point&) override;
+	void draw(uint32_t gametime,
+	          TextToDraw draw_text,
+	          const Vector2f& point_on_dst,
+				 float scale,
+	          RenderTarget* dst) override;
 };
 }
 

=== modified file 'src/logic/map_objects/tribes/road_textures.cc'
--- src/logic/map_objects/tribes/road_textures.cc	2016-01-13 07:27:55 +0000
+++ src/logic/map_objects/tribes/road_textures.cc	2016-10-28 17:51:15 +0000
@@ -21,12 +21,12 @@
 
 #include <memory>
 
-const Image& RoadTextures::get_normal_texture(int x, int y, int direction) const {
-	return *normal_textures_.at((x + y + direction) % normal_textures_.size());
+const Image& RoadTextures::get_normal_texture(const Widelands::Coords& coords, int direction) const {
+	return *normal_textures_.at((coords.x + coords.y + direction) % normal_textures_.size());
 }
 
-const Image& RoadTextures::get_busy_texture(int x, int y, int direction) const {
-	return *busy_textures_.at((x + y + direction) % busy_textures_.size());
+const Image& RoadTextures::get_busy_texture(const Widelands::Coords& coords, int direction) const {
+	return *busy_textures_.at((coords.x + coords.y + direction) % busy_textures_.size());
 }
 
 void RoadTextures::add_normal_road_texture(const Image* image) {

=== modified file 'src/logic/map_objects/tribes/road_textures.h'
--- src/logic/map_objects/tribes/road_textures.h	2016-01-13 07:27:55 +0000
+++ src/logic/map_objects/tribes/road_textures.h	2016-10-28 17:51:15 +0000
@@ -24,14 +24,15 @@
 #include <vector>
 
 #include "graphic/image.h"
+#include "logic/widelands_geometry.h"
 
 // Simple container to give access of the road textures of a tribe.
 class RoadTextures {
 public:
-	// Returns the road texture that should be used for the Cooordinate x, y and
-	// the road going into direction 'direction' (which can be any number).
-	const Image& get_normal_texture(int x, int y, int direction) const;
-	const Image& get_busy_texture(int x, int y, int direction) const;
+	// Returns the road texture that should be used for 'coords' and the road
+	// going into direction 'direction' (which can be any number).
+	const Image& get_normal_texture(const Widelands::Coords& coords, int direction) const;
+	const Image& get_busy_texture(const Widelands::Coords& coords, int direction) const;
 
 	// Adds a new road texture.
 	void add_normal_road_texture(const Image* texture);

=== modified file 'src/logic/map_objects/tribes/ship.cc'
--- src/logic/map_objects/tribes/ship.cc	2016-09-07 09:30:49 +0000
+++ src/logic/map_objects/tribes/ship.cc	2016-10-28 17:51:15 +0000
@@ -126,14 +126,13 @@
 
 Ship::Ship(const ShipDescr& gdescr)
    : Bob(gdescr),
-     window_(nullptr),
      fleet_(nullptr),
      economy_(nullptr),
      ship_state_(ShipStates::kTransport) {
 }
 
 Ship::~Ship() {
-	close_window();
+	Notifications::publish(NoteShipWindow(serial(), NoteShipWindow::Action::kClose));
 }
 
 PortDock* Ship::get_destination(EditorGameBase& egbase) const {
@@ -680,8 +679,7 @@
 
 			expedition_.reset(nullptr);
 
-			if (upcast(InteractiveGameBase, igb, game.get_ibase()))
-				refresh_window(*igb);
+			Notifications::publish(NoteShipWindow(serial(), NoteShipWindow::Action::kRefresh));
 			return start_task_idle(game, descr().main_animation(), 1500);
 		}
 	}
@@ -743,7 +741,7 @@
 /**
  * Find a path to the dock @p pd, returns its length, and the path optionally.
  */
-uint32_t Ship::calculate_sea_route(Game& game, PortDock& pd, Path* finalpath) {
+uint32_t Ship::calculate_sea_route(Game& game, PortDock& pd, Path* finalpath) const {
 	Map& map = game.map();
 	StepEvalAStar se(pd.get_warehouse()->get_position());
 	se.swim_ = true;
@@ -847,7 +845,7 @@
 	expedition_->island_exploration = false;
 }
 
-WalkingDir Ship::get_scouting_direction() {
+WalkingDir Ship::get_scouting_direction() const {
 	if (expedition_ && ship_state_ == ShipStates::kExpeditionScouting &&
 	    !expedition_->island_exploration) {
 		return expedition_->scouting_direction;
@@ -882,7 +880,7 @@
 	expedition_->island_exploration = true;
 }
 
-IslandExploreDirection Ship::get_island_explore_direction() {
+IslandExploreDirection Ship::get_island_explore_direction() const {
 	if (expedition_ && ship_state_ == ShipStates::kExpeditionScouting &&
 	    expedition_->island_exploration) {
 		return expedition_->island_explore_direction;
@@ -926,8 +924,7 @@
 	expedition_.reset(nullptr);
 
 	// And finally update our ship window
-	if (upcast(InteractiveGameBase, igb, game.get_ibase()))
-		refresh_window(*igb);
+	Notifications::publish(NoteShipWindow(serial(), NoteShipWindow::Action::kRefresh));
 }
 
 /// Sinks the ship
@@ -936,19 +933,22 @@
 	// Running colonization has the highest priority + a sink request is only valid once
 	if (!state_is_sinkable())
 		return;
+	Notifications::publish(NoteShipWindow(serial(), NoteShipWindow::Action::kClose));
 	ship_state_ = ShipStates::kSinkRequest;
 	// Make sure the ship is active and close possible open windows
 	ship_wakeup(game);
-	close_window();
 }
 
-void Ship::draw(const EditorGameBase& game, RenderTarget& dst, const Point& pos) const {
-	Bob::draw(game, dst, pos);
+void Ship::draw(const EditorGameBase& egbase,
+                const TextToDraw& draw_text,
+                const Vector2f& field_on_dst,
+                const float scale,
+                RenderTarget* dst) const {
+	Bob::draw(egbase, draw_text, field_on_dst, scale, dst);
 
 	// Show ship name and current activity
-	uint32_t const display_flags = game.get_ibase()->get_display_flags();
 	std::string statistics_string = "";
-	if (display_flags & InteractiveBase::dfShowStatistics) {
+	if (draw_text & TextToDraw::kStatistics) {
 		switch (ship_state_) {
 		case (ShipStates::kTransport):
 			/** TRANSLATORS: This is a ship state */
@@ -980,9 +980,8 @@
 		                       .str();
 	}
 
-	do_draw_info(display_flags & InteractiveBase::dfShowCensus, shipname_,
-	             display_flags & InteractiveBase::dfShowStatistics, statistics_string, dst,
-	             calc_drawpos(game, pos));
+	do_draw_info(
+	   draw_text, shipname_, statistics_string, calc_drawpos(egbase, field_on_dst, scale), scale, dst);
 }
 
 void Ship::log_general_info(const EditorGameBase& egbase) {

=== modified file 'src/logic/map_objects/tribes/ship.h'
--- src/logic/map_objects/tribes/ship.h	2016-09-07 09:30:49 +0000
+++ src/logic/map_objects/tribes/ship.h	2016-10-28 17:51:15 +0000
@@ -28,11 +28,6 @@
 #include "graphic/diranimations.h"
 #include "logic/map_objects/bob.h"
 
-namespace UI {
-class Window;
-}
-class InteractiveGameBase;
-
 namespace Widelands {
 
 class Economy;
@@ -59,6 +54,19 @@
 	}
 };
 
+struct NoteShipWindow {
+	CAN_BE_SENT_AS_NOTE(NoteId::ShipWindow)
+
+	Serial serial;
+
+	enum class Action { kRefresh, kClose };
+	const Action action;
+
+	NoteShipWindow(Serial init_serial, const Action& init_action)
+		: serial(init_serial), action(init_action) {
+	}
+};
+
 class ShipDescr : public BobDescr {
 public:
 	ShipDescr(const std::string& init_descname, const LuaTable& t);
@@ -119,7 +127,7 @@
 	void start_task_movetodock(Game&, PortDock&);
 	void start_task_expedition(Game&);
 
-	uint32_t calculate_sea_route(Game& game, PortDock& pd, Path* finalpath = nullptr);
+	uint32_t calculate_sea_route(Game& game, PortDock& pd, Path* finalpath = nullptr) const;
 
 	void log_general_info(const EditorGameBase&) override;
 
@@ -133,10 +141,6 @@
 	void withdraw_items(Game& game, PortDock& pd, std::vector<ShippingItem>& items);
 	void add_item(Game&, const ShippingItem& item);
 
-	void show_window(InteractiveGameBase&, bool avoid_fastclick = false);
-	void close_window();
-	void refresh_window(InteractiveGameBase&);
-
 	// A ship with task expedition can be in four states: kExpeditionWaiting, kExpeditionScouting,
 	// kExpeditionPortspaceFound or kExpeditionColonizing in the first states, the owning player of
 	// this ship
@@ -169,42 +173,42 @@
 	};
 
 	/// \returns the current state the ship is in
-	ShipStates get_ship_state() {
+	ShipStates get_ship_state() const {
 		return ship_state_;
 	}
 
 	/// \returns the current name of ship
-	const std::string& get_shipname() {
+	const std::string& get_shipname() const {
 		return shipname_;
 	}
 
 	/// \returns whether the ship is currently on an expedition
-	bool state_is_expedition() {
+	bool state_is_expedition() const {
 		return (ship_state_ == ShipStates::kExpeditionScouting ||
 		        ship_state_ == ShipStates::kExpeditionWaiting ||
 		        ship_state_ == ShipStates::kExpeditionPortspaceFound ||
 		        ship_state_ == ShipStates::kExpeditionColonizing);
 	}
 	/// \returns whether the ship is in transport mode
-	bool state_is_transport() {
+	bool state_is_transport() const {
 		return (ship_state_ == ShipStates::kTransport);
 	}
 	/// \returns whether a sink request for the ship is currently valid
-	bool state_is_sinkable() {
+	bool state_is_sinkable() const {
 		return (ship_state_ != ShipStates::kSinkRequest &&
 		        ship_state_ != ShipStates::kSinkAnimation &&
 		        ship_state_ != ShipStates::kExpeditionColonizing);
 	}
 
 	/// \returns (in expedition mode only!) whether the next field in direction \arg dir is swimmable
-	bool exp_dir_swimmable(Direction dir) {
+	bool exp_dir_swimmable(Direction dir) const {
 		if (!expedition_)
 			return false;
 		return expedition_->swimmable[dir - 1];
 	}
 
 	/// \returns whether the expedition ship is close to the coast
-	bool exp_close_to_coast() {
+	bool exp_close_to_coast() const {
 		if (!expedition_)
 			return false;
 		for (uint8_t dir = FIRST_DIRECTION; dir <= LAST_DIRECTION; ++dir)
@@ -214,7 +218,7 @@
 	}
 
 	/// \returns (in expedition mode only!) the list of currently seen port build spaces
-	const std::vector<Coords>& exp_port_spaces() {
+	const std::vector<Coords>& exp_port_spaces() const {
 		return expedition_->seen_port_buildspaces;
 	}
 
@@ -224,22 +228,25 @@
 
 	// Returns integer of direction, or WalkingDir::IDLE if query invalid
 	// Intended for LUA scripting
-	WalkingDir get_scouting_direction();
+	WalkingDir get_scouting_direction() const;
 
 	// Returns integer of direction, or IslandExploreDirection::kNotSet
 	// if query invalid
 	// Intended for LUA scripting
-	IslandExploreDirection get_island_explore_direction();
+	IslandExploreDirection get_island_explore_direction() const;
 
 	void exp_cancel(Game&);
 	void sink_ship(Game&);
 
 protected:
-	void draw(const EditorGameBase&, RenderTarget&, const Point&) const override;
+	void draw(const EditorGameBase&,
+	          const TextToDraw& draw_text,
+	          const Vector2f& field_on_dst,
+	          float scale,
+	          RenderTarget* dst) const override;
 
 private:
 	friend struct Fleet;
-	friend struct ShipWindow;
 
 	void wakeup_neighbours(Game&);
 
@@ -261,8 +268,6 @@
 	                  const std::string& description,
 	                  const std::string& picture);
 
-	UI::Window* window_;
-
 	Fleet* fleet_;
 	Economy* economy_;
 	OPtr<PortDock> lastdock_;

=== modified file 'src/logic/map_objects/tribes/soldier.cc'
--- src/logic/map_objects/tribes/soldier.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/soldier.cc	2016-10-28 17:51:15 +0000
@@ -26,6 +26,7 @@
 #include <boost/format.hpp>
 
 #include "base/macros.h"
+#include "base/math.h"
 #include "base/wexception.h"
 #include "economy/economy.h"
 #include "economy/flag.h"
@@ -384,56 +385,53 @@
 ///
 /// pos is the location, in pixels, of the node position_ (height is already
 /// taken into account).
-Point Soldier::calc_drawpos(const EditorGameBase& game, const Point pos) const {
+Vector2f Soldier::calc_drawpos(const EditorGameBase& game,
+                                 const Vector2f& field_on_dst,
+                                 const float scale) const {
 	if (combat_walking_ == CD_NONE) {
-		return Bob::calc_drawpos(game, pos);
+		return Bob::calc_drawpos(game, field_on_dst, scale);
 	}
 
 	bool moving = false;
-	Point spos = pos, epos = pos;
+	Vector2f spos = field_on_dst, epos = field_on_dst;
 
+	const float triangle_width = kTriangleWidth * scale;
 	switch (combat_walking_) {
 	case CD_WALK_W:
 		moving = true;
-		epos.x -= kTriangleWidth / 4;
+		epos.x -= triangle_width / 4;
 		break;
 	case CD_WALK_E:
 		moving = true;
-		epos.x += kTriangleWidth / 4;
+		epos.x += triangle_width / 4;
 		break;
 	case CD_RETURN_W:
 		moving = true;
-		spos.x -= kTriangleWidth / 4;
+		spos.x -= triangle_width / 4;
 		break;
 	case CD_RETURN_E:
 		moving = true;
-		spos.x += kTriangleWidth / 4;
+		spos.x += triangle_width / 4;
 		break;
 	case CD_COMBAT_W:
 		moving = false;
-		epos.x -= kTriangleWidth / 4;
+		epos.x -= triangle_width / 4;
 		break;
 	case CD_COMBAT_E:
 		moving = false;
-		epos.x += kTriangleWidth / 4;
+		epos.x += triangle_width / 4;
 		break;
 	case CD_NONE:
 		break;
 	}
 
 	if (moving) {
-
-		float f = static_cast<float>(game.get_gametime() - combat_walkstart_) /
-		          (combat_walkend_ - combat_walkstart_);
+		const float f = math::clamp(static_cast<float>(game.get_gametime() - combat_walkstart_) /
+		                               (combat_walkend_ - combat_walkstart_),
+		                            0.f, 1.f);
 		assert(combat_walkstart_ <= game.get_gametime());
 		assert(combat_walkstart_ < combat_walkend_);
-
-		if (f < 0)
-			f = 0;
-		else if (f > 1)
-			f = 1;
-
-		epos.x = static_cast<int32_t>(f * epos.x + (1 - f) * spos.x);
+		epos.x = f * epos.x + (1 - f) * spos.x;
 	}
 	return epos;
 }
@@ -441,79 +439,104 @@
 /*
  * Draw this soldier. This basically draws him as a worker, but add health points
  */
-void Soldier::draw(const EditorGameBase& game, RenderTarget& dst, const Point& pos) const {
-	if (const uint32_t anim = get_current_anim()) {
-		const Point drawpos = calc_drawpos(game, pos);
-		draw_info_icon(
-		   dst, Point(drawpos.x, drawpos.y - g_gr->animations().get_animation(anim).height() - 7),
-		   true);
-
-		draw_inner(game, dst, drawpos);
+void Soldier::draw(const EditorGameBase& game,
+                   const TextToDraw&,
+                   const Vector2f& field_on_dst,
+                   const float scale,
+                   RenderTarget* dst) const {
+	const uint32_t anim = get_current_anim();
+	if (!anim) {
+		return;
 	}
+
+	const Vector2f point_on_dst = calc_drawpos(game, field_on_dst, scale);
+	draw_info_icon(
+	   point_on_dst -
+	      Vector2f(0.f, (g_gr->animations().get_animation(get_current_anim()).height() - 7) * scale),
+	   scale, true, dst);
+	draw_inner(game, point_on_dst, scale, dst);
 }
 
 /**
  * Draw the info icon (level indicators + health bar) for this soldier.
- *
- * \param anchor_below if \c true, the icon is drawn horizontally centered above
- * \p pt. Otherwise, the icon is drawn below and right of \p pt.
  */
-void Soldier::draw_info_icon(RenderTarget& dst, Point pt, bool anchor_below) const {
-	// Gather information to determine coordinates
-	uint32_t w;
-	w = kSoldierHealthBarWidth;
+void Soldier::draw_info_icon(Vector2f draw_position,
+                             float scale,
+                             const bool anchor_below,
+                             RenderTarget* dst) const {
+	// Since the graphics below are all pixel perfect and scaling them as floats
+	// looks weird, we round to the nearest fullest integer.
+	scale = std::round(scale);
+	if (scale == 0.f) {
+		return;
+	}
 
 	const Image* healthpic = get_health_level_pic();
 	const Image* attackpic = get_attack_level_pic();
 	const Image* defensepic = get_defense_level_pic();
 	const Image* evadepic = get_evade_level_pic();
 
-	uint16_t hpw = healthpic->width();
-	uint16_t hph = healthpic->height();
-	uint16_t atw = attackpic->width();
-	uint16_t ath = attackpic->height();
-	uint16_t dew = defensepic->width();
-	uint16_t deh = defensepic->height();
-	uint16_t evw = evadepic->width();
-	uint16_t evh = evadepic->height();
+#ifndef NDEBUG
+	// This function assumes stuff about our data files: level icons are all the
+	// same size and this is smaller than the width of the healthbar. This
+	// simplifies the drawing code below a lot. Before it had a lot of if () that
+	// were never tested - since our data files never changed.
+	const int dimension = attackpic->width();
+	assert(attackpic->height() == dimension);
+	assert(healthpic->width() == dimension);
+	assert(healthpic->height() == dimension);
+	assert(defensepic->width() == dimension);
+	assert(defensepic->height() == dimension);
+	assert(evadepic->width() == dimension);
+	assert(evadepic->height() == dimension);
+	assert(kSoldierHealthBarWidth > dimension);
+#endif
 
-	uint32_t totalwidth = std::max<int>(std::max<int>(atw + dew, hpw + evw), 2 * w);
-	uint32_t totalheight = 5 + std::max<int>(hph + ath, evh + deh);
+	const float icon_size = healthpic->width();
+	const float half_width = kSoldierHealthBarWidth;
 
 	if (!anchor_below) {
-		pt.x += totalwidth / 2;
-		pt.y += totalheight - 5;
+		float totalwidth = 2 * half_width;
+		float totalheight = 5.f + 2 * icon_size;
+		draw_position.x += (totalwidth / 2.f) * scale;
+		draw_position.y += (totalheight - 5.f) * scale;
 	} else {
-		pt.y -= 5;
+		draw_position.y -= 5.f * scale;
 	}
 
 	// Draw energy bar
-	Rect energy_outer(Point(pt.x - w, pt.y), w * 2, 5);
-	dst.draw_rect(energy_outer, RGBColor(255, 255, 255));
-
 	assert(get_max_health());
-	uint32_t health_width = 2 * (w - 1) * current_health_ / get_max_health();
-	Rect energy_inner(Point(pt.x - w + 1, pt.y + 1), health_width, 3);
-	Rect energy_complement(
-	   energy_inner.origin() + Point(health_width, 0), 2 * (w - 1) - health_width, 3);
+	const Rectf energy_outer(
+	   draw_position - Vector2f(half_width, 0.f) * scale, half_width * 2.f * scale, 5.f * scale);
+	dst->fill_rect(energy_outer, RGBColor(255, 255, 255));
+
+	float health_width = 2.f * (half_width - 1.f) * current_health_ / get_max_health();
+	Rectf energy_inner(
+	   draw_position + Vector2f(-half_width + 1.f, 1.f) * scale, health_width * scale, 3 * scale);
+	Rectf energy_complement(energy_inner.origin() + Vector2f(health_width, 0.f) * scale,
+	                        (2 * (half_width - 1) - health_width) * scale, 3 * scale);
+
 	const RGBColor& color = owner().get_playercolor();
 	RGBColor complement_color;
-
-	if (static_cast<uint32_t>(color.r) + color.g + color.b > 128 * 3)
+	if (static_cast<uint32_t>(color.r) + color.g + color.b > 128 * 3) {
 		complement_color = RGBColor(32, 32, 32);
-	else
+	} else {
 		complement_color = RGBColor(224, 224, 224);
-
-	dst.fill_rect(energy_inner, color);
-	dst.fill_rect(energy_complement, complement_color);
-
-	// Draw level pictures
-	{
-		dst.blit(pt + Point(-atw, -(hph + ath)), attackpic);
-		dst.blit(pt + Point(0, -(evh + deh)), defensepic);
-		dst.blit(pt + Point(-hpw, -hph), healthpic);
-		dst.blit(pt + Point(0, -evh), evadepic);
 	}
+
+	dst->fill_rect(energy_inner, color);
+	dst->fill_rect(energy_complement, complement_color);
+
+	const auto draw_level_image = [icon_size, scale, &draw_position, dst](
+	   const Vector2f& offset, const Image* image) {
+		dst->blitrect_scale(
+		   Rectf(draw_position + offset * icon_size * scale, icon_size * scale, icon_size * scale),
+		   image, Recti(0, 0, icon_size, icon_size), 1.f, BlendMode::UseAlpha);
+	};
+	draw_level_image(Vector2f(-1.f, -2.f), attackpic);
+	draw_level_image(Vector2f(0.f, -2.f), defensepic);
+	draw_level_image(Vector2f(-1.f, -1.f), healthpic);
+	draw_level_image(Vector2f(0.f, -1.f), evadepic);
 }
 
 /**
@@ -594,7 +617,7 @@
  * each other.
  */
 bool Soldier::can_be_challenged() {
-	if (current_health_ < 1) {  //< Soldier is dead!
+	if (current_health_ < 1) {  // Soldier is dead!
 		return false;
 	}
 	if (!is_on_battlefield()) {
@@ -896,9 +919,6 @@
 
 /**
  * Accept Bob when is a Soldier alive that is attacking the Player.
- *
- * \param g
- * \param p
  */
 struct FindBobSoldierAttackingPlayer : public FindBob {
 	FindBobSoldierAttackingPlayer(Game& g, Player& p) : player(p), game(g) {

=== modified file 'src/logic/map_objects/tribes/soldier.h'
--- src/logic/map_objects/tribes/soldier.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/soldier.h	2016-10-28 17:51:15 +0000
@@ -204,12 +204,25 @@
 	/// Automatically select a task.
 	void init_auto_task(Game&) override;
 
-	Point calc_drawpos(const EditorGameBase&, Point) const;
+	Vector2f
+	calc_drawpos(const EditorGameBase& game, const Vector2f& field_on_dst, const float scale) const;
+
 	/// Draw this soldier
-	void draw(const EditorGameBase&, RenderTarget&, const Point&) const override;
+	void draw(const EditorGameBase&,
+	          const TextToDraw& draw_text,
+	          const Vector2f& point_on_dst,
+	          float scale,
+	          RenderTarget* dst) const override;
 
 	static void calc_info_icon_size(const TribeDescr&, uint32_t& w, uint32_t& h);
-	void draw_info_icon(RenderTarget&, Point, bool anchor_below) const;
+
+	// Draw the info icon containing health bar and levels. If 'anchor_below' is
+	// true, the icon is drawn horizontally centered above Otherwise, the icon
+	// is drawn below and right of 'draw_position'.
+	void draw_info_icon(Vector2f draw_position,
+	                    const float scale,
+	                    const bool anchor_below,
+	                    RenderTarget*) const;
 
 	uint32_t get_current_health() const {
 		return current_health_;

=== modified file 'src/logic/map_objects/tribes/worker.cc'
--- src/logic/map_objects/tribes/worker.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/worker.cc	2016-10-28 17:51:15 +0000
@@ -2512,25 +2512,37 @@
 	return;
 }
 
-void Worker::draw_inner(const EditorGameBase& game, RenderTarget& dst, const Point& drawpos) const {
+void Worker::draw_inner(const EditorGameBase& game,
+                  const Vector2f& point_on_dst,
+                  const float scale,
+                  RenderTarget* dst) const {
 	assert(get_owner() != nullptr);
 	const RGBColor& player_color = get_owner()->get_playercolor();
 
-	dst.blit_animation(
-	   drawpos, get_current_anim(), game.get_gametime() - get_animstart(), player_color);
+	dst->blit_animation(
+	   point_on_dst, scale, get_current_anim(), game.get_gametime() - get_animstart(), player_color);
 
 	if (WareInstance const* const carried_ware = get_carried_ware(game)) {
-		dst.blit_animation(drawpos - descr().get_ware_hotspot(),
-		                   carried_ware->descr().get_animation("idle"), 0, player_color);
+		const Vector2f hotspot = descr().get_ware_hotspot().cast<float>();
+		const Vector2f location(
+		   point_on_dst.x - hotspot.x * scale, point_on_dst.y - hotspot.y * scale);
+		dst->blit_animation(
+		   location, scale, carried_ware->descr().get_animation("idle"), 0, player_color);
 	}
 }
 
 /**
  * Draw the worker, taking the carried ware into account.
  */
-void Worker::draw(const EditorGameBase& game, RenderTarget& dst, const Point& pos) const {
-	if (get_current_anim())
-		draw_inner(game, dst, calc_drawpos(game, pos));
+void Worker::draw(const EditorGameBase& egbase,
+                  const TextToDraw&,
+                  const Vector2f& field_on_dst,
+                  const float scale,
+                  RenderTarget* dst) const {
+	if (!get_current_anim()) {
+		return;
+	}
+	draw_inner(egbase, calc_drawpos(egbase, field_on_dst, scale), scale, dst);
 }
 
 /*

=== modified file 'src/logic/map_objects/tribes/worker.h'
--- src/logic/map_objects/tribes/worker.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/worker.h	2016-10-28 17:51:15 +0000
@@ -176,8 +176,15 @@
 
 protected:
 	virtual bool is_evict_allowed();
-	void draw_inner(const EditorGameBase&, RenderTarget&, const Point&) const;
-	void draw(const EditorGameBase&, RenderTarget&, const Point&) const override;
+	void draw_inner(const EditorGameBase& game,
+	                const Vector2f& point_on_dst,
+	                const float scale,
+	                RenderTarget* dst) const;
+	void draw(const EditorGameBase&,
+	          const TextToDraw& draw_text,
+	          const Vector2f& field_on_dst,
+	          float scale,
+	          RenderTarget* dst) const override;
 	void init_auto_task(Game&) override;
 
 	bool does_carry_ware() {

=== modified file 'src/logic/map_objects/tribes/worker_descr.cc'
--- src/logic/map_objects/tribes/worker_descr.cc	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/worker_descr.cc	2016-10-28 17:51:15 +0000
@@ -22,7 +22,7 @@
 #include <memory>
 
 #include "base/i18n.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "base/wexception.h"
 #include "graphic/graphic.h"
 #include "logic/game_data_error.h"
@@ -41,7 +41,7 @@
                          const LuaTable& table,
                          const EditorGameBase& egbase)
    : BobDescr(init_descname, init_type, MapObjectDescr::OwnerType::kTribe, table),
-     ware_hotspot_(Point(0, 15)),
+     ware_hotspot_(Vector2i(0, 15)),
      buildable_(false),
      needed_experience_(INVALID_INDEX),
      becomes_(INVALID_INDEX),
@@ -122,7 +122,7 @@
 	}
 	if (table.has_key("ware_hotspot")) {
 		items_table = table.get_table("ware_hotspot");
-		ware_hotspot_ = Point(items_table->get_int(1), items_table->get_int(2));
+		ware_hotspot_ = Vector2i(items_table->get_int(1), items_table->get_int(2));
 	}
 }
 

=== modified file 'src/logic/map_objects/tribes/worker_descr.h'
--- src/logic/map_objects/tribes/worker_descr.h	2016-08-04 15:49:05 +0000
+++ src/logic/map_objects/tribes/worker_descr.h	2016-10-28 17:51:15 +0000
@@ -62,7 +62,7 @@
 		return buildcost_;
 	}
 
-	Point get_ware_hotspot() const {
+	Vector2i get_ware_hotspot() const {
 		return ware_hotspot_;
 	}
 
@@ -124,7 +124,7 @@
 	}
 
 protected:
-	Point ware_hotspot_;
+	Vector2i ware_hotspot_;
 	Quantity default_target_quantity_;
 	std::string helptext_script_;  // The path and filename to the worker's helptext script
 	DirAnimations walk_anims_;

=== modified file 'src/logic/player.cc'
--- src/logic/player.cc	2016-08-04 15:49:05 +0000
+++ src/logic/player.cc	2016-10-28 17:51:15 +0000
@@ -36,7 +36,6 @@
 #include "io/filewrite.h"
 #include "logic/cmd_delete_message.h"
 #include "logic/cmd_luacoroutine.h"
-#include "logic/constants.h"
 #include "logic/findimmovable.h"
 #include "logic/game.h"
 #include "logic/game_data_error.h"
@@ -88,17 +87,6 @@
 
 namespace Widelands {
 
-const RGBColor Player::Colors[MAX_PLAYERS] = {
-   RGBColor(2, 2, 198),      // blue
-   RGBColor(255, 41, 0),     // red
-   RGBColor(255, 232, 0),    // yellow
-   RGBColor(59, 223, 3),     // green
-   RGBColor(57, 57, 57),     // black/dark gray
-   RGBColor(255, 172, 0),    // orange
-   RGBColor(215, 0, 218),    // purple
-   RGBColor(255, 255, 255),  // white
-};
-
 /**
  * Find the longest possible enhancement chain leading to the given
  * building descr. The FormerBuildings given in reference must be empty and will be
@@ -272,7 +260,7 @@
 	if (!team_number_)
 		return;
 
-	for (PlayerNumber i = 1; i <= MAX_PLAYERS; ++i) {
+	for (PlayerNumber i = 1; i <= kMaxPlayers; ++i) {
 		Player* other = egbase().get_player(i);
 		if (!other)
 			continue;

=== modified file 'src/logic/player.h'
--- src/logic/player.h	2016-08-04 15:49:05 +0000
+++ src/logic/player.h	2016-10-28 17:51:15 +0000
@@ -25,7 +25,7 @@
 
 #include "base/macros.h"
 #include "graphic/color.h"
-#include "logic/constants.h"
+#include "graphic/playercolor.h"
 #include "logic/editor_game_base.h"
 #include "logic/map_objects/tribes/building.h"
 #include "logic/map_objects/tribes/constructionsite.h"
@@ -64,9 +64,6 @@
  */
 class Player {
 public:
-	// hard-coded playercolors
-	static const RGBColor Colors[MAX_PLAYERS];
-
 	struct BuildingStats {
 		bool is_constructionsite;
 		Coords pos;
@@ -130,7 +127,7 @@
 		return team_number_;
 	}
 	const RGBColor& get_playercolor() const {
-		return Colors[player_number_ - 1];
+		return kPlayerColors[player_number_ - 1];
 	}
 	const TribeDescr& tribe() const {
 		return tribe_;

=== modified file 'src/logic/playersmanager.cc'
--- src/logic/playersmanager.cc	2016-08-04 15:49:05 +0000
+++ src/logic/playersmanager.cc	2016-10-28 17:51:15 +0000
@@ -22,7 +22,6 @@
 #include <cstring>
 
 #include "base/wexception.h"
-#include "logic/constants.h"
 #include "logic/editor_game_base.h"
 #include "logic/game_settings.h"
 #include "logic/player.h"
@@ -39,7 +38,7 @@
 }
 
 void PlayersManager::cleanup() {
-	const Player* const* const players_end = players_ + MAX_PLAYERS;
+	const Player* const* const players_end = players_ + kMaxPlayers;
 	for (Player** p = players_; p < players_end; ++p) {
 		delete *p;
 		*p = nullptr;
@@ -49,7 +48,7 @@
 
 void PlayersManager::remove_player(PlayerNumber plnum) {
 	assert(1 <= plnum);
-	assert(plnum <= MAX_PLAYERS);
+	assert(plnum <= kMaxPlayers);
 
 	Player*& p = players_[plnum - 1];
 	if (p) {
@@ -67,7 +66,7 @@
                                    const std::string& name,
                                    TeamNumber team) {
 	assert(1 <= player_number);
-	assert(player_number <= MAX_PLAYERS);
+	assert(player_number <= kMaxPlayers);
 
 	Player*& p = players_[player_number - 1];
 	if (p) {

=== modified file 'src/logic/playersmanager.h'
--- src/logic/playersmanager.h	2016-08-04 15:49:05 +0000
+++ src/logic/playersmanager.h	2016-10-28 17:51:15 +0000
@@ -23,7 +23,7 @@
 #include <string>
 #include <vector>
 
-#include "logic/constants.h"
+#include "graphic/playercolor.h"
 #include "logic/widelands.h"
 
 namespace Widelands {
@@ -76,12 +76,12 @@
 	                   TeamNumber team = 0);
 	Player* get_player(int32_t n) const {
 		assert(1 <= n);
-		assert(n <= MAX_PLAYERS);
+		assert(n <= kMaxPlayers);
 		return players_[n - 1];
 	}
 	Player& player(int32_t n) const {
 		assert(1 <= n);
-		assert(n <= MAX_PLAYERS);
+		assert(n <= kMaxPlayers);
 		return *players_[n - 1];
 	}
 
@@ -107,7 +107,7 @@
 	void set_player_end_status(const PlayerEndStatus& status);
 
 private:
-	Player* players_[MAX_PLAYERS];
+	Player* players_[kMaxPlayers];
 	EditorGameBase& egbase_;
 	uint8_t number_of_players_;
 	std::vector<PlayerEndStatus> players_end_status_;

=== modified file 'src/logic/widelands.h'
--- src/logic/widelands.h	2016-08-04 15:49:05 +0000
+++ src/logic/widelands.h	2016-10-28 17:51:15 +0000
@@ -33,7 +33,9 @@
 //  Type definitions for the game logic.
 using MilitaryInfluence = uint16_t;
 
-using PlayerNumber = uint8_t;  /// 5 bits used, so 0 .. 31
+/// 5 bits used, so 0 .. 31
+/// Data type must match kMaxPlayers in graphics/playercolor.h
+using PlayerNumber = uint8_t;
 inline PlayerNumber neutral() {
 	return 0;
 }

=== modified file 'src/logic/widelands_geometry.h'
--- src/logic/widelands_geometry.h	2016-08-04 15:49:05 +0000
+++ src/logic/widelands_geometry.h	2016-10-28 17:51:15 +0000
@@ -38,6 +38,7 @@
 /**
  * Structure used to store map coordinates
  */
+// TODO(sirver): This should go away and be replaced by Vector2i16.
 struct Coords {
 	Coords();
 	Coords(int16_t nx, int16_t ny);

=== modified file 'src/map_io/CMakeLists.txt'
--- src/map_io/CMakeLists.txt	2016-02-20 11:29:55 +0000
+++ src/map_io/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -96,6 +96,7 @@
     graphic
     graphic_image_io
     graphic_minimap_renderer
+    graphic_playercolor
     graphic_surface
     helper
     io_fileread

=== modified file 'src/map_io/map_elemental_packet.cc'
--- src/map_io/map_elemental_packet.cc	2016-08-04 15:49:05 +0000
+++ src/map_io/map_elemental_packet.cc	2016-10-28 17:51:15 +0000
@@ -30,7 +30,8 @@
 
 namespace Widelands {
 
-constexpr int32_t kCurrentPacketVersion = 1;
+constexpr int32_t kEightPlayersPacketVersion = 1;
+constexpr int32_t kSixteenPlayersPacketVersion = 2;
 
 void MapElementalPacket::pre_read(FileSystem& fs, Map* map) {
 	Profile prof;
@@ -39,7 +40,8 @@
 
 	try {
 		int32_t const packet_version = s.get_int("packet_version");
-		if (packet_version == kCurrentPacketVersion) {
+		if (packet_version >= kEightPlayersPacketVersion &&
+		    packet_version <= kSixteenPlayersPacketVersion) {
 			map->width_ = s.get_int("map_w");
 			map->height_ = s.get_int("map_h");
 			map->set_nrplayers(s.get_int("nr_players"));
@@ -85,7 +87,7 @@
 
 					for (const std::string& player : players_string) {
 						PlayerNumber player_number = static_cast<PlayerNumber>(atoi(player.c_str()));
-						assert(player_number < MAX_PLAYERS);
+						assert(player_number < kMaxPlayers);
 						team.push_back(player_number);
 					}
 
@@ -104,7 +106,8 @@
 				teamsection_key = (boost::format("teams%02i") % team_section_id).str().c_str();
 			}
 		} else
-			throw UnhandledVersionError("MapElementalPacket", packet_version, kCurrentPacketVersion);
+			throw UnhandledVersionError(
+			   "MapElementalPacket", packet_version, kEightPlayersPacketVersion);
 	} catch (const WException& e) {
 		throw GameDataError("elemental data: %s", e.what());
 	}
@@ -119,11 +122,17 @@
 	Profile prof;
 	Section& global_section = prof.create_section("global");
 
-	global_section.set_int("packet_version", kCurrentPacketVersion);
 	const Map& map = egbase.map();
+	Widelands::PlayerNumber nr_players = map.get_nrplayers();
+
+	// Maps with more than 8 players won't be compatible with older versions of Widelands.
+	// The packet format itself hasn't changed, so we always want to allow loading maps with <= 8
+	// players.
+	global_section.set_int("packet_version", nr_players <= 8 ? kEightPlayersPacketVersion :
+	                                                           kSixteenPlayersPacketVersion);
 	global_section.set_int("map_w", map.get_width());
 	global_section.set_int("map_h", map.get_height());
-	global_section.set_int("nr_players", map.get_nrplayers());
+	global_section.set_int("nr_players", nr_players);
 	global_section.set_string("name", map.get_name());
 	global_section.set_string("author", map.get_author());
 	global_section.set_string("descr", map.get_description());

=== modified file 'src/map_io/map_exploration_packet.cc'
--- src/map_io/map_exploration_packet.cc	2016-08-04 15:49:05 +0000
+++ src/map_io/map_exploration_packet.cc	2016-10-28 17:51:15 +0000
@@ -22,7 +22,6 @@
 #include "base/log.h"
 #include "io/fileread.h"
 #include "io/filewrite.h"
-#include "logic/constants.h"
 #include "logic/editor_game_base.h"
 #include "logic/game_data_error.h"
 #include "logic/map.h"
@@ -50,7 +49,7 @@
 		}
 	}
 
-	static_assert(MAX_PLAYERS < 32, "assert(MAX_PLAYERS < 32) failed.");
+	static_assert(kMaxPlayers < 32, "assert(MAX_PLAYERS < 32) failed.");
 	Map& map = egbase.map();
 	PlayerNumber const nr_players = map.get_nrplayers();
 	MapIndex const max_index = map.max_index();
@@ -82,7 +81,7 @@
 
 	fw.unsigned_16(kCurrentPacketVersion);
 
-	static_assert(MAX_PLAYERS < 32, "assert(MAX_PLAYERS < 32) failed.");
+	static_assert(kMaxPlayers < 32, "assert(MAX_PLAYERS < 32) failed.");
 	Map& map = egbase.map();
 	PlayerNumber const nr_players = map.get_nrplayers();
 	MapIndex const max_index = map.max_index();

=== modified file 'src/map_io/map_object_saver.h'
--- src/map_io/map_object_saver.h	2016-08-04 15:49:05 +0000
+++ src/map_io/map_object_saver.h	2016-10-28 17:51:15 +0000
@@ -23,7 +23,7 @@
 #include <map>
 #include <string>
 
-#include "logic/constants.h"
+#include "graphic/playercolor.h"
 #include "logic/widelands.h"
 #include "map_io/map_message_saver.h"
 
@@ -76,7 +76,7 @@
 	bool is_object_saved(const MapObject&);
 
 	/// \note Indexed by player number - 1.
-	MapMessageSaver message_savers[MAX_PLAYERS];
+	MapMessageSaver message_savers[kMaxPlayers];
 
 private:
 	struct MapObjectRec {

=== modified file 'src/map_io/map_saver.cc'
--- src/map_io/map_saver.cc	2016-08-13 18:54:33 +0000
+++ src/map_io/map_saver.cc	2016-10-28 17:51:15 +0000
@@ -296,11 +296,12 @@
 
 	// Write minimap
 	{
-		std::unique_ptr<Texture> minimap(
-		   draw_minimap(egbase_, nullptr, Point(0, 0), MiniMapLayer::Terrain));
+		std::unique_ptr<Texture> minimap(draw_minimap(
+		   egbase_, nullptr, Rectf(), MiniMapType::kStaticMap, MiniMapLayer::Terrain));
 		FileWrite fw;
 		save_to_png(minimap.get(), &fw, ColorType::RGBA);
 		fw.write(fs_, "minimap.png");
 	}
 }
-}
+
+}  // namespace Widelands

=== modified file 'src/network/CMakeLists.txt'
--- src/network/CMakeLists.txt	2016-02-06 11:11:24 +0000
+++ src/network/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -31,6 +31,7 @@
     build_info
     chat
     game_io
+    graphic_playercolor
     helper
     io_fileread
     io_filesystem

=== modified file 'src/network/network_player_settings_backend.h'
--- src/network/network_player_settings_backend.h	2016-08-04 15:49:05 +0000
+++ src/network/network_player_settings_backend.h	2016-10-28 17:51:15 +0000
@@ -20,13 +20,13 @@
 #ifndef WL_NETWORK_NETWORK_PLAYER_SETTINGS_BACKEND_H
 #define WL_NETWORK_NETWORK_PLAYER_SETTINGS_BACKEND_H
 
-#include "logic/constants.h"
+#include "graphic/playercolor.h"
 #include "logic/game_settings.h"
 
 struct NetworkPlayerSettingsBackend {
 
 	NetworkPlayerSettingsBackend(GameSettingsProvider* const settings) : s(settings) {
-		for (uint8_t i = 0; i < MAX_PLAYERS; ++i)
+		for (uint8_t i = 0; i < kMaxPlayers; ++i)
 			shared_in_tribe[i] = std::string();
 	}
 
@@ -37,7 +37,7 @@
 	void refresh(uint8_t id);
 
 	GameSettingsProvider* const s;
-	std::string shared_in_tribe[MAX_PLAYERS];
+	std::string shared_in_tribe[kMaxPlayers];
 };
 
 #endif  // end of include guard: WL_NETWORK_NETWORK_PLAYER_SETTINGS_BACKEND_H

=== modified file 'src/notifications/note_ids.h'
--- src/notifications/note_ids.h	2016-03-03 21:46:11 +0000
+++ src/notifications/note_ids.h	2016-10-28 17:51:15 +0000
@@ -35,6 +35,7 @@
 	ProductionSiteOutOfResources,
 	TrainingSiteSoldierTrained,
 	ShipMessage,
+	ShipWindow,
 	GraphicResolutionChanged,
 	NoteExpeditionCanceled
 };

=== modified file 'src/profile/profile.cc'
--- src/profile/profile.cc	2016-08-13 20:01:13 +0000
+++ src/profile/profile.cc	2016-10-28 17:51:15 +0000
@@ -137,14 +137,14 @@
 	throw wexception("%s: '%s' is not a boolean value", get_name(), get_string());
 }
 
-Point Section::Value::get_point() const {
+Vector2i Section::Value::get_point() const {
 	char* endp = value_.get();
 	long int const x = strtol(endp, &endp, 0);
 	long int const y = strtol(endp, &endp, 0);
 	if (*endp)
-		throw wexception("%s: '%s' is not a Point", get_name(), get_string());
+		throw wexception("%s: '%s' is not a Vector2i", get_name(), get_string());
 
-	return Point(x, y);
+	return Vector2i(x, y);
 }
 
 void Section::Value::set_string(char const* const value) {
@@ -413,7 +413,7 @@
 	return v ? v->get_string() : def;
 }
 
-Point Section::get_point(const char* const name, const Point def) {
+Vector2i Section::get_point(const char* const name, const Vector2i def) {
 	Value const* const v = get_val(name);
 	return v ? v->get_point() : def;
 }

=== modified file 'src/profile/profile.h'
--- src/profile/profile.h	2016-08-04 15:49:05 +0000
+++ src/profile/profile.h	2016-10-28 17:51:15 +0000
@@ -26,7 +26,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 #include "io/filesystem/layered_filesystem.h"
 // TODO(unknown): as soon as g_fs is not needed anymore,
 // include "filesystem.h" instead of layered_filesystem.h.
@@ -85,7 +85,7 @@
 		char* get_string() {
 			return value_.get();
 		}
-		Point get_point() const;
+		Vector2i get_point() const;
 
 		void set_string(char const*);
 
@@ -126,7 +126,7 @@
 	uint32_t get_positive(char const* name, uint32_t def = 1);
 	bool get_bool(char const* name, bool def = false);
 	const char* get_string(char const* name, char const* def = nullptr);
-	Point get_point(char const* name, Point def = Point(0, 0));
+	Vector2i get_point(char const* name, Vector2i def = Vector2i(0, 0));
 
 	int32_t get_safe_int(const char* name);
 	uint32_t get_safe_natural(char const* name);

=== modified file 'src/scripting/lua_bases.cc'
--- src/scripting/lua_bases.cc	2016-08-04 15:49:05 +0000
+++ src/scripting/lua_bases.cc	2016-10-28 17:51:15 +0000
@@ -22,7 +22,6 @@
 #include <boost/format.hpp>
 
 #include "economy/economy.h"
-#include "logic/constants.h"
 #include "logic/map_objects/checkstep.h"
 #include "logic/map_objects/tribes/tribe_descr.h"
 #include "logic/map_objects/tribes/tribes.h"
@@ -132,7 +131,7 @@
 	lua_newtable(L);
 
 	uint32_t idx = 1;
-	for (PlayerNumber i = 1; i <= MAX_PLAYERS; i++) {
+	for (PlayerNumber i = 1; i <= kMaxPlayers; i++) {
 		Player* rv = egbase.get_player(i);
 		if (!rv)
 			continue;
@@ -695,7 +694,7 @@
  ==========================================================
  */
 Player& LuaPlayerBase::get(lua_State* L, Widelands::EditorGameBase& egbase) {
-	if (player_number_ > MAX_PLAYERS)
+	if (player_number_ > kMaxPlayers)
 		report_error(L, "Illegal player number %i", player_number_);
 	Player* rv = egbase.get_player(player_number_);
 	if (!rv)

=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc	2016-08-07 20:39:44 +0000
+++ src/scripting/lua_game.cc	2016-10-28 17:51:15 +0000
@@ -26,7 +26,6 @@
 #include "economy/economy.h"
 #include "economy/flag.h"
 #include "logic/campaign_visibility.h"
-#include "logic/constants.h"
 #include "logic/game_controller.h"
 #include "logic/map_objects/tribes/tribe_descr.h"
 #include "logic/message.h"
@@ -448,7 +447,7 @@
 		lua_getfield(L, 4, "field");
 		if (!lua_isnil(L, -1)) {
 			Coords c = (*get_user_class<LuaField>(L, -1))->coords();
-			game.get_ipl()->move_view_to(c);
+			game.get_ipl()->center_view_on_coords(c);
 		}
 		lua_pop(L, 1);
 	}
@@ -1250,7 +1249,7 @@
  ==========================================================
  */
 Player& LuaMessage::get_plr(lua_State* L, Widelands::Game& game) {
-	if (player_number_ > MAX_PLAYERS)
+	if (player_number_ > kMaxPlayers)
 		report_error(L, "Illegal player number %i", player_number_);
 	Player* rv = game.get_player(player_number_);
 	if (!rv)

=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc	2016-09-07 09:30:49 +0000
+++ src/scripting/lua_map.cc	2016-10-28 17:51:15 +0000
@@ -4970,15 +4970,15 @@
       this field for the current interactive player
 */
 int LuaField::get_viewpoint_x(lua_State* L) {
-	int32_t px, py;
-	MapviewPixelFunctions::get_save_pix(get_egbase(L).map(), coords_, px, py);
-	lua_pushint32(L, px);
+	Vector2f point =
+	   MapviewPixelFunctions::to_map_pixel_with_normalization(get_egbase(L).map(), coords_);
+	lua_pushdouble(L, point.x);
 	return 1;
 }
 int LuaField::get_viewpoint_y(lua_State* L) {
-	int32_t px, py;
-	MapviewPixelFunctions::get_save_pix(get_egbase(L).map(), coords_, px, py);
-	lua_pushint32(L, py);
+	Vector2f point =
+	   MapviewPixelFunctions::to_map_pixel_with_normalization(get_egbase(L).map(), coords_);
+	lua_pushdouble(L, point.y);
 	return 1;
 }
 

=== modified file 'src/scripting/lua_ui.cc'
--- src/scripting/lua_ui.cc	2016-08-04 15:49:05 +0000
+++ src/scripting/lua_ui.cc	2016-10-28 17:51:15 +0000
@@ -192,7 +192,7 @@
 }
 int LuaPanel::set_mouse_position_x(lua_State* L) {
 	assert(panel_);
-	Point p = panel_->get_mouse_position();
+	Vector2i p = panel_->get_mouse_position();
 	p.x = floor(luaL_checkdouble(L, -1));
 	panel_->set_mouse_pos(p);
 	return 1;
@@ -204,7 +204,7 @@
 }
 int LuaPanel::set_mouse_position_y(lua_State* L) {
 	assert(panel_);
-	Point p = panel_->get_mouse_position();
+	Vector2i p = panel_->get_mouse_position();
 	p.y = floor(luaL_checkdouble(L, -1));
 	panel_->set_mouse_pos(p);
 	return 1;
@@ -244,27 +244,27 @@
 */
 int LuaPanel::get_position_x(lua_State* L) {
 	assert(panel_);
-	Point p = panel_->to_parent(Point(0, 0));
+	Vector2i p = panel_->to_parent(Vector2i(0, 0));
 
 	lua_pushint32(L, p.x);
 	return 1;
 }
 int LuaPanel::set_position_x(lua_State* L) {
 	assert(panel_);
-	Point p(luaL_checkint32(L, -1) - panel_->get_lborder(), panel_->get_y());
+	Vector2i p(luaL_checkint32(L, -1) - panel_->get_lborder(), panel_->get_y());
 	panel_->set_pos(p);
 	return 1;
 }
 int LuaPanel::get_position_y(lua_State* L) {
 	assert(panel_);
-	Point p = panel_->to_parent(Point(0, 0));
+	Vector2i p = panel_->to_parent(Vector2i(0, 0));
 
 	lua_pushint32(L, p.y);
 	return 1;
 }
 int LuaPanel::set_position_y(lua_State* L) {
 	assert(panel_);
-	Point p(panel_->get_x(), luaL_checkint32(L, -1) - panel_->get_tborder());
+	Vector2i p(panel_->get_x(), luaL_checkint32(L, -1) - panel_->get_tborder());
 	panel_->set_pos(p);
 	return 1;
 }
@@ -289,9 +289,9 @@
 
 	UI::Panel* cur = (*get_base_user_class<LuaPanel>(L, 2))->panel_;
 
-	Point cp = Point(0, 0);
+	Vector2i cp = Vector2i(0, 0);
 	while (cur && cur != panel_) {
-		cp += cur->to_parent(Point(0, 0));
+		cp += cur->to_parent(Vector2i(0, 0));
 		cur = cur->get_parent();
 	}
 
@@ -515,7 +515,7 @@
       to fields quickly.
 */
 int LuaMapView::get_viewpoint_x(lua_State* L) {
-	lua_pushuint32(L, get()->get_viewpoint().x);
+	lua_pushdouble(L, get()->get_viewpoint().x);
 	return 1;
 }
 int LuaMapView::set_viewpoint_x(lua_State* L) {
@@ -526,13 +526,13 @@
 	}
 
 	MapView* mv = get();
-	Point p = mv->get_viewpoint();
-	p.x = floor(luaL_checkdouble(L, -1));
+	Vector2f p = mv->get_viewpoint();
+	p.x = luaL_checkdouble(L, -1);
 	mv->set_viewpoint(p, true);
 	return 0;
 }
 int LuaMapView::get_viewpoint_y(lua_State* L) {
-	lua_pushuint32(L, get()->get_viewpoint().y);
+	lua_pushdouble(L, get()->get_viewpoint().y);
 	return 1;
 }
 int LuaMapView::set_viewpoint_y(lua_State* L) {
@@ -543,8 +543,8 @@
 	}
 
 	MapView* mv = get();
-	Point p = mv->get_viewpoint();
-	p.y = floor(luaL_checkdouble(L, -1));
+	Vector2f p = mv->get_viewpoint();
+	p.y = luaL_checkdouble(L, -1);
 	mv->set_viewpoint(p, true);
 	return 0;
 }

=== modified file 'src/sound/CMakeLists.txt'
--- src/sound/CMakeLists.txt	2015-11-01 10:11:56 +0000
+++ src/sound/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -21,4 +21,5 @@
     random
     wui
     wui_mapview_pixelfunctions
+    wui_mapview
 )

=== modified file 'src/sound/sound_handler.cc'
--- src/sound/sound_handler.cc	2016-08-04 15:49:05 +0000
+++ src/sound/sound_handler.cc	2016-10-28 17:51:15 +0000
@@ -310,27 +310,26 @@
 	// Viewpoint is the point of the map in pixel which is shown in the upper
 	// left corner of window or fullscreen
 	const InteractiveBase& ibase = *egbase_->get_ibase();
-	Point const vp = ibase.get_viewpoint();
+	Vector2f const vp = ibase.get_viewpoint();
 
 	// Resolution of window or fullscreen
 	int32_t const xres = g_gr->get_xres();
 	int32_t const yres = g_gr->get_yres();
 
 	// Get pixel coordinates of sound source from map coordinates
-	Point position_pix;
-	MapviewPixelFunctions::get_pix(egbase_->map(), position_map, position_pix.x, position_pix.y);
+	Vector2f position_pix = MapviewPixelFunctions::to_map_pixel(egbase_->map(), position_map);
 
 	// Adjust pixel coordinates to viewpoint
 	position_pix.x -= vp.x;
 	position_pix.y -= vp.y;
 	// Normalizing correct invalid pixel coordinates
-	MapviewPixelFunctions::normalize_pix(egbase_->map(), position_pix);
+	MapviewPixelFunctions::normalize_pix(egbase_->map(), &position_pix);
 
 	// Make sure position is inside viewport
 	if (position_pix.x >= 0 && position_pix.x <= xres && position_pix.y >= 0 &&
-	    position_pix.y <= yres)
+	    position_pix.y <= yres) {
 		return position_pix.x * 254 / xres;
-
+	}
 	return -1;
 }
 

=== modified file 'src/ui_basic/box.cc'
--- src/ui_basic/box.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/box.cc	2016-10-28 17:51:15 +0000
@@ -169,7 +169,7 @@
 			scrollbar_.reset(new Scrollbar(this, sb_x, sb_y, sb_w, sb_h, orientation_ == Horizontal));
 			scrollbar_->moved.connect(boost::bind(&Box::scrollbar_moved, this, _1));
 		} else {
-			scrollbar_->set_pos(Point(sb_x, sb_y));
+			scrollbar_->set_pos(Vector2i(sb_x, sb_y));
 			scrollbar_->set_size(sb_w, sb_h);
 		}
 		scrollbar_->set_steps(totaldepth - pagesize);
@@ -379,9 +379,9 @@
 		}
 
 		if (orientation_ == Horizontal)
-			it.u.panel.panel->set_pos(Point(pos, breadth));
+			it.u.panel.panel->set_pos(Vector2i(pos, breadth));
 		else
-			it.u.panel.panel->set_pos(Point(breadth, pos));
+			it.u.panel.panel->set_pos(Vector2i(breadth, pos));
 		break;
 	}
 

=== modified file 'src/ui_basic/button.cc'
--- src/ui_basic/button.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/button.cc	2016-10-28 17:51:15 +0000
@@ -43,17 +43,14 @@
     const Image* bg_pic,
     const std::string& title_text,
     const std::string& tooltip_text,
-    bool const init_enabled,
-    bool const flat)
+    UI::Button::Style init_style)
    : NamedPanel(parent, name, x, y, w, h, tooltip_text),
      highlighted_(false),
      pressed_(false),
-     permpressed_(false),
-     enabled_(init_enabled),
+     enabled_(true),
+     style_(init_style),
      repeating_(false),
-     flat_(flat),
-     keep_image_size_(false),
-     draw_flat_background_(false),
+     image_mode_(UI::Button::ImageMode::kShrink),
      time_nextact_(0),
      title_(title_text),
      pic_background_(bg_pic),
@@ -80,18 +77,15 @@
     const Image* bg_pic,
     const Image* fg_pic,
     const std::string& tooltip_text,
-    bool const init_enabled,
-    bool const flat,
-    const bool keep_image_size)
+    UI::Button::Style init_style,
+    ImageMode mode)
    : NamedPanel(parent, name, x, y, w, h, tooltip_text),
      highlighted_(false),
      pressed_(false),
-     permpressed_(false),
-     enabled_(init_enabled),
+     enabled_(true),
+     style_(init_style),
      repeating_(false),
-     flat_(flat),
-     keep_image_size_(keep_image_size),
-     draw_flat_background_(false),
+     image_mode_(mode),
      time_nextact_(0),
      pic_background_(bg_pic),
      pic_custom_(fg_pic),
@@ -152,50 +146,47 @@
 */
 void Button::draw(RenderTarget& dst) {
 	// Draw the background
-	if (!flat_ || draw_flat_background_) {
-		assert(pic_background_);
-		dst.fill_rect(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 255));
-		dst.tile(Rect(Point(0, 0), get_w(), get_h()), pic_background_, Point(get_x(), get_y()));
+	if (pic_background_) {
+		dst.fill_rect(Rectf(0.f, 0.f, get_w(), get_h()), RGBAColor(0, 0, 0, 255));
+		dst.tile(Recti(Vector2i(0, 0), get_w(), get_h()), pic_background_, Vector2i(get_x(), get_y()));
 	}
 
-	if (enabled_ && highlighted_ && !flat_)
-		dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
+	if (enabled_ && highlighted_ && style_ != Style::kFlat)
+		dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
 
 	//  If we've got a picture, draw it centered
 	if (pic_custom_) {
-		if (keep_image_size_) {
+		if (image_mode_ == UI::Button::ImageMode::kUnscaled) {
 			if (enabled_) {
-				//  ">> 1" is almost like "/ 2", but simpler for signed types (difference
-				//  is that -1 >> 1 is -1 but -1 / 2 is 0).
-				dst.blit(Point((get_w() - static_cast<int32_t>(pic_custom_->width())) >> 1,
-				               (get_h() - static_cast<int32_t>(pic_custom_->height())) >> 1),
+				dst.blit(Vector2f((get_w() - static_cast<int32_t>(pic_custom_->width())) / 2.f,
+				                  (get_h() - static_cast<int32_t>(pic_custom_->height())) / 2.f),
 				         pic_custom_);
 			} else {
-				//  ">> 1" is almost like "/ 2", but simpler for signed types (difference
-				//  is that -1 >> 1 is -1 but -1 / 2 is 0).
-				dst.blit_monochrome(Point((get_w() - static_cast<int32_t>(pic_custom_->width())) >> 1,
-				                          (get_h() - static_cast<int32_t>(pic_custom_->height())) >> 1),
-				                    pic_custom_, RGBAColor(255, 255, 255, 127));
+				dst.blit_monochrome(
+				   Vector2f((get_w() - static_cast<int32_t>(pic_custom_->width())) / 2.f,
+				            (get_h() - static_cast<int32_t>(pic_custom_->height())) / 2.f),
+				   pic_custom_, RGBAColor(255, 255, 255, 127));
 			}
 		} else {
 			const int max_image_w = get_w() - 2 * kButtonImageMargin;
 			const int max_image_h = get_h() - 2 * kButtonImageMargin;
-			double image_scale =
-			   std::min(1., std::min(static_cast<double>(max_image_w) / pic_custom_->width(),
-			                         static_cast<double>(max_image_h) / pic_custom_->height()));
+			const float image_scale =
+			   std::min(1.f, std::min(static_cast<float>(max_image_w) / pic_custom_->width(),
+			                          static_cast<float>(max_image_h) / pic_custom_->height()));
 			int blit_width = image_scale * pic_custom_->width();
 			int blit_height = image_scale * pic_custom_->height();
 
 			if (enabled_) {
-				dst.blitrect_scale(Rect((get_w() - blit_width) / 2, (get_h() - blit_height) / 2,
-				                        blit_width, blit_height),
-				                   pic_custom_, Rect(0, 0, pic_custom_->width(), pic_custom_->height()),
-				                   1., BlendMode::UseAlpha);
+				dst.blitrect_scale(Rectf((get_w() - blit_width) / 2.f, (get_h() - blit_height) / 2.f,
+				                         blit_width, blit_height),
+				                   pic_custom_,
+				                   Recti(0, 0, pic_custom_->width(), pic_custom_->height()), 1.,
+				                   BlendMode::UseAlpha);
 			} else {
 				dst.blitrect_scale_monochrome(
-				   Rect(
-				      (get_w() - blit_width) / 2, (get_h() - blit_height) / 2, blit_width, blit_height),
-				   pic_custom_, Rect(0, 0, pic_custom_->width(), pic_custom_->height()),
+				   Rectf((get_w() - blit_width) / 2.f, (get_h() - blit_height) / 2.f, blit_width,
+				         blit_height),
+				   pic_custom_, Recti(0, 0, pic_custom_->width(), pic_custom_->height()),
 				   RGBAColor(255, 255, 255, 127));
 			}
 		}
@@ -205,10 +196,10 @@
 		const Image* entry_text_im =
 		   autofit_ui_text(title_, get_inner_w() - 2 * kButtonImageMargin,
 		                   enabled_ ? UI_FONT_CLR_FG : UI_FONT_CLR_DISABLED);
-
+		// Blit on pixel boundary (not float), so that the text is blitted pixel perfect.
 		dst.blit(
-		   Point((get_w() - entry_text_im->width()) / 2, (get_h() - entry_text_im->height()) / 2),
-		   entry_text_im);
+			Vector2f((get_w() - entry_text_im->width()) / 2, (get_h() - entry_text_im->height()) / 2),
+			entry_text_im);
 	}
 
 	//  draw border
@@ -217,45 +208,42 @@
 	//  stays pressed when it is pressed once
 	RGBAColor black(0, 0, 0, 255);
 
-	// permpressed_ is true, we invert the behaviour on pressed_
-	bool draw_pressed = permpressed_ ? !(pressed_ && highlighted_) : (pressed_ && highlighted_);
-
-	if (!flat_) {
+	if (style_ != Style::kFlat) {
 		assert(2 <= get_w());
 		assert(2 <= get_h());
-		//  button is a normal one, not flat
-		if (!draw_pressed) {
+		//  Button is a normal one, not flat. We invert the behaviour for kPermpressed.
+		if ((style_ == Style::kPermpressed) == (pressed_ && highlighted_)) {
 			//  top edge
-			dst.brighten_rect(Rect(Point(0, 0), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			dst.brighten_rect(Rectf(0.f, 0.f, get_w(), 2.f), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  left edge
-			dst.brighten_rect(Rect(Point(0, 2), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			dst.brighten_rect(Rectf(0, 2, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  bottom edge
-			dst.fill_rect(Rect(Point(2, get_h() - 2), get_w() - 2, 1), black);
-			dst.fill_rect(Rect(Point(1, get_h() - 1), get_w() - 1, 1), black);
+			dst.fill_rect(Rectf(2, get_h() - 2, get_w() - 2, 1), black);
+			dst.fill_rect(Rectf(1, get_h() - 1, get_w() - 1, 1), black);
 			//  right edge
-			dst.fill_rect(Rect(Point(get_w() - 2, 2), 1, get_h() - 2), black);
-			dst.fill_rect(Rect(Point(get_w() - 1, 1), 1, get_h() - 1), black);
+			dst.fill_rect(Rectf(get_w() - 2, 2, 1, get_h() - 2), black);
+			dst.fill_rect(Rectf(get_w() - 1, 1, 1, get_h() - 1), black);
 		} else {
 			//  bottom edge
-			dst.brighten_rect(Rect(Point(0, get_h() - 2), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			dst.brighten_rect(Rectf(0, get_h() - 2, get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  right edge
-			dst.brighten_rect(Rect(Point(get_w() - 2, 0), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			dst.brighten_rect(Rectf(get_w() - 2, 0, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 			//  top edge
-			dst.fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
-			dst.fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
+			dst.fill_rect(Rectf(0, 0, get_w() - 1, 1), black);
+			dst.fill_rect(Rectf(0, 1, get_w() - 2, 1), black);
 			//  left edge
-			dst.fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
-			dst.fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
+			dst.fill_rect(Rectf(0, 0, 1, get_h() - 1), black);
+			dst.fill_rect(Rectf(1, 0, 1, get_h() - 2), black);
 		}
 	} else {
 		//  Button is flat, do not draw borders, instead, if it is pressed, draw
 		//  a box around it.
 		if (enabled_ && highlighted_) {
 			RGBAColor shade(100, 100, 100, 80);
-			dst.fill_rect(Rect(Point(0, 0), get_w(), 2), shade);
-			dst.fill_rect(Rect(Point(0, 2), 2, get_h() - 2), shade);
-			dst.fill_rect(Rect(Point(0, get_h() - 2), get_w(), get_h()), shade);
-			dst.fill_rect(Rect(Point(get_w() - 2, 0), get_w(), get_h()), shade);
+			dst.fill_rect(Rectf(0, 0, get_w(), 2), shade);
+			dst.fill_rect(Rectf(0, 2, 2, get_h() - 2), shade);
+			dst.fill_rect(Rectf(0, get_h() - 2, get_w(), get_h()), shade);
+			dst.fill_rect(Rectf(get_w() - 2, 0, get_w(), get_h()), shade);
 		}
 	}
 }
@@ -340,17 +328,23 @@
 	return true;  // We handle this always by lighting up
 }
 
-void Button::set_perm_pressed(bool state) {
-	if (state != permpressed_) {
-		permpressed_ = state;
+void Button::set_style(UI::Button::Style input_style) {
+	style_ = input_style;
+}
+
+void Button::set_perm_pressed(bool pressed) {
+	set_style(pressed ? UI::Button::Style::kPermpressed : UI::Button::Style::kRaised);
+}
+
+void Button::toggle() {
+	switch (style_) {
+	case UI::Button::Style::kRaised:
+		style_ = UI::Button::Style::kPermpressed;
+		break;
+	case UI::Button::Style::kPermpressed:
+		style_ = UI::Button::Style::kRaised;
+		break;
+	default:;  // Do nothing for flat buttons
 	}
 }
-
-void Button::set_flat(bool flat) {
-	flat_ = flat;
-}
-
-void Button::set_draw_flat_background(bool set) {
-	draw_flat_background_ = set;
-}
 }

=== modified file 'src/ui_basic/button.h'
--- src/ui_basic/button.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/button.h	2016-10-28 17:51:15 +0000
@@ -36,6 +36,17 @@
 /// This is all that is needed in most cases, but if there is a need to give a
 /// callback function to the button, there are some templates for that below.
 struct Button : public NamedPanel {
+	enum class Style {
+		kRaised,       // Normal raised Button
+		kPermpressed,  // Button will appear pressed
+		kFlat         // Flat button with simple coloured outline
+	};
+
+	enum class ImageMode {
+		kShrink,   // Shrink foreground image to fit into the button
+		kUnscaled  // Show the foreground image without any scaling
+	};
+
 	Button  /// for textual buttons
 	   (Panel* const parent,
 	    const std::string& name,
@@ -46,9 +57,8 @@
 	    const Image* background_picture_id,
 	    const std::string& title_text,
 	    const std::string& tooltip_text = std::string(),
-	    bool const enabled = true,
-	    bool const flat = false);
-	// TODO(GunChleoc): We have a lot of bools here. Introduce an enum class.
+	    UI::Button::Style init_style = UI::Button::Style::kRaised);
+
 	Button  /// for pictorial buttons
 	   (Panel* const parent,
 	    const std::string& name,
@@ -59,9 +69,8 @@
 	    const Image* background_picture_id,
 	    const Image* foreground_picture_id,
 	    const std::string& tooltip_text = std::string(),
-	    bool const enabled = true,
-	    bool const flat = false,
-	    bool const keep_image_size = false);
+	    UI::Button::Style init_style = UI::Button::Style::kRaised,
+	    UI::Button::ImageMode mode = UI::Button::ImageMode::kShrink);
 	~Button();
 
 	void set_pic(const Image* pic);
@@ -90,16 +99,18 @@
 	bool handle_mouserelease(uint8_t btn, int32_t x, int32_t y) override;
 	bool handle_mousemove(uint8_t, int32_t, int32_t, int32_t, int32_t) override;
 
-	// Set the permanently pressed state of the button
-	void set_perm_pressed(bool state);
-	bool get_perm_pressed() const {
-		return permpressed_;
+	/// Sets the visual style of the button
+	void set_style(UI::Button::Style input_style);
+	UI::Button::Style style() const {
+		return style_;
 	}
 
-	// Set button to flat / not flat
-	void set_flat(bool flat);
-	// If no background is drawn, the button is drawn over the current background
-	void set_draw_flat_background(bool set);
+	/// Convenience function. If 'pressed', sets the style to kPermpressed, otherwise to kRaised.
+	void set_perm_pressed(bool pressed);
+
+
+	/// Convenience function. Toggles between raised and permpressed style
+	void toggle();
 
 	boost::signals2::signal<void()> sigclicked;
 	boost::signals2::signal<void()> sigmousein;
@@ -111,12 +122,10 @@
 
 	bool highlighted_;  //  mouse is over the button
 	bool pressed_;      //  mouse is clicked over the button
-	bool permpressed_;  //  button should appear  pressed
 	bool enabled_;
+	UI::Button::Style style_;
 	bool repeating_;
-	bool flat_;
-	bool keep_image_size_;  // Keep image's original size and center it
-	bool draw_flat_background_;
+	const UI::Button::ImageMode image_mode_;
 
 	uint32_t time_nextact_;
 

=== modified file 'src/ui_basic/checkbox.cc'
--- src/ui_basic/checkbox.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/checkbox.cc	2016-10-28 17:51:15 +0000
@@ -33,7 +33,7 @@
  * checkbox graphics.
 */
 Statebox::Statebox(Panel* const parent,
-                   Point const p,
+                   Vector2i const p,
                    const Image* pic,
                    const std::string& tooltip_text)
    : Panel(parent, p.x, p.y, kStateboxSize, kStateboxSize, tooltip_text),
@@ -49,7 +49,7 @@
 }
 
 Statebox::Statebox(Panel* const parent,
-                   Point const p,
+                   Vector2i const p,
                    const std::string& label_text,
                    const std::string& tooltip_text,
                    uint32_t width)
@@ -113,18 +113,18 @@
 		const uint16_t w = pic_graphics_->width();
 		const uint16_t h = pic_graphics_->height();
 
-		dst.blit(Point((get_inner_w() - w) / 2, (get_inner_h() - h) / 2), pic_graphics_);
+		dst.blit(Vector2f((get_inner_w() - w) / 2., (get_inner_h() - h) / 2.), pic_graphics_);
 
 		if (flags_ & Is_Checked) {
-			dst.draw_rect(Rect(Point(0, 0), get_w(), get_h()), RGBColor(229, 116, 2));
+			dst.draw_rect(Rectf(0.f, 0.f, get_w(), get_h()), RGBColor(229, 116, 2));
 		} else if (flags_ & Is_Highlighted) {
-			dst.draw_rect(Rect(Point(0, 0), get_w(), get_h()), RGBColor(100, 100, 80));
+			dst.draw_rect(Rectf(0.f, 0.f, get_w(), get_h()), RGBColor(100, 100, 80));
 		}
 	} else {
 		static_assert(0 <= kStateboxSize, "assert(0 <= STATEBOX_WIDTH) failed.");
 		static_assert(0 <= kStateboxSize, "assert(0 <= STATEBOX_HEIGHT) failed.");
-		Point image_anchor(0, 0);
-		Point text_anchor(kStateboxSize + kPadding, 0);
+		Vector2f image_anchor(0.f, 0.f);
+		Vector2f text_anchor(kStateboxSize + kPadding, 0);
 
 		if (rendered_text_) {
 			if (UI::g_fh1->fontset()->is_rtl()) {
@@ -137,11 +137,11 @@
 
 		dst.blitrect(
 		   image_anchor, pic_graphics_,
-		   Rect(Point(flags_ & Is_Checked ? kStateboxSize : 0, 0), kStateboxSize, kStateboxSize));
+		   Recti(Vector2i(flags_ & Is_Checked ? kStateboxSize : 0, 0), kStateboxSize, kStateboxSize));
 
 		if (flags_ & Is_Highlighted)
 			dst.draw_rect(
-			   Rect(image_anchor, kStateboxSize + 1, kStateboxSize + 1), RGBColor(100, 100, 80));
+			   Rectf(image_anchor, kStateboxSize + 1, kStateboxSize + 1), RGBColor(100, 100, 80));
 	}
 }
 

=== modified file 'src/ui_basic/checkbox.h'
--- src/ui_basic/checkbox.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/checkbox.h	2016-10-28 17:51:15 +0000
@@ -39,7 +39,7 @@
 	 * Pictorial Statebox
 	 */
 	Statebox(Panel* parent,
-	         Point,
+	         Vector2i,
 	         const Image* pic,
 	         const std::string& tooltip_text = std::string());
 
@@ -49,7 +49,7 @@
 	 * Otherwise, it will take up multiple lines if necessary (automatic height).
 	 */
 	Statebox(Panel* parent,
-	         Point,
+	         Vector2i,
 	         const std::string& label_text,
 	         const std::string& tooltip_text = std::string(),
 	         uint32_t width = 0);
@@ -111,7 +111,7 @@
 	 * Pictorial Checkbox
 	 */
 	Checkbox(Panel* const parent,
-	         Point const p,
+	         Vector2i const p,
 	         const Image* pic,
 	         const std::string& tooltip_text = std::string())
 	   : Statebox(parent, p, pic, tooltip_text) {
@@ -123,7 +123,7 @@
 	 * Otherwise, it will take up multiple lines if necessary (automatic height).
 	 */
 	Checkbox(Panel* const parent,
-	         Point const p,
+	         Vector2i const p,
 	         const std::string& label_text,
 	         const std::string& tooltip_text = std::string(),
 	         uint32_t width = 0)

=== modified file 'src/ui_basic/editbox.cc'
--- src/ui_basic/editbox.cc	2016-08-07 08:18:51 +0000
+++ src/ui_basic/editbox.cc	2016-10-28 17:51:15 +0000
@@ -359,26 +359,26 @@
 	RenderTarget& dst = odst;
 
 	// Draw the background
-	dst.tile(Rect(Point(0, 0), get_w(), get_h()), m_->background, Point(get_x(), get_y()));
+	dst.tile(Recti(0, 0, get_w(), get_h()), m_->background, Vector2i(get_x(), get_y()));
 
 	// Draw border.
 	if (get_w() >= 2 && get_h() >= 2) {
 		static const RGBColor black(0, 0, 0);
 
 		// bottom edge
-		dst.brighten_rect(Rect(Point(0, get_h() - 2), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0, get_h() - 2, get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// right edge
-		dst.brighten_rect(Rect(Point(get_w() - 2, 0), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(get_w() - 2, 0, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// top edge
-		dst.fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
-		dst.fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
+		dst.fill_rect(Rectf(0.f, 0.f, get_w() - 1, 1), black);
+		dst.fill_rect(Rectf(0.f, 1.f, get_w() - 2, 1), black);
 		// left edge
-		dst.fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
-		dst.fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
+		dst.fill_rect(Rectf(0.f, 0.f, 1, get_h() - 1), black);
+		dst.fill_rect(Rectf(1.f, 0.f, 1, get_h() - 2), black);
 	}
 
 	if (has_focus()) {
-		dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
 	}
 
 	const int max_width = get_w() - 2 * kMarginX;
@@ -393,7 +393,7 @@
 	         ->height() :
 	      entry_text_im->height();
 
-	Point point(kMarginX, get_h() / 2);
+	Vector2f point(kMarginX, get_h() / 2.f);
 
 	if (static_cast<int>(m_->align & UI::Align::kRight)) {
 		point.x += max_width;
@@ -405,23 +405,23 @@
 	if (max_width < linewidth) {
 		// Fix positioning for BiDi languages.
 		if (UI::g_fh1->fontset()->is_rtl()) {
-			point.x = 0;
+			point.x = 0.f;
 		}
 		// We want this always on, e.g. for mixed language savegame filenames
 		if (i18n::has_rtl_character(m_->text.c_str(), 100)) {  // Restrict check for efficiency
 			// TODO(GunChleoc): Arabic: Fix scrolloffset
-			dst.blitrect(point, entry_text_im, Rect(linewidth - max_width, 0, linewidth, lineheight));
+			dst.blitrect(point, entry_text_im, Recti(linewidth - max_width, 0, linewidth, lineheight));
 		} else {
 			if (static_cast<int>(m_->align & UI::Align::kRight)) {
 				// TODO(GunChleoc): Arabic: Fix scrolloffset
 				dst.blitrect(point, entry_text_im,
-				             Rect(point.x + m_->scrolloffset + kMarginX, 0, max_width, lineheight));
+				             Recti(point.x + m_->scrolloffset + kMarginX, 0, max_width, lineheight));
 			} else {
-				dst.blitrect(point, entry_text_im, Rect(-m_->scrolloffset, 0, max_width, lineheight));
+				dst.blitrect(point, entry_text_im, Recti(-m_->scrolloffset, 0, max_width, lineheight));
 			}
 		}
 	} else {
-		dst.blitrect(point, entry_text_im, Rect(0, 0, max_width, lineheight));
+		dst.blitrect(point, entry_text_im, Recti(0, 0, max_width, lineheight));
 	}
 
 	if (has_focus()) {
@@ -433,9 +433,9 @@
 		const uint16_t fontheight = text_height(m_->text, m_->fontsize);
 
 		const Image* caret_image = g_gr->images().get("images/ui_basic/caret.png");
-		Point caretpt;
+		Vector2f caretpt;
 		caretpt.x = point.x + m_->scrolloffset + caret_x - caret_image->width() + LINE_MARGIN;
-		caretpt.y = point.y + (fontheight - caret_image->height()) / 2;
+		caretpt.y = point.y + (fontheight - caret_image->height()) / 2.f;
 		dst.blit(caretpt, caret_image);
 	}
 }

=== modified file 'src/ui_basic/icon.cc'
--- src/ui_basic/icon.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/icon.cc	2016-10-28 17:51:15 +0000
@@ -52,19 +52,18 @@
 
 void Icon::draw(RenderTarget& dst) {
 	if (pic_) {
-		double scale = std::min(static_cast<double>(get_w()) / pic_->width(),
-		                        static_cast<double>(get_h()) / pic_->height());
-		scale = std::min(1., scale);
+		const float scale = std::min(1.f, std::min(static_cast<float>(get_w()) / pic_->width(),
+		                                           static_cast<float>(get_h()) / pic_->height()));
 
-		int width = scale * get_w();
-		int height = scale * get_h();
-		int x = (get_w() - width) / 2;
-		int y = (get_h() - height) / 2;
-		dst.blitrect_scale(Rect(x, y, width, height), pic_, Rect(0, 0, pic_->width(), pic_->height()),
-		                   1., BlendMode::UseAlpha);
+		const float width = scale * get_w();
+		const float height = scale * get_h();
+		const float x = (get_w() - width) / 2.f;
+		const float y = (get_h() - height) / 2.f;
+		dst.blitrect_scale(Rectf(x, y, width, height), pic_,
+		                   Recti(0, 0, pic_->width(), pic_->height()), 1., BlendMode::UseAlpha);
 	}
 	if (draw_frame_) {
-		dst.draw_rect(Rect(0, 0, get_w(), get_h()), framecolor_);
+		dst.draw_rect(Rectf(0.f, 0.f, get_w(), get_h()), framecolor_);
 	}
 }
 }

=== modified file 'src/ui_basic/icongrid.cc'
--- src/ui_basic/icongrid.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/icongrid.cc	2016-10-28 17:51:15 +0000
@@ -43,8 +43,7 @@
 	            background_picture_id,
 	            foreground_picture_id,
 	            tooltip_text,
-	            true,
-	            true),
+	            UI::Button::Style::kFlat),
 	     icongrid_(parent),
 	     callback_argument_id_(callback_argument_id) {
 	}

=== modified file 'src/ui_basic/listselect.cc'
--- src/ui_basic/listselect.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/listselect.cc	2016-10-28 17:51:15 +0000
@@ -309,9 +309,9 @@
 	// draw text lines
 	const uint32_t lineheight = get_lineheight();
 	uint32_t idx = scrollpos_ / lineheight;
-	int32_t y = 1 + idx * lineheight - scrollpos_;
+	float y = 1 + idx * lineheight - scrollpos_;
 
-	dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), ms_darken_value);
+	dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), ms_darken_value);
 
 	while (idx < entry_records_.size()) {
 		assert(get_h() < std::numeric_limits<int32_t>::max());
@@ -321,12 +321,12 @@
 
 		const EntryRecord& er = *entry_records_[idx];
 
-		Point point(1, y);
+		Vector2f point(1.f, y);
 		uint32_t maxw = get_eff_w() - 2;
 
 		// Highlight the current selected entry
 		if (idx == selection_) {
-			Rect r = Rect(point, maxw, lineheight_);
+			Rectf r(point, maxw, lineheight_);
 			if (r.x < 0) {
 				r.w += r.x;
 				r.x = 0;
@@ -346,8 +346,8 @@
 
 		// Now draw pictures
 		if (er.pic) {
-			dst.blit(Point(UI::g_fh1->fontset()->is_rtl() ? get_eff_w() - er.pic->width() - 1 : 1,
-			               y + (get_lineheight() - er.pic->height()) / 2),
+			dst.blit(Vector2f(UI::g_fh1->fontset()->is_rtl() ? get_eff_w() - er.pic->width() - 1 : 1,
+			                  y + (get_lineheight() - er.pic->height()) / 2.f),
 			         er.pic);
 		}
 
@@ -383,9 +383,9 @@
 			// We want this always on, e.g. for mixed language savegame filenames, or the languages
 			// list
 			dst.blitrect(point, entry_text_im,
-			             Rect(entry_text_im->width() - maxw + picw, 0, maxw, entry_text_im->height()));
+			             Recti(entry_text_im->width() - maxw + picw, 0, maxw, entry_text_im->height()));
 		} else {
-			dst.blitrect(point, entry_text_im, Rect(0, 0, maxw, entry_text_im->height()));
+			dst.blitrect(point, entry_text_im, Recti(0, 0, maxw, entry_text_im->height()));
 		}
 
 		y += lineheight;

=== modified file 'src/ui_basic/multilineeditbox.cc'
--- src/ui_basic/multilineeditbox.cc	2016-08-07 10:10:18 +0000
+++ src/ui_basic/multilineeditbox.cc	2016-10-28 17:51:15 +0000
@@ -424,32 +424,32 @@
  */
 void MultilineEditbox::draw(RenderTarget& dst) {
 	// Draw the background
-	dst.tile(Rect(Point(0, 0), get_w(), get_h()), d_->background, Point(get_x(), get_y()));
+	dst.tile(Recti(Vector2i(0, 0), get_w(), get_h()), d_->background, Vector2i(get_x(), get_y()));
 
 	// Draw border.
 	if (get_w() >= 4 && get_h() >= 4) {
 		static const RGBColor black(0, 0, 0);
 
 		// bottom edge
-		dst.brighten_rect(Rect(Point(0, get_h() - 2), get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0.f, get_h() - 2, get_w(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// right edge
-		dst.brighten_rect(Rect(Point(get_w() - 2, 0), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(get_w() - 2, 0, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// top edge
-		dst.fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
-		dst.fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
+		dst.fill_rect(Rectf(0, 0, get_w() - 1, 1), black);
+		dst.fill_rect(Rectf(0, 1, get_w() - 2, 1), black);
 		// left edge
-		dst.fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
-		dst.fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
+		dst.fill_rect(Rectf(0, 0, 1, get_h() - 1), black);
+		dst.fill_rect(Rectf(1, 0, 1, get_h() - 2), black);
 	}
 
 	if (has_focus())
-		dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0, 0, get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
 
 	d_->refresh_ww();
 
 	d_->ww.set_draw_caret(has_focus());
 
-	d_->ww.draw(dst, Point(0, -int32_t(d_->scrollbar.get_scrollpos())), UI::Align::kLeft,
+	d_->ww.draw(dst, Vector2i(0, -int32_t(d_->scrollbar.get_scrollpos())), UI::Align::kLeft,
 	            has_focus() ? d_->cursor_pos : std::numeric_limits<uint32_t>::max());
 }
 

=== modified file 'src/ui_basic/multilinetextarea.cc'
--- src/ui_basic/multilinetextarea.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/multilinetextarea.cc	2016-10-28 17:51:15 +0000
@@ -134,7 +134,7 @@
 	recompute();
 
 	// Take care of the scrollbar
-	scrollbar_.set_pos(Point(get_w() - Scrollbar::kSize, 0));
+	scrollbar_.set_pos(Vector2i(get_w() - Scrollbar::kSize, 0));
 	scrollbar_.set_size(Scrollbar::kSize, get_h());
 	scrollbar_.set_pagesize(get_h() - 2 * UI_FONT_SIZE_BIG);
 }
@@ -144,7 +144,7 @@
  */
 void MultilineTextarea::draw(RenderTarget& dst) {
 	if (use_old_renderer_) {
-		rt.draw(dst, Point(RICHTEXT_MARGIN, RICHTEXT_MARGIN - scrollbar_.get_scrollpos()));
+		rt.draw(dst, Vector2i(RICHTEXT_MARGIN, RICHTEXT_MARGIN - scrollbar_.get_scrollpos()));
 	} else {
 		const Image* text_im;
 		if (!is_richtext(text_)) {
@@ -157,11 +157,11 @@
 		uint32_t blit_height = std::min(text_im->height(), static_cast<int>(get_inner_h()));
 
 		if (blit_width > 0 && blit_height > 0) {
-			int32_t anchor = 0;
+			float anchor = 0.f;
 			Align alignment = mirror_alignment(align_);
 			switch (alignment & UI::Align::kHorizontal) {
 			case UI::Align::kHCenter:
-				anchor = (get_eff_w() - blit_width) / 2;
+				anchor = (get_eff_w() - blit_width) / 2.f;
 				break;
 			case UI::Align::kRight:
 				anchor = get_eff_w() - blit_width - RICHTEXT_MARGIN;
@@ -170,9 +170,9 @@
 				anchor = RICHTEXT_MARGIN;
 			}
 
-			dst.blitrect_scale(Rect(anchor, 0, blit_width, blit_height), text_im,
-			                   Rect(0, scrollbar_.get_scrollpos(), blit_width, blit_height), 1.,
-			                   BlendMode::UseAlpha);
+			dst.blitrect(Vector2f(anchor, 0), text_im,
+			             Recti(0, scrollbar_.get_scrollpos(), blit_width, blit_height),
+			             BlendMode::UseAlpha);
 		}
 	}
 }

=== modified file 'src/ui_basic/panel.cc'
--- src/ui_basic/panel.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/panel.cc	2016-10-28 17:51:15 +0000
@@ -190,9 +190,9 @@
 		if (start_time >= next_draw_time) {
 			RenderTarget& rt = *g_gr->get_render_target();
 			forefather->do_draw(rt);
-			rt.blit(app->get_mouse_position() - Point(3, 7), WLApplication::get()->is_mouse_pressed() ?
-			                                                    default_cursor_click_ :
-			                                                    default_cursor_);
+			rt.blit(
+			   (app->get_mouse_position() - Vector2i(3, 7)).cast<float>(),
+			   WLApplication::get()->is_mouse_pressed() ? default_cursor_click_ : default_cursor_);
 			forefather->do_tooltip();
 			g_gr->refresh();
 			next_draw_time = start_time + draw_delay;
@@ -252,7 +252,7 @@
 /**
  * Move the panel. Panel's position is relative to the parent.
  */
-void Panel::set_pos(const Point n) {
+void Panel::set_pos(const Vector2i n) {
 	x_ = n.x;
 	y_ = n.y;
 }
@@ -320,11 +320,11 @@
  * and translate it into the interior coordinate system of the parent
  * and return the result.
  */
-Point Panel::to_parent(const Point& pt) const {
+Vector2i Panel::to_parent(const Vector2i& pt) const {
 	if (!parent_)
 		return pt;
 
-	return pt + Point(lborder_ + x_, tborder_ + y_);
+	return pt + Vector2i(lborder_ + x_, tborder_ + y_);
 }
 
 /**
@@ -447,16 +447,16 @@
 /**
  * Get mouse position relative to this panel
 */
-Point Panel::get_mouse_position() const {
+Vector2i Panel::get_mouse_position() const {
 	return (parent_ ? parent_->get_mouse_position() : WLApplication::get()->get_mouse_position()) -
-	       Point(get_x() + get_lborder(), get_y() + get_tborder());
+	       Vector2i(get_x() + get_lborder(), get_y() + get_tborder());
 }
 
 /**
  * Set mouse position relative to this panel
 */
-void Panel::set_mouse_pos(const Point p) {
-	const Point relative_p = p + Point(get_x() + get_lborder(), get_y() + get_tborder());
+void Panel::set_mouse_pos(const Vector2i p) {
+	const Vector2i relative_p = p + Vector2i(get_x() + get_lborder(), get_y() + get_tborder());
 	if (parent_)
 		parent_->set_mouse_pos(relative_p);
 	else
@@ -467,7 +467,7 @@
  * Center the mouse on this panel.
 */
 void Panel::center_mouse() {
-	set_mouse_pos(Point(get_w() / 2, get_h() / 2));
+	set_mouse_pos(Vector2i(get_w() / 2, get_h() / 2));
 }
 
 /**
@@ -728,16 +728,16 @@
 	if (!is_visible())
 		return;
 
-	Rect outerrc;
-	Point outerofs;
+	Recti outerrc;
+	Vector2i outerofs;
 
-	if (!dst.enter_window(Rect(Point(x_, y_), w_, h_), &outerrc, &outerofs))
+	if (!dst.enter_window(Recti(Vector2i(x_, y_), w_, h_), &outerrc, &outerofs))
 		return;
 
 	draw_border(dst);
 
-	Rect innerwindow(
-	   Point(lborder_, tborder_), w_ - (lborder_ + rborder_), h_ - (tborder_ + bborder_));
+	Recti innerwindow(
+	   Vector2i(lborder_, tborder_), w_ - (lborder_ + rborder_), h_ - (tborder_ + bborder_));
 
 	if (dst.enter_window(innerwindow, nullptr, nullptr))
 		do_draw_inner(dst);
@@ -804,7 +804,7 @@
 	return handle_mousepress(btn, x, y);
 }
 
-bool Panel::do_mousewheel(uint32_t which, int32_t x, int32_t y, Point rel_mouse_pos) {
+bool Panel::do_mousewheel(uint32_t which, int32_t x, int32_t y, Vector2i rel_mouse_pos) {
 
 	// Check if a child-panel is beneath the mouse and processes the event
 	for (Panel* child = first_child_; child; child = child->next_) {
@@ -819,7 +819,7 @@
 		}
 		// Found a child at the position
 		if (child->do_mousewheel(
-		       which, x, y, rel_mouse_pos - Point(child->get_x() + child->get_lborder(),
+		       which, x, y, rel_mouse_pos - Vector2i(child->get_x() + child->get_lborder(),
 		                                          child->get_y() + child->get_tborder()))) {
 			return true;
 		}
@@ -1051,9 +1051,9 @@
 	uint16_t tip_width = rendered_text->width() + 4;
 	uint16_t tip_height = rendered_text->height() + 4;
 
-	Rect r(WLApplication::get()->get_mouse_position() + Point(2, 32), tip_width, tip_height);
-	const Point tooltip_bottom_right = r.opposite_of_origin();
-	const Point screen_bottom_right(g_gr->get_xres(), g_gr->get_yres());
+	Rectf r(WLApplication::get()->get_mouse_position() + Vector2i(2, 32), tip_width, tip_height);
+	const Vector2f tooltip_bottom_right = r.opposite_of_origin();
+	const Vector2f screen_bottom_right(g_gr->get_xres(), g_gr->get_yres());
 	if (screen_bottom_right.x < tooltip_bottom_right.x)
 		r.x -= 4 + r.w;
 	if (screen_bottom_right.y < tooltip_bottom_right.y)
@@ -1061,7 +1061,7 @@
 
 	dst.fill_rect(r, RGBColor(63, 52, 34));
 	dst.draw_rect(r, RGBColor(0, 0, 0));
-	dst.blit(r.origin() + Point(2, 2), rendered_text);
+	dst.blit(r.origin() + Vector2f(2.f, 2.f), rendered_text);
 	return true;
 }
 }

=== modified file 'src/ui_basic/panel.h'
--- src/ui_basic/panel.h	2016-08-04 15:59:26 +0000
+++ src/ui_basic/panel.h	2016-10-28 17:51:15 +0000
@@ -28,7 +28,7 @@
 #include <boost/signals2/trackable.hpp>
 
 #include "base/macros.h"
-#include "base/point.h"
+#include "base/vector.h"
 
 class RenderTarget;
 class Image;
@@ -113,7 +113,7 @@
 	// Geometry
 	void set_size(int nw, int nh);
 	void set_desired_size(int w, int h);
-	void set_pos(Point);
+	void set_pos(Vector2i);
 	virtual void move_inside_parent();
 	virtual void layout();
 
@@ -128,8 +128,8 @@
 	int32_t get_y() const {
 		return y_;
 	}
-	Point get_pos() const {
-		return Point(x_, y_);
+	Vector2i get_pos() const {
+		return Vector2i(x_, y_);
 	}
 	// int instead of uint because of overflow situations
 	int32_t get_w() const {
@@ -139,7 +139,7 @@
 		return h_;
 	}
 
-	Point to_parent(const Point&) const;
+	Vector2i to_parent(const Vector2i&) const;
 
 	virtual bool is_snap_target() const {
 		return false;
@@ -229,8 +229,8 @@
 	// Events
 	virtual void think();
 
-	Point get_mouse_position() const;
-	void set_mouse_pos(Point);
+	Vector2i get_mouse_position() const;
+	void set_mouse_pos(Vector2i);
 	void center_mouse();
 
 	virtual void handle_mousein(bool inside);
@@ -337,7 +337,7 @@
 	bool do_mousepress(const uint8_t btn, int32_t x, int32_t y);
 	bool do_mouserelease(const uint8_t btn, int32_t x, int32_t y);
 	bool do_mousemove(const uint8_t state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff);
-	bool do_mousewheel(uint32_t which, int32_t x, int32_t y, Point rel_mouse_pos);
+	bool do_mousewheel(uint32_t which, int32_t x, int32_t y, Vector2i rel_mouse_pos);
 	bool do_key(bool down, SDL_Keysym code);
 	bool do_textinput(const std::string& text);
 	bool do_tooltip();

=== modified file 'src/ui_basic/progressbar.cc'
--- src/ui_basic/progressbar.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/progressbar.cc	2016-10-28 17:51:15 +0000
@@ -62,26 +62,26 @@
 	assert(0 < get_w());
 	assert(0 < get_h());
 	assert(total_);
-	const float fraction = state_ < total_ ? static_cast<float>(state_) / total_ : 1.0;
+	const float fraction = state_ < total_ ? static_cast<float>(state_) / total_ : 1.0f;
 	assert(0 <= fraction);
 	assert(fraction <= 1);
 
-	const RGBColor color = fraction <= 0.33 ? RGBColor(255, 0, 0) : fraction <= 0.67 ?
+	const RGBColor color = fraction <= 0.33f ? RGBColor(255, 0, 0) : fraction <= 0.67f ?
 	                                          RGBColor(255, 255, 0) :
 	                                          RGBColor(0, 255, 0);
 
 	// Draw the actual bar
 	if (orientation_ == Horizontal) {
-		const uint32_t w = static_cast<uint32_t>(get_w() * fraction);
-		assert(w <= static_cast<uint32_t>(get_w()));
+		const float w = get_w() * fraction;
+		assert(w <= get_w());
 
-		dst.fill_rect(Rect(Point(0, 0), w, get_h()), color);
-		dst.fill_rect(Rect(Point(w, 0), get_w() - w, get_h()), RGBColor(0, 0, 0));
+		dst.fill_rect(Rectf(0.f, 0.f, w, get_h()), color);
+		dst.fill_rect(Rectf(w, 0.f, get_w() - w, get_h()), RGBColor(0, 0, 0));
 	} else {
-		const uint32_t h = static_cast<uint32_t>(get_h() * (1.0 - fraction));
+		const uint32_t h = static_cast<uint32_t>(get_h() * (1.0f - fraction));
 
-		dst.fill_rect(Rect(Point(0, 0), get_w(), h), RGBColor(0, 0, 0));
-		dst.fill_rect(Rect(Point(0, h), get_w(), get_h() - h), color);
+		dst.fill_rect(Rectf(0.f, 0.f, get_w(), h), RGBColor(0, 0, 0));
+		dst.fill_rect(Rectf(0.f, h, get_w(), get_h() - h), color);
 	}
 
 	// Print the state in percent
@@ -89,8 +89,7 @@
 	uint32_t percent = static_cast<uint32_t>(fraction * 100);
 	const std::string progress_text =
 	   (boost::format("<font color=%1$s>%2$i%%</font>") % "ffffff" % percent).str();
-	const Point pos(get_w() / 2, get_h() / 2);
-	dst.blit(
-	   pos, UI::g_fh1->render(as_uifont(progress_text)), BlendMode::UseAlpha, UI::Align::kCenter);
+	dst.blit(Vector2f(get_w() / 2.f, get_h() / 2.f), UI::g_fh1->render(as_uifont(progress_text)),
+	         BlendMode::UseAlpha, UI::Align::kCenter);
 }
 }

=== modified file 'src/ui_basic/progresswindow.cc'
--- src/ui_basic/progresswindow.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/progresswindow.cc	2016-10-28 17:51:15 +0000
@@ -59,21 +59,21 @@
 void ProgressWindow::draw_background(RenderTarget& rt, const uint32_t xres, const uint32_t yres) {
 	label_center_.x = xres / 2;
 	label_center_.y = yres * PROGRESS_LABEL_POSITION_Y / 100;
-	Rect wnd_rect(Point(0, 0), xres, yres);
+	Recti wnd_rect(Vector2i(0, 0), xres, yres);
 
 	const uint32_t h =
 	   UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height();
 
-	label_rectangle_.x = xres / 4;
-	label_rectangle_.w = xres / 2;
-	label_rectangle_.y = label_center_.y - h / 2 - PROGRESS_STATUS_RECT_PADDING;
-	label_rectangle_.h = h + 2 * PROGRESS_STATUS_RECT_PADDING;
+	label_rectangle_.x = xres / 4.f;
+	label_rectangle_.w = xres / 2.f;
+	label_rectangle_.y = label_center_.y - h / 2.f - PROGRESS_STATUS_RECT_PADDING;
+	label_rectangle_.h = h + 2.f * PROGRESS_STATUS_RECT_PADDING;
 
 	const Image* bg = g_gr->images().get(background_);
-	rt.blitrect_scale(
-	   Rect(0, 0, xres, yres), bg, Rect(0, 0, bg->width(), bg->height()), 1., BlendMode::UseAlpha);
+	rt.blitrect_scale(Rectf(0.f, 0.f, xres, yres), bg, Recti(0, 0, bg->width(), bg->height()), 1.,
+	                  BlendMode::UseAlpha);
 
-	Rect border_rect = label_rectangle_;
+	Rectf border_rect = label_rectangle_;
 	border_rect.x -= PROGRESS_STATUS_BORDER_X;
 	border_rect.y -= PROGRESS_STATUS_BORDER_Y;
 	border_rect.w += 2 * PROGRESS_STATUS_BORDER_X;
@@ -103,7 +103,7 @@
 	draw_background(rt, xres, yres);
 
 	rt.fill_rect(label_rectangle_, PROGRESS_FONT_COLOR_BG);
-	rt.blit(label_center_,
+	rt.blit(label_center_.cast<float>(),
 	        UI::g_fh1->render(as_uifont(description, UI_FONT_SIZE_SMALL, PROGRESS_FONT_COLOR_FG)),
 	        BlendMode::UseAlpha, UI::Align::kCenter);
 

=== modified file 'src/ui_basic/progresswindow.h'
--- src/ui_basic/progresswindow.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/progresswindow.h	2016-10-28 17:51:15 +0000
@@ -24,8 +24,8 @@
 #include <string>
 #include <vector>
 
-#include "base/point.h"
 #include "base/rect.h"
+#include "base/vector.h"
 
 class Image;
 class RenderTarget;
@@ -62,8 +62,11 @@
 
 private:
 	using VisualizationArray = std::vector<IProgressVisualization*>;
-	Point label_center_;
-	Rect label_rectangle_;
+
+	// This is an integer vector to make sure that we blit at pixel boundaries
+	// to avoid Texture subsampling.
+	Vector2i label_center_;
+	Rectf label_rectangle_;
 	VisualizationArray visualizations_;
 	std::string background_;
 

=== modified file 'src/ui_basic/radiobutton.cc'
--- src/ui_basic/radiobutton.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/radiobutton.cc	2016-10-28 17:51:15 +0000
@@ -27,7 +27,7 @@
  * Initialize the radiobutton and link it into the group's linked list
 */
 Radiobutton::Radiobutton(
-   Panel* const parent, Point const p, const Image* pic, Radiogroup& group, int32_t const id)
+   Panel* const parent, Vector2i const p, const Image* pic, Radiogroup& group, int32_t const id)
    : Statebox(parent, p, pic), nextbtn_(group.buttons_), group_(group), id_(id) {
 	group.buttons_ = this;
 }
@@ -86,7 +86,7 @@
  * Returns the ID of the new button.
 */
 int32_t Radiogroup::add_button(Panel* const parent,
-                               Point const p,
+                               Vector2i const p,
                                const Image* pic,
                                const std::string& tooltip,
                                Radiobutton** ret_btn) {

=== modified file 'src/ui_basic/radiobutton.h'
--- src/ui_basic/radiobutton.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/radiobutton.h	2016-10-28 17:51:15 +0000
@@ -22,7 +22,7 @@
 
 #include <stdint.h>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "ui_basic/checkbox.h"
 
 namespace UI {
@@ -34,7 +34,7 @@
 struct Radiobutton : public Statebox {
 	friend struct Radiogroup;
 
-	Radiobutton(Panel* parent, Point, const Image* pic, Radiogroup&, int32_t id);
+	Radiobutton(Panel* parent, Vector2i, const Image* pic, Radiogroup&, int32_t id);
 	~Radiobutton();
 
 	Radiobutton* next_button() {
@@ -64,7 +64,7 @@
 	boost::signals2::signal<void()> clicked;  //  clicked without things changed
 
 	int32_t add_button(Panel* parent,
-	                   Point,
+	                   Vector2i,
 	                   const Image* pic,
 	                   const std::string& tooltip = "",
 	                   Radiobutton** = nullptr);

=== modified file 'src/ui_basic/scrollbar.cc'
--- src/ui_basic/scrollbar.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/scrollbar.cc	2016-10-28 17:51:15 +0000
@@ -233,9 +233,8 @@
 	set_scrollpos(pos);
 }
 
-void Scrollbar::draw_button(RenderTarget& dst, const Area area, const Rect r) {
-
-	dst.tile(r, pic_buttons_, Point(get_x(), get_y()));
+void Scrollbar::draw_button(RenderTarget& dst, const Area area, const Rectf& r) {
+	dst.tile(r.cast<int>(), pic_buttons_, Vector2i(get_x(), get_y()));
 
 	// Draw the picture
 	const Image* pic = nullptr;
@@ -250,9 +249,10 @@
 		int blit_width = image_scale * pic->width();
 		int blit_height = image_scale * pic->height();
 
-		dst.blitrect_scale(Rect(r.origin() + Point((r.w - blit_width) / 2, (r.h - blit_height) / 2),
-		                        blit_width, blit_height),
-		                   pic, Rect(0, 0, pic->width(), pic->height()), 1., BlendMode::UseAlpha);
+		dst.blitrect_scale(
+		   Rectf(r.origin() + Vector2f((r.w - blit_width) / 2.f, (r.h - blit_height) / 2.f),
+		         blit_width, blit_height),
+		   pic, Recti(0, 0, pic->width(), pic->height()), 1., BlendMode::UseAlpha);
 	}
 
 	// Draw border
@@ -260,32 +260,32 @@
 
 	if (area != pressed_) {
 		// top edge
-		dst.brighten_rect(Rect(r.origin(), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(r.origin(), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// left edge
-		dst.brighten_rect(Rect(r.origin() + Point(0, 2), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(r.origin() + Vector2f(0, 2), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// bottom edge
-		dst.fill_rect(Rect(r.origin() + Point(2, r.h - 2), r.w - 2, 1), black);
-		dst.fill_rect(Rect(r.origin() + Point(1, r.h - 1), r.w - 1, 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(2, r.h - 2), r.w - 2, 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(1, r.h - 1), r.w - 1, 1), black);
 		// right edge
-		dst.fill_rect(Rect(r.origin() + Point(r.w - 2, 2), 1, r.h - 2), black);
-		dst.fill_rect(Rect(r.origin() + Point(r.w - 1, 1), 1, r.h - 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(r.w - 2, 2), 1, r.h - 2), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(r.w - 1, 1), 1, r.h - 1), black);
 	} else {
 		// bottom edge
-		dst.brighten_rect(Rect(r.origin() + Point(0, r.h - 2), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(r.origin() + Vector2f(0, r.h - 2), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// right edge
 		dst.brighten_rect(
-		   Rect(r.origin() + Point(r.w - 2, 0), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   Rectf(r.origin() + Vector2f(r.w - 2, 0), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		// top edge
-		dst.fill_rect(Rect(r.origin(), r.w - 1, 1), black);
-		dst.fill_rect(Rect(r.origin() + Point(0, 1), r.w - 2, 1), black);
+		dst.fill_rect(Rectf(r.origin(), r.w - 1, 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(0, 1), r.w - 2, 1), black);
 		// left edge
-		dst.fill_rect(Rect(r.origin(), 1, r.h - 1), black);
-		dst.fill_rect(Rect(r.origin() + Point(1, 0), 1, r.h - 2), black);
+		dst.fill_rect(Rectf(r.origin(), 1, r.h - 1), black);
+		dst.fill_rect(Rectf(r.origin() + Vector2f(1, 0), 1, r.h - 2), black);
 	}
 }
 
-void Scrollbar::draw_area(RenderTarget& dst, const Area area, const Rect r) {
-	dst.tile(r, pic_background_, Point(get_x(), get_y()) + r.origin());
+void Scrollbar::draw_area(RenderTarget& dst, const Area area, const Rectf& r) {
+	dst.tile(r.cast<int>(), pic_background_, Vector2i(get_x(), get_y()) + r.origin().cast<int>());
 
 	if (area == pressed_)
 		dst.brighten_rect(r, BUTTON_EDGE_BRIGHT_FACTOR);
@@ -306,46 +306,46 @@
 		if ((2 * buttonsize_ + knobsize) > static_cast<uint32_t>(get_w())) {
 			// Our owner allocated too little space
 			if (static_cast<uint32_t>(get_w()) >= 2 * buttonsize_) {
-				draw_button(dst, Minus, Rect(Point(0, 0), get_w() / 2, get_h()));
-				draw_button(dst, Plus, Rect(Point(get_w() - buttonsize_, 0), get_w() / 2, get_h()));
+				draw_button(dst, Minus, Rectf(0, 0, get_w() / 2, get_h()));
+				draw_button(dst, Plus, Rectf(get_w() - buttonsize_, 0, get_w() / 2, get_h()));
 			} else {
-				draw_button(dst, Minus, Rect(Point(0, 0), get_w(), get_h()));
+				draw_button(dst, Minus, Rectf(0.f, 0.f, get_w(), get_h()));
 			}
 			return;
 		}
 
-		draw_button(dst, Minus, Rect(Point(0, 0), buttonsize_, get_h()));
-		draw_button(dst, Plus, Rect(Point(get_w() - buttonsize_, 0), buttonsize_, get_h()));
-		draw_button(dst, Knob, Rect(Point(knobpos - knobsize / 2, 0), knobsize, get_h()));
+		draw_button(dst, Minus, Rectf(0, 0, buttonsize_, get_h()));
+		draw_button(dst, Plus, Rectf(get_w() - buttonsize_, 0, buttonsize_, get_h()));
+		draw_button(dst, Knob, Rectf(knobpos - knobsize / 2.f, 0, knobsize, get_h()));
 
 		assert(buttonsize_ + knobsize / 2 <= knobpos);
-		draw_area(dst, MinusPage,
-		          Rect(Point(buttonsize_, 0), knobpos - buttonsize_ - knobsize / 2, get_h()));
+		draw_area(
+		   dst, MinusPage, Rectf(buttonsize_, 0, knobpos - buttonsize_ - knobsize / 2, get_h()));
 		assert(knobpos + knobsize / 2 + buttonsize_ <= static_cast<uint32_t>(get_w()));
-		draw_area(dst, PlusPage, Rect(Point(knobpos + knobsize / 2, 0),
-		                              get_w() - knobpos - knobsize / 2 - buttonsize_, get_h()));
+		draw_area(dst, PlusPage, Rectf(knobpos + knobsize / 2.f, 0.f,
+		                               get_w() - knobpos - knobsize / 2 - buttonsize_, get_h()));
 	} else {
 		if ((2 * buttonsize_ + knobsize) > static_cast<uint32_t>(get_h())) {
 			// Our owner allocated too little space
 			if (static_cast<uint32_t>(get_h()) >= 2 * buttonsize_) {
-				draw_button(dst, Minus, Rect(Point(0, 0), get_w(), get_h() / 2));
-				draw_button(dst, Plus, Rect(Point(0, get_h() - buttonsize_), get_w(), get_h() / 2));
+				draw_button(dst, Minus, Rectf(0.f, 0.f, get_w(), get_h() / 2.f));
+				draw_button(dst, Plus, Rectf(0.f, get_h() - buttonsize_, get_w(), get_h() / 2));
 			} else {
-				draw_button(dst, Minus, Rect(Point(0, 0), get_w(), get_h()));
+				draw_button(dst, Minus, Rectf(0.f, 0.f, get_w(), get_h()));
 			}
 			return;
 		}
 
-		draw_button(dst, Minus, Rect(Point(0, 0), get_w(), buttonsize_));
-		draw_button(dst, Plus, Rect(Point(0, get_h() - buttonsize_), get_w(), buttonsize_));
-		draw_button(dst, Knob, Rect(Point(0, knobpos - knobsize / 2), get_w(), knobsize));
+		draw_button(dst, Minus, Rectf(0, 0, get_w(), buttonsize_));
+		draw_button(dst, Plus, Rectf(0, get_h() - buttonsize_, get_w(), buttonsize_));
+		draw_button(dst, Knob, Rectf(0, knobpos - knobsize / 2.f, get_w(), knobsize));
 
 		assert(buttonsize_ + knobsize / 2 <= knobpos);
-		draw_area(dst, MinusPage,
-		          Rect(Point(0, buttonsize_), get_w(), knobpos - buttonsize_ - knobsize / 2));
+		draw_area(
+		   dst, MinusPage, Rectf(0.f, buttonsize_, get_w(), knobpos - buttonsize_ - knobsize / 2));
 		assert(knobpos + knobsize / 2 + buttonsize_ <= static_cast<uint32_t>(get_h()));
-		draw_area(dst, PlusPage, Rect(Point(0, knobpos + knobsize / 2), get_w(),
-		                              get_h() - knobpos - knobsize / 2 - buttonsize_));
+		draw_area(dst, PlusPage, Rectf(0.f, knobpos + knobsize / 2.f, get_w(),
+		                               get_h() - knobpos - knobsize / 2.f - buttonsize_));
 	}
 }
 

=== modified file 'src/ui_basic/scrollbar.h'
--- src/ui_basic/scrollbar.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/scrollbar.h	2016-10-28 17:51:15 +0000
@@ -75,8 +75,8 @@
 
 	void action(Area area);
 
-	void draw_button(RenderTarget&, Area, Rect);
-	void draw_area(RenderTarget&, Area, Rect);
+	void draw_button(RenderTarget&, Area, const Rectf&);
+	void draw_area(RenderTarget&, Area, const Rectf&);
 	void draw(RenderTarget&) override;
 	void think() override;
 

=== modified file 'src/ui_basic/slider.cc'
--- src/ui_basic/slider.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/slider.cc	2016-10-28 17:51:15 +0000
@@ -148,37 +148,37 @@
 	RGBColor black(0, 0, 0);
 
 	dst.tile  //  background
-	   (Rect(Point(x, y), w, h), pic_background_, Point(get_x(), get_y()));
+	   (Recti(Vector2i(x, y), w, h), pic_background_, Vector2i(get_x(), get_y()));
 
 	if (highlighted_)
-		dst.brighten_rect(Rect(Point(x, y), w, h), MOUSE_OVER_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(x, y, w, h), MOUSE_OVER_BRIGHT_FACTOR);
 
 	if (pressed_) {       //  draw border
 		dst.brighten_rect  //  bottom edge
-		   (Rect(Point(x, y + h - 2), w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(x, y + h - 2, w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		dst.brighten_rect  //  right edge
-		   (Rect(Point(x + w - 2, y), 2, h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(x + w - 2, y, 2, h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
 		//  top edge
-		dst.fill_rect(Rect(Point(x, y), w - 1, 1), black);
-		dst.fill_rect(Rect(Point(x, y + 1), w - 2, 1), black);
+		dst.fill_rect(Rectf(x, y, w - 1, 1), black);
+		dst.fill_rect(Rectf(x, y + 1, w - 2, 1), black);
 
 		//  left edge
-		dst.fill_rect(Rect(Point(x, y), 1, h - 1), black);
-		dst.fill_rect(Rect(Point(x + 1, y), 1, h - 2), black);
+		dst.fill_rect(Rectf(x, y, 1, h - 1), black);
+		dst.fill_rect(Rectf(x + 1, y, 1, h - 2), black);
 	} else {
 		dst.brighten_rect  //  top edge
-		   (Rect(Point(x, y), w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(x, y, w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		dst.brighten_rect  //  left edge
-		   (Rect(Point(x, y + 2), 2, h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(x, y + 2, 2, h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
 		//  bottom edge
-		dst.fill_rect(Rect(Point(x + 2, y + h - 2), w - 2, 1), black);
-		dst.fill_rect(Rect(Point(x + 1, y + h - 1), w - 1, 1), black);
+		dst.fill_rect(Rectf(x + 2, y + h - 2, w - 2, 1), black);
+		dst.fill_rect(Rectf(x + 1, y + h - 1, w - 1, 1), black);
 
 		//  right edge
-		dst.fill_rect(Rect(Point(x + w - 2, y + 2), 1, h - 2), black);
-		dst.fill_rect(Rect(Point(x + w - 1, y + 1), 1, h - 1), black);
+		dst.fill_rect(Rectf(x + w - 2, y + 2, 1, h - 2), black);
+		dst.fill_rect(Rectf(x + w - 1, y + 1, 1, h - 1), black);
 	}
 }
 
@@ -359,19 +359,18 @@
 
 	if (get_bar_size() > 0) {
 		dst.brighten_rect  //  bottom edge
-		   (Rect(Point(get_x_gap(), get_h() / 2), get_bar_size(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(get_x_gap(), get_h() / 2.f, get_bar_size(), 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		dst.brighten_rect  //  right edge
-		   (Rect(Point(get_x_gap() + get_bar_size() - 2, get_y_gap()), 2, 2),
-		    BUTTON_EDGE_BRIGHT_FACTOR);
+		   (Rectf(get_x_gap() + get_bar_size() - 2, get_y_gap(), 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
 		//  top edge
-		dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()), get_bar_size() - 1, 1), black);
-		dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap() + 1), get_bar_size() - 2, 1), black);
+		dst.fill_rect(Rectf(get_x_gap(), get_y_gap(), get_bar_size() - 1, 1), black);
+		dst.fill_rect(Rectf(get_x_gap(), get_y_gap() + 1, get_bar_size() - 2, 1), black);
 	}
 
 	//  left edge
-	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()), 1, 4), black);
-	dst.fill_rect(Rect(Point(get_x_gap() + 1, get_y_gap()), 1, 3), black);
+	dst.fill_rect(Rectf(get_x_gap(), get_y_gap(), 1, 4), black);
+	dst.fill_rect(Rectf(get_x_gap() + 1, get_y_gap(), 1, 3), black);
 
 	draw_cursor(dst, cursor_pos_, 0, cursor_size_, get_h());
 }
@@ -432,17 +431,17 @@
 	RGBAColor black(0, 0, 0, 255);
 
 	dst.brighten_rect  //  right edge
-	   (Rect(Point(get_w() / 2, get_y_gap()), 2, get_bar_size()), BUTTON_EDGE_BRIGHT_FACTOR);
+	   (Rectf(get_w() / 2.f, get_y_gap(), 2, get_bar_size()), BUTTON_EDGE_BRIGHT_FACTOR);
 	dst.brighten_rect  //  bottom edge
-	   (Rect(Point(get_x_gap(), get_y_gap() + get_bar_size() - 2), 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+	   (Rectf(get_x_gap(), get_y_gap() + get_bar_size() - 2, 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
 	//  left edge
-	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()), 1, get_bar_size() - 1), black);
-	dst.fill_rect(Rect(Point(get_x_gap() + 1, get_y_gap()), 1, get_bar_size() - 2), black);
+	dst.fill_rect(Rectf(get_x_gap(), get_y_gap(), 1, get_bar_size() - 1), black);
+	dst.fill_rect(Rectf(get_x_gap() + 1, get_y_gap(), 1, get_bar_size() - 2), black);
 
 	//  top edge
-	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap()), 4, 1), black);
-	dst.fill_rect(Rect(Point(get_x_gap(), get_y_gap() + 1), 3, 1), black);
+	dst.fill_rect(Rectf(get_x_gap(), get_y_gap(), 4, 1), black);
+	dst.fill_rect(Rectf(get_x_gap(), get_y_gap() + 1, 3, 1), black);
 
 	draw_cursor(dst, 0, cursor_pos_, get_w(), cursor_size_);
 }
@@ -535,7 +534,7 @@
 	uint32_t gap_n = get_w() / labels.size();
 
 	for (uint32_t i = 0; i < labels.size(); i++) {
-		dst.blit(Point(gap_1 + i * gap_n, get_h()),
+		dst.blit(Vector2f(gap_1 + i * gap_n, get_h()),
 		         UI::g_fh1->render(
 		            as_condensed(labels[i], UI::Align::kBottomCenter, UI_FONT_SIZE_SMALL - 2)),
 		         BlendMode::UseAlpha, UI::Align::kBottomCenter);
@@ -552,7 +551,7 @@
 	uint32_t w = get_w();
 	uint32_t h = get_h();
 	assert(labels.size());
-	slider.set_pos(Point(w / (2 * labels.size()) - slider.cursor_size_ / 2, 0));
+	slider.set_pos(Vector2i(w / (2 * labels.size()) - slider.cursor_size_ / 2, 0));
 	slider.set_size(w - (w / labels.size()) + slider.cursor_size_,
 	                h -
 	                   UI::g_fh1

=== modified file 'src/ui_basic/table.cc'
--- src/ui_basic/table.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/table.cc	2016-10-28 17:51:15 +0000
@@ -98,8 +98,7 @@
 		// All columns have a title button that is clickable for sorting.
 		// The title text can be empty.
 		c.btn = new Button(this, title, complete_width, 0, width, headerheight_,
-		                   g_gr->images().get("images/ui_basic/but3.png"), title, tooltip_string,
-		                   true, false);
+		                   g_gr->images().get("images/ui_basic/but3.png"), title, tooltip_string);
 		c.btn->sigclicked.connect(
 		   boost::bind(&Table::header_button_clicked, boost::ref(*this), columns_.size()));
 		c.width = width;
@@ -225,7 +224,7 @@
 	uint32_t idx = scrollpos_ / lineheight;
 	int32_t y = 1 + idx * lineheight - scrollpos_ + headerheight_;
 
-	dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), ms_darken_value);
+	dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), ms_darken_value);
 
 	while (idx < entry_records_.size()) {
 		if (y >= static_cast<int32_t>(get_h()))
@@ -235,7 +234,7 @@
 
 		if (idx == selection_) {
 			assert(2 <= get_eff_w());
-			dst.brighten_rect(Rect(Point(1, y), get_eff_w() - 2, lineheight_), -ms_darken_value);
+			dst.brighten_rect(Rectf(1.f, y, get_eff_w() - 2, lineheight_), -ms_darken_value);
 		}
 
 		Columns::size_type const nr_columns = columns_.size();
@@ -247,14 +246,14 @@
 			const Image* entry_picture = er.get_picture(i);
 			const std::string& entry_string = er.get_string(i);
 
-			Point point(curx, y);
+			Vector2f point(curx, y);
 			int picw = 0;
 
 			if (entry_picture != nullptr) {
 				picw = entry_picture->width();
 				const int pich = entry_picture->height();
 
-				int draw_x = point.x;
+				float draw_x = point.x;
 
 				// We want a bit of margin
 				int max_pic_height = lineheight - 3;
@@ -266,9 +265,9 @@
 
 					if (entry_string.empty()) {
 						if (i == nr_columns - 1 && scrollbar_->is_enabled()) {
-							draw_x = point.x + (curw - blit_width - scrollbar_->get_w()) / 2;
+							draw_x = point.x + (curw - blit_width - scrollbar_->get_w()) / 2.f;
 						} else {
-							draw_x = point.x + (curw - blit_width) / 2;
+							draw_x = point.x + (curw - blit_width) / 2.f;
 						}
 					}
 
@@ -277,22 +276,22 @@
 					}
 
 					// Create the scaled image
-					dst.blitrect_scale(Rect(draw_x, point.y + 1, blit_width, max_pic_height),
-					                   entry_picture, Rect(0, 0, picw, pich), 1., BlendMode::UseAlpha);
+					dst.blitrect_scale(Rectf(draw_x, point.y + 1.f, blit_width, max_pic_height),
+					                   entry_picture, Recti(0, 0, picw, pich), 1., BlendMode::UseAlpha);
 
 					// For text alignment below
 					picw = blit_width;
 				} else {
 					if (entry_string.empty()) {
 						if (i == nr_columns - 1 && scrollbar_->is_enabled()) {
-							draw_x = point.x + (curw - picw - scrollbar_->get_w()) / 2;
+							draw_x = point.x + (curw - picw - scrollbar_->get_w()) / 2.f;
 						} else {
-							draw_x = point.x + (curw - picw) / 2;
+							draw_x = point.x + (curw - picw) / 2.f;
 						}
 					} else if (static_cast<int>(alignment & UI::Align::kRight)) {
 						draw_x += curw - picw;
 					}
-					dst.blit(Point(draw_x, point.y + (lineheight - pich) / 2), entry_picture);
+					dst.blit(Vector2f(draw_x, point.y + (lineheight - pich) / 2.f), entry_picture);
 				}
 				point.x += picw;
 			}
@@ -308,7 +307,7 @@
 			if (static_cast<int>(alignment & UI::Align::kRight)) {
 				point.x += curw - 2 * picw;
 			} else if (static_cast<int>(alignment & UI::Align::kHCenter)) {
-				point.x += (curw - picw) / 2;
+				point.x += (curw - picw) / 2.f;
 			}
 
 			// Add an offset for rightmost column when the scrollbar is shown.
@@ -328,12 +327,12 @@
 				if (i18n::has_rtl_character(
 				       entry_string.c_str(), 20)) {  // Restrict check for efficiency
 					dst.blitrect(
-					   point, entry_text_im, Rect(text_width - curw + picw, 0, text_width, lineheight));
+					   point, entry_text_im, Recti(text_width - curw + picw, 0, text_width, lineheight));
 				} else {
-					dst.blitrect(point, entry_text_im, Rect(0, 0, curw - picw, lineheight));
+					dst.blitrect(point, entry_text_im, Recti(0, 0, curw - picw, lineheight));
 				}
 			} else {
-				dst.blitrect(point, entry_text_im, Rect(0, 0, curw - picw, lineheight));
+				dst.blitrect(point, entry_text_im, Recti(0, 0, curw - picw, lineheight));
 			}
 			curx += curw;
 		}

=== modified file 'src/ui_basic/tabpanel.cc'
--- src/ui_basic/tabpanel.cc	2016-09-08 11:59:42 +0000
+++ src/ui_basic/tabpanel.cc	2016-10-28 17:51:15 +0000
@@ -198,9 +198,9 @@
 	if (border_type_ == TabPanel::Type::kBorder) {
 		panel->set_border(kTabPanelSeparatorHeight + 1, kTabPanelSeparatorHeight + 1,
 		                  kTabPanelSeparatorHeight, kTabPanelSeparatorHeight);
-		panel->set_pos(Point(0, kTabPanelButtonHeight));
+		panel->set_pos(Vector2i(0, kTabPanelButtonHeight));
 	} else {
-		panel->set_pos(Point(0, kTabPanelButtonHeight + kTabPanelSeparatorHeight));
+		panel->set_pos(Vector2i(0, kTabPanelButtonHeight + kTabPanelSeparatorHeight));
 	}
 
 	panel->set_visible(id == active_);
@@ -259,20 +259,20 @@
 
 	if (pic_background_) {
 		if (!tabs_.empty()) {
-			dst.tile(Rect(Point(0, 0), tabs_.back()->get_x() + tabs_.back()->get_w(),
+			dst.tile(Recti(Vector2i(0, 0), tabs_.back()->get_x() + tabs_.back()->get_w(),
 			              kTabPanelButtonHeight - 2),
-			         pic_background_, Point(get_x(), get_y()));
+			         pic_background_, Vector2i(get_x(), get_y()));
 		}
 		assert(kTabPanelButtonHeight - 2 <= get_h());
 		dst.tile(
-		   Rect(Point(0, kTabPanelButtonHeight - 2), get_w(), get_h() - kTabPanelButtonHeight + 2),
-		   pic_background_, Point(get_x(), get_y() + kTabPanelButtonHeight - 2));
+		   Recti(Vector2i(0, kTabPanelButtonHeight - 2), get_w(), get_h() - kTabPanelButtonHeight + 2),
+		   pic_background_, Vector2i(get_x(), get_y() + kTabPanelButtonHeight - 2));
 	}
 
 	RGBColor black(0, 0, 0);
 
 	// draw the buttons
-	int32_t x = 0;
+	float x = 0;
 	int tab_width = 0;
 	for (size_t idx = 0; idx < tabs_.size(); ++idx) {
 		x = tabs_[idx]->get_x();
@@ -280,7 +280,7 @@
 
 		if (highlight_ == idx) {
 			dst.brighten_rect(
-			   Rect(Point(x, 0), tab_width, kTabPanelButtonHeight), MOUSE_OVER_BRIGHT_FACTOR);
+			   Rectf(x, 0, tab_width, kTabPanelButtonHeight), MOUSE_OVER_BRIGHT_FACTOR);
 		}
 
 		assert(tabs_[idx]->pic);
@@ -296,53 +296,52 @@
 			uint16_t picture_width = image_scale * tabs_[idx]->pic->width();
 			uint16_t picture_height = image_scale * tabs_[idx]->pic->height();
 			dst.blitrect_scale(
-			   Rect(x + (kTabPanelButtonHeight - picture_width) / 2,
-			        (kTabPanelButtonHeight - picture_height) / 2, picture_width, picture_height),
-			   tabs_[idx]->pic, Rect(0, 0, tabs_[idx]->pic->width(), tabs_[idx]->pic->height()), 1.,
+			   Rectf(x + (kTabPanelButtonHeight - picture_width) / 2.f,
+			        (kTabPanelButtonHeight - picture_height) / 2.f, picture_width, picture_height),
+			   tabs_[idx]->pic, Recti(0, 0, tabs_[idx]->pic->width(), tabs_[idx]->pic->height()), 1.,
 			   BlendMode::UseAlpha);
 		} else {
 			dst.blit(
-			   Point(x + kTabPanelTextMargin, (kTabPanelButtonHeight - tabs_[idx]->pic->height()) / 2),
+			   Vector2f(x + kTabPanelTextMargin, (kTabPanelButtonHeight - tabs_[idx]->pic->height()) / 2.f),
 			   tabs_[idx]->pic, BlendMode::UseAlpha, UI::Align::kLeft);
 		}
 
 		// Draw top part of border
-		dst.brighten_rect(Rect(Point(x, 0), tab_width, 2), BUTTON_EDGE_BRIGHT_FACTOR);
-		dst.brighten_rect(Rect(Point(x, 2), 2, kTabPanelButtonHeight - 4), BUTTON_EDGE_BRIGHT_FACTOR);
-		dst.fill_rect(Rect(Point(x + tab_width - 2, 2), 1, kTabPanelButtonHeight - 4), black);
-		dst.fill_rect(Rect(Point(x + tab_width - 1, 1), 1, kTabPanelButtonHeight - 3), black);
+		dst.brighten_rect(Rectf(x, 0, tab_width, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(x, 2, 2, kTabPanelButtonHeight - 4), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.fill_rect(Rectf(x + tab_width - 2, 2, 1, kTabPanelButtonHeight - 4), black);
+		dst.fill_rect(Rectf(x + tab_width - 1, 1, 1, kTabPanelButtonHeight - 3), black);
 
 		// Draw bottom part
 		if (active_ != idx)
 			dst.brighten_rect(
-			   Rect(Point(x, kTabPanelButtonHeight - 2), tab_width, 2), 2 * BUTTON_EDGE_BRIGHT_FACTOR);
+			   Rectf(x, kTabPanelButtonHeight - 2, tab_width, 2), 2 * BUTTON_EDGE_BRIGHT_FACTOR);
 		else {
 			dst.brighten_rect(
-			   Rect(Point(x, kTabPanelButtonHeight - 2), 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
+			   Rectf(x, kTabPanelButtonHeight - 2, 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
 
-			dst.brighten_rect(Rect(Point(x + tab_width - 2, kTabPanelButtonHeight - 2), 2, 2),
+			dst.brighten_rect(Rectf(x + tab_width - 2, kTabPanelButtonHeight - 2, 2, 2),
 			                  2 * BUTTON_EDGE_BRIGHT_FACTOR);
-			dst.fill_rect(Rect(Point(x + tab_width - 2, kTabPanelButtonHeight - 1), 1, 1), black);
-			dst.fill_rect(Rect(Point(x + tab_width - 2, kTabPanelButtonHeight - 2), 2, 1), black);
+			dst.fill_rect(Rectf(x + tab_width - 2, kTabPanelButtonHeight - 1, 1, 1), black);
+			dst.fill_rect(Rectf(x + tab_width - 2, kTabPanelButtonHeight - 2, 2, 1), black);
 		}
 	}
 
 	// draw the remaining separator
 	assert(x <= get_w());
-	dst.brighten_rect(Rect(Point(x + tab_width, kTabPanelButtonHeight - 2), get_w() - x, 2),
+	dst.brighten_rect(Rectf(x + tab_width, kTabPanelButtonHeight - 2, get_w() - x, 2),
 	                  2 * BUTTON_EDGE_BRIGHT_FACTOR);
 
 	// Draw border around the main panel
 	if (border_type_ == TabPanel::Type::kBorder) {
 		//  left edge
-		dst.brighten_rect(
-		   Rect(Point(0, kTabPanelButtonHeight), 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
+		dst.brighten_rect(Rectf(0, kTabPanelButtonHeight, 2, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR);
 		//  bottom edge
-		dst.fill_rect(Rect(Point(2, get_h() - 2), get_w() - 2, 1), black);
-		dst.fill_rect(Rect(Point(1, get_h() - 1), get_w() - 1, 1), black);
+		dst.fill_rect(Rectf(2, get_h() - 2, get_w() - 2, 1), black);
+		dst.fill_rect(Rectf(1, get_h() - 1, get_w() - 1, 1), black);
 		//  right edge
-		dst.fill_rect(Rect(Point(get_w() - 2, kTabPanelButtonHeight - 1), 1, get_h() - 2), black);
-		dst.fill_rect(Rect(Point(get_w() - 1, kTabPanelButtonHeight - 2), 1, get_h() - 1), black);
+		dst.fill_rect(Rectf(get_w() - 2, kTabPanelButtonHeight - 1, 1, get_h() - 2), black);
+		dst.fill_rect(Rectf(get_w() - 1, kTabPanelButtonHeight - 2, 1, get_h() - 1), black);
 	}
 }
 

=== modified file 'src/ui_basic/textarea.cc'
--- src/ui_basic/textarea.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/textarea.cc	2016-10-28 17:51:15 +0000
@@ -125,13 +125,13 @@
  */
 void Textarea::draw(RenderTarget& dst) {
 	if (!text_.empty()) {
-		Point anchor(static_cast<int>(align_ & UI::Align::kHCenter) ?
-		                get_w() / 2 :
-		                static_cast<int>(align_ & UI::Align::kRight) ? get_w() : 0,
-		             static_cast<int>(align_ & UI::Align::kVCenter) ?
-		                get_h() / 2 :
-		                static_cast<int>(align_ & UI::Align::kBottom) ? get_h() : 0);
-
+		// Blit on pixel boundary (not float), so that the text is blitted pixel perfect.
+		Vector2f anchor(static_cast<int>(align_ & UI::Align::kHCenter) ?
+		                   get_w() / 2 :
+		                   static_cast<int>(align_ & UI::Align::kRight) ? get_w() : 0,
+		                static_cast<int>(align_ & UI::Align::kVCenter) ?
+		                   get_h() / 2 :
+		                   static_cast<int>(align_ & UI::Align::kBottom) ? get_h() : 0);
 		dst.blit(anchor, rendered_text_, BlendMode::UseAlpha, align_);
 	}
 }
@@ -155,7 +155,7 @@
 	else if (static_cast<int>(align_ & UI::Align::kBottom))
 		y += h;
 
-	set_pos(Point(x, y));
+	set_pos(Vector2i(x, y));
 	set_size(0, 0);
 }
 
@@ -180,7 +180,7 @@
 	else if (static_cast<int>(align_ & UI::Align::kBottom))
 		y -= h;
 
-	set_pos(Point(x, y));
+	set_pos(Vector2i(x, y));
 	set_size(w, h);
 }
 

=== modified file 'src/ui_basic/unique_window.cc'
--- src/ui_basic/unique_window.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/unique_window.cc	2016-10-28 17:51:15 +0000
@@ -80,7 +80,7 @@
 
 		registry_->window = this;
 		if (registry_->valid_pos) {
-			set_pos(Point(registry_->x, registry_->y));
+			set_pos(Vector2i(registry_->x, registry_->y));
 			usedefaultpos_ = false;
 		}
 		if (registry_->on_create) {

=== modified file 'src/ui_basic/window.cc'
--- src/ui_basic/window.cc	2016-08-04 15:49:05 +0000
+++ src/ui_basic/window.cc	2016-10-28 17:51:15 +0000
@@ -141,7 +141,7 @@
  */
 void Window::layout() {
 	if (center_panel_ && !is_minimal_) {
-		center_panel_->set_pos(Point(0, 0));
+		center_panel_->set_pos(Vector2i(0, 0));
 		center_panel_->set_size(get_inner_w(), get_inner_h());
 	}
 }
@@ -152,9 +152,9 @@
 void Window::move_out_of_the_way() {
 	center_to_parent();
 
-	const Point mouse = get_mouse_position();
+	const Vector2i mouse = get_mouse_position();
 	if (0 <= mouse.x && mouse.x < get_w() && 0 <= mouse.y && mouse.y < get_h()) {
-		set_pos(Point(get_x(), get_y()) + Point(0, (mouse.y < get_h() / 2 ? 1 : -1) * get_h()));
+		set_pos(Vector2i(get_x(), get_y()) + Vector2i(0, (mouse.y < get_h() / 2 ? 1 : -1) * get_h()));
 		move_inside_parent();
 	}
 }
@@ -164,7 +164,7 @@
  */
 void Window::warp_mouse_to_fastclick_panel() {
 	if (fastclick_panel_) {
-		Point pt(fastclick_panel_->get_w() / 2, fastclick_panel_->get_h() / 2);
+		Vector2i pt(fastclick_panel_->get_w() / 2, fastclick_panel_->get_h() / 2);
 		UI::Panel* p = fastclick_panel_;
 
 		while (p->get_parent() && p != this) {
@@ -215,7 +215,7 @@
 			if (docked_bottom_)
 				py += BT_B_PIXMAP_THICKNESS;
 		}
-		set_pos(Point(px, py));
+		set_pos(Vector2i(px, py));
 	}
 }
 
@@ -225,7 +225,7 @@
 void Window::center_to_parent() {
 	Panel& parent = *get_parent();
 
-	set_pos(Point((static_cast<int32_t>(parent.get_inner_w()) - get_w()) / 2,
+	set_pos(Vector2i((static_cast<int32_t>(parent.get_inner_w()) - get_w()) / 2,
 	              (static_cast<int32_t>(parent.get_inner_h()) - get_h()) / 2));
 }
 
@@ -234,7 +234,7 @@
  */
 void Window::draw(RenderTarget& dst) {
 	if (!is_minimal()) {
-		dst.tile(Rect(Point(0, 0), get_inner_w(), get_inner_h()), pic_background_, Point(0, 0));
+		dst.tile(Recti(Vector2i(0, 0), get_inner_w(), get_inner_h()), pic_background_, Vector2i(0, 0));
 	}
 }
 
@@ -252,26 +252,29 @@
 		int32_t pos = HZ_B_CORNER_PIXMAP_LEN;
 
 		dst.blitrect  //  top left corner
-		   (Point(0, 0), pic_top_, Rect(Point(0, 0), pos, TP_B_PIXMAP_THICKNESS));
+		   (Vector2f(0.f, 0.f), pic_top_, Recti(Vector2i(0, 0), pos, TP_B_PIXMAP_THICKNESS));
 
 		//  top bar
 		static_assert(0 <= HZ_B_CORNER_PIXMAP_LEN, "assert(0 <= HZ_B_CORNER_PIXMAP_LEN) failed.");
 		for (; pos < hz_bar_end_minus_middle; pos += HZ_B_MIDDLE_PIXMAP_LEN)
-			dst.blitrect(Point(pos, 0), pic_top_, Rect(Point(HZ_B_CORNER_PIXMAP_LEN, 0),
+			dst.blitrect(Vector2f(pos, 0), pic_top_, Recti(Vector2i(HZ_B_CORNER_PIXMAP_LEN, 0),
 			                                           HZ_B_MIDDLE_PIXMAP_LEN, TP_B_PIXMAP_THICKNESS));
 
 		// odd pixels of top bar and top right corner
 		const int32_t width = hz_bar_end - pos + HZ_B_CORNER_PIXMAP_LEN;
 		assert(0 <= HZ_B_TOTAL_PIXMAP_LEN - width);
-		dst.blitrect(Point(pos, 0), pic_top_,
-		             Rect(Point(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, TP_B_PIXMAP_THICKNESS));
+		dst.blitrect(Vector2f(pos, 0), pic_top_,
+		             Recti(Vector2i(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, TP_B_PIXMAP_THICKNESS));
 	}
 
 	// draw the title if we have one
 	if (!title_.empty()) {
 		// The title shouldn't be richtext, but we escape it just to make sure.
-		dst.blit(Point(get_lborder() + get_inner_w() / 2, TP_B_PIXMAP_THICKNESS / 2),
-		         autofit_ui_text(richtext_escape(title_), get_inner_w(), UI_FONT_CLR_FG, 13),
+		const Image* text =
+		   autofit_ui_text(richtext_escape(title_), get_inner_w(), UI_FONT_CLR_FG, 13);
+
+		// Blit on pixel boundary (not float), so that the text is blitted pixel perfect.
+		dst.blit(Vector2f(get_lborder() + get_inner_w() / 2, TP_B_PIXMAP_THICKNESS / 2), text,
 		         BlendMode::UseAlpha, UI::Align::kCenter);
 	}
 
@@ -284,8 +287,8 @@
 
 			static_assert(0 <= VT_B_PIXMAP_THICKNESS, "assert(0 <= VT_B_PIXMAP_THICKNESS) failed.");
 			dst.blitrect  // left top thingy
-			   (Point(0, TP_B_PIXMAP_THICKNESS), pic_lborder_,
-			    Rect(Point(0, 0), VT_B_PIXMAP_THICKNESS, VT_B_THINGY_PIXMAP_LEN));
+			   (Vector2f(0, TP_B_PIXMAP_THICKNESS), pic_lborder_,
+			    Recti(Vector2i(0, 0), VT_B_PIXMAP_THICKNESS, VT_B_THINGY_PIXMAP_LEN));
 
 			int32_t pos = TP_B_PIXMAP_THICKNESS + VT_B_THINGY_PIXMAP_LEN;
 
@@ -293,13 +296,13 @@
 			static_assert(0 <= VT_B_THINGY_PIXMAP_LEN, "assert(0 <= VT_B_THINGY_PIXMAP_LEN) failed.");
 			for (; pos < vt_bar_end_minus_middle; pos += VT_B_MIDDLE_PIXMAP_LEN)
 				dst.blitrect(
-				   Point(0, pos), pic_lborder_, Rect(Point(0, VT_B_THINGY_PIXMAP_LEN),
+				   Vector2f(0, pos), pic_lborder_, Recti(Vector2i(0, VT_B_THINGY_PIXMAP_LEN),
 				                                     VT_B_PIXMAP_THICKNESS, VT_B_MIDDLE_PIXMAP_LEN));
 
 			//  odd pixels of left bar and left bottom thingy
 			const int32_t height = vt_bar_end - pos + VT_B_THINGY_PIXMAP_LEN;
 			assert(0 <= VT_B_TOTAL_PIXMAP_LEN - height);
-			dst.blitrect(Point(0, pos), pic_lborder_, Rect(Point(0, VT_B_TOTAL_PIXMAP_LEN - height),
+			dst.blitrect(Vector2f(0, pos), pic_lborder_, Recti(Vector2i(0, VT_B_TOTAL_PIXMAP_LEN - height),
 			                                               VT_B_PIXMAP_THICKNESS, height));
 		}
 
@@ -307,42 +310,42 @@
 			const int32_t right_border_x = get_w() - VT_B_PIXMAP_THICKNESS;
 
 			dst.blitrect  // right top thingy
-			   (Point(right_border_x, TP_B_PIXMAP_THICKNESS), pic_rborder_,
-			    Rect(Point(0, 0), VT_B_PIXMAP_THICKNESS, VT_B_THINGY_PIXMAP_LEN));
+			   (Vector2f(right_border_x, TP_B_PIXMAP_THICKNESS), pic_rborder_,
+			    Recti(Vector2i(0, 0), VT_B_PIXMAP_THICKNESS, VT_B_THINGY_PIXMAP_LEN));
 
 			int32_t pos = TP_B_PIXMAP_THICKNESS + VT_B_THINGY_PIXMAP_LEN;
 
 			//  right bar
 			static_assert(0 <= VT_B_THINGY_PIXMAP_LEN, "assert(0 <= VT_B_THINGY_PIXMAP_LEN) failed.");
 			for (; pos < vt_bar_end_minus_middle; pos += VT_B_MIDDLE_PIXMAP_LEN)
-				dst.blitrect(Point(right_border_x, pos), pic_rborder_,
-				             Rect(Point(0, VT_B_THINGY_PIXMAP_LEN), VT_B_PIXMAP_THICKNESS,
+				dst.blitrect(Vector2f(right_border_x, pos), pic_rborder_,
+				             Recti(Vector2i(0, VT_B_THINGY_PIXMAP_LEN), VT_B_PIXMAP_THICKNESS,
 				                  VT_B_MIDDLE_PIXMAP_LEN));
 
 			// odd pixels of right bar and right bottom thingy
 			const int32_t height = vt_bar_end - pos + VT_B_THINGY_PIXMAP_LEN;
 			dst.blitrect(
-			   Point(right_border_x, pos), pic_rborder_,
-			   Rect(Point(0, VT_B_TOTAL_PIXMAP_LEN - height), VT_B_PIXMAP_THICKNESS, height));
+			   Vector2f(right_border_x, pos), pic_rborder_,
+			   Recti(Vector2i(0, VT_B_TOTAL_PIXMAP_LEN - height), VT_B_PIXMAP_THICKNESS, height));
 		}
 
 		{  // Bottom border
 			int32_t pos = HZ_B_CORNER_PIXMAP_LEN;
 
 			dst.blitrect  //  bottom left corner
-			   (Point(0, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
-			    Rect(Point(0, 0), pos, BT_B_PIXMAP_THICKNESS));
+			   (Vector2f(0, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
+			    Recti(Vector2i(0, 0), pos, BT_B_PIXMAP_THICKNESS));
 
 			//  bottom bar
 			for (; pos < hz_bar_end_minus_middle; pos += HZ_B_MIDDLE_PIXMAP_LEN)
-				dst.blitrect(Point(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
-				             Rect(Point(HZ_B_CORNER_PIXMAP_LEN, 0), HZ_B_MIDDLE_PIXMAP_LEN,
+				dst.blitrect(Vector2f(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
+				             Recti(Vector2i(HZ_B_CORNER_PIXMAP_LEN, 0), HZ_B_MIDDLE_PIXMAP_LEN,
 				                  BT_B_PIXMAP_THICKNESS));
 
 			// odd pixels of bottom bar and bottom right corner
 			const int32_t width = hz_bar_end - pos + HZ_B_CORNER_PIXMAP_LEN;
-			dst.blitrect(Point(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
-			             Rect(Point(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, BT_B_PIXMAP_THICKNESS));
+			dst.blitrect(Vector2f(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
+			             Recti(Vector2i(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, BT_B_PIXMAP_THICKNESS));
 		}
 	}
 }
@@ -427,7 +430,7 @@
 	is_minimal_ = true;
 	set_border(get_lborder(), get_rborder(), get_tborder(), 0);
 	set_size(get_w(), TP_B_PIXMAP_THICKNESS);
-	set_pos(Point(x, y));  // If on border, this feels more natural
+	set_pos(Vector2i(x, y));  // If on border, this feels more natural
 }
 
 /**
@@ -574,7 +577,7 @@
 				}
 			}
 		}
-		set_pos(Point(new_left, new_top));
+		set_pos(Vector2i(new_left, new_top));
 	}
 	return true;
 }

=== modified file 'src/ui_basic/window.h'
--- src/ui_basic/window.h	2016-08-04 15:49:05 +0000
+++ src/ui_basic/window.h	2016-10-28 17:51:15 +0000
@@ -52,7 +52,7 @@
  */
 class Window : public NamedPanel {
 public:
-	/// Do not use richtext for the \param title.
+	/// Do not use richtext for 'title'.
 	Window(Panel* parent,
 	       const std::string& name,
 	       int32_t x,
@@ -61,7 +61,7 @@
 	       uint32_t h,
 	       const std::string& title);
 
-	/// This will set the window title. Do not use richtext for the \param text.
+	/// This will set the window title. Do not use richtext for 'text'.
 	void set_title(const std::string& text);
 	const std::string& get_title() const {
 		return title_;

=== modified file 'src/ui_fsmenu/CMakeLists.txt'
--- src/ui_fsmenu/CMakeLists.txt	2016-03-10 12:57:08 +0000
+++ src/ui_fsmenu/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -44,6 +44,7 @@
     game_io
     graphic
     graphic_image_io
+    graphic_playercolor
     graphic_surface
     graphic_text
     graphic_text_layout

=== modified file 'src/ui_fsmenu/about.cc'
--- src/ui_fsmenu/about.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/about.cc	2016-10-28 17:51:15 +0000
@@ -43,10 +43,7 @@
             butw_,
             buth_,
             g_gr->images().get("images/ui_basic/but2.png"),
-            _("Close"),
-            std::string(),
-            true,
-            false),
+            _("Close")),
 
      tabs_(this,
            hmargin_,
@@ -56,7 +53,7 @@
            g_gr->images().get("images/ui_basic/but1.png"),
            UI::TabPanel::Type::kBorder) {
 	title_.set_fontsize(UI_FONT_SIZE_BIG);
-	tabs_.set_pos(Point(hmargin_, tab_panel_y_));
+	tabs_.set_pos(Vector2i(hmargin_, tab_panel_y_));
 
 	tabs_.add_tab("txts/README.lua");
 	tabs_.add_tab("txts/LICENSE.lua");

=== modified file 'src/ui_fsmenu/base.cc'
--- src/ui_fsmenu/base.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/base.cc	2016-10-28 17:51:15 +0000
@@ -58,7 +58,7 @@
 */
 void FullscreenMenuBase::draw(RenderTarget& dst) {
 	const Image* bg = g_gr->images().get(background_image_);
-	dst.blitrect_scale(Rect(0, 0, get_w(), get_h()), bg, Rect(0, 0, bg->width(), bg->height()), 1.,
+	dst.blitrect_scale(Rectf(0, 0, get_w(), get_h()), bg, Recti(0, 0, bg->width(), bg->height()), 1.,
 	                   BlendMode::UseAlpha);
 }
 

=== modified file 'src/ui_fsmenu/helpwindow.cc'
--- src/ui_fsmenu/helpwindow.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/helpwindow.cc	2016-10-28 17:51:15 +0000
@@ -48,12 +48,11 @@
 	width = (width == 0) ? g_gr->get_xres() * 3 / 5 : width;
 	height = (height == 0) ? g_gr->get_yres() * 4 / 5 : height;
 
-	Button* btn =
-	   new Button(this, "ok", width / 3, 0, width / 3, 0,
-	              g_gr->images().get("images/ui_basic/but5.png"), _("OK"), "", true, false);
+	Button* btn = new Button(this, "ok", width / 3, 0, width / 3, 0,
+	                         g_gr->images().get("images/ui_basic/but5.png"), _("OK"));
 
 	btn->sigclicked.connect(boost::bind(&FullscreenHelpWindow::clicked_ok, boost::ref(*this)));
-	btn->set_pos(Point(btn->get_x(), height - margin - btn->get_h()));
+	btn->set_pos(Vector2i(btn->get_x(), height - margin - btn->get_h()));
 
 	std::string helptext;
 	try {

=== modified file 'src/ui_fsmenu/internet_lobby.cc'
--- src/ui_fsmenu/internet_lobby.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/internet_lobby.cc	2016-10-28 17:51:15 +0000
@@ -61,10 +61,7 @@
                butw_,
                buth_,
                g_gr->images().get("images/ui_basic/but1.png"),
-               _("Join this game"),
-               std::string(),
-               false,
-               false),
+               _("Join this game")),
      hostgame_(this,
                "host_game",
                get_w() * 17 / 25,
@@ -72,10 +69,7 @@
                butw_,
                buth_,
                g_gr->images().get("images/ui_basic/but1.png"),
-               _("Open a new game"),
-               std::string(),
-               true,
-               false),
+               _("Open a new game")),
      back_(this,
            "back",
            get_w() * 17 / 25,
@@ -83,10 +77,7 @@
            butw_,
            buth_,
            g_gr->images().get("images/ui_basic/but0.png"),
-           _("Back"),
-           std::string(),
-           true,
-           false),
+           _("Back")),
 
      // Edit boxes
      edit_servername_(this,

=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/launch_mpg.cc	2016-10-28 17:51:15 +0000
@@ -26,9 +26,9 @@
 #include "base/i18n.h"
 #include "base/warning.h"
 #include "graphic/graphic.h"
+#include "graphic/playercolor.h"
 #include "graphic/text_constants.h"
 #include "io/filesystem/layered_filesystem.h"
-#include "logic/constants.h"
 #include "logic/game.h"
 #include "logic/game_controller.h"
 #include "logic/game_settings.h"
@@ -60,7 +60,7 @@
 		uint32_t buth = (get_inner_h() - 2 * space) / 5;
 		UI::Button* btn = new UI::Button(this, "map", space, y, butw, buth,
 		                                 g_gr->images().get("images/ui_basic/but0.png"), _("Map"),
-		                                 _("Select a map"), true, false);
+		                                 _("Select a map"));
 		btn->sigclicked.connect(boost::bind(&MapOrSaveSelectionWindow::pressedButton,
 		                                    boost::ref(*this),
 		                                    FullscreenMenuBase::MenuTarget::kNormalGame));
@@ -68,14 +68,14 @@
 		btn = new UI::Button(this, "saved_game", space, y + buth + space, butw, buth,
 		                     g_gr->images().get("images/ui_basic/but0.png"),
 		                     /** Translators: This is a button to select a savegame */
-		                     _("Saved Game"), _("Select a saved game"), true, false);
+		                     _("Saved Game"), _("Select a saved game"));
 		btn->sigclicked.connect(boost::bind(&MapOrSaveSelectionWindow::pressedButton,
 		                                    boost::ref(*this),
 		                                    FullscreenMenuBase::MenuTarget::kScenarioGame));
 
 		btn = new UI::Button(this, "cancel", space + butw / 4, y + 3 * buth + 2 * space, butw / 2,
 		                     buth, g_gr->images().get("images/ui_basic/but1.png"), _("Cancel"),
-		                     _("Cancel selection"), true, false);
+		                     _("Cancel selection"));
 		btn->sigclicked.connect(boost::bind(&MapOrSaveSelectionWindow::pressedButton,
 		                                    boost::ref(*this),
 		                                    FullscreenMenuBase::MenuTarget::kBack));
@@ -118,9 +118,7 @@
                          buth_,
                          g_gr->images().get("images/ui_basic/but1.png"),
                          g_gr->images().get("images/wui/menus/menu_toggle_minimap.png"),
-                         _("Change map or saved game"),
-                         false,
-                         false),
+                         _("Change map or saved game")),
      ok_(this,
          "ok",
          right_column_x_,
@@ -128,10 +126,7 @@
          butw_,
          buth_,
          g_gr->images().get("images/ui_basic/but2.png"),
-         _("Start game"),
-         std::string(),
-         false,
-         false),
+         _("Start game")),
      back_(this,
            "back",
            right_column_x_,
@@ -139,10 +134,7 @@
            butw_,
            buth_,
            g_gr->images().get("images/ui_basic/but0.png"),
-           _("Back"),
-           std::string(),
-           true,
-           false),
+           _("Back")),
      wincondition_(this,
                    "win_condition",
                    right_column_x_,
@@ -150,10 +142,7 @@
                    butw_,
                    buth_,
                    g_gr->images().get("images/ui_basic/but1.png"),
-                   "",
-                   std::string(),
-                   false,
-                   false),
+                   ""),
      help_button_(this,
                   "help",
                   right_column_x_ + butw_ - buth_,
@@ -162,9 +151,7 @@
                   buth_,
                   g_gr->images().get("images/ui_basic/but1.png"),
                   g_gr->images().get("images/ui_basic/menu_help.png"),
-                  _("Show the help window"),
-                  true,
-                  false),
+                  _("Show the help window")),
 
      // Text labels
      title_(this, get_w() / 2, get_h() / 25, _("Multiplayer Game Setup"), UI::Align::kHCenter),
@@ -227,7 +214,7 @@
 	map_info_.set_text(_("The host has not yet selected a map or saved game."));
 
 	mpsg_ = new MultiPlayerSetupGroup(
-	   this, get_w() / 50, get_h() / 8, get_w() * 57 / 80, get_h() / 2, settings, butw_, buth_);
+	   this, get_w() / 50, get_h() / 8, get_w() * 57 / 80, get_h(), settings, butw_, buth_);
 
 	// If we are the host, open the map or save selection menu at startup
 	if (settings_->settings().usernum == 0 && settings_->settings().mapname.empty()) {
@@ -494,7 +481,7 @@
 	} else {
 		// Write client infos
 		std::string client_info =
-		   (settings.playernum >= 0) && (settings.playernum < MAX_PLAYERS) ?
+		   (settings.playernum >= 0) && (settings.playernum < kMaxPlayers) ?
 		      (boost::format(_("You are Player %i.")) % (settings.playernum + 1)).str() :
 		      _("You are a spectator.");
 		client_info_.set_text(client_info);
@@ -551,9 +538,9 @@
 	Profile prof;
 	prof.read("map/player_names", nullptr, *l_fs);
 	std::string infotext = _("Saved players are:");
-	std::string player_save_name[MAX_PLAYERS];
-	std::string player_save_tribe[MAX_PLAYERS];
-	std::string player_save_ai[MAX_PLAYERS];
+	std::string player_save_name[kMaxPlayers];
+	std::string player_save_tribe[kMaxPlayers];
+	std::string player_save_ai[kMaxPlayers];
 
 	uint8_t i = 1;
 	for (; i <= nr_players_; ++i) {
@@ -662,7 +649,7 @@
 	suggested_teams_box_->hide();
 	suggested_teams_box_->show(map.get_suggested_teams());
 	suggested_teams_box_->set_pos(
-	   Point(suggested_teams_box_->get_x(),
+	   Vector2i(suggested_teams_box_->get_x(),
 	         back_.get_y() - padding_ - suggested_teams_box_->get_h() - padding_));
 }
 

=== modified file 'src/ui_fsmenu/launch_spg.cc'
--- src/ui_fsmenu/launch_spg.cc	2016-08-27 10:15:32 +0000
+++ src/ui_fsmenu/launch_spg.cc	2016-10-28 17:51:15 +0000
@@ -30,7 +30,6 @@
 #include "graphic/text_constants.h"
 #include "helper.h"
 #include "io/filesystem/layered_filesystem.h"
-#include "logic/constants.h"
 #include "logic/game.h"
 #include "logic/game_controller.h"
 #include "logic/game_settings.h"
@@ -44,18 +43,6 @@
 #include "ui_fsmenu/mapselect.h"
 #include "wui/playerdescrgroup.h"
 
-namespace {
-static char const* const player_pictures_small[] = {
-   "images/players/fsel_editor_set_player_01_pos.png",
-   "images/players/fsel_editor_set_player_02_pos.png",
-   "images/players/fsel_editor_set_player_03_pos.png",
-   "images/players/fsel_editor_set_player_04_pos.png",
-   "images/players/fsel_editor_set_player_05_pos.png",
-   "images/players/fsel_editor_set_player_06_pos.png",
-   "images/players/fsel_editor_set_player_07_pos.png",
-   "images/players/fsel_editor_set_player_08_pos.png"};
-}  // namespace
-
 FullscreenMenuLaunchSPG::FullscreenMenuLaunchSPG(GameSettingsProvider* const settings,
                                                  GameController* const ctrl,
                                                  bool /* autolaunch */)
@@ -73,10 +60,7 @@
                  butw_,
                  buth_,
                  g_gr->images().get("images/ui_basic/but1.png"),
-                 _("Select map"),
-                 std::string(),
-                 false,
-                 false),
+                 _("Select map")),
      wincondition_(this,
                    "win_condition",
                    get_w() * 7 / 10,
@@ -84,10 +68,7 @@
                    butw_,
                    buth_,
                    g_gr->images().get("images/ui_basic/but1.png"),
-                   "",
-                   std::string(),
-                   false,
-                   false),
+                   ""),
      back_(this,
            "back",
            get_w() * 7 / 10,
@@ -95,10 +76,7 @@
            butw_,
            buth_,
            g_gr->images().get("images/ui_basic/but0.png"),
-           _("Back"),
-           std::string(),
-           true,
-           false),
+           _("Back")),
      ok_(this,
          "ok",
          get_w() * 7 / 10,
@@ -106,10 +84,7 @@
          butw_,
          buth_,
          g_gr->images().get("images/ui_basic/but2.png"),
-         _("Start game"),
-         std::string(),
-         false,
-         false),
+         _("Start game")),
 
      // Text labels
      title_(this, get_w() / 2, get_h() / 10, _("Launch Game"), UI::Align::kHCenter),
@@ -172,14 +147,16 @@
 	init_.set_fontsize(smaller_fontsize);
 
 	uint32_t y = get_h() * 3 / 10 - buth_;
-	for (uint32_t i = 0; i < MAX_PLAYERS; ++i) {
-		const Image* player_image = g_gr->images().get(player_pictures_small[i]);
+	for (uint32_t i = 0; i < kMaxPlayers; ++i) {
+		const Image* player_image =
+		   playercolor_image(i, g_gr->images().get("images/players/player_position_menu.png"),
+		                     g_gr->images().get("images/players/player_position_menu_pc.png"));
 		assert(player_image);
 
 		pos_[i] =
 		   new UI::Button(this, "switch_to_position", get_w() / 100, y += buth_, get_h() * 17 / 500,
 		                  get_h() * 17 / 500, g_gr->images().get("images/ui_basic/but1.png"),
-		                  player_image, _("Switch to position"), false);
+		                  player_image, _("Switch to position"));
 		pos_[i]->sigclicked.connect(
 		   boost::bind(&FullscreenMenuLaunchSPG::switch_to_position, boost::ref(*this), i));
 		players_[i] = new PlayerDescriptionGroup(
@@ -346,11 +323,11 @@
 		pos_[i]->set_enabled(!is_scenario_ && (player.state == PlayerSettings::stateOpen ||
 		                                       player.state == PlayerSettings::stateComputer));
 	}
-	for (uint32_t i = nr_players_; i < MAX_PLAYERS; ++i)
+	for (uint32_t i = nr_players_; i < kMaxPlayers; ++i)
 		pos_[i]->set_visible(false);
 
 	// update the player description groups
-	for (uint32_t i = 0; i < MAX_PLAYERS; ++i)
+	for (uint32_t i = 0; i < kMaxPlayers; ++i)
 		players_[i]->refresh();
 
 	win_condition_update();

=== modified file 'src/ui_fsmenu/launch_spg.h'
--- src/ui_fsmenu/launch_spg.h	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/launch_spg.h	2016-10-28 17:51:15 +0000
@@ -22,7 +22,7 @@
 
 #include <string>
 
-#include "logic/constants.h"
+#include "graphic/playercolor.h"
 #include "ui_basic/button.h"
 #include "ui_basic/multilinetextarea.h"
 #include "ui_basic/textarea.h"
@@ -75,16 +75,16 @@
 	uint32_t buth_;
 
 	UI::Button select_map_, wincondition_, back_, ok_;
-	UI::Button* pos_[MAX_PLAYERS];
+	UI::Button* pos_[kMaxPlayers];
 	UI::Textarea title_, mapname_;
 	UI::Textarea name_, type_, team_, tribe_, init_, wincondition_type_;
 	GameSettingsProvider* settings_;
 	GameController* ctrl_;  // optional
-	PlayerDescriptionGroup* players_[MAX_PLAYERS];
+	PlayerDescriptionGroup* players_[kMaxPlayers];
 	std::string filename_;
 	std::string filename_proof_;  // local var. to check UI state
-	std::string player_save_name_[MAX_PLAYERS];
-	std::string player_save_tribe_[MAX_PLAYERS];
+	std::string player_save_name_[kMaxPlayers];
+	std::string player_save_tribe_[kMaxPlayers];
 	int8_t nr_players_;
 	bool is_scenario_;
 	std::vector<std::string> win_condition_scripts_;

=== modified file 'src/ui_fsmenu/load_map_or_game.cc'
--- src/ui_fsmenu/load_map_or_game.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/load_map_or_game.cc	2016-10-28 17:51:15 +0000
@@ -57,10 +57,7 @@
            butw_,
            buth_,
            g_gr->images().get("images/ui_basic/but0.png"),
-           _("Back"),
-           std::string(),
-           true,
-           false),
+           _("Back")),
      ok_(this,
          "ok",
          get_w() - right_column_margin_ - butw_,
@@ -68,10 +65,7 @@
          butw_,
          buth_,
          g_gr->images().get("images/ui_basic/but2.png"),
-         _("OK"),
-         std::string(),
-         false,
-         false) {
+         _("OK")) {
 }
 
 int32_t FullscreenMenuLoadMapOrGame::get_y_from_preceding(UI::Panel& preceding_panel) {

=== modified file 'src/ui_fsmenu/loadgame.cc'
--- src/ui_fsmenu/loadgame.cc	2016-09-25 12:27:22 +0000
+++ src/ui_fsmenu/loadgame.cc	2016-10-28 17:51:15 +0000
@@ -143,10 +143,7 @@
              butw_,
              buth_,
              g_gr->images().get("images/ui_basic/but0.png"),
-             _("Delete"),
-             std::string(),
-             false,
-             false),
+             _("Delete")),
 
      ta_errormessage_(this,
                       right_column_x_,
@@ -409,7 +406,7 @@
 					}
 
 					minimap_icon_.set_size(w, h);
-					minimap_icon_.set_pos(Point(xpos, ypos));
+					minimap_icon_.set_pos(Vector2i(xpos, ypos));
 					minimap_icon_.set_frame(UI_FONT_CLR_FG);
 					minimap_icon_.set_visible(true);
 					minimap_icon_.set_icon(minimap_image_.get());

=== modified file 'src/ui_fsmenu/main.cc'
--- src/ui_fsmenu/main.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/main.cc	2016-10-28 17:51:15 +0000
@@ -44,10 +44,7 @@
                   butw_,
                   buth_,
                   g_gr->images().get(button_background_),
-                  _("Play Tutorial"),
-                  "",
-                  true,
-                  false),
+                  _("Play Tutorial")),
      singleplayer(&vbox,
                   "single_player",
                   0,
@@ -55,10 +52,7 @@
                   butw_,
                   buth_,
                   g_gr->images().get(button_background_),
-                  _("Single Player"),
-                  "",
-                  true,
-                  false),
+                  _("Single Player")),
      multiplayer(&vbox,
                  "multi_player",
                  0,
@@ -66,10 +60,7 @@
                  butw_,
                  buth_,
                  g_gr->images().get(button_background_),
-                 _("Multiplayer"),
-                 "",
-                 true,
-                 false),
+                 _("Multiplayer")),
      replay(&vbox,
             "replay",
             0,
@@ -77,32 +68,11 @@
             butw_,
             buth_,
             g_gr->images().get(button_background_),
-            _("Watch Replay"),
-            "",
-            true,
-            false),
-     editor(&vbox,
-            "editor",
-            0,
-            0,
-            butw_,
-            buth_,
-            g_gr->images().get(button_background_),
-            _("Editor"),
-            "",
-            true,
-            false),
-     options(&vbox,
-             "options",
-             0,
-             0,
-             butw_,
-             buth_,
-             g_gr->images().get(button_background_),
-             _("Options"),
-             "",
-             true,
-             false),
+            _("Watch Replay")),
+     editor(
+        &vbox, "editor", 0, 0, butw_, buth_, g_gr->images().get(button_background_), _("Editor")),
+     options(
+        &vbox, "options", 0, 0, butw_, buth_, g_gr->images().get(button_background_), _("Options")),
      about(&vbox,
            "about",
            0,
@@ -110,10 +80,7 @@
            butw_,
            buth_,
            g_gr->images().get(button_background_),
-           _("About Widelands"),
-           "",
-           true,
-           false),
+           _("About Widelands")),
      exit(&vbox,
           "exit",
           0,
@@ -121,10 +88,7 @@
           butw_,
           buth_,
           g_gr->images().get(button_background_),
-          _("Exit Widelands"),
-          "",
-          true,
-          false),
+          _("Exit Widelands")),
 
      // Textlabels
      version(

=== modified file 'src/ui_fsmenu/mapselect.cc'
--- src/ui_fsmenu/mapselect.cc	2016-09-25 12:27:22 +0000
+++ src/ui_fsmenu/mapselect.cc	2016-10-28 17:51:15 +0000
@@ -81,7 +81,7 @@
 	   new UI::Box(this, tablex_, checkboxes_y_, UI::Box::Horizontal, checkbox_space_, get_w());
 
 	// Must be initialized before tag checkboxes
-	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Point(0, 0), _("Show original map names"));
+	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Vector2i(0, 0), _("Show original map names"));
 	cb_dont_localize_mapnames_->set_state(false);
 	cb_dont_localize_mapnames_->changedto.connect(
 	   boost::bind(&FullscreenMenuMapSelect::fill_table, boost::ref(*this)));
@@ -290,7 +290,7 @@
 	int32_t id = tags_ordered_.size();
 	tags_ordered_.push_back(tag);
 
-	UI::Checkbox* cb = new UI::Checkbox(box, Point(0, 0), displ_name);
+	UI::Checkbox* cb = new UI::Checkbox(box, Vector2i(0, 0), displ_name);
 	cb->changedto.connect(boost::bind(&FullscreenMenuMapSelect::tagbox_changed, this, id, _1));
 
 	box->add(cb, UI::Align::kLeft, true);

=== modified file 'src/ui_fsmenu/multiplayer.cc'
--- src/ui_fsmenu/multiplayer.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/multiplayer.cc	2016-10-28 17:51:15 +0000
@@ -41,10 +41,7 @@
                 butw_,
                 buth_,
                 g_gr->images().get(button_background_),
-                _("Internet game"),
-                "",
-                true,
-                false),
+                _("Internet game")),
      lan(&vbox,
          "lan",
          0,
@@ -52,21 +49,8 @@
          butw_,
          buth_,
          g_gr->images().get(button_background_),
-         _("LAN / Direct IP"),
-         "",
-         true,
-         false),
-     back(&vbox,
-          "back",
-          0,
-          0,
-          butw_,
-          buth_,
-          g_gr->images().get(button_background_),
-          _("Back"),
-          "",
-          true,
-          false) {
+         _("LAN / Direct IP")),
+     back(&vbox, "back", 0, 0, butw_, buth_, g_gr->images().get(button_background_), _("Back")) {
 	metaserver.sigclicked.connect(
 	   boost::bind(&FullscreenMenuMultiPlayer::internet_login, boost::ref(*this)));
 
@@ -96,10 +80,10 @@
 	Section& s = g_options.pull_section("global");
 	auto_log_ = s.get_bool("auto_log", false);
 	if (auto_log_) {
-		showloginbox = new UI::Button(
-		   this, "login_dialog", box_x_ + butw_ + buth_ / 4, get_h() * 6 / 25, buth_, buth_,
-		   g_gr->images().get("images/ui_basic/but1.png"),
-		   g_gr->images().get("images/ui_basic/continue.png"), _("Show login dialog"), true, false);
+		showloginbox =
+		   new UI::Button(this, "login_dialog", box_x_ + butw_ + buth_ / 4, get_h() * 6 / 25, buth_,
+		                  buth_, g_gr->images().get("images/ui_basic/but1.png"),
+		                  g_gr->images().get("images/ui_basic/continue.png"), _("Show login dialog"));
 		showloginbox->sigclicked.connect(
 		   boost::bind(&FullscreenMenuMultiPlayer::show_internet_login, boost::ref(*this)));
 	}

=== modified file 'src/ui_fsmenu/netsetup_lan.cc'
--- src/ui_fsmenu/netsetup_lan.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/netsetup_lan.cc	2016-10-28 17:51:15 +0000
@@ -51,10 +51,7 @@
               butw_,
               buth_,
               g_gr->images().get("images/ui_basic/but1.png"),
-              _("Join this game"),
-              std::string(),
-              true,
-              false),
+              _("Join this game")),
      hostgame(this,
               "host_game",
               get_w() * 16 / 25,
@@ -62,10 +59,7 @@
               butw_,
               buth_,
               g_gr->images().get("images/ui_basic/but1.png"),
-              _("Host a new game"),
-              std::string(),
-              true,
-              false),
+              _("Host a new game")),
      back(this,
           "back",
           get_w() * 16 / 25,
@@ -73,10 +67,7 @@
           butw_,
           buth_,
           g_gr->images().get("images/ui_basic/but0.png"),
-          _("Back"),
-          std::string(),
-          true,
-          false),
+          _("Back")),
      loadlasthost(this,
                   "load_previous_host",
                   get_w() * 171 / 200,
@@ -85,9 +76,7 @@
                   buth_,
                   g_gr->images().get("images/ui_basic/but1.png"),
                   g_gr->images().get("images/ui_fsmenu/menu_load_game.png"),
-                  _("Load previous host"),
-                  true,
-                  false),
+                  _("Load previous host")),
 
      // Edit boxes
      playername(this,

=== modified file 'src/ui_fsmenu/options.cc'
--- src/ui_fsmenu/options.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/options.cc	2016-10-28 17:51:15 +0000
@@ -113,10 +113,7 @@
         butw_,
         buth_,
         g_gr->images().get("images/ui_basic/but0.png"),
-        _("Cancel"),
-        std::string(),
-        true,
-        false),
+        _("Cancel")),
      apply_(this,
             "apply",
             get_w() * 2 / 4 - butw_ / 2,
@@ -124,10 +121,7 @@
             butw_,
             buth_,
             g_gr->images().get("images/ui_basic/but0.png"),
-            _("Apply"),
-            std::string(),
-            true,
-            false),
+            _("Apply")),
      ok_(this,
          "ok",
          UI::g_fh1->fontset()->is_rtl() ? get_w() * 1 / 4 - butw_ / 2 : get_w() * 3 / 4 - butw_ / 2,
@@ -135,10 +129,7 @@
          butw_,
          buth_,
          g_gr->images().get("images/ui_basic/but2.png"),
-         _("OK"),
-         std::string(),
-         true,
-         false),
+         _("OK")),
 
      tabs_(this,
            hmargin_,
@@ -159,8 +150,8 @@
      label_resolution_(&box_interface_, _("In-game resolution"), UI::Align::kLeft),
      resolution_list_(&box_interface_, 0, 0, column_width_ / 2, 80, true),
 
-     fullscreen_(&box_interface_, Point(0, 0), _("Fullscreen"), "", column_width_),
-     inputgrab_(&box_interface_, Point(0, 0), _("Grab Input"), "", column_width_),
+     fullscreen_(&box_interface_, Vector2i(0, 0), _("Fullscreen"), "", column_width_),
+     inputgrab_(&box_interface_, Vector2i(0, 0), _("Grab Input"), "", column_width_),
 
      sb_maxfps_(&box_interface_,
                 0,
@@ -174,9 +165,9 @@
 
      // Windows options
      snap_win_overlap_only_(
-        &box_windows_, Point(0, 0), _("Snap windows only when overlapping"), "", column_width_),
+        &box_windows_, Vector2i(0, 0), _("Snap windows only when overlapping"), "", column_width_),
      dock_windows_to_edges_(
-        &box_windows_, Point(0, 0), _("Dock windows to edges"), "", column_width_),
+        &box_windows_, Vector2i(0, 0), _("Dock windows to edges"), "", column_width_),
 
      sb_dis_panel_(&box_windows_,
                    0,
@@ -201,10 +192,10 @@
                     UI::SpinBox::Units::kPixels),
 
      // Sound options
-     music_(&box_sound_, Point(0, 0), _("Enable Music"), "", column_width_),
-     fx_(&box_sound_, Point(0, 0), _("Enable Sound Effects"), "", column_width_),
+     music_(&box_sound_, Vector2i(0, 0), _("Enable Music"), "", column_width_),
+     fx_(&box_sound_, Vector2i(0, 0), _("Enable Sound Effects"), "", column_width_),
      message_sound_(
-        &box_sound_, Point(0, 0), _("Play a sound at message arrival"), "", column_width_),
+        &box_sound_, Vector2i(0, 0), _("Play a sound at message arrival"), "", column_width_),
 
      // Saving options
      sb_autosave_(&box_saving_,
@@ -234,28 +225,28 @@
                           UI::SpinBox::Type::kBig),
 
      zip_(&box_saving_,
-          Point(0, 0),
+          Vector2i(0, 0),
           _("Compress widelands data files (maps, replays and savegames)"),
           "",
           column_width_),
      write_syncstreams_(&box_saving_,
-                        Point(0, 0),
+                        Vector2i(0, 0),
                         _("Write syncstreams in network games to debug desyncs"),
                         "",
                         column_width_),
 
      // Game options
-     auto_roadbuild_mode_(&box_game_, Point(0, 0), _("Start building road after placing a flag")),
-     show_workarea_preview_(&box_game_, Point(0, 0), _("Show buildings area preview")),
+     auto_roadbuild_mode_(&box_game_, Vector2i(0, 0), _("Start building road after placing a flag")),
+     show_workarea_preview_(&box_game_, Vector2i(0, 0), _("Show buildings area preview")),
      transparent_chat_(&box_game_,
-                       Point(0, 0),
+                       Vector2i(0, 0),
                        _("Show in-game chat with transparent background"),
                        "",
                        column_width_),
 
      /** TRANSLATORS: A watchwindow is a window where you keep watching an object or a map region,*/
      /** TRANSLATORS: and it also lets you jump to it on the map. */
-     single_watchwin_(&box_game_, Point(0, 0), _("Use single watchwindow mode")),
+     single_watchwin_(&box_game_, Vector2i(0, 0), _("Use single watchwindow mode")),
 
      // Language options
      label_language_(&box_language_, _("Language"), UI::Align::kLeft),
@@ -282,7 +273,7 @@
 		tabs_.activate(os_.active_tab);
 	}
 
-	tabs_.set_pos(Point(hmargin_, tab_panel_y_));
+	tabs_.set_pos(Vector2i(hmargin_, tab_panel_y_));
 
 	box_interface_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());
 	box_windows_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());

=== modified file 'src/ui_fsmenu/singleplayer.cc'
--- src/ui_fsmenu/singleplayer.cc	2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/singleplayer.cc	2016-10-28 17:51:15 +0000
@@ -38,10 +38,7 @@
               butw_,
               buth_,
               g_gr->images().get(button_background_),
-              _("New Game"),
-              "",
-              true,
-              false),
+              _("New Game")),
      campaign(&vbox,
               "campaigns",
               0,
@@ -49,10 +46,7 @@
               butw_,
               buth_,
               g_gr->images().get(button_background_),
-              _("Campaigns"),
-              "",
-              true,
-              false),
+              _("Campaigns")),
      load_game(&vbox,
                "load_game",
                0,
@@ -60,21 +54,8 @@
                butw_,
                buth_,
                g_gr->images().get(button_background_),
-               _("Load Game"),
-               "",
-               true,
-               false),
-     back(&vbox,
-          "back",
-          0,
-          0,
-          butw_,
-          buth_,
-          g_gr->images().get(button_background_),
-          _("Back"),
-          "",
-          true,
-          false) {
+               _("Load Game")),
+     back(&vbox, "back", 0, 0, butw_, buth_, g_gr->images().get(button_background_), _("Back")) {
 	new_game.sigclicked.connect(
 	   boost::bind(&FullscreenMenuSinglePlayer::end_modal<FullscreenMenuBase::MenuTarget>,
 	               boost::ref(*this), FullscreenMenuBase::MenuTarget::kNewGame));

=== modified file 'src/website/map_info.cc'
--- src/website/map_info.cc	2016-08-04 15:49:05 +0000
+++ src/website/map_info.cc	2016-10-28 17:51:15 +0000
@@ -88,8 +88,8 @@
 		ml->preload_map(true);
 		ml->load_map_complete(egbase, Widelands::MapLoader::LoadType::kScenario);
 
-		std::unique_ptr<Texture> minimap(
-		   draw_minimap(egbase, nullptr, Point(0, 0), MiniMapLayer::Terrain));
+		std::unique_ptr<Texture> minimap(draw_minimap(
+		   egbase, nullptr, Rectf(), MiniMapType::kStaticMap, MiniMapLayer::Terrain));
 
 		// Write minimap
 		{

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2016-09-16 16:54:11 +0000
+++ src/wlapplication.cc	2016-10-28 17:51:15 +0000
@@ -465,7 +465,7 @@
 	case SDL_MOUSEMOTION:
 		ev.motion.xrel += mouse_compensate_warp_.x;
 		ev.motion.yrel += mouse_compensate_warp_.y;
-		mouse_compensate_warp_ = Point(0, 0);
+		mouse_compensate_warp_ = Vector2i(0, 0);
 
 		if (mouse_locked_) {
 			warp_mouse(mouse_position_);
@@ -576,7 +576,7 @@
 			}
 			break;
 		case SDL_MOUSEMOTION:
-			mouse_position_ = Point(ev.motion.x, ev.motion.y);
+			mouse_position_ = Vector2i(ev.motion.x, ev.motion.y);
 
 			if ((ev.motion.xrel || ev.motion.yrel) && cb && cb->mouse_move)
 				cb->mouse_move(
@@ -654,10 +654,10 @@
 /// eliminate the motion event in poll_event()
 ///
 /// \param position The new mouse position
-void WLApplication::warp_mouse(const Point position) {
+void WLApplication::warp_mouse(const Vector2i position) {
 	mouse_position_ = position;
 
-	Point cur_position;
+	Vector2i cur_position;
 	SDL_GetMouseState(&cur_position.x, &cur_position.y);
 	if (cur_position != position) {
 		mouse_compensate_warp_ += cur_position - position;

=== modified file 'src/wlapplication.h'
--- src/wlapplication.h	2016-08-13 12:16:14 +0000
+++ src/wlapplication.h	2016-10-28 17:51:15 +0000
@@ -36,7 +36,7 @@
 #include <SDL_events.h>
 #include <SDL_keyboard.h>
 
-#include "base/point.h"
+#include "base/vector.h"
 
 namespace Widelands {
 class Game;
@@ -152,11 +152,11 @@
 	}
 
 	// @{
-	void warp_mouse(Point);
+	void warp_mouse(Vector2i);
 	void set_input_grab(bool grab);
 
 	/// The mouse's current coordinates
-	Point get_mouse_position() const {
+	Vector2i get_mouse_position() const {
 		return mouse_position_;
 	}
 	//
@@ -239,15 +239,15 @@
 	bool faking_middle_mouse_button_;
 
 	/// The current position of the mouse pointer
-	Point mouse_position_;
+	Vector2i mouse_position_;
 
 	/// If true, the mouse cursor will \e not move with a mousemotion event:
 	/// instead, the map will be scrolled
 	bool mouse_locked_;
 
-	/// If the mouse needs to be moved in warp_mouse(), this Point is
+	/// If the mouse needs to be moved in warp_mouse(), this Vector2i is
 	/// used to cancel the resulting SDL_MouseMotionEvent.
-	Point mouse_compensate_warp_;
+	Vector2i mouse_compensate_warp_;
 
 	/// true if an external entity wants us to quit
 	bool should_die_;

=== modified file 'src/wui/CMakeLists.txt'
--- src/wui/CMakeLists.txt	2016-04-15 17:23:00 +0000
+++ src/wui/CMakeLists.txt	2016-10-28 17:51:15 +0000
@@ -48,7 +48,6 @@
     mapviewpixelconstants.h
     mapviewpixelfunctions.cc
     mapviewpixelfunctions.h
-    vector.h
   DEPENDS
     base_geometry
     logic
@@ -72,6 +71,7 @@
     base_i18n
     base_log
     graphic
+    graphic_playercolor
     graphic_text_layout
     io_filesystem
     logic
@@ -81,6 +81,36 @@
     ui_basic
 )
 
+wl_library(wui_quicknavigation
+  SRCS
+    quicknavigation.cc
+    quicknavigation.h
+  DEPENDS
+    base_geometry
+    logic
+    widelands_ball_of_mud
+    wui_mapview
+    wui_mapview_pixelfunctions
+)
+
+wl_library(wui_mapview
+  SRCS
+    mapview.cc
+    mapview.h
+  DEPENDS
+    base_geometry
+    base_macros
+    base_math
+    graphic
+    graphic_game_renderer
+    logic
+    logic_widelands_geometry
+    ui_basic
+    widelands_ball_of_mud
+    wui
+    wui_mapview_pixelfunctions
+)
+
 wl_library(wui
   SRCS
     actionconfirm.cc
@@ -135,8 +165,6 @@
     login_box.cc
     login_box.h
     logmessage.h
-    mapview.cc
-    mapview.h
     militarysitewindow.cc
     minimap.cc
     minimap.h
@@ -150,9 +178,8 @@
     portdockwaresdisplay.h
     productionsitewindow.cc
     productionsitewindow.h
-    quicknavigation.cc
-    quicknavigation.h
     shipwindow.cc
+    shipwindow.h
     soldiercapacitycontrol.cc
     soldiercapacitycontrol.h
     soldierlist.cc
@@ -191,14 +218,15 @@
     game_io
     graphic
     graphic_color
-    graphic_game_renderer
     graphic_minimap_renderer
+    graphic_playercolor
     graphic_surface
     graphic_text
     graphic_text_layout
     io_fileread
     io_filesystem
     logic
+    logic_constants
     logic_game_controller
     logic_game_settings
     logic_widelands_geometry
@@ -214,5 +242,7 @@
     wui_chat_ui
     wui_edge_overlay_manager
     wui_field_overlay_manager
+    wui_mapview
     wui_mapview_pixelfunctions
+    wui_quicknavigation
 )

=== modified file 'src/wui/building_statistics_menu.cc'
--- src/wui/building_statistics_menu.cc	2016-08-04 15:49:05 +0000
+++ src/wui/building_statistics_menu.cc	2016-10-28 17:51:15 +0000
@@ -264,36 +264,36 @@
 	navigation_buttons_[NavigationButton::PrevOwned] = new UI::Button(
 	   &navigation_panel_, "previous_owned", get_inner_w() - 2 * kButtonRowHeight, kButtonRowHeight,
 	   kButtonHeight, kButtonHeight, g_gr->images().get("images/ui_basic/but4.png"),
-	   g_gr->images().get("images/ui_basic/scrollbar_left.png"), _("Show previous building"), false);
+	   g_gr->images().get("images/ui_basic/scrollbar_left.png"), _("Show previous building"));
 
 	navigation_buttons_[NavigationButton::NextOwned] = new UI::Button(
 	   &navigation_panel_, "next_owned", get_inner_w() - kButtonRowHeight, kButtonRowHeight,
 	   kButtonHeight, kButtonHeight, g_gr->images().get("images/ui_basic/but4.png"),
-	   g_gr->images().get("images/ui_basic/scrollbar_right.png"), _("Show next building"), false);
+	   g_gr->images().get("images/ui_basic/scrollbar_right.png"), _("Show next building"));
 
 	navigation_buttons_[NavigationButton::PrevConstruction] = new UI::Button(
 	   &navigation_panel_, "previous_constructed", get_inner_w() - 2 * kButtonRowHeight,
 	   2 * kButtonRowHeight, kButtonHeight, kButtonHeight,
 	   g_gr->images().get("images/ui_basic/but4.png"),
-	   g_gr->images().get("images/ui_basic/scrollbar_left.png"), _("Show previous building"), false);
+	   g_gr->images().get("images/ui_basic/scrollbar_left.png"), _("Show previous building"));
 
 	navigation_buttons_[NavigationButton::NextConstruction] = new UI::Button(
 	   &navigation_panel_, "next_constructed", get_inner_w() - kButtonRowHeight,
 	   2 * kButtonRowHeight, kButtonHeight, kButtonHeight,
 	   g_gr->images().get("images/ui_basic/but4.png"),
-	   g_gr->images().get("images/ui_basic/scrollbar_right.png"), _("Show next building"), false);
+	   g_gr->images().get("images/ui_basic/scrollbar_right.png"), _("Show next building"));
 
 	navigation_buttons_[NavigationButton::PrevUnproductive] = new UI::Button(
 	   &navigation_panel_, "previous_unproductive", get_inner_w() - 2 * kButtonRowHeight,
 	   3 * kButtonRowHeight, kButtonHeight, kButtonHeight,
 	   g_gr->images().get("images/ui_basic/but4.png"),
-	   g_gr->images().get("images/ui_basic/scrollbar_left.png"), _("Show previous building"), false);
+	   g_gr->images().get("images/ui_basic/scrollbar_left.png"), _("Show previous building"));
 
 	navigation_buttons_[NavigationButton::NextUnproductive] = new UI::Button(
 	   &navigation_panel_, "next_unproductive", get_inner_w() - kButtonRowHeight,
 	   3 * kButtonRowHeight, kButtonHeight, kButtonHeight,
 	   g_gr->images().get("images/ui_basic/but4.png"),
-	   g_gr->images().get("images/ui_basic/scrollbar_right.png"), _("Show next building"), false);
+	   g_gr->images().get("images/ui_basic/scrollbar_right.png"), _("Show next building"));
 
 	navigation_buttons_[NavigationButton::PrevOwned]->sigclicked.connect(boost::bind(
 	   &BuildingStatisticsMenu::jump_building, boost::ref(*this), JumpTarget::kOwned, true));
@@ -335,7 +335,8 @@
 	building_buttons_[id] = new UI::Button(
 	   button_box, (boost::format("building_button%s") % id).str(), 0, 0, kBuildGridCellWidth,
 	   kBuildGridCellHeight, g_gr->images().get("images/ui_basic/but1.png"),
-	   descr.representative_image(&iplayer().get_player()->get_playercolor()), "", false, true);
+	   descr.representative_image(&iplayer().get_player()->get_playercolor()), "",
+	   UI::Button::Style::kFlat);
 	button_box->add(building_buttons_[id], UI::Align::kLeft);
 
 	owned_labels_[id] =
@@ -481,7 +482,7 @@
 
 	if (found) {
 		validate_pointer(&last_building_index_, stats_vector.size());
-		iplayer().move_view_to(stats_vector[last_building_index_].pos);
+		iplayer().center_view_on_coords(stats_vector[last_building_index_].pos);
 	}
 	low_production_reset_focus();
 	update();
@@ -501,7 +502,7 @@
 		tab_panel_.set_size(kWindowWidth, tab_height);
 		set_size(
 		   get_w(), tab_height + kMargin + 4 * kButtonRowHeight + get_tborder() + get_bborder());
-		navigation_panel_.set_pos(Point(0, tab_height + kMargin));
+		navigation_panel_.set_pos(Vector2i(0, tab_height + kMargin));
 	}
 
 	// Update statistics
@@ -718,12 +719,11 @@
 		if (building_button == nullptr) {
 			continue;
 		}
-		building_button->set_flat(true);
+		building_button->set_style(UI::Button::Style::kFlat);
 	}
 
 	// Update for current button
 	current_building_type_ = id;
-	building_buttons_[current_building_type_]->set_flat(false);
 	building_buttons_[current_building_type_]->set_perm_pressed(true);
 	building_name_.set_text(iplayer().player().tribe().get_building_descr(id)->descname());
 	low_production_reset_focus();

=== modified file 'src/wui/building_ui.cc'
--- src/wui/building_ui.cc	2016-08-04 15:49:05 +0000
+++ src/wui/building_ui.cc	2016-10-28 17:51:15 +0000
@@ -31,7 +31,7 @@
  * Create the building's options window if necessary and bring it to
  * the top to be seen by the player.
  */
-void Building::show_options(InteractiveGameBase& igbase, bool avoid_fastclick, Point pos) {
+void Building::show_options(InteractiveGameBase& igbase, bool avoid_fastclick, Vector2i pos) {
 	if (optionswindow_) {
 		if (optionswindow_->is_minimal())
 			optionswindow_->restore();
@@ -66,7 +66,7 @@
 void Building::refresh_options(InteractiveGameBase& igb) {
 	// Only do something if there is actually a window
 	if (optionswindow_) {
-		Point window_position = optionswindow_->get_pos();
+		Vector2i window_position = optionswindow_->get_pos();
 		hide_options();
 		show_options(igb, true);
 		optionswindow_->set_pos(window_position);

=== modified file 'src/wui/buildingwindow.cc'
--- src/wui/buildingwindow.cc	2016-08-04 15:49:05 +0000
+++ src/wui/buildingwindow.cc	2016-10-28 17:51:15 +0000
@@ -110,9 +110,10 @@
 	// TODO(sirver): chang this to directly blit the animation. This needs support for or removal of
 	// RenderTarget.
 	const Image* image = building().representative_image();
-	dst.blitrect_scale(Rect((get_inner_w() - image->width()) / 2,
-	                        (get_inner_h() - image->height()) / 2, image->width(), image->height()),
-	                   image, Rect(0, 0, image->width(), image->height()), 0.5, BlendMode::UseAlpha);
+	dst.blitrect_scale(
+	   Rectf((get_inner_w() - image->width()) / 2.f, (get_inner_h() - image->height()) / 2.f,
+	         image->width(), image->height()),
+	   image, Recti(0, 0, image->width(), image->height()), 0.5, BlendMode::UseAlpha);
 }
 
 /*
@@ -460,7 +461,7 @@
  * for the corresponding button.
  */
 void BuildingWindow::clicked_goto() {
-	igbase().move_view_to(building().get_position());
+	igbase().center_view_on_coords(building().get_position());
 }
 
 void BuildingWindow::update_expedition_button(bool expedition_was_canceled) {

=== modified file 'src/wui/chat_msg_layout.cc'
--- src/wui/chat_msg_layout.cc	2016-08-04 15:49:05 +0000
+++ src/wui/chat_msg_layout.cc	2016-10-28 17:51:15 +0000
@@ -24,15 +24,14 @@
 #include "chat/chat.h"
 #include "graphic/color.h"
 #include "graphic/text_layout.h"
-#include "logic/constants.h"
 #include "logic/player.h"
 
 namespace {
 
 // Returns the hexcolor for the 'player'.
 std::string color(const int16_t playern) {
-	if ((playern >= 0) && playern < MAX_PLAYERS) {
-		const RGBColor& clr = Widelands::Player::Colors[playern];
+	if ((playern >= 0) && playern < kMaxPlayers) {
+		const RGBColor& clr = kPlayerColors[playern];
 		char buf[sizeof("ffffff")];
 		snprintf(buf, sizeof(buf), "%.2x%.2x%.2x", clr.r, clr.g, clr.b);
 		return buf;

=== modified file 'src/wui/chatoverlay.cc'
--- src/wui/chatoverlay.cc	2016-08-04 15:49:05 +0000
+++ src/wui/chatoverlay.cc	2016-10-28 17:51:15 +0000
@@ -183,12 +183,10 @@
 	const int width = std::min<int>(get_w(), im->width());
 
 	if (!m->transparent_) {
-		Rect rect(0, top, width, height);
-		dst.fill_rect(rect, RGBAColor(50, 50, 50, 128), BlendMode::Default);
+		dst.fill_rect(Rectf(0, top, width, height), RGBAColor(50, 50, 50, 128), BlendMode::Default);
 	}
 	int32_t topcrop = im->height() - height;
-	Rect cropRect(0, topcrop, width, height);
+	Recti cropRect(0, topcrop, width, height);
 
-	Point pt(0, top);
-	dst.blitrect(pt, im, cropRect);
+	dst.blitrect(Vector2f(0, top), im, cropRect);
 }

=== modified file 'src/wui/field_overlay_manager.cc'
--- src/wui/field_overlay_manager.cc	2016-08-04 15:49:05 +0000
+++ src/wui/field_overlay_manager.cc	2016-10-28 17:51:15 +0000
@@ -36,7 +36,7 @@
 	//  Special case for flag, which has a different formula for hotspot_y.
 	buildhelp_info->pic = g_gr->images().get(*filename);
 	buildhelp_info->hotspot =
-	   Point(buildhelp_info->pic->width() / 2, buildhelp_info->pic->height() - 1);
+	   Vector2i(buildhelp_info->pic->width() / 2, buildhelp_info->pic->height() - 1);
 
 	const OverlayInfo* const buildhelp_infos_end = buildhelp_info + Widelands::Field::Buildhelp_None;
 	for (;;) {  // The other buildhelp overlays.
@@ -45,7 +45,7 @@
 			break;
 		buildhelp_info->pic = g_gr->images().get(*filename);
 		buildhelp_info->hotspot =
-		   Point(buildhelp_info->pic->width() / 2, buildhelp_info->pic->height() / 2);
+		   Vector2i(buildhelp_info->pic->width() / 2, buildhelp_info->pic->height() / 2);
 	}
 }
 
@@ -113,13 +113,13 @@
 void FieldOverlayManager::register_overlay(const Widelands::TCoords<>& c,
                                            const Image* pic,
                                            int32_t const level,
-                                           Point hotspot,
+                                           Vector2i hotspot,
                                            OverlayId const overlay_id) {
 	assert(c.t <= 2);
 	assert(level != 5);  //  level == 5 is undefined behavior
 
-	if (hotspot == Point::invalid()) {
-		hotspot = Point(pic->width() / 2, pic->height() / 2);
+	if (hotspot == Vector2i::invalid()) {
+		hotspot = Vector2i(pic->width() / 2, pic->height() / 2);
 	}
 
 	RegisteredOverlaysMap& overlay_map = overlays_[c.t];

=== modified file 'src/wui/field_overlay_manager.h'
--- src/wui/field_overlay_manager.h	2016-08-04 15:49:05 +0000
+++ src/wui/field_overlay_manager.h	2016-10-28 17:51:15 +0000
@@ -25,7 +25,7 @@
 #include <set>
 #include <vector>
 
-#include "base/point.h"
+#include "base/vector.h"
 #include "logic/field.h"
 #include "logic/widelands_geometry.h"
 
@@ -55,12 +55,12 @@
 	/// A overlay as drawn onto the screen.
 	struct OverlayInfo {
 		OverlayInfo() = default;
-		OverlayInfo(const Image* init_pic, const Point& init_hotspot)
+		OverlayInfo(const Image* init_pic, const Vector2i& init_hotspot)
 		   : pic(init_pic), hotspot(init_hotspot) {
 		}
 
 		const Image* pic;
-		Point hotspot;
+		Vector2i hotspot;
 	};
 
 	/// A function returning Field::nodecaps() for the build overlay. This can be
@@ -84,11 +84,11 @@
 
 	/// Register an overlay at a location (node or triangle). hotspot is the point
 	/// of the picture that will be exactly over the location. If hotspot is
-	/// Point::invalid(), the center of the picture will be used as hotspot.
+	/// Vector2i::invalid(), the center of the picture will be used as hotspot.
 	void register_overlay(const Widelands::TCoords<>& coords,
 	                      const Image* pic,
 	                      int32_t level,
-	                      Point hotspot = Point::invalid(),
+	                      Vector2i hotspot = Vector2i::invalid(),
 	                      OverlayId overlay_id = 0);
 
 	/// removes all overlays when pic is nullptr.
@@ -111,14 +111,14 @@
 	struct RegisteredOverlays {
 		RegisteredOverlays(const OverlayId init_overlay_id,
 		                   const Image* init_pic,
-		                   const Point init_hotspot,
+		                   const Vector2i init_hotspot,
 		                   const int init_level)
 		   : pic(init_pic), hotspot(init_hotspot), level(init_level) {
 			overlay_ids.insert(init_overlay_id);
 		}
 		std::set<OverlayId> overlay_ids;
 		const Image* pic;
-		Point hotspot;
+		Vector2i hotspot;
 		int level;
 	};
 

=== modified file 'src/wui/fieldaction.cc'
--- src/wui/fieldaction.cc	2016-08-04 15:49:05 +0000
+++ src/wui/fieldaction.cc	2016-10-28 17:51:15 +0000
@@ -282,7 +282,7 @@
 	move_out_of_the_way();
 
 	// Now force the mouse onto the first button
-	set_mouse_pos(Point(17 + kBuildGridCellSize * best_tab_, fastclick_ ? 51 : 17));
+	set_mouse_pos(Vector2i(17 + kBuildGridCellSize * best_tab_, fastclick_ ? 51 : 17));
 
 	// Will only do something if we explicitly set another fast click panel
 	// than the first button

=== modified file 'src/wui/game_main_menu_save_game.cc'
--- src/wui/game_main_menu_save_game.cc	2016-08-04 18:09:55 +0000
+++ src/wui/game_main_menu_save_game.cc	2016-10-28 17:51:15 +0000
@@ -79,9 +79,8 @@
 	editbox_.changed.connect(boost::bind(&GameMainMenuSaveGame::edit_box_changed, this));
 	editbox_.ok.connect(boost::bind(&GameMainMenuSaveGame::ok, this));
 
-	button_ok_ =
-	   new UI::Button(this, "ok", DESCRIPTION_X, OK_Y, DESCRIPTION_WIDTH, BUTTON_HEIGHT,
-	                  g_gr->images().get("images/ui_basic/but4.png"), _("OK"), std::string(), false);
+	button_ok_ = new UI::Button(this, "ok", DESCRIPTION_X, OK_Y, DESCRIPTION_WIDTH, BUTTON_HEIGHT,
+	                            g_gr->images().get("images/ui_basic/but4.png"), _("OK"));
 	button_ok_->sigclicked.connect(boost::bind(&GameMainMenuSaveGame::ok, this));
 
 	UI::Button* cancelbtn =
@@ -138,7 +137,7 @@
 	Widelands::GamePreloadPacket gpdp;
 	gl.preload_game(gpdp);  //  This has worked before, no problem
 	{ editbox_.set_text(FileSystem::filename_without_ext(name.c_str())); }
-	button_ok_->set_enabled(true);
+	edit_box_changed();
 
 	// Try to translate the map name.
 	{
@@ -191,6 +190,7 @@
 		} catch (const WException&) {
 		}  //  we simply skip illegal entries
 	}
+	edit_box_changed();
 }
 
 void GameMainMenuSaveGame::select_by_name(std::string name) {

=== modified file 'src/wui/game_message_menu.cc'
--- src/wui/game_message_menu.cc	2016-09-16 10:32:40 +0000
+++ src/wui/game_message_menu.cc	2016-10-28 17:51:15 +0000
@@ -77,35 +77,35 @@
 	geologistsbtn_ =
 	   new UI::Button(this, "filter_geologists_messages", kPadding, kPadding, kButtonSize,
 	                  kButtonSize, g_gr->images().get("images/ui_basic/but0.png"),
-	                  g_gr->images().get("images/wui/fieldaction/menu_geologist.png"), "", true);
+	                  g_gr->images().get("images/wui/fieldaction/menu_geologist.png"));
 	geologistsbtn_->sigclicked.connect(
 	   boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::kGeologists));
 
 	economybtn_ =
 	   new UI::Button(this, "filter_economy_messages", 2 * kPadding + kButtonSize, kPadding,
 	                  kButtonSize, kButtonSize, g_gr->images().get("images/ui_basic/but0.png"),
-	                  g_gr->images().get("images/wui/stats/genstats_nrwares.png"), "", true);
+	                  g_gr->images().get("images/wui/stats/genstats_nrwares.png"));
 	economybtn_->sigclicked.connect(
 	   boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::kEconomy));
 
 	seafaringbtn_ =
 	   new UI::Button(this, "filter_seafaring_messages", 3 * kPadding + 2 * kButtonSize, kPadding,
 	                  kButtonSize, kButtonSize, g_gr->images().get("images/ui_basic/but0.png"),
-	                  g_gr->images().get("images/wui/buildings/start_expedition.png"), "", true);
+	                  g_gr->images().get("images/wui/buildings/start_expedition.png"));
 	seafaringbtn_->sigclicked.connect(
 	   boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::kSeafaring));
 
 	warfarebtn_ =
 	   new UI::Button(this, "filter_warfare_messages", 4 * kPadding + 3 * kButtonSize, kPadding,
 	                  kButtonSize, kButtonSize, g_gr->images().get("images/ui_basic/but0.png"),
-	                  g_gr->images().get("images/wui/messages/messages_warfare.png"), "", true);
+	                  g_gr->images().get("images/wui/messages/messages_warfare.png"));
 	warfarebtn_->sigclicked.connect(
 	   boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::kWarfare));
 
 	scenariobtn_ =
 	   new UI::Button(this, "filter_scenario_messages", 5 * kPadding + 4 * kButtonSize, kPadding,
 	                  kButtonSize, kButtonSize, g_gr->images().get("images/ui_basic/but0.png"),
-	                  g_gr->images().get("images/wui/menus/menu_objectives.png"), "", true);
+	                  g_gr->images().get("images/wui/menus/menu_objectives.png"));
 	scenariobtn_->sigclicked.connect(
 	   boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::kScenario));
 
@@ -140,8 +140,7 @@
 	                  (boost::format(_("G: %s"))
 	                   /** TRANSLATORS: Tooltip in the messages window */
 	                   % _("Center main mapview on location"))
-	                     .str(),
-	                  false);
+	                     .str());
 	centerviewbtn_->sigclicked.connect(boost::bind(&GameMessageMenu::center_view, this));
 
 	if (get_usedefaultpos())
@@ -445,7 +444,7 @@
 	if (Message const* const message =
 	       iplayer().player().messages()[MessageId((*list)[selection])]) {
 		assert(message->position());
-		iplayer().move_view_to(message->position());
+		iplayer().center_view_on_coords(message->position());
 	}
 }
 
@@ -501,7 +500,7 @@
 void GameMessageMenu::toggle_filter_messages_button(UI::Button& button,
                                                     Widelands::Message::Type msgtype) {
 	set_filter_messages_tooltips();
-	if (button.get_perm_pressed()) {
+	if (button.style() == UI::Button::Style::kPermpressed) {
 		button.set_perm_pressed(false);
 		message_filter_ = Widelands::Message::Type::kAllMessages;
 	} else {

=== modified file 'src/wui/game_options_sound_menu.cc'
--- src/wui/game_options_sound_menu.cc	2016-08-04 15:49:05 +0000
+++ src/wui/game_options_sound_menu.cc	2016-10-28 17:51:15 +0000
@@ -25,9 +25,10 @@
 GameOptionsSoundMenu::GameOptionsSoundMenu(InteractiveGameBase& gb,
                                            UI::UniqueWindow::Registry& registry)
    : UI::UniqueWindow(&gb, "sound_options_menu", &registry, 160, 160, _("Sound Options")),
-     ingame_music(this, Point(hmargin(), vmargin()), _("Enable Music")),
-     ingame_sound(
-        this, Point(hmargin(), vmargin() + kStateboxSize + vspacing()), _("Enable Sound Effects")),
+     ingame_music(this, Vector2i(hmargin(), vmargin()), _("Enable Music")),
+     ingame_sound(this,
+                  Vector2i(hmargin(), vmargin() + kStateboxSize + vspacing()),
+                  _("Enable Sound Effects")),
      ingame_music_volume_label(this,
                                hmargin(),
                                vmargin() + 2 * (kStateboxSize + vspacing()) + vbigspacing(),

=== modified file 'src/wui/game_summary.cc'
--- src/wui/game_summary.cc	2016-08-04 15:49:05 +0000
+++ src/wui/game_summary.cc	2016-10-28 17:51:15 +0000
@@ -24,6 +24,7 @@
 
 #include "base/time_string.h"
 #include "graphic/graphic.h"
+#include "graphic/playercolor.h"
 #include "logic/game.h"
 #include "logic/player.h"
 #include "logic/playersmanager.h"
@@ -36,14 +37,6 @@
 #include "wui/interactive_gamebase.h"
 #include "wui/interactive_player.h"
 
-namespace {
-static char const* const flag_pictures[] = {
-   "images/players/genstats_enable_plr_01.png", "images/players/genstats_enable_plr_02.png",
-   "images/players/genstats_enable_plr_03.png", "images/players/genstats_enable_plr_04.png",
-   "images/players/genstats_enable_plr_05.png", "images/players/genstats_enable_plr_06.png",
-   "images/players/genstats_enable_plr_07.png", "images/players/genstats_enable_plr_08.png"};
-}  // namespace
-
 #define PADDING 4
 
 GameSummaryScreen::GameSummaryScreen(InteractiveGameBase* parent, UI::UniqueWindow::Registry* r)
@@ -153,7 +146,9 @@
 		Widelands::Player* p = game_.get_player(pes.player);
 		UI::Table<uintptr_t const>::EntryRecord& te = players_table_->add(i);
 		// Player name & pic
-		const Image* player_image = g_gr->images().get(flag_pictures[pes.player - 1]);
+		const Image* player_image =
+		   playercolor_image(pes.player - 1, g_gr->images().get("images/players/genstats_player.png"),
+		                     g_gr->images().get("images/players/genstats_player_pc.png"));
 		assert(player_image);
 		te.set_picture(0, player_image, p->get_name());
 		// Team

=== modified file 'src/wui/game_tips.cc'
--- src/wui/game_tips.cc	2016-08-04 15:49:05 +0000
+++ src/wui/game_tips.cc	2016-10-28 17:51:15 +0000
@@ -104,15 +104,14 @@
 	assert(pic_background);
 
 	RenderTarget& rt = *g_gr->get_render_target();
-	Rect tips_area;
 
 	uint16_t w = pic_background->width();
 	uint16_t h = pic_background->height();
-	Point pt((g_gr->get_xres() - w) / 2, (g_gr->get_yres() - h) / 2);
-	tips_area = Rect(pt, w, h);
+	Vector2f pt((g_gr->get_xres() - w) / 2, (g_gr->get_yres() - h) / 2);
+	Rectf tips_area(pt, w, h);
 	rt.blit(pt, pic_background);
 
-	Point center(tips_area.x + tips_area.w / 2, tips_area.y + tips_area.h / 2);
 	const Image* rendered_text = UI::g_fh1->render(as_game_tip(tips_[index].text), tips_area.w);
-	rt.blit(center - Point(rendered_text->width() / 2, rendered_text->height() / 2), rendered_text);
+	rt.blit(tips_area.center() - Vector2f(rendered_text->width() / 2, rendered_text->height() / 2),
+	        rendered_text);
 }

=== modified file 'src/wui/general_statistics_menu.cc'
--- src/wui/general_statistics_menu.cc	2016-08-04 15:49:05 +0000
+++ src/wui/general_statistics_menu.cc	2016-10-28 17:51:15 +0000
@@ -41,14 +41,6 @@
 #include "ui_basic/textarea.h"
 #include "wui/interactive_player.h"
 
-namespace {
-static char const* const flag_pictures[] = {
-   "images/players/genstats_enable_plr_01.png", "images/players/genstats_enable_plr_02.png",
-   "images/players/genstats_enable_plr_03.png", "images/players/genstats_enable_plr_04.png",
-   "images/players/genstats_enable_plr_05.png", "images/players/genstats_enable_plr_06.png",
-   "images/players/genstats_enable_plr_07.png", "images/players/genstats_enable_plr_08.png"};
-}  // namespace
-
 using namespace Widelands;
 
 #define PLOT_HEIGHT 130
@@ -85,7 +77,7 @@
 	}
 
 	for (Game::GeneralStatsVector::size_type i = 0; i < general_statistics_size; ++i) {
-		const RGBColor& color = Player::Colors[i];
+		const RGBColor& color = kPlayerColors[i];
 		plot_.register_plot_data(i * ndatasets_ + 0, &genstats[i].land_size, color);
 		plot_.register_plot_data(i * ndatasets_ + 1, &genstats[i].nr_workers, color);
 		plot_.register_plot_data(i * ndatasets_ + 2, &genstats[i].nr_buildings, color);
@@ -116,7 +108,9 @@
 	iterate_players_existing_novar(p, nr_players, game)++ plr_in_game;
 
 	iterate_players_existing_const(p, nr_players, game, player) {
-		const Image* player_image = g_gr->images().get(flag_pictures[p - 1]);
+		const Image* player_image =
+		   playercolor_image(p - 1, g_gr->images().get("images/players/genstats_player.png"),
+		                     g_gr->images().get("images/players/genstats_player_pc.png"));
 		assert(player_image);
 		UI::Button& cb = *new UI::Button(hbox1, "playerbutton", 0, 0, 25, 25,
 		                                 g_gr->images().get("images/ui_basic/but4.png"), player_image,
@@ -137,63 +131,64 @@
 
 	UI::Radiobutton* btn;
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_landsize.png"), _("Land"),
 	                       &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_nrworkers.png"),
 	                       _("Workers"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_nrbuildings.png"),
 	                       _("Buildings"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_nrwares.png"), _("Wares"),
 	                       &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_productivity.png"),
 	                       _("Productivity"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_casualties.png"),
 	                       _("Casualties"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_kills.png"), _("Kills"),
 	                       &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_msites_lost.png"),
 	                       _("Military buildings lost"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_msites_defeated.png"),
 	                       _("Military buildings defeated"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_civil_blds_lost.png"),
 	                       _("Civilian buildings lost"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
-	radiogroup_.add_button(hbox2, Point(0, 0),
+	radiogroup_.add_button(hbox2, Vector2i(0, 0),
 	                       g_gr->images().get("images/wui/stats/genstats_militarystrength.png"),
 	                       _("Military"), &btn);
 	hbox2->add(btn, UI::Align::kLeft, false, true);
 
 	if (hook) {
-		radiogroup_.add_button(hbox2, Point(0, 0), g_gr->images().get(cs_pic), cs_name.c_str(), &btn);
+		radiogroup_.add_button(
+		   hbox2, Vector2i(0, 0), g_gr->images().get(cs_pic), cs_name.c_str(), &btn);
 		hbox2->add(btn, UI::Align::kLeft, false, true);
 	}
 
@@ -215,7 +210,8 @@
 		my_registry_->time = plot_.get_time();
 		PlayerNumber const nr_players = game.map().get_nrplayers();
 		iterate_players_existing_novar(p, nr_players, game) {
-			my_registry_->selected_players[p - 1] = cbs_[p - 1]->get_perm_pressed();
+			my_registry_->selected_players[p - 1] =
+			   cbs_[p - 1]->style() == UI::Button::Style::kPermpressed;
 		}
 	}
 }
@@ -232,9 +228,9 @@
  */
 void GeneralStatisticsMenu::cb_changed_to(int32_t const id) {
 	// This represents our player number
-	cbs_[id - 1]->set_perm_pressed(!cbs_[id - 1]->get_perm_pressed());
-
-	plot_.show_plot((id - 1) * ndatasets_ + selected_information_, cbs_[id - 1]->get_perm_pressed());
+	cbs_[id - 1]->toggle();
+	plot_.show_plot((id - 1) * ndatasets_ + selected_information_,
+	                cbs_[id - 1]->style() == UI::Button::Style::kPermpressed);
 }
 
 /*
@@ -245,7 +241,7 @@
 	   dynamic_cast<InteractiveGameBase&>(*get_parent()).game().get_general_statistics().size();
 	for (uint32_t i = 0; i < statistics_size; ++i)
 		if (cbs_[i]) {
-			plot_.show_plot(i * ndatasets_ + id, cbs_[i]->get_perm_pressed());
+			plot_.show_plot(i * ndatasets_ + id, cbs_[i]->style() == UI::Button::Style::kPermpressed);
 			plot_.show_plot(i * ndatasets_ + selected_information_, false);
 		}
 	selected_information_ = id;

=== modified file 'src/wui/general_statistics_menu.h'
--- src/wui/general_statistics_menu.h	2016-08-04 15:49:05 +0000
+++ src/wui/general_statistics_menu.h	2016-10-28 17:51:15 +0000
@@ -20,7 +20,7 @@
 #ifndef WL_WUI_GENERAL_STATISTICS_MENU_H
 #define WL_WUI_GENERAL_STATISTICS_MENU_H
 
-#include "logic/constants.h"
+#include "graphic/playercolor.h"
 #include "ui_basic/box.h"
 #include "ui_basic/button.h"
 #include "ui_basic/radiobutton.h"
@@ -39,7 +39,7 @@
 		Registry()
 		   : UI::UniqueWindow::Registry(),
 		     selected_information(0),
-		     selected_players(true, MAX_PLAYERS),
+		     selected_players(true, kMaxPlayers),
 		     time(WuiPlotArea::TIME_GAME) {
 		}
 
@@ -57,7 +57,7 @@
 	WuiPlotArea plot_;
 	UI::Radiogroup radiogroup_;
 	int32_t selected_information_;
-	UI::Button* cbs_[MAX_PLAYERS];
+	UI::Button* cbs_[kMaxPlayers];
 	uint32_t ndatasets_;
 
 	void clicked_help();

=== modified file 'src/wui/interactive_base.cc'
--- src/wui/interactive_base.cc	2016-09-25 16:45:37 +0000
+++ src/wui/interactive_base.cc	2016-10-28 17:51:15 +0000
@@ -81,7 +81,7 @@
      show_workarea_preview_(global_s.get_bool("workareapreview", true)),
      chat_overlay_(new ChatOverlay(this, 10, 25, get_w() / 2, get_h() - 25)),
      toolbar_(this, 0, 0, UI::Box::Horizontal),
-     m(new InteractiveBaseInternals(new QuickNavigation(the_egbase, get_w(), get_h()))),
+     m(new InteractiveBaseInternals(new QuickNavigation(the_egbase, this))),
      field_overlay_manager_(new FieldOverlayManager()),
      edge_overlay_manager_(new EdgeOverlayManager()),
      egbase_(the_egbase),
@@ -116,10 +116,7 @@
 		});
 
 	toolbar_.set_layout_toplevel(true);
-	m->quicknavigation->set_setview(boost::bind(&MapView::set_viewpoint, this, _1, true));
-	set_changeview(boost::bind(&QuickNavigation::view_changed, m->quicknavigation.get(), _1, _2));
-
-	changeview.connect(boost::bind(&InteractiveBase::mainview_move, this, _1, _2));
+	changeview.connect([this](bool) { mainview_move(); });
 
 	set_border_snap_distance(global_s.get_int("border_snap_distance", 0));
 	set_panel_snap_distance(global_s.get_int("panel_snap_distance", 10));
@@ -161,13 +158,13 @@
 		Widelands::MapTriangleRegion<> mr(map, Area<TCoords<>>(center.triangle, sel_.radius));
 		do
 			field_overlay_manager_->register_overlay(
-			   mr.location(), sel_.pic, 7, Point::invalid(), jobid);
+			   mr.location(), sel_.pic, 7, Vector2i::invalid(), jobid);
 		while (mr.advance(map));
 	} else {
 		Widelands::MapRegion<> mr(map, Area<>(center.node, sel_.radius));
 		do
 			field_overlay_manager_->register_overlay(
-			   mr.location(), sel_.pic, 7, Point::invalid(), jobid);
+			   mr.location(), sel_.pic, 7, Vector2i::invalid(), jobid);
 		while (mr.advance(map));
 		if (upcast(InteractiveGameBase const, igbase, this))
 			if (upcast(Widelands::ProductionSite, productionsite, map[center.node].get_immovable())) {
@@ -199,12 +196,12 @@
 /*
  * Set/Unset sel picture
  */
-void InteractiveBase::set_sel_picture(const char* const file) {
-	sel_.pic = g_gr->images().get(file);
+void InteractiveBase::set_sel_picture(const Image* image) {
+	sel_.pic = image;
 	set_sel_pos(get_sel_pos());  //  redraw
 }
 void InteractiveBase::unset_sel_picture() {
-	set_sel_picture("images/ui_basic/fsel.png");
+	set_sel_picture(g_gr->images().get("images/ui_basic/fsel.png"));
 }
 
 bool InteractiveBase::buildhelp() const {
@@ -255,7 +252,7 @@
 		Widelands::MapHollowRegion<> mr(map, hollow_area);
 		do
 			field_overlay_manager_->register_overlay(
-			   mr.location(), workarea_pics_[wa_index], 0, Point::invalid(), overlay_id);
+			   mr.location(), workarea_pics_[wa_index], 0, Vector2i::invalid(), overlay_id);
 		while (mr.advance(map));
 		wa_index++;
 		hollow_area.hole_radius = hollow_area.radius;
@@ -288,19 +285,19 @@
 	if (keyboard_free() && Panel::allow_user_input()) {
 		if (get_key_state(SDL_SCANCODE_UP) ||
 		    (get_key_state(SDL_SCANCODE_KP_8) && (SDL_GetModState() ^ KMOD_NUM))) {
-			set_rel_viewpoint(Point(0, -scrollval), false);
+			pan_by(Vector2i(0, -scrollval));
 		}
 		if (get_key_state(SDL_SCANCODE_DOWN) ||
 		    (get_key_state(SDL_SCANCODE_KP_2) && (SDL_GetModState() ^ KMOD_NUM))) {
-			set_rel_viewpoint(Point(0, scrollval), false);
+			pan_by(Vector2i(0, scrollval));
 		}
 		if (get_key_state(SDL_SCANCODE_LEFT) ||
 		    (get_key_state(SDL_SCANCODE_KP_4) && (SDL_GetModState() ^ KMOD_NUM))) {
-			set_rel_viewpoint(Point(-scrollval, 0), false);
+			pan_by(Vector2i(-scrollval, 0));
 		}
 		if (get_key_state(SDL_SCANCODE_RIGHT) ||
 		    (get_key_state(SDL_SCANCODE_KP_6) && (SDL_GetModState() ^ KMOD_NUM))) {
-			set_rel_viewpoint(Point(scrollval, 0), false);
+			pan_by(Vector2i(scrollval, 0));
 		}
 	}
 	egbase().think();  // Call game logic here. The game advances.
@@ -330,7 +327,7 @@
 		if (is_game) {
 			const std::string gametime(gametimestring(egbase().get_gametime(), true));
 			const std::string gametime_text = as_condensed(gametime);
-			dst.blit(Point(5, 5), UI::g_fh1->render(gametime_text), BlendMode::UseAlpha,
+			dst.blit(Vector2f(5, 5), UI::g_fh1->render(gametime_text), BlendMode::UseAlpha,
 			         UI::Align::kTopLeft);
 
 			static boost::format node_format("(%i, %i)");
@@ -341,8 +338,8 @@
 			node_text = as_condensed((node_format % sel_.pos.node.x % sel_.pos.node.y % height).str());
 		}
 
-		dst.blit(Point(get_w() - 5, get_h() - 5), UI::g_fh1->render(node_text), BlendMode::UseAlpha,
-		         UI::Align::kBottomRight);
+		dst.blit(Vector2f(get_w() - 5, get_h() - 5), UI::g_fh1->render(node_text),
+		         BlendMode::UseAlpha, UI::Align::kBottomRight);
 	}
 
 	// Blit FPS when playing a game in debug mode.
@@ -350,101 +347,33 @@
 		static boost::format fps_format("%5.1f fps (avg: %5.1f fps)");
 		const Image* rendered_text = UI::g_fh1->render(as_condensed(
 		   (fps_format % (1000.0 / frametime_) % (1000.0 / (avg_usframetime_ / 1000))).str()));
-		dst.blit(Point((get_w() - rendered_text->width()) / 2, 5), rendered_text, BlendMode::UseAlpha,
-		         UI::Align::kLeft);
+		dst.blit(Vector2f((get_w() - rendered_text->width()) / 2, 5), rendered_text,
+		         BlendMode::UseAlpha, UI::Align::kLeft);
 	}
 }
 
-/** InteractiveBase::mainview_move(int32_t x, int32_t y)
- *
- * Signal handler for the main view's warpview updates the mini map's
- * viewpos marker position
- */
-void InteractiveBase::mainview_move(int32_t x, int32_t y) {
+void InteractiveBase::mainview_move() {
 	if (m->minimap.window) {
-		const Map& map = egbase().map();
-		const int32_t maxx = MapviewPixelFunctions::get_map_end_screen_x(map);
-		const int32_t maxy = MapviewPixelFunctions::get_map_end_screen_y(map);
-
-		x += get_w() >> 1;
-		if (x >= maxx)
-			x -= maxx;
-		y += get_h() >> 1;
-		if (y >= maxy)
-			y -= maxy;
-
-		m->mm->set_view_pos(x, y);
+		m->mm->set_view(get_view_area());
 	}
 }
 
-/*
-===============
-Called whenever the player clicks on a location on the minimap.
-Warps the main mapview position to the clicked location.
-===============
-*/
-void InteractiveBase::minimap_warp(int32_t x, int32_t y) {
-	x -= get_w() >> 1;
-	y -= get_h() >> 1;
-	const Map& map = egbase().map();
-	if (x < 0)
-		x += map.get_width() * kTriangleWidth;
-	if (y < 0)
-		y += map.get_height() * kTriangleHeight;
-	set_viewpoint(Point(x, y), true);
-}
-
-/*
-===============
-Move the mainview to the given position (in node coordinates)
-===============
-*/
-void InteractiveBase::move_view_to(const Coords c) {
-	assert(0 <= c.x);
-	assert(c.x < egbase().map().get_width());
-	assert(0 <= c.y);
-	assert(c.y < egbase().map().get_height());
-
-	const Map& map = egbase().map();
-	uint32_t const x = (c.x + (c.y & 1) * 0.5) * kTriangleWidth;
-	uint32_t const y = c.y * kTriangleHeight - map[c].get_height() * kHeightFactor;
-	if (m->minimap.window)
-		m->mm->set_view_pos(x, y);
-	minimap_warp(x, y);
-}
-
-/*
-===============
-Center the mainview on the given position (in pixels)
-===============
-*/
-void InteractiveBase::move_view_to_point(Point pos) {
-	if (m->minimap.window)
-		m->mm->set_view_pos(pos.x, pos.y);
-
-	set_viewpoint(pos - Point(get_w() / 2, get_h() / 2), true);
-}
-
 // Open the minimap or close it if it's open
 void InteractiveBase::toggle_minimap() {
 	if (m->minimap.window) {
 		delete m->minimap.window;
 	} else {
 		m->mm = new MiniMap(*this, &m->minimap);
-		m->mm->warpview.connect(boost::bind(&InteractiveBase::minimap_warp, this, _1, _2));
-
-		// make sure the viewpos marker is at the right pos to start with
-		const Point p = get_viewpoint();
-
-		mainview_move(p.x, p.y);
+		m->mm->warpview.connect(boost::bind(&InteractiveBase::center_view_on_map_pixel, this, _1));
+		mainview_move();
 	}
 }
 
 const std::vector<QuickNavigation::Landmark>& InteractiveBase::landmarks() {
 	return m->quicknavigation->landmarks();
 }
-void InteractiveBase::set_landmark(size_t key, const Point& point) {
-	m->quicknavigation->set_landmark(key, point);
+void InteractiveBase::set_landmark(size_t key, const QuickNavigation::View& view) {
+	m->quicknavigation->set_landmark(key, view);
 }
 
 /**
@@ -461,7 +390,7 @@
 Exposes the Registry object of the minimap to derived classes
 ===========
 */
-UI::UniqueWindow::Registry& InteractiveBase::minimap_registry() {
+MiniMap::Registry& InteractiveBase::minimap_registry() {
 	return m->minimap;
 }
 
@@ -742,7 +671,7 @@
 			name = "images/wui/overlays/roadb_red.png";
 
 		field_overlay_manager_->register_overlay(
-		   neighb, g_gr->images().get(name), 7, Point::invalid(), road_buildhelp_overlay_jobid_);
+		   neighb, g_gr->images().get(name), 7, Vector2i::invalid(), road_buildhelp_overlay_jobid_);
 	}
 }
 

=== modified file 'src/wui/interactive_base.h'
--- src/wui/interactive_base.h	2016-08-04 15:49:05 +0000
+++ src/wui/interactive_base.h	2016-10-28 17:51:15 +0000
@@ -37,6 +37,7 @@
 #include "wui/edge_overlay_manager.h"
 #include "wui/field_overlay_manager.h"
 #include "wui/mapview.h"
+#include "wui/minimap.h"
 #include "wui/quicknavigation.h"
 
 namespace Widelands {
@@ -117,9 +118,6 @@
 	}
 	void set_sel_radius(uint32_t);
 
-	void move_view_to(Widelands::Coords);
-	void move_view_to_point(Point pos);
-
 	//  display flags
 	uint32_t get_display_flags() const;
 	void set_display_flags(uint32_t flags);
@@ -166,8 +164,9 @@
 
 	// Returns the list of landmarks that have been mapped to the keys 0-9
 	const std::vector<QuickNavigation::Landmark>& landmarks();
+
 	// Sets the landmark for the keyboard 'key' to 'point'
-	void set_landmark(size_t key, const Point& point);
+	void set_landmark(size_t key, const QuickNavigation::View& view);
 
 protected:
 	// Will be called whenever the buildhelp is changed with the new 'value'.
@@ -176,18 +175,17 @@
 	void toggle_buildhelp();
 	void hide_minimap();
 
-	UI::UniqueWindow::Registry& minimap_registry();
+	MiniMap::Registry& minimap_registry();
 
-	void mainview_move(int32_t x, int32_t y);
-	void minimap_warp(int32_t x, int32_t y);
+	void mainview_move();
 
 	void draw_overlay(RenderTarget&) override;
 	bool handle_key(bool down, SDL_Keysym) override;
 
 	void unset_sel_picture();
-	void set_sel_picture(const char* const);
+	void set_sel_picture(const Image* image);
 	void adjust_toolbar_position() {
-		toolbar_.set_pos(Point((get_inner_w() - toolbar_.get_w()) >> 1, get_inner_h() - 34));
+		toolbar_.set_pos(Vector2i((get_inner_w() - toolbar_.get_w()) >> 1, get_inner_h() - 34));
 	}
 
 	// TODO(sirver): why are these protected?

=== modified file 'src/wui/interactive_gamebase.cc'
--- src/wui/interactive_gamebase.cc	2016-08-04 15:49:05 +0000
+++ src/wui/interactive_gamebase.cc	2016-10-28 17:51:15 +0000
@@ -34,6 +34,7 @@
 #include "logic/player.h"
 #include "profile/profile.h"
 #include "wui/game_summary.h"
+#include "wui/shipwindow.h"
 
 namespace {
 
@@ -61,8 +62,11 @@
 	TOOLBAR_BUTTON_COMMON_PARAMETERS(name), g_gr->images().get("images/" picture ".png"), tooltip
 
      toggle_buildhelp_(INIT_BTN(
-        "wui/menus/menu_toggle_buildhelp", "buildhelp", _("Show Building Spaces (on/off)"))) {
+        "wui/menus/menu_toggle_buildhelp", "buildhelp", _("Show Building Spaces (on/off)"))),
+     reset_zoom_(INIT_BTN("wui/menus/menu_reset_zoom", "reset_zoom", _("Reset zoom"))) {
 	toggle_buildhelp_.sigclicked.connect(boost::bind(&InteractiveGameBase::toggle_buildhelp, this));
+	reset_zoom_.sigclicked.connect(
+	   [this] { zoom_around(1.f, Vector2f(get_w() / 2.f, get_h() / 2.f)); });
 }
 
 /// \return a pointer to the running \ref Game instance.
@@ -107,7 +111,7 @@
 		}
 
 		if (!game_speed.empty()) {
-			dst.blit(Point(get_w() - 5, 5), UI::g_fh1->render(game_speed), BlendMode::UseAlpha,
+			dst.blit(Vector2f(get_w() - 5, 5), UI::g_fh1->render(game_speed), BlendMode::UseAlpha,
 			         UI::Align::kTopRight);
 		}
 	}
@@ -158,7 +162,7 @@
 	for (Widelands::Bob* temp_ship : ships) {
 		if (upcast(Widelands::Ship, ship, temp_ship)) {
 			if (can_see(ship->get_owner()->player_number())) {
-				ship->show_window(*this);
+				new ShipWindow(*this, *ship);
 				return true;
 			}
 		}

=== modified file 'src/wui/interactive_gamebase.h'
--- src/wui/interactive_gamebase.h	2016-08-04 15:49:05 +0000
+++ src/wui/interactive_gamebase.h	2016-10-28 17:51:15 +0000
@@ -31,8 +31,7 @@
 
 class InteractiveGameBase : public InteractiveBase {
 public:
-	class GameMainMenuWindows {
-	public:
+	struct GameMainMenuWindows {
 		UI::UniqueWindow::Registry loadgame;
 		UI::UniqueWindow::Registry savegame;
 		UI::UniqueWindow::Registry readme;
@@ -94,6 +93,7 @@
 	UI::UniqueWindow::Registry game_summary_;
 
 	UI::Button toggle_buildhelp_;
+	UI::Button reset_zoom_;
 
 private:
 	void on_buildhelp_changed(const bool value) override;

=== modified file 'src/wui/interactive_player.cc'
--- src/wui/interactive_player.cc	2016-08-04 15:49:05 +0000
+++ src/wui/interactive_player.cc	2016-10-28 17:51:15 +0000
@@ -31,7 +31,6 @@
 #include "economy/flag.h"
 #include "game_io/game_loader.h"
 #include "logic/cmd_queue.h"
-#include "logic/constants.h"
 #include "logic/map_objects/immovable.h"
 #include "logic/map_objects/tribes/building.h"
 #include "logic/map_objects/tribes/constructionsite.h"
@@ -104,12 +103,16 @@
 	// they should not at all be generated. -> implement more dynamic toolbar UI
 	toolbar_.add(&toggle_options_menu_, UI::Align::kLeft);
 	toolbar_.add(&toggle_statistics_menu_, UI::Align::kLeft);
+	toolbar_.add_space(15);
 	toolbar_.add(&toggle_minimap_, UI::Align::kLeft);
 	toolbar_.add(&toggle_buildhelp_, UI::Align::kLeft);
+	toolbar_.add(&reset_zoom_, UI::Align::kLeft);
+	toolbar_.add_space(15);
 	if (multiplayer) {
 		toolbar_.add(&toggle_chat_, UI::Align::kLeft);
 		toggle_chat_.set_visible(false);
 		toggle_chat_.set_enabled(false);
+		toolbar_.add_space(15);
 	}
 
 	toolbar_.add(&toggle_objectives_, UI::Align::kLeft);
@@ -322,7 +325,7 @@
 				break;
 		/* no break */
 		case SDLK_HOME:
-			move_view_to(game().map().get_starting_pos(player_number_));
+			center_view_on_coords(game().map().get_starting_pos(player_number_));
 			return true;
 
 		case SDLK_KP_ENTER:
@@ -364,7 +367,7 @@
 	}
 
 	int const n = atoi(args[1].c_str());
-	if (n < 1 || n > MAX_PLAYERS || !game().get_player(n)) {
+	if (n < 1 || n > kMaxPlayers || !game().get_player(n)) {
 		DebugConsole::write(str(boost::format("Player #%1% does not exist.") % n));
 		return;
 	}

=== modified file 'src/wui/itemwaresdisplay.cc'
--- src/wui/itemwaresdisplay.cc	2016-08-04 15:49:05 +0000
+++ src/wui/itemwaresdisplay.cc	2016-10-28 17:51:15 +0000
@@ -98,7 +98,7 @@
 void ItemWaresDisplay::draw(RenderTarget& dst) {
 	const Widelands::TribeDescr& tribe(player().tribe());
 
-	dst.fill_rect(Rect(Point(0, 0), get_w(), get_h()), RGBAColor(0, 0, 0, 0));
+	dst.fill_rect(Rectf(0, 0, get_w(), get_h()), RGBAColor(0, 0, 0, 0));
 
 	for (uint32_t idx = 0; idx < items_.size(); ++idx) {
 		const Item& it = items_[idx];
@@ -110,13 +110,14 @@
 
 		if (it.worker) {
 			y += IWD_WorkerBaseline;
-			dst.blit_animation(Point(x + (IWD_ItemWidth / 2), y + (IWD_ItemHeight / 2)),
+			constexpr float kZoom = 1.f;
+			dst.blit_animation(Vector2f(x + (IWD_ItemWidth / 2.f), y + (IWD_ItemHeight / 2.f)), kZoom,
 			                   tribe.get_worker_descr(it.index)->main_animation(), 0,
 			                   player().get_playercolor());
 		} else {
 			y += IWD_WareBaseLine;
 			if (tribe.get_ware_descr(it.index)->icon())
-				dst.blit(Point(x, y), tribe.get_ware_descr(it.index)->icon());
+				dst.blit(Vector2f(x, y), tribe.get_ware_descr(it.index)->icon());
 		}
 	}
 }

=== modified file 'src/wui/login_box.cc'
--- src/wui/login_box.cc	2016-08-07 08:18:51 +0000
+++ src/wui/login_box.cc	2016-10-28 17:51:15 +0000
@@ -42,9 +42,9 @@
 	                                        _("WARNING: Password will be shown and saved readable!"),
 	                                        UI::Align::kLeft);
 
-	cb_register = new UI::Checkbox(this, Point(margin, 110), _("Log in to a registered account"), "",
-	                               get_inner_w() - 2 * margin);
-	cb_auto_log = new UI::Checkbox(this, Point(margin, 135),
+	cb_register = new UI::Checkbox(this, Vector2i(margin, 110), _("Log in to a registered account"),
+	                               "", get_inner_w() - 2 * margin);
+	cb_auto_log = new UI::Checkbox(this, Vector2i(margin, 135),
 	                               _("Automatically use this login information from now on."), "",
 	                               get_inner_w() - 2 * margin);
 

=== modified file 'src/wui/mapdetails.cc'
--- src/wui/mapdetails.cc	2016-08-04 15:49:05 +0000
+++ src/wui/mapdetails.cc	2016-10-28 17:51:15 +0000
@@ -111,7 +111,7 @@
 void MapDetails::update_layout() {
 	// Adjust sizes for show / hide suggested teams
 	if (suggested_teams_box_->is_visible()) {
-		suggested_teams_box_->set_pos(Point(0, max_h_ - suggested_teams_box_->get_h()));
+		suggested_teams_box_->set_pos(Vector2i(0, max_h_ - suggested_teams_box_->get_h()));
 		main_box_.set_size(main_box_.get_w(), max_h_ - suggested_teams_box_->get_h() - padding_);
 	} else {
 		main_box_.set_size(main_box_.get_w(), max_h_);

=== modified file 'src/wui/mapview.cc'
--- src/wui/mapview.cc	2016-08-04 15:49:05 +0000
+++ src/wui/mapview.cc	2016-10-28 17:51:15 +0000
@@ -20,58 +20,107 @@
 #include "wui/mapview.h"
 
 #include "base/macros.h"
+#include "base/math.h"
 #include "graphic/game_renderer.h"
 #include "graphic/graphic.h"
 #include "graphic/rendertarget.h"
 #include "logic/map.h"
+#include "logic/map_objects/draw_text.h"
 #include "logic/player.h"
 #include "wlapplication.h"
 #include "wui/interactive_base.h"
 #include "wui/interactive_player.h"
 #include "wui/mapviewpixelfunctions.h"
 
+namespace {
+
+// Given 'p' on a torus of dimension ('h', 'h') and 'r' that contains this
+// point, change 'p' so that r.x < p.x < r.x + r.w and similar for y.
+// Containing is defined as such that the shortest distance between the center
+// of 'r' is smaller than (r.w / 2, r.h / 2). If 'p' is NOT contained in 'r'
+// this method will loop forever.
+Vector2f move_inside(Vector2f p, const Rectf& r, float w, float h) {
+	while (p.x < r.x && r.x < r.x + r.w) {
+		p.x += w;
+	}
+	while (p.x > r.x && r.x > r.x + r.w) {
+		p.x -= w;
+	}
+	while (p.y < r.y && r.y < r.y + r.y) {
+		p.y += h;
+	}
+	while (p.y > r.y && r.y > r.y + r.y) {
+		p.y -= h;
+	}
+	return p;
+}
+
+}  // namespace
+
 MapView::MapView(
    UI::Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, InteractiveBase& player)
    : UI::Panel(parent, x, y, w, h),
      renderer_(new GameRenderer()),
      intbase_(player),
-     viewpoint_(Point(0, 0)),
+     viewpoint_(0.f, 0.f),
+     zoom_(1.f),
      dragging_(false) {
 }
 
 MapView::~MapView() {
-	// explicit destructor so that smart pointer destructors
-	// with forward-declared types are properly instantiated
+}
+
+Vector2f MapView::get_viewpoint() const {
+	return viewpoint_;
+}
+
+Vector2f MapView::to_panel(const Vector2f& map_pixel) const {
+	return MapviewPixelFunctions::map_to_panel(viewpoint_, zoom_, map_pixel);
+}
+
+Vector2f MapView::to_map(const Vector2f& panel_pixel) const {
+	return MapviewPixelFunctions::panel_to_map(viewpoint_, zoom_, panel_pixel);
 }
 
 /// Moves the mouse cursor so that it is directly above the given node
 void MapView::warp_mouse_to_node(Widelands::Coords const c) {
+	// This problem is surprisingly hard: We want to figure out if the
+	// 'minimap_pixel' is currently visible on screen and if so, what pixel it
+	// has. Since Wideland's map is a torus, the current 'view_area' could span
+	// the origin. Without loss of generality we only discuss x - y follows
+	// accordingly.
+	// Depending on the interpretation, the area spanning the origin means:
+	// 1) either view_area.x + view_area.w < view_area.x - which would be surprising to
+	//    the rest of Widelands.
+	// 2) map_pixel.x > get_map_end_screen_x(map).
+	//
+	// We are dealing with the problem in two steps: first we figure out if
+	// 'map_pixel' is visible on screen. To do this, we calculate the shortest
+	// distance to 'view_area.center()' on a torus. If the distance is less than
+	// 'view_area.w / 2', the point is visible.
+	// If that is the case, we move the point by adding or substracting
+	// 'get_map_end_screen_x()' such that the point is contained inside of
+	// 'view_area'. If we now convert to panel pixels, we are guaranteed that
+	// the pixel we get back is inside the panel.
+
 	const Widelands::Map& map = intbase().egbase().map();
-	Point p;
-	MapviewPixelFunctions::get_save_pix(map, c, p.x, p.y);
-	p -= viewpoint_;
-
-	//  If the user has scrolled the node outside the viewable area, he most
-	//  surely doesn't want to jump there.
-	if (p.x < get_w() && p.y < get_h()) {
-		if (p.x <= 0)
-			warp_mouse_to_node(Widelands::Coords(c.x + map.get_width(), c.y));
-		else if (p.y <= 0)
-			warp_mouse_to_node(Widelands::Coords(c.x, c.y + map.get_height()));
-		else {
-			set_mouse_pos(p);
-			track_sel(p);
-		}
+	const Vector2f map_pixel = MapviewPixelFunctions::to_map_pixel_with_normalization(map, c);
+	const Rectf view_area = get_view_area();
+
+	const Vector2f view_center = view_area.center();
+	const int w = MapviewPixelFunctions::get_map_end_screen_x(map);
+	const int h = MapviewPixelFunctions::get_map_end_screen_y(map);
+	const Vector2f dist = MapviewPixelFunctions::calc_pix_difference(map, view_center, map_pixel);
+
+	// Check if the point is visible on screen.
+	if (dist.x > view_area.w / 2.f || dist.y > view_area.h / 2.f) {
+		return;
 	}
+	const Vector2f in_panel = to_panel(move_inside(map_pixel, view_area, w, h));
+	set_mouse_pos(round(in_panel));
+	track_sel(in_panel);
 }
 
-/*
-===============
-This is the guts!! this function draws the whole
-map the user can see. we spend a lot of time
-in this function
-===============
-*/
 void MapView::draw(RenderTarget& dst) {
 	Widelands::EditorGameBase& egbase = intbase().egbase();
 
@@ -82,15 +131,29 @@
 			return;
 	}
 
+	TextToDraw draw_text = TextToDraw::kNone;
+	auto display_flags = intbase().get_display_flags();
+	if (display_flags & InteractiveBase::dfShowCensus) {
+		draw_text = draw_text | TextToDraw::kCensus;
+	}
+	if (display_flags & InteractiveBase::dfShowStatistics) {
+		draw_text = draw_text | TextToDraw::kStatistics;
+	}
+
 	if (upcast(InteractivePlayer const, interactive_player, &intbase())) {
-		renderer_->rendermap(dst, egbase, viewpoint_, interactive_player->player());
+		renderer_->rendermap(
+		   egbase, viewpoint_, zoom_, interactive_player->player(), draw_text, &dst);
 	} else {
-		renderer_->rendermap(dst, egbase, viewpoint_);
+		renderer_->rendermap(egbase, viewpoint_, zoom_, static_cast<TextToDraw>(draw_text), &dst);
 	}
 }
 
-void MapView::set_changeview(const MapView::ChangeViewFn& fn) {
-	changeview_ = fn;
+float MapView::get_zoom() const {
+	return zoom_;
+}
+
+void MapView::set_zoom(const float zoom) {
+	zoom_ = zoom;
 }
 
 /*
@@ -98,16 +161,35 @@
 Set the viewpoint to the given pixel coordinates
 ===============
 */
-void MapView::set_viewpoint(Point vp, bool jump) {
-	if (vp == viewpoint_)
-		return;
-
-	MapviewPixelFunctions::normalize_pix(intbase().egbase().map(), vp);
-	viewpoint_ = vp;
-
-	if (changeview_)
-		changeview_(vp, jump);
-	changeview(viewpoint_.x, viewpoint_.y);
+void MapView::set_viewpoint(const Vector2f& viewpoint, bool jump) {
+	viewpoint_ = viewpoint;
+	const Widelands::Map& map = intbase().egbase().map();
+	MapviewPixelFunctions::normalize_pix(map, &viewpoint_);
+	changeview(jump);
+}
+
+void MapView::center_view_on_coords(const Widelands::Coords& c) {
+	const Widelands::Map& map = intbase().egbase().map();
+	assert(0 <= c.x);
+	assert(c.x < map.get_width());
+	assert(0 <= c.y);
+	assert(c.y < map.get_height());
+
+	const Vector2f in_mappixel = MapviewPixelFunctions::to_map_pixel(map.get_fcoords(c));
+	center_view_on_map_pixel(in_mappixel);
+}
+
+void MapView::center_view_on_map_pixel(const Vector2f& pos) {
+	const Rectf view_area = get_view_area();
+	set_viewpoint(pos - Vector2f(view_area.w / 2.f, view_area.h / 2.f), true);
+}
+
+Rectf MapView::get_view_area() const {
+	return Rectf(viewpoint_, get_w() * zoom_, get_h() * zoom_);
+}
+
+void MapView::pan_by(Vector2i delta_pixels) {
+	set_viewpoint(get_viewpoint() + delta_pixels.cast<float>() * zoom_, false);
 }
 
 void MapView::stop_dragging() {
@@ -125,7 +207,7 @@
 bool MapView::handle_mousepress(uint8_t const btn, int32_t const x, int32_t const y) {
 	if (btn == SDL_BUTTON_LEFT) {
 		stop_dragging();
-		track_sel(Point(x, y));
+		track_sel(Vector2f(x, y));
 
 		fieldclicked();
 	} else if (btn == SDL_BUTTON_RIGHT) {
@@ -135,29 +217,55 @@
 	}
 	return true;
 }
+
 bool MapView::handle_mouserelease(const uint8_t btn, int32_t, int32_t) {
 	if (btn == SDL_BUTTON_RIGHT && dragging_)
 		stop_dragging();
 	return true;
 }
 
-/*
-===============
-Scroll the view according to mouse movement.
-===============
-*/
 bool MapView::handle_mousemove(
    uint8_t const state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff) {
+	last_mouse_pos_.x = x;
+	last_mouse_pos_.y = y;
+
 	if (dragging_) {
-		if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
-			set_rel_viewpoint(Point(xdiff, ydiff), false);
-		else
+		if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
+			pan_by(Vector2i(xdiff, ydiff));
+		} else {
 			stop_dragging();
+		}
 	}
 
 	if (!intbase().get_sel_freeze())
-		track_sel(Point(x, y));
-	return true;
+		track_sel(Vector2f(x, y));
+	return true;
+}
+
+bool MapView::handle_mousewheel(uint32_t which, int32_t /* x */, int32_t y) {
+	if (which != 0) {
+		return false;
+	}
+
+	constexpr float kPercentPerMouseWheelTick = 0.02f;
+	float zoom = zoom_ * static_cast<float>(
+	                        std::pow(1.f - math::sign(y) * kPercentPerMouseWheelTick, std::abs(y)));
+	zoom_around(zoom, last_mouse_pos_.cast<float>());
+	return true;
+}
+
+void MapView::zoom_around(float new_zoom, const Vector2f& panel_pixel) {
+	// Somewhat arbitrarily we limit the zoom to a reasonable value. This is for
+	// performance and to avoid numeric glitches with more extreme values.
+	constexpr float kMaxZoom = 4.f;
+	new_zoom = math::clamp(new_zoom, 1.f / kMaxZoom, kMaxZoom);
+
+	// Zoom around the current mouse position. See
+	// http://stackoverflow.com/questions/2916081/zoom-in-on-a-point-using-scale-and-translate
+	// for a good explanation of this math.
+	const Vector2f offset = -panel_pixel * (new_zoom - zoom_);
+	zoom_ = new_zoom;
+	set_viewpoint(viewpoint_ + offset, false);
 }
 
 /*
@@ -168,8 +276,34 @@
 Does not honour sel freeze.
 ===============
 */
-void MapView::track_sel(Point m) {
-	m += viewpoint_;
-	intbase_.set_sel_pos(
-	   MapviewPixelFunctions::calc_node_and_triangle(intbase().egbase().map(), m.x, m.y));
-}
+void MapView::track_sel(const Vector2f& p) {
+	Vector2f p_in_map = to_map(p);
+	intbase_.set_sel_pos(MapviewPixelFunctions::calc_node_and_triangle(
+	   intbase().egbase().map(), p_in_map.x, p_in_map.y));
+}
+
+bool MapView::handle_key(bool down, SDL_Keysym code) {
+	if (!down) {
+		return false;
+	}
+	if (!code.mod & KMOD_CTRL) {
+		return false;
+	}
+
+	constexpr float kPercentPerKeyPress = 0.10f;
+	switch (code.sym) {
+	case SDLK_PLUS:
+		zoom_around(zoom_ - kPercentPerKeyPress, Vector2f(get_w() / 2.f, get_h() / 2.f));
+		return true;
+	case SDLK_MINUS:
+		zoom_around(zoom_ + kPercentPerKeyPress, Vector2f(get_w() / 2.f, get_h() / 2.f));
+		return true;
+	case SDLK_0:
+		zoom_around(1.f, Vector2f(get_w() / 2.f, get_h() / 2.f));
+		return true;
+	default:
+		return false;
+	}
+	NEVER_HERE();
+}
+

=== modified file 'src/wui/mapview.h'
--- src/wui/mapview.h	2016-08-04 15:49:05 +0000
+++ src/wui/mapview.h	2016-10-28 17:51:15 +0000
@@ -25,6 +25,8 @@
 #include <boost/function.hpp>
 #include <boost/signals2.hpp>
 
+#include "base/rect.h"
+#include "base/vector.h"
 #include "logic/widelands_geometry.h"
 #include "ui_basic/panel.h"
 
@@ -35,14 +37,6 @@
  * Implements a view of a map. It is used to render a valid map on the screen.
  */
 struct MapView : public UI::Panel {
-	/**
-	 * Callback function type for when the view position changes.
-	 *
-	 * Parameters are x/y screen coordinates and whether the change should
-	 * be considered a "jump" or a smooth scrolling event.
-	 */
-	using ChangeViewFn = boost::function<void(Point, bool)>;
-
 	MapView(UI::Panel* const parent,
 	        const int32_t x,
 	        const int32_t y,
@@ -51,27 +45,32 @@
 	        InteractiveBase&);
 	virtual ~MapView();
 
-	void set_changeview(const ChangeViewFn& fn);
-
 	/**
-	 * Called whenever the view position changes, for whatever reason.
-	 *
-	 * Parameters are x/y position in screen coordinates.
+	 * Called when the view changed.  'jump' defines if the change should be
+	 * considered a "jump" or a smooth scrolling event.
 	 */
-	boost::signals2::signal<void(int32_t, int32_t)> changeview;
+	boost::signals2::signal<void(bool jump)> changeview;
 
 	boost::signals2::signal<void()> fieldclicked;
 
 	void warp_mouse_to_node(Widelands::Coords);
 
-	void set_viewpoint(Point vp, bool jump);
-	void set_rel_viewpoint(Point r, bool jump) {
-		set_viewpoint(viewpoint_ + r, jump);
-	}
-
-	Point get_viewpoint() const {
-		return viewpoint_;
-	}
+	void set_viewpoint(const Vector2f& vp, bool jump);
+	void center_view_on_coords(const Widelands::Coords& coords);
+	void center_view_on_map_pixel(const Vector2f& pos);
+
+	Vector2f get_viewpoint() const;
+	Rectf get_view_area() const;
+	float get_zoom() const;
+
+	// Set the zoom to the new value without changing view_point. For the user
+	// the view will perceivably jump.
+	void set_zoom(float zoom);
+
+	// Set the zoom to the 'new_zoom'. This keeps the map_pixel that is
+	// displayed at 'panel_pixel' unchanging, i.e. the center of the zoom.
+	void zoom_around(float new_zoom, const Vector2f& panel_pixel);
+
 	bool is_dragging() const {
 		return dragging_;
 	}
@@ -84,21 +83,31 @@
 	bool handle_mouserelease(uint8_t btn, int32_t x, int32_t y) override;
 	bool
 	handle_mousemove(uint8_t state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff) override;
+	bool
+	handle_mousewheel(uint32_t which, int32_t x, int32_t y) override;
+	bool handle_key(bool down, SDL_Keysym code) override;
 
-	void track_sel(Point m);
+	void track_sel(const Vector2f& m);
 
 protected:
 	InteractiveBase& intbase() const {
 		return intbase_;
 	}
 
+	// Move the view by 'delta_pixels'.
+	void pan_by(Vector2i delta_pixels);
+
 private:
 	void stop_dragging();
 
+	Vector2f to_panel(const Vector2f& map_pixel) const;
+	Vector2f to_map(const Vector2f& panel_pixel) const;
+
 	std::unique_ptr<GameRenderer> renderer_;
 	InteractiveBase& intbase_;
-	ChangeViewFn changeview_;
-	Point viewpoint_;
+	Vector2f viewpoint_;
+	float zoom_;
+	Vector2i last_mouse_pos_;
 	bool dragging_;
 };
 

=== modified file 'src/wui/mapviewpixelconstants.h'
--- src/wui/mapviewpixelconstants.h	2016-08-04 15:49:05 +0000
+++ src/wui/mapviewpixelconstants.h	2016-10-28 17:51:15 +0000
@@ -20,7 +20,11 @@
 #ifndef WL_WUI_MAPVIEWPIXELCONSTANTS_H
 #define WL_WUI_MAPVIEWPIXELCONSTANTS_H
 
-//  These are constants with the unit pixel

Follow ups