← Back to team overview

widelands-dev team mailing list archive

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

 

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

Commit message:
Add support for representative images to the font renderer

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1638356 in widelands: "Implement support for Spritemaps"
  https://bugs.launchpad.net/widelands/+bug/1638356

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

This is the second step in a series to improve graphics quality in Widelands, hopefully for Build 21.

1. Implement support for Mipmaps

2. Add support to the font renderer

3. Implement spritesheets, otherwise the number of files will explode

4. Implement compressed spritemaps, otherwise the filesize will explode.
   This is only feasible for immovables.

5. Re-export everything from Blender
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/representative_image_in_font_renderer into lp:widelands.
=== modified file 'data/campaigns/atl01.wmf/scripting/mission_thread.lua'
--- data/campaigns/atl01.wmf/scripting/mission_thread.lua	2018-11-16 06:41:28 +0000
+++ data/campaigns/atl01.wmf/scripting/mission_thread.lua	2019-02-28 11:27:44 +0000
@@ -3,8 +3,7 @@
 -- =======================================================================
 
 function send_building_lost_message(f)
-   local icon = f.immovable.descr.representative_image
-   local message = building_lost(icon)
+   local message = building_lost(f.immovable.descr.name)
    send_message(
       p1,
       message.title,
@@ -12,7 +11,7 @@
       {
          field = f,
          popup = false,
-         icon = icon,
+         icon = f.immovable.descr.icon_name,
          message.title
       }
    )

=== modified file 'data/campaigns/atl01.wmf/scripting/texts.lua'
--- data/campaigns/atl01.wmf/scripting/texts.lua	2017-12-09 19:06:07 +0000
+++ data/campaigns/atl01.wmf/scripting/texts.lua	2019-02-28 11:27:44 +0000
@@ -480,11 +480,11 @@
    }
 }
 
-function building_lost(icon)
+function building_lost(buildingname)
    set_textdomain("scenario_atl01.wmf")
    return {
       -- TRANSLATORS: Short message title. Translate as "Lost!" if you don't have enough space.
       title = pgettext("message_short_title", "Building lost!"),
-      text = li_image(icon, _"We lost a building to the ocean!")
+      text = li_object(buildingname, _"We lost a building to the ocean!")
    }
 end

=== modified file 'data/campaigns/bar01.wmf/scripting/texts.lua'
--- data/campaigns/bar01.wmf/scripting/texts.lua	2018-09-02 11:44:52 +0000
+++ data/campaigns/bar01.wmf/scripting/texts.lua	2019-02-28 11:27:44 +0000
@@ -43,16 +43,16 @@
    body = objective_text(_"Build coal and iron mines",
       li(_"Build a coal mine and an iron mine.") ..
       li_arrow(_"To do so, place a flag up on the mountain’s flank to the east (on mountain terrain though, not mountain meadow). When you click on the new flag, you can send geologists there. Because the flag is on a mountain, the geologists will search for ores; otherwise, they would search for water. Then build a mine for both kinds of resources that they will find, choosing the appropriate mine to be built:") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_coal_1").representative_image, _"a bit of coal") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_coal_2").representative_image, _"a lot of coal") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_iron_1").representative_image, _"a bit of iron") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_iron_2").representative_image, _"a lot of iron") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_gold_1").representative_image, _"a bit of gold") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_gold_2").representative_image, _"a lot of gold") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_stones_1").representative_image, _"a bit of granite") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_stones_2").representative_image, _"a lot of granite") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_water").representative_image, _"water") ..
-      li_image(wl.Game():get_immovable_description("barbarians_resi_none").representative_image, _"nothing was found here") ..
+      li_object("barbarians_resi_coal_1", _"a bit of coal") ..
+      li_object("barbarians_resi_coal_2", _"a lot of coal") ..
+      li_object("barbarians_resi_iron_1", _"a bit of iron") ..
+      li_object("barbarians_resi_iron_2", _"a lot of iron") ..
+      li_object("barbarians_resi_gold_1", _"a bit of gold") ..
+      li_object("barbarians_resi_gold_2", _"a lot of gold") ..
+      li_object("barbarians_resi_stones_1", _"a bit of granite") ..
+      li_object("barbarians_resi_stones_2", _"a lot of granite") ..
+      li_object("barbarians_resi_water", _"water") ..
+      li_object("barbarians_resi_none", _"nothing was found here") ..
       p(_[[Mines can only be built on mountain terrain. Suitable places for mines are displayed as orange mine symbols.]]))
 }
 

=== modified file 'data/scripting/editor/editor_help.lua'
--- data/scripting/editor/editor_help.lua	2016-10-19 09:00:29 +0000
+++ data/scripting/editor/editor_help.lua	2019-02-28 11:27:44 +0000
@@ -32,7 +32,7 @@
          result[counter] = {
             name = immovable.name,
             title = immovable.species,
-            icon = immovable.representative_image,
+            icon = immovable.icon_name,
             script = "scripting/editor/tree_help.lua",
             script_parameters = {[1] = immovable.name}
          }

=== modified file 'data/scripting/editor/terrain_help.lua'
--- data/scripting/editor/terrain_help.lua	2018-01-10 16:21:50 +0000
+++ data/scripting/editor/terrain_help.lua	2019-02-28 11:27:44 +0000
@@ -59,7 +59,7 @@
 
       local tree_string = ""
       for k,v in ipairs(tree_list) do
-         tree_string = tree_string .. li_image(v.tree.representative_image,
+         tree_string = tree_string .. li_object(v.tree.name,
             v.tree.species .. ("<br>%2.1f%%"):bformat(100 * v.probability)) .. vspace(3)
       end
 

=== modified file 'data/scripting/editor/tree_help.lua'
--- data/scripting/editor/tree_help.lua	2018-01-10 16:21:50 +0000
+++ data/scripting/editor/tree_help.lua	2019-02-28 11:27:44 +0000
@@ -13,7 +13,7 @@
       set_textdomain("widelands_editor")
       local world = wl.World();
       local tree = wl.Editor():get_immovable_description(tree_name)
-      local result = li_image(tree.representative_image, "")
+      local result = li_object(tree.name, "")
 
       -- TRANSLATORS: A header in the editor help. Terrains preferred by a type of tree.
       result = result .. vspace(3) .. h2(vspace(12) .. _"Preferred terrains") .. vspace(3)

=== modified file 'data/scripting/richtext.lua'
--- data/scripting/richtext.lua	2018-03-24 13:51:48 +0000
+++ data/scripting/richtext.lua	2019-02-28 11:27:44 +0000
@@ -402,7 +402,6 @@
    return li("→", text)
 end
 
-
 -- RST
 -- .. function:: li_image(imagepath, text)
 --
@@ -424,6 +423,26 @@
       )
 end
 
+-- RST
+-- .. function:: li_object(name, text)
+--
+--    Places a paragraph of text to the right of an image representing the given map object
+--
+--    :arg name: the name of the map object to be represented by an image
+--    :type name: :class:`string`
+--
+--    :arg text: the text to be placed next to the image
+--    :type text: :class:`string`
+--
+--    :returns: the text wrapped in a paragraph and placed next to the image, the outer tag is a div.
+
+function li_object(name, text)
+   return
+      div("width=100%",
+         div("float=left padding_r=6", p(img_object(name))) ..
+         p(text)
+      )
+end
 
 -- RST
 -- :ref:`Return to index<richtext.lua>`
@@ -455,6 +474,27 @@
    end
 end
 
+-- RST
+-- .. function:: img_object(object[, attributes = nil])
+--
+--    Creates a richtest image tag for the given map object type. See also :any:`li_object`.
+--
+--    :arg name: the name of the map object.
+--    :type name: :class:`string`
+--    :arg attributes: see the :ref:`img tag's documentation <rt_tags_img>`
+--                     for a list of attributes and their descriptions.
+--    :type attributes: :class:`string`
+--
+--    :returns: the img tag.
+
+function img_object(name, attributes)
+   if attributes then
+      return "<img object=" .. name .. " " .. attributes .. ">"
+   else
+      return "<img object=" .. name .. ">"
+   end
+end
+
 
 -- RST
 -- :ref:`Return to index<richtext.lua>`

=== modified file 'data/tribes/immovables/resi/atlanteans/init.lua'
--- data/tribes/immovables/resi/atlanteans/init.lua	2018-09-10 06:25:11 +0000
+++ data/tribes/immovables/resi/atlanteans/init.lua	2019-02-28 11:27:44 +0000
@@ -6,6 +6,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: None"),
    helptext_script = dirname .. "../helptexts/none.lua",
+   icon = dirname .. "pics/none_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -28,6 +29,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Water Vein"),
    helptext_script = dirname .. "../helptexts/water.lua",
+   icon = dirname .. "pics/water_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -51,6 +53,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Coal Vein"),
    helptext_script = dirname .. "../helptexts/coal_1.lua",
+   icon = dirname .. "pics/coal_1_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -74,6 +77,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Gold Vein"),
    helptext_script = dirname .. "../helptexts/gold_1.lua",
+   icon = dirname .. "pics/gold_1_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -97,6 +101,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Iron Vein"),
    helptext_script = dirname .. "../helptexts/iron_1.lua",
+   icon = dirname .. "pics/iron_1_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -120,6 +125,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Some Stones"),
    helptext_script = dirname .. "../helptexts/stones_1.lua",
+   icon = dirname .. "pics/stones_1_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -143,6 +149,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Coal Vein"),
    helptext_script = dirname .. "../helptexts/coal_2.lua",
+   icon = dirname .. "pics/coal_2_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -166,6 +173,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Gold Vein"),
    helptext_script = dirname .. "../helptexts/gold_2.lua",
+   icon = dirname .. "pics/gold_2_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -189,6 +197,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Iron Vein"),
    helptext_script = dirname .. "../helptexts/iron_2.lua",
+   icon = dirname .. "pics/iron_2_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -212,6 +221,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: A Lot of Stones"),
    helptext_script = dirname .. "../helptexts/stones_2.lua",
+   icon = dirname .. "pics/stones_2_0.png",
    attributes = { "resi" },
    programs = {
       program = {

=== modified file 'data/tribes/immovables/resi/barbarians/init.lua'
--- data/tribes/immovables/resi/barbarians/init.lua	2018-09-01 10:50:00 +0000
+++ data/tribes/immovables/resi/barbarians/init.lua	2019-02-28 11:27:44 +0000
@@ -6,6 +6,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: None"),
    helptext_script = dirname .. "../helptexts/none.lua",
+   icon = dirname .. "pics/none.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -28,6 +29,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Water Vein"),
    helptext_script = dirname .. "../helptexts/water.lua",
+   icon = dirname .. "pics/water.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -50,6 +52,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Coal Vein"),
    helptext_script = dirname .. "../helptexts/coal_1.lua",
+   icon = dirname .. "pics/coal_1.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -72,6 +75,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Gold Vein"),
    helptext_script = dirname .. "../helptexts/gold_1.lua",
+   icon = dirname .. "pics/gold_1.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -94,6 +98,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Iron Vein"),
    helptext_script = dirname .. "../helptexts/iron_1.lua",
+   icon = dirname .. "pics/iron_1.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -116,6 +121,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Some Stones"),
    helptext_script = dirname .. "../helptexts/stones_1.lua",
+   icon = dirname .. "pics/stones_1.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -138,6 +144,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Coal Vein"),
    helptext_script = dirname .. "../helptexts/coal_2.lua",
+   icon = dirname .. "pics/coal_2.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -160,6 +167,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Gold Vein"),
    helptext_script = dirname .. "../helptexts/gold_2.lua",
+   icon = dirname .. "pics/gold_2.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -182,6 +190,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Iron Vein"),
    helptext_script = dirname .. "../helptexts/iron_2.lua",
+   icon = dirname .. "pics/iron_2.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -204,6 +213,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: A Lot of Stones"),
    helptext_script = dirname .. "../helptexts/stones_2.lua",
+   icon = dirname .. "pics/stones_2.png",
    attributes = { "resi" },
    programs = {
       program = {

=== modified file 'data/tribes/immovables/resi/empire/init.lua'
--- data/tribes/immovables/resi/empire/init.lua	2018-09-01 10:50:00 +0000
+++ data/tribes/immovables/resi/empire/init.lua	2019-02-28 11:27:44 +0000
@@ -6,6 +6,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: None"),
    helptext_script = dirname .. "../helptexts/none.lua",
+   icon = dirname .. "pics/none.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -28,6 +29,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Water Vein"),
    helptext_script = dirname .. "../helptexts/water.lua",
+   icon = dirname .. "pics/water.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -50,6 +52,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Coal Vein"),
    helptext_script = dirname .. "../helptexts/coal_1.lua",
+   icon = dirname .. "pics/coal_1.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -72,6 +75,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Gold Vein"),
    helptext_script = dirname .. "../helptexts/gold_1.lua",
+   icon = dirname .. "pics/gold_1.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -94,6 +98,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Iron Vein"),
    helptext_script = dirname .. "../helptexts/iron_1.lua",
+   icon = dirname .. "pics/iron_1.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -116,6 +121,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Some Stones"),
    helptext_script = dirname .. "../helptexts/stones_1.lua",
+   icon = dirname .. "pics/stones_1.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -138,6 +144,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Coal Vein"),
    helptext_script = dirname .. "../helptexts/coal_2.lua",
+   icon = dirname .. "pics/coal_2.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -160,6 +167,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Gold Vein"),
    helptext_script = dirname .. "../helptexts/gold_2.lua",
+   icon = dirname .. "pics/gold_2.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -182,6 +190,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Iron Vein"),
    helptext_script = dirname .. "../helptexts/iron_2.lua",
+   icon = dirname .. "pics/iron_2.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -204,6 +213,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: A Lot of Stones"),
    helptext_script = dirname .. "../helptexts/stones_2.lua",
+   icon = dirname .. "pics/stones_2.png",
    attributes = { "resi" },
    programs = {
       program = {

=== modified file 'data/tribes/immovables/resi/frisians/init.lua'
--- data/tribes/immovables/resi/frisians/init.lua	2018-09-21 20:12:46 +0000
+++ data/tribes/immovables/resi/frisians/init.lua	2019-02-28 11:27:44 +0000
@@ -6,6 +6,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: None"),
    helptext_script = dirname .. "../helptexts/none.lua",
+   icon = dirname .. "pics/none_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -28,6 +29,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Water Vein"),
    helptext_script = dirname .. "../helptexts/water.lua",
+   icon = dirname .. "pics/water_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -51,6 +53,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Coal Vein"),
    helptext_script = dirname .. "../helptexts/coal_1.lua",
+   icon = dirname .. "pics/coal_1_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -74,6 +77,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Gold Vein"),
    helptext_script = dirname .. "../helptexts/gold_1.lua",
+   icon = dirname .. "pics/gold_1_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -97,6 +101,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Iron Vein"),
    helptext_script = dirname .. "../helptexts/iron_1.lua",
+   icon = dirname .. "pics/iron_1_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -120,6 +125,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Some Stones"),
    helptext_script = dirname .. "../helptexts/stones_1.lua",
+   icon = dirname .. "pics/stones_1_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -143,6 +149,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Coal Vein"),
    helptext_script = dirname .. "../helptexts/coal_2.lua",
+   icon = dirname .. "pics/coal_2_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -166,6 +173,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Gold Vein"),
    helptext_script = dirname .. "../helptexts/gold_2.lua",
+   icon = dirname .. "pics/gold_2_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -189,6 +197,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: Main Iron Vein"),
    helptext_script = dirname .. "../helptexts/iron_2.lua",
+   icon = dirname .. "pics/iron_2_0.png",
    attributes = { "resi" },
    programs = {
       program = {
@@ -212,6 +221,7 @@
    -- TRANSLATORS: This is a resource name used in lists of resources
    descname = pgettext("immovable", "Resources: A Lot of Stones"),
    helptext_script = dirname .. "../helptexts/stones_2.lua",
+   icon = dirname .. "pics/stones_2_0.png",
    attributes = { "resi" },
    programs = {
       program = {

=== modified file 'data/tribes/immovables/shipconstruction_frisians/init.lua'
--- data/tribes/immovables/shipconstruction_frisians/init.lua	2018-03-25 18:28:00 +0000
+++ data/tribes/immovables/shipconstruction_frisians/init.lua	2019-02-28 11:27:44 +0000
@@ -7,7 +7,6 @@
    descname = pgettext("immovable", "Ship Under Construction"),
    size = "small",
    helptext_script = dirname .. "helptexts.lua",
-   representative_image = dirname .. "build_03.png",
    attributes = { "shipconstruction" },
    programs = {
       program = {
@@ -25,7 +24,8 @@
       idle = {
          pictures = path.list_files (dirname .. "build_??.png"),
          hotspot = { 75, 141 },
-         fps = 1
+         fps = 1,
+         representative_frame = 3
       },
    }
 }

=== modified file 'data/tribes/scripting/help/building_help.lua'
--- data/tribes/scripting/help/building_help.lua	2018-09-26 07:08:39 +0000
+++ data/tribes/scripting/help/building_help.lua	2019-02-28 11:27:44 +0000
@@ -57,7 +57,7 @@
          am = amount
       end
    end
-   local items_with_resource = { wl.Game():get_immovable_description(resi).representative_image }
+   local items_with_resource = { wl.Game():get_immovable_description(resi).icon_name }
    for count, item in pairs(items) do
       table.insert(items_with_resource, item.icon_name)
    end
@@ -180,13 +180,13 @@
    local result = h2(_"Lore")
    local lore_text = building_helptext_lore()
    if type(lore_text) == "table" then
-      result = result .. li_image(building_description.representative_image, lore_text[1])
+      result = result .. li_object(building_description.name, lore_text[1])
       for k,v in ipairs({table.unpack(lore_text, 2)}) do
          result = result .. p(v)
       end
    else
     result = result ..
-      li_image(building_description.representative_image, lore_text)
+      li_object(building_description.name, lore_text)
    end
 
    local lore_author = building_helptext_lore_author()

=== modified file 'data/tribes/scripting/help/immovable_help.lua'
--- data/tribes/scripting/help/immovable_help.lua	2018-03-24 14:31:37 +0000
+++ data/tribes/scripting/help/immovable_help.lua	2019-02-28 11:27:44 +0000
@@ -32,7 +32,7 @@
 
    -- TRANSLATORS: Put 2 sentences one after the other. Languages using Chinese script probably want to lose the blank space here.
    local purpose_text = pgettext("sentence_separator", "%s %s"):bformat(immovable_helptext(), immovable_helptext(tribe.name))
-   local result = li_image(immovable_description.representative_image, purpose_text)
+   local result = li_object(immovable_description.name, purpose_text)
 
    -- Build cost
    local buildcost = ""

=== modified file 'data/world/immovables/trees/alder/init.lua'
--- data/world/immovables/trees/alder/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/alder/init.lua	2019-02-28 11:27:44 +0000
@@ -88,6 +88,7 @@
    name = "alder_summer_old",
    descname = _ "Alder (Old)",
    species = _ "Alder",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_deciduous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/aspen/init.lua'
--- data/world/immovables/trees/aspen/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/aspen/init.lua	2019-02-28 11:27:44 +0000
@@ -83,6 +83,7 @@
    name = "aspen_summer_old",
    descname = _ "Aspen (Old)",
    species = _ "Aspen",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_deciduous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/beech/init.lua'
--- data/world/immovables/trees/beech/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/beech/init.lua	2019-02-28 11:27:44 +0000
@@ -80,6 +80,7 @@
    name = "beech_summer_old",
    descname = _ "Beech (Old)",
    species = _ "Beech",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_deciduous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/birch/init.lua'
--- data/world/immovables/trees/birch/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/birch/init.lua	2019-02-28 11:27:44 +0000
@@ -83,6 +83,7 @@
    name = "birch_summer_old",
    descname = _ "Birch (Old)",
    species = _ "Birch",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_deciduous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/cirrus/init.lua'
--- data/world/immovables/trees/cirrus/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/cirrus/init.lua	2019-02-28 11:27:44 +0000
@@ -85,6 +85,7 @@
    descname = _ "Cirrus Tree (Old)",
    -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
    species = _ "Cirrus Tree",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_wasteland",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/larch/init.lua'
--- data/world/immovables/trees/larch/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/larch/init.lua	2019-02-28 11:27:44 +0000
@@ -80,6 +80,7 @@
    name = "larch_summer_old",
    descname = _ "Larch (Old)",
    species = _ "Larch",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_coniferous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/liana/init.lua'
--- data/world/immovables/trees/liana/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/liana/init.lua	2019-02-28 11:27:44 +0000
@@ -88,6 +88,7 @@
    descname = _ "Liana Tree (Old)",
    -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
    species = _ "Liana Tree",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_wasteland",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/maple/init.lua'
--- data/world/immovables/trees/maple/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/maple/init.lua	2019-02-28 11:27:44 +0000
@@ -80,6 +80,7 @@
    name = "maple_winter_old",
    descname = _ "Maple (Old)",
    species = _ "Maple",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_deciduous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/mushroom_dark/init.lua'
--- data/world/immovables/trees/mushroom_dark/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/mushroom_dark/init.lua	2019-02-28 11:27:44 +0000
@@ -85,6 +85,7 @@
    descname = _ "Dark Mushroom Tree (Old)",
    -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
    species = _ "Dark Mushroom Tree",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_wasteland",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/mushroom_green/init.lua'
--- data/world/immovables/trees/mushroom_green/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/mushroom_green/init.lua	2019-02-28 11:27:44 +0000
@@ -85,6 +85,7 @@
    descname = _ "Green Mushroom Tree (Old)",
    -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
    species = _ "Green Mushroom Tree",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_wasteland",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/mushroom_red/init.lua'
--- data/world/immovables/trees/mushroom_red/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/mushroom_red/init.lua	2019-02-28 11:27:44 +0000
@@ -88,6 +88,7 @@
    descname = _ "Red Mushroom Tree (Old)",
    -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
    species = _ "Red Mushroom Tree",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_wasteland",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/oak/init.lua'
--- data/world/immovables/trees/oak/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/oak/init.lua	2019-02-28 11:27:44 +0000
@@ -80,6 +80,7 @@
    name = "oak_summer_old",
    descname = _ "Oak (Old)",
    species = _ "Oak",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_deciduous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/palm_borassus/init.lua'
--- data/world/immovables/trees/palm_borassus/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/palm_borassus/init.lua	2019-02-28 11:27:44 +0000
@@ -80,6 +80,7 @@
    name = "palm_borassus_desert_old",
    descname = _ "Borassus Palm (Old)",
    species = _ "Borassus Palm",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_palm",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/palm_coconut/init.lua'
--- data/world/immovables/trees/palm_coconut/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/palm_coconut/init.lua	2019-02-28 11:27:44 +0000
@@ -80,6 +80,7 @@
    name = "palm_coconut_desert_old",
    descname = _ "Coconut Palm (Old)",
    species = _ "Coconut Palm",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_palm",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/palm_date/init.lua'
--- data/world/immovables/trees/palm_date/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/palm_date/init.lua	2019-02-28 11:27:44 +0000
@@ -83,6 +83,7 @@
    name = "palm_date_desert_old",
    descname = _ "Date Palm (Old)",
    species = _ "Date Palm",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_palm",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/palm_oil/init.lua'
--- data/world/immovables/trees/palm_oil/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/palm_oil/init.lua	2019-02-28 11:27:44 +0000
@@ -84,6 +84,7 @@
    name = "palm_oil_desert_old",
    descname = _ "Oil Palm (Old)",
    species = _ "Oil Palm",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_palm",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/palm_roystonea/init.lua'
--- data/world/immovables/trees/palm_roystonea/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/palm_roystonea/init.lua	2019-02-28 11:27:44 +0000
@@ -80,6 +80,7 @@
    name = "palm_roystonea_desert_old",
    descname = _ "Roystonea regia Palm (Old)",
    species = _ "Roystonea regia Palm",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_palm",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/rowan/init.lua'
--- data/world/immovables/trees/rowan/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/rowan/init.lua	2019-02-28 11:27:44 +0000
@@ -83,6 +83,7 @@
    name = "rowan_summer_old",
    descname = _ "Rowan (Old)",
    species = _ "Rowan",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_deciduous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/spruce/init.lua'
--- data/world/immovables/trees/spruce/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/spruce/init.lua	2019-02-28 11:27:44 +0000
@@ -80,6 +80,7 @@
    name = "spruce_summer_old",
    descname = _ "Spruce (Old)",
    species = _ "Spruce",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_coniferous",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/twine/init.lua'
--- data/world/immovables/trees/twine/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/twine/init.lua	2019-02-28 11:27:44 +0000
@@ -85,6 +85,7 @@
    descname = _ "Twine Tree (Old)",
    -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
    species = _ "Twine Tree",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_wasteland",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/umbrella_green/init.lua'
--- data/world/immovables/trees/umbrella_green/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/umbrella_green/init.lua	2019-02-28 11:27:44 +0000
@@ -85,6 +85,7 @@
    descname = _ "Green Umbrella Tree (Old)",
    -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
    species = _ "Green Umbrella Tree",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_wasteland",
    size = "small",
    attributes = { "tree" },

=== modified file 'data/world/immovables/trees/umbrella_red/init.lua'
--- data/world/immovables/trees/umbrella_red/init.lua	2018-11-03 11:27:18 +0000
+++ data/world/immovables/trees/umbrella_red/init.lua	2019-02-28 11:27:44 +0000
@@ -88,6 +88,7 @@
    descname = _ "Red Umbrella Tree (Old)",
    -- TRANSLATORS: This is a fictitious tree. Be creative if you want.
    species = _ "Red Umbrella Tree",
+   icon = dirname .. "old/idle_0.png",
    editor_category = "trees_wasteland",
    size = "small",
    attributes = { "tree" },

=== modified file 'doc/sphinx/source/animations.rst'
--- doc/sphinx/source/animations.rst	2018-04-09 08:01:28 +0000
+++ doc/sphinx/source/animations.rst	2019-02-28 11:27:44 +0000
@@ -15,6 +15,7 @@
             directory = "sound/foo",
             name = "bar",
          },
+         representative_frame = 3,
       },
       working = ...
    }
@@ -40,6 +41,8 @@
 **sound_effect**
    *Optional*. Our example will look for the sound files ``bar_00.ogg`` through ``bar_99.ogg`` in the directory ``data/sound/foo`` and play them in sequence.
 
+**representative_frame**
+   *Optional*. Choose the animation frame that will be displayed in messages and in the encyclopedia as a representative image. Default is 0.
 
 Directional Animations
 ----------------------

=== modified file 'src/graphic/animation.cc'
--- src/graphic/animation.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/animation.cc	2019-02-28 11:27:44 +0000
@@ -61,7 +61,6 @@
 	uint16_t nr_frames() const override;
 	uint32_t frametime() const override;
 	const Image* representative_image(const RGBColor* clr) const override;
-	const std::string& representative_image_filename() const override;
 	virtual void blit(uint32_t time,
 	                  const Rectf& source_rect,
 	                  const Rectf& destination_rect,
@@ -96,7 +95,7 @@
 };
 
 NonPackedAnimation::NonPackedAnimation(const LuaTable& table)
-   : frametime_(FRAME_LENGTH),
+   : Animation(table.has_key("representative_frame") ? table.get_int("representative_frame") : 0),
      hotspot_(table.get_vector<std::string, int>("hotspot")),
      hasplrclrs_(false),
      scale_(1),
@@ -147,6 +146,10 @@
 			}
 		}
 
+		if (representative_frame_ < 0 || static_cast<unsigned int>(representative_frame_) > image_files_.size() - 1) {
+			throw wexception("Animation has %d as its representative frame, but the frame indices available are 0 - %" PRIuS, representative_frame_, image_files_.size() - 1);
+		}
+
 		assert(!image_files_.empty());
 		assert(pc_mask_image_files_.size() == image_files_.size() || pc_mask_image_files_.empty());
 		assert(scale_ > 0);
@@ -211,8 +214,8 @@
 
 const Image* NonPackedAnimation::representative_image(const RGBColor* clr) const {
 	assert(!image_files_.empty());
-	const Image* image = (hasplrclrs_ && clr) ? playercolor_image(*clr, image_files_[0]) :
-	                                            g_gr->images().get(image_files_[0]);
+	const Image* image = (hasplrclrs_ && clr) ? playercolor_image(*clr, image_files_[representative_frame_]) :
+	                                            g_gr->images().get(image_files_[representative_frame_]);
 
 	const int w = image->width();
 	const int h = image->height();
@@ -222,11 +225,6 @@
 	return rv;
 }
 
-// TODO(GunChleoc): This is only here for the font renderers.
-const std::string& NonPackedAnimation::representative_image_filename() const {
-	return image_files_[0];
-}
-
 uint32_t NonPackedAnimation::current_frame(uint32_t time) const {
 	if (nr_frames() > 1) {
 		return (play_once_ && time / frametime_ > static_cast<uint32_t>(nr_frames() - 1)) ?
@@ -314,6 +312,12 @@
 	animations_.push_back(std::unique_ptr<Animation>(new NonPackedAnimation(table)));
 	return animations_.size();
 }
+uint32_t AnimationManager::load(const std::string& map_object_name, const LuaTable& table) {
+	animations_.push_back(std::unique_ptr<Animation>(new NonPackedAnimation(table)));
+	const size_t result = animations_.size();
+	representative_animations_by_map_object_name_.insert(std::make_pair(map_object_name, result));
+	return result;
+}
 
 const Animation& AnimationManager::get_animation(uint32_t id) const {
 	if (!id || id > animations_.size())
@@ -331,3 +335,11 @@
 	}
 	return representative_images_.at(hash).get();
 }
+
+const Image* AnimationManager::get_representative_image(const std::string& map_object_name, const RGBColor* clr) {
+	if (representative_animations_by_map_object_name_.count(map_object_name) != 1) {
+		log("Warning: %s has no animation assigned for its representative image, or it's not a known map object\n", map_object_name.c_str());
+		return new Texture(0, 0);
+	}
+	return get_representative_image(representative_animations_by_map_object_name_.at(map_object_name), clr);
+}

=== modified file 'src/graphic/animation.h'
--- src/graphic/animation.h	2019-02-23 11:00:49 +0000
+++ src/graphic/animation.h	2019-02-28 11:27:44 +0000
@@ -52,7 +52,7 @@
  */
 class Animation {
 public:
-	Animation() {
+	Animation(int representative_frame) : representative_frame_(representative_frame) {
 	}
 	virtual ~Animation() {
 	}
@@ -81,8 +81,6 @@
 	/// The 'clr' is the player color used for blending - the parameter can be
 	/// 'nullptr', in which case the neutral image will be returned.
 	virtual const Image* representative_image(const RGBColor* clr) const = 0;
-	/// The filename of the image used for the first frame, without player color.
-	virtual const std::string& representative_image_filename() const = 0;
 
 	/// Blit the animation frame that should be displayed at the given time index
 	/// into the given 'destination_rect'.
@@ -99,6 +97,9 @@
 	/// 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;
 
+protected:
+	int representative_frame_;
+
 private:
 	DISALLOW_COPY_AND_ASSIGN(Animation);
 };
@@ -116,6 +117,8 @@
 	 * Optional parameters in the Lua table are 'fps' and 'sound_effect'.
 	 */
 	uint32_t load(const LuaTable& table);
+	/// Same as above, but this animation will be used for getting a representative image by map object name
+	uint32_t load(const std::string& map_object_name, const LuaTable& table);
 
 	/// Returns the animation with the given ID or throws an exception if it is
 	/// unknown.
@@ -125,11 +128,13 @@
 	/// If this image has been generated before, it is pulled from the cache using
 	/// the clr argument that was used previously.
 	const Image* get_representative_image(uint32_t id, const RGBColor* clr = nullptr);
+	const Image* get_representative_image(const std::string& map_object_name, const RGBColor* clr = nullptr);
 
 private:
 	std::vector<std::unique_ptr<Animation>> animations_;
 	std::map<std::pair<uint32_t, const RGBColor*>, std::unique_ptr<const Image>>
 	   representative_images_;
+	std::map<std::string, uint32_t> representative_animations_by_map_object_name_;
 };
 
 #endif  // end of include guard: WL_GRAPHIC_ANIMATION_H

=== modified file 'src/graphic/text/rt_parse.cc'
--- src/graphic/text/rt_parse.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/text/rt_parse.cc	2019-02-28 11:27:44 +0000
@@ -481,15 +481,16 @@
 ^^^^^^^^^^
 
 * **src**: The path to the image, relative to the ``data`` directory.
+* **object**: Show the representative image of a map object
 * **ref**: To be implemented
 * **color**: Player color for the image as a hex value
-* **width**: Width of the image as a pixel amount. The corresponding height will be matched
-  automatically.
+* **width**: Width of the image as a pixel amount. The corresponding height will be matched automatically. Not supported for map objects.
 
 :ref:`Return to tag index<rt_tags>`
 		*/
 		TagConstraint tc;
 		tc.allowed_attrs.insert("src");
+		tc.allowed_attrs.insert("object");
 		tc.allowed_attrs.insert("ref");
 		tc.allowed_attrs.insert("color");
 		tc.allowed_attrs.insert("width");

=== modified file 'src/graphic/text/rt_render.cc'
--- src/graphic/text/rt_render.cc	2019-02-23 11:00:49 +0000
+++ src/graphic/text/rt_render.cc	2019-02-28 11:27:44 +0000
@@ -36,6 +36,7 @@
 #include "base/vector.h"
 #include "base/wexception.h"
 #include "graphic/align.h"
+#include "graphic/animation.h"
 #include "graphic/graphic.h"
 #include "graphic/image_cache.h"
 #include "graphic/image_io.h"
@@ -970,6 +971,17 @@
 		check_size();
 	}
 
+	ImgRenderNode(NodeStyle& ns,
+	              const Image* image)
+	   : RenderNode(ns),
+	     image_(image),
+	     filename_(""),
+	     scale_(1.0f),
+	     color_(RGBColor(0, 0, 0)),
+	     use_playercolor_(false) {
+		check_size();
+	}
+
 	std::string debug_info() const override {
 		return "img";
 	}
@@ -989,14 +1001,14 @@
 	const Image* image_;
 	const std::string filename_;
 	const double scale_;
-	const RGBColor& color_;
+	const RGBColor color_;
 	bool use_playercolor_;
 };
 
 std::shared_ptr<UI::RenderedText> ImgRenderNode::render(TextureCache* texture_cache) {
 	std::shared_ptr<UI::RenderedText> rendered_text(new UI::RenderedText());
 
-	if (scale_ == 1.0) {
+	if (scale_ == 1.0 || filename_.empty()) {
 		// Image can be used as is, and has already been cached in g_gr->images()
 		assert(image_ != nullptr);
 		rendered_text->rects.push_back(
@@ -1267,28 +1279,34 @@
 		const AttrMap& a = tag_.attrs();
 		RGBColor color;
 		bool use_playercolor = false;
-		const std::string image_filename = a["src"].get_string();
 		double scale = 1.0;
 
 		if (a.has("color")) {
 			color = a["color"].get_color();
 			use_playercolor = true;
 		}
-		if (a.has("width")) {
-			int width = a["width"].get_int();
-			if (width > renderer_style_.overall_width) {
-				log("WARNING: Font renderer: Specified image width of %d exceeds the overall available "
-				    "width of %d. Setting width to %d.\n",
-				    width, renderer_style_.overall_width, renderer_style_.overall_width);
-				width = renderer_style_.overall_width;
-			}
-			const int image_width = image_cache_->get(image_filename)->width();
-			if (width < image_width) {
-				scale = static_cast<double>(width) / image_width;
-			}
+		if (a.has("object")) {
+			const Image* representative_image = g_gr->animations().get_representative_image(a["object"].get_string(), use_playercolor ? &color : nullptr);
+			render_node_.reset(new ImgRenderNode(nodestyle_, representative_image));
+		} else {
+			const std::string image_filename = a["src"].get_string();
+
+			if (a.has("width")) {
+				int width = a["width"].get_int();
+				if (width > renderer_style_.overall_width) {
+					log("WARNING: Font renderer: Specified image width of %d exceeds the overall available "
+						"width of %d. Setting width to %d.\n",
+						width, renderer_style_.overall_width, renderer_style_.overall_width);
+					width = renderer_style_.overall_width;
+				}
+				const int image_width = image_cache_->get(image_filename)->width();
+				if (width < image_width) {
+					scale = static_cast<double>(width) / image_width;
+				}
+			}
+			render_node_.reset(
+			   new ImgRenderNode(nodestyle_, image_filename, scale, color, use_playercolor));
 		}
-		render_node_.reset(
-		   new ImgRenderNode(nodestyle_, image_filename, scale, color, use_playercolor));
 	}
 	void emit_nodes(std::vector<std::shared_ptr<RenderNode>>& nodes) override {
 		nodes.push_back(render_node_);

=== modified file 'src/logic/map_objects/immovable.cc'
--- src/logic/map_objects/immovable.cc	2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/immovable.cc	2019-02-28 11:27:44 +0000
@@ -222,6 +222,16 @@
 		   table.get_table("attributes")->array_entries<std::string>();
 		add_attributes(attributes, {MapObject::Attribute::RESI});
 
+		// All resource indicators must have a menu icon
+		for (const std::string& attribute : attributes) {
+			if (attribute == "resi") {
+				if (icon_filename().empty()) {
+					throw GameDataError("Resource indicator %s has no menu icon", name().c_str());
+				}
+				break;
+			}
+		}
+
 		// Old trees get an extra species name so we can use it in help lists.
 		bool is_tree = false;
 		for (const std::string& attribute : attributes) {

=== modified file 'src/logic/map_objects/map_object.cc'
--- src/logic/map_objects/map_object.cc	2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/map_object.cc	2019-02-28 11:27:44 +0000
@@ -239,14 +239,18 @@
 	if (table.has_key("animations")) {
 		std::unique_ptr<LuaTable> anims(table.get_table("animations"));
 		for (const std::string& animation : anims->keys<std::string>()) {
-			add_animation(animation, g_gr->animations().load(*anims->get_table(animation)));
+			if (animation == "idle") {
+				add_animation(animation, g_gr->animations().load(init_name, *anims->get_table(animation)));
+			} else {
+				add_animation(animation, g_gr->animations().load(*anims->get_table(animation)));
+			}
 		}
 		if (!is_animation_known("idle")) {
 			throw GameDataError(
 			   "Map object %s has animations but no idle animation", init_name.c_str());
 		}
-		representative_image_filename_ =
-		   g_gr->animations().get_animation(get_animation("idle")).representative_image_filename();
+
+		assert(g_gr->animations().get_representative_image(name())->width() > 0);
 	}
 	if (table.has_key("icon")) {
 		icon_filename_ = table.get_string("icon");
@@ -254,11 +258,6 @@
 			throw GameDataError("Map object %s has a menu icon, but it is empty", init_name.c_str());
 		}
 	}
-	// TODO(GunChleoc): We can't scale down images in the font renderer yet, so we need an extra
-	// representative image if the animation has high resolution.
-	if (table.has_key("representative_image")) {
-		representative_image_filename_ = table.get_string("representative_image");
-	}
 	check_representative_image();
 }
 MapObjectDescr::~MapObjectDescr() {
@@ -326,9 +325,6 @@
 	}
 	return nullptr;
 }
-const std::string& MapObjectDescr::representative_image_filename() const {
-	return representative_image_filename_;
-}
 
 void MapObjectDescr::check_representative_image() {
 	if (representative_image() == nullptr) {

=== modified file 'src/logic/map_objects/map_object.h'
--- src/logic/map_objects/map_object.h	2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/map_object.h	2019-02-28 11:27:44 +0000
@@ -137,9 +137,6 @@
 	/// Returns the image for the first frame of the idle animation if the MapObject has animations,
 	/// nullptr otherwise
 	const Image* representative_image(const RGBColor* player_color = nullptr) const;
-	/// Returns the image fileneme for first frame of the idle animation if the MapObject has
-	/// animations, is empty otherwise
-	const std::string& representative_image_filename() const;
 
 	/// Returns the menu image if the MapObject has one, nullptr otherwise
 	const Image* icon() const;
@@ -174,7 +171,6 @@
 	Anims anims_;
 	static uint32_t dyn_attribhigh_;  ///< highest attribute ID used
 	static AttribMap dyn_attribs_;
-	std::string representative_image_filename_;  // Image for big represenations, e.g. on buttons
 	std::string icon_filename_;                  // Filename for the menu icon
 
 	DISALLOW_COPY_AND_ASSIGN(MapObjectDescr);

=== modified file 'src/logic/map_objects/tribes/building.cc'
--- src/logic/map_objects/tribes/building.cc	2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/tribes/building.cc	2019-02-28 11:27:44 +0000
@@ -752,12 +752,10 @@
                             bool link_to_building_lifetime,
                             uint32_t throttle_time,
                             uint32_t throttle_radius) {
-	const std::string& img = descr().representative_image_filename();
-	const int width = descr().representative_image()->width();
 	const std::string rt_description =
-	   (boost::format("<div padding_r=10><p><img width=%d src=%s color=%s></p></div>"
+	   (boost::format("<div padding_r=10><p><img object=%s color=%s></p></div>"
 	                  "<div width=*><p><font size=%d>%s</font></p></div>") %
-	    width % img % owner().get_playercolor().hex_value() % UI_FONT_SIZE_MESSAGE % description)
+	    descr().name() % owner().get_playercolor().hex_value() % UI_FONT_SIZE_MESSAGE % description)
 	      .str();
 
 	std::unique_ptr<Message> msg(new Message(msgtype, game.get_gametime(), title, icon_filename,

=== modified file 'src/logic/map_objects/tribes/tribe_descr.cc'
--- src/logic/map_objects/tribes/tribe_descr.cc	2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/tribes/tribe_descr.cc	2019-02-28 11:27:44 +0000
@@ -64,8 +64,8 @@
 		initializations_ = info.initializations;
 
 		std::unique_ptr<LuaTable> items_table = table.get_table("animations");
-		frontier_animation_id_ = g_gr->animations().load(*items_table->get_table("frontier"));
-		flag_animation_id_ = g_gr->animations().load(*items_table->get_table("flag"));
+		frontier_animation_id_ = g_gr->animations().load(name_ + std::string("frontier"), *items_table->get_table("frontier"));
+		flag_animation_id_ = g_gr->animations().load(name_ + std::string("flag"), *items_table->get_table("flag"));
 
 		items_table = table.get_table("roads");
 		const auto load_roads = [&items_table](

=== modified file 'src/logic/map_objects/tribes/worker.cc'
--- src/logic/map_objects/tribes/worker.cc	2019-02-24 17:01:51 +0000
+++ src/logic/map_objects/tribes/worker.cc	2019-02-28 11:27:44 +0000
@@ -968,11 +968,10 @@
 
 		// Geologist also sends a message notifying the player
 		if (rdescr && rdescr->detectable() && position.field->get_resources_amount()) {
-			const int width = g_gr->images().get(rdescr->representative_image())->width();
 			const std::string message =
-			   (boost::format("<div padding_r=10><p><img width=%d src=%s></p></div>"
+			   (boost::format("<div padding_r=10><p><img object=%s></p></div>"
 			                  "<div width=*><p><font size=%d>%s</font></p></div>") %
-			    width % ri.descr().representative_image_filename() % UI_FONT_SIZE_MESSAGE %
+			    ri.descr().name() % UI_FONT_SIZE_MESSAGE %
 			    _("A geologist found resources."))
 			      .str();
 

=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc	2019-02-26 12:02:52 +0000
+++ src/scripting/lua_map.cc	2019-02-28 11:27:44 +0000
@@ -1776,7 +1776,6 @@
    PROP_RO(LuaMapObjectDescription, icon_name),
    PROP_RO(LuaMapObjectDescription, name),
    PROP_RO(LuaMapObjectDescription, type_name),
-   PROP_RO(LuaMapObjectDescription, representative_image),
    {nullptr, nullptr, nullptr},
 };
 
@@ -1838,17 +1837,6 @@
 }
 
 /* RST
-   .. attribute:: representative_image
-
-         (RO) a :class:`string` with the file path to the representative image
-         of the map object's idle animation
-*/
-int LuaMapObjectDescription::get_representative_image(lua_State* L) {
-	lua_pushstring(L, get()->representative_image_filename());
-	return 1;
-}
-
-/* RST
    .. attribute:: type_name
 
          (RO) the map object's type as a string. Map object types are
@@ -3653,7 +3641,6 @@
 
          (RO) the :class:`string` file path to a representative image
 */
-
 int LuaTerrainDescription::get_representative_image(lua_State* L) {
 	lua_pushstring(L, get()->texture_paths().front());
 	return 1;

=== modified file 'src/scripting/lua_map.h'
--- src/scripting/lua_map.h	2019-02-24 22:50:04 +0000
+++ src/scripting/lua_map.h	2019-02-28 11:27:44 +0000
@@ -197,7 +197,6 @@
 	int get_helptext_script(lua_State*);
 	int get_name(lua_State*);
 	int get_type_name(lua_State*);
-	int get_representative_image(lua_State*);
 
 	/*
 	 * Lua methods

=== modified file 'src/website/map_object_info.cc'
--- src/website/map_object_info.cc	2019-02-23 11:00:49 +0000
+++ src/website/map_object_info.cc	2019-02-28 11:27:44 +0000
@@ -70,7 +70,7 @@
 		JSON::Object* json_building = json_buildings_array->add_object();
 		json_building->add_string("name", building.name());
 		json_building->add_string("descname", building.descname());
-		json_building->add_string("icon", building.representative_image_filename());
+		json_building->add_string("icon", building.icon_filename());
 
 		// Buildcost
 		if (building.is_buildable()) {


Follow ups