← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/list-directories-in-cpp into lp:widelands

 

GunChleoc has proposed merging lp:~widelands-dev/widelands/list-directories-in-cpp into lp:widelands.

Commit message:
Improve performance and memory usage when loading tribes and world
- Save memory and loading time by not listing files via Lua
- Common sequential file loading function for image and sound files
- Replace regular expressions with NumberGlob for speedup
- Only load mipmap scales that are being used

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/list-directories-in-cpp/+merge/366614

Performance :)

I have only converted the directional animations to the new system - the remaining animations will take care of themselves once we move to Spritemaps. Converting them now would cause a lot of unnecessary extra work.

Some stats:

TRUNK:

┏━ Running Lua for world:
┃    Resources: 58ms
┃    Terrains: 85ms
┃    Immovables: 1157ms
┃    Critters: 709ms
┗━ took: 2009ms
Loading the world took 2050ms
┏━ Running Lua for tribes:
┃    Ships: 280ms
┃    Wares: 871ms
┃    Immovables: 671ms
┃    Workers: 5775ms
┃    Warehouses: 357ms
┃    Productionsites: 3167ms
┃    Trainingsites: 162ms
┃    Militarysites: 318ms
┃    Partially finished buildings: 26ms
┃    Tribe infos: 380ms
┗━ took: 12007ms
Loading the tribes took 12033ms


THIS BRANCH:

┏━ Running Lua for world:
┃    Resources: 1ms
┃    Terrains: 13ms
┃    Immovables: 172ms
┃    Critters: 163ms
┗━ took: 349ms
Loading the world took 360ms
┏━ Running Lua for tribes:
┃    Ships: 70ms
┃    Wares: 65ms
┃    Immovables: 127ms
┃    Workers: 2134ms
┃    Warehouses: 33ms
┃    Productionsites: 384ms
┃    Trainingsites: 35ms
┃    Militarysites: 55ms
┃    Partially finished buildings: 2ms
┃    Tribe infos: 60ms
┗━ took: 2965ms
Loading the tribes took 2966ms

-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/list-directories-in-cpp into lp:widelands.
=== renamed file 'data/music/intro_00.ogg' => 'data/music/intro.ogg'
=== renamed file 'data/music/menu_00.ogg' => 'data/music/menu.ogg'
=== modified file 'data/scripting/mapobjects.lua'
--- data/scripting/mapobjects.lua	2019-04-24 20:48:37 +0000
+++ data/scripting/mapobjects.lua	2019-04-28 09:46:14 +0000
@@ -21,25 +21,6 @@
    print(("%s: %dms"):format(preamble, ticks() - start))
 end
 
-
--- Helper function for finding animation files with varying numbering length
-function get_animation_files(prefix)
-   local animation_files = path.list_files(prefix .. "_??.png")
-   if #animation_files < 1 then
-      animation_files = path.list_files(prefix .. "_???.png")
-   end
-   if #animation_files < 1 then
-      animation_files = path.list_files(prefix .. "_?.png")
-   end
-   return animation_files
-end
-
-
--- The mipmap scales supported by the engine.
--- Ensure that this always matches kSupportedScales in animations.cc
-local supported_scales = { 0.5, 1, 2, 4 }
-
-
 -- RST
 -- .. function:: add_animation(animationtable, animationname, dirname, basename, hotspot [, fps])
 --
@@ -55,8 +36,8 @@
 --    :arg dirname: The name of the directory where the animation image files are located.
 --    :type dirname: :class:`string`
 --    :arg basename: The basename of the animation files. The filenames of the
---       animation files need to have the format ``<basename>_\d{2,3}.png`` for simple
---       file animations, and  ``<basename>_<scale>_\d{2,3}.png`` for mipmaps.
+--       animation files need to have the format ``<basename>_[_\d+].png`` for simple
+--       file animations, and  ``<basename>_<scale>[_\d+].png`` for mipmaps.
 --       Supported scales are ``0.5``, ``1``, ``2`` and ``4``.
 --    :type basename: :class:`string`
 --    :arg hotspot: The hotspot coordinates for blitting, e.g. ``{2, 20}``.
@@ -65,30 +46,9 @@
 --       1 frame, and if you need to deviate from the default frame rate.
 --    :type fps: :class:`integer`
 function add_animation(animationtable, animationname, dirname, basename, hotspot, fps)
-   mipmap = {}
-   for scale_idx, current_scale in ipairs(supported_scales) do
-      local listed_files = get_animation_files(dirname .. basename .. "_" .. current_scale)
-      if #listed_files > 0 then
-         table.insert(
-            mipmap,
-            {
-               scale = current_scale,
-               files = listed_files,
-            }
-         )
-      end
-   end
-   if #mipmap < 1 then
-      table.insert(
-      mipmap,
-         {
-            scale = 1,
-            files = get_animation_files(dirname .. basename),
-         }
-      )
-   end
    animationtable[animationname] = {
-      mipmap = mipmap,
+      directory = dirname,
+      basename = basename,
       hotspot = hotspot,
    }
    if (fps ~= nil) then
@@ -96,10 +56,8 @@
    end
 end
 
-
-
 -- RST
--- .. function:: add_walking_animations(animationtable, animationname, dirname, basename, hotspot [, fps])
+-- .. function:: add_directional_animation(animationtable, animationname, dirname, basename, hotspot [, fps])
 --
 --    Adds 6 walk or sail animations - one for each walking direction - to `animationtable`.
 --    Supports both simple animations and mipmaps.
@@ -123,12 +81,7 @@
 --    :arg fps: Frames per second. Only use this if the animation has more than
 --       1 frame, and if you need to deviate from the default frame rate.
 --    :type fps: :class:`integer`
-function add_walking_animations(animationtable, animationname, dirname, basename, hotspot, fps)
-   for idx, dir in ipairs{ "ne", "e", "se", "sw", "w", "nw" } do
-      if fps ~= nil then
-         add_animation(animationtable, animationname .. "_" .. dir, dirname, basename .. "_" .. dir, hotspot, fps)
-      else
-         add_animation(animationtable, animationname .. "_" .. dir, dirname, basename .. "_" .. dir, hotspot)
-      end
-   end
+function add_directional_animation(animationtable, animationname, dirname, basename, hotspot, fps)
+   add_animation(animationtable, animationname, dirname, basename, hotspot, fps)
+   animationtable[animationname]["directional"] = true
 end

=== renamed file 'data/sound/animals/boar_01.ogg' => 'data/sound/animals/boar.ogg'
=== renamed file 'data/sound/animals/coyote_01.ogg' => 'data/sound/animals/coyote_00.ogg'
=== renamed file 'data/sound/animals/coyote_02.ogg' => 'data/sound/animals/coyote_01.ogg'
=== renamed file 'data/sound/animals/crickets1_01.ogg' => 'data/sound/animals/crickets1_00.ogg'
=== renamed file 'data/sound/animals/crickets2_01.ogg' => 'data/sound/animals/crickets2_00.ogg'
=== renamed file 'data/sound/animals/elk_01.ogg' => 'data/sound/animals/elk_00.ogg'
=== renamed file 'data/sound/animals/elk_02.ogg' => 'data/sound/animals/elk_01.ogg'
=== renamed file 'data/sound/animals/elk_10.ogg' => 'data/sound/animals/elk_02.ogg'
=== renamed file 'data/sound/animals/elk_11.ogg' => 'data/sound/animals/elk_03.ogg'
=== renamed file 'data/sound/animals/frog1_00.ogg' => 'data/sound/animals/frog.ogg'
=== renamed file 'data/sound/animals/stag_01.ogg' => 'data/sound/animals/stag_00.ogg'
=== renamed file 'data/sound/animals/stag_02.ogg' => 'data/sound/animals/stag_01.ogg'
=== renamed file 'data/sound/animals/stag_10.ogg' => 'data/sound/animals/stag_02.ogg'
=== renamed file 'data/sound/animals/stag_11.ogg' => 'data/sound/animals/stag_03.ogg'
=== renamed file 'data/sound/animals/stag_12.ogg' => 'data/sound/animals/stag_04.ogg'
=== renamed file 'data/sound/animals/stag_13.ogg' => 'data/sound/animals/stag_05.ogg'
=== renamed file 'data/sound/animals/wolf_01.ogg' => 'data/sound/animals/wolf_00.ogg'
=== renamed file 'data/sound/animals/wolf_02.ogg' => 'data/sound/animals/wolf_01.ogg'
=== renamed file 'data/sound/animals/wolf_03.ogg' => 'data/sound/animals/wolf_02.ogg'
=== renamed file 'data/sound/animals/wolf_10.ogg' => 'data/sound/animals/wolf_03.ogg'
=== renamed file 'data/sound/animals/wolf_11.ogg' => 'data/sound/animals/wolf_04.ogg'
=== renamed file 'data/sound/animals/wolf_12.ogg' => 'data/sound/animals/wolf_05.ogg'
=== renamed file 'data/sound/animals/wolf_13.ogg' => 'data/sound/animals/wolf_06.ogg'
=== renamed file 'data/sound/animals/wolf_14.ogg' => 'data/sound/animals/wolf_07.ogg'
=== renamed file 'data/sound/atlanteans/cutting/stonecutter_01.ogg' => 'data/sound/atlanteans/cutting/stonecutter_00.ogg'
=== renamed file 'data/sound/atlanteans/cutting/stonecutter_02.ogg' => 'data/sound/atlanteans/cutting/stonecutter_01.ogg'
=== renamed file 'data/sound/atlanteans/cutting/stonecutter_03.ogg' => 'data/sound/atlanteans/cutting/stonecutter_02.ogg'
=== renamed file 'data/sound/atlanteans/goldspin_01.ogg' => 'data/sound/atlanteans/goldspin_00.ogg'
=== renamed file 'data/sound/atlanteans/goldspin_02.ogg' => 'data/sound/atlanteans/goldspin_01.ogg'
=== renamed file 'data/sound/atlanteans/saw/benchsaw_01.ogg' => 'data/sound/atlanteans/saw/benchsaw_00.ogg'
=== renamed file 'data/sound/atlanteans/saw/benchsaw_02.ogg' => 'data/sound/atlanteans/saw/benchsaw_01.ogg'
=== renamed file 'data/sound/atlanteans/saw/benchsaw_03.ogg' => 'data/sound/atlanteans/saw/benchsaw_02.ogg'
=== renamed file 'data/sound/atlanteans/saw/sawing_01.ogg' => 'data/sound/atlanteans/saw/sawing_00.ogg'
=== renamed file 'data/sound/atlanteans/saw/sawing_02.ogg' => 'data/sound/atlanteans/saw/sawing_01.ogg'
=== renamed file 'data/sound/atlanteans/saw/sawing_03.ogg' => 'data/sound/atlanteans/saw/sawing_02.ogg'
=== renamed file 'data/sound/barbarians/blackwood_01.ogg' => 'data/sound/barbarians/blackwood.ogg'
=== renamed file 'data/sound/barbarians/mortar_01.ogg' => 'data/sound/barbarians/mortar.ogg'
=== renamed file 'data/sound/barbarians/stonegrind_01.ogg' => 'data/sound/barbarians/stonegrind.ogg'
=== renamed file 'data/sound/barbarians/taverns/biginn_01.ogg' => 'data/sound/barbarians/taverns/biginn_00.ogg'
=== renamed file 'data/sound/barbarians/taverns/biginn_02.ogg' => 'data/sound/barbarians/taverns/biginn_01.ogg'
=== removed file 'data/sound/barbarians/taverns/biginn_10.ogg'
Binary files data/sound/barbarians/taverns/biginn_10.ogg	2016-07-18 09:25:41 +0000 and data/sound/barbarians/taverns/biginn_10.ogg	1970-01-01 00:00:00 +0000 differ
=== renamed file 'data/sound/barbarians/taverns/inn_01.ogg' => 'data/sound/barbarians/taverns/inn_00.ogg'
=== renamed file 'data/sound/barbarians/taverns/inn_02.ogg' => 'data/sound/barbarians/taverns/inn_01.ogg'
=== removed file 'data/sound/barbarians/taverns/inn_10.ogg'
Binary files data/sound/barbarians/taverns/inn_10.ogg	2016-07-18 09:25:41 +0000 and data/sound/barbarians/taverns/inn_10.ogg	1970-01-01 00:00:00 +0000 differ
=== renamed file 'data/sound/barbarians/taverns/tavern_01.ogg' => 'data/sound/barbarians/taverns/tavern_00.ogg'
=== renamed file 'data/sound/barbarians/taverns/tavern_02.ogg' => 'data/sound/barbarians/taverns/tavern_01.ogg'
=== removed file 'data/sound/barbarians/taverns/tavern_10.ogg'
Binary files data/sound/barbarians/taverns/tavern_10.ogg	2016-07-18 09:25:41 +0000 and data/sound/barbarians/taverns/tavern_10.ogg	1970-01-01 00:00:00 +0000 differ
=== renamed file 'data/sound/barbarians/weaver_01.ogg' => 'data/sound/barbarians/weaver.ogg'
=== renamed file 'data/sound/click_00.ogg' => 'data/sound/click.ogg'
=== renamed file 'data/sound/create_construction_site_00.ogg' => 'data/sound/create_construction_site.ogg'
=== renamed file 'data/sound/empire/beerbubble_01.ogg' => 'data/sound/empire/beerbubble_00.ogg'
=== renamed file 'data/sound/empire/beerbubble_02.ogg' => 'data/sound/empire/beerbubble_01.ogg'
=== renamed file 'data/sound/empire/taverns/meal_01.ogg' => 'data/sound/empire/taverns/meal_00.ogg'
=== renamed file 'data/sound/empire/taverns/meal_02.ogg' => 'data/sound/empire/taverns/meal_01.ogg'
=== removed file 'data/sound/empire/taverns/meal_10.ogg'
Binary files data/sound/empire/taverns/meal_10.ogg	2016-07-18 09:25:41 +0000 and data/sound/empire/taverns/meal_10.ogg	1970-01-01 00:00:00 +0000 differ
=== renamed file 'data/sound/empire/taverns/ration_01.ogg' => 'data/sound/empire/taverns/ration_00.ogg'
=== renamed file 'data/sound/empire/taverns/ration_02.ogg' => 'data/sound/empire/taverns/ration_01.ogg'
=== removed file 'data/sound/empire/taverns/ration_10.ogg'
Binary files data/sound/empire/taverns/ration_10.ogg	2016-07-18 09:25:41 +0000 and data/sound/empire/taverns/ration_10.ogg	1970-01-01 00:00:00 +0000 differ
=== renamed file 'data/sound/empire/winebubble_01.ogg' => 'data/sound/empire/winebubble_00.ogg'
=== renamed file 'data/sound/empire/winebubble_02.ogg' => 'data/sound/empire/winebubble_01.ogg'
=== renamed file 'data/sound/farm/donkey_00.ogg' => 'data/sound/farm/donkey.ogg'
=== renamed file 'data/sound/farm/sheep_01.ogg' => 'data/sound/farm/sheep_00.ogg'
=== renamed file 'data/sound/farm/sheep_02.ogg' => 'data/sound/farm/sheep_01.ogg'
=== renamed file 'data/sound/farm/sheep_03.ogg' => 'data/sound/farm/sheep_02.ogg'
=== renamed file 'data/sound/fisher/fisher_pull_net_00.ogg' => 'data/sound/fisher/fisher_pull_net.ogg'
=== renamed file 'data/sound/fisher/fisher_throw_net_00.ogg' => 'data/sound/fisher/fisher_throw_net.ogg'
=== renamed file 'data/sound/hammering/geologist_hammer_00.ogg' => 'data/sound/hammering/geologist_hammer.ogg'
=== renamed file 'data/sound/lobby_chat_00.ogg' => 'data/sound/lobby_chat.ogg'
=== renamed file 'data/sound/lobby_freshmen_00.ogg' => 'data/sound/lobby_freshmen.ogg'
=== renamed file 'data/sound/metal/fizzle_01.ogg' => 'data/sound/metal/fizzle.ogg'
=== renamed file 'data/sound/metal/furnace_01.ogg' => 'data/sound/metal/furnace.ogg'
=== renamed file 'data/sound/metal/goldping_01.ogg' => 'data/sound/metal/goldping.ogg'
=== renamed file 'data/sound/metal/ironping_01.ogg' => 'data/sound/metal/ironping.ogg'
=== renamed file 'data/sound/military/site_occupied_00.ogg' => 'data/sound/military/site_occupied.ogg'
=== renamed file 'data/sound/military/under_attack_00.ogg' => 'data/sound/military/under_attack.ogg'
=== renamed file 'data/sound/mill/weaving_01.ogg' => 'data/sound/mill/weaving.ogg'
=== renamed file 'data/sound/smiths/sharpening_00.ogg' => 'data/sound/smiths/sharpening.ogg'
=== removed directory 'data/sound/spoken'
=== removed file 'data/sound/spoken/timber_00.ogg'
Binary files data/sound/spoken/timber_00.ogg	2008-10-19 07:47:24 +0000 and data/sound/spoken/timber_00.ogg	1970-01-01 00:00:00 +0000 differ
=== removed file 'data/sound/spoken/timber_01.ogg'
Binary files data/sound/spoken/timber_01.ogg	2008-10-19 07:47:24 +0000 and data/sound/spoken/timber_01.ogg	1970-01-01 00:00:00 +0000 differ
=== renamed file 'data/sound/stonecutting/stonecutter_00.ogg' => 'data/sound/stonecutting/stonecutter.ogg'
=== renamed file 'data/sound/stonecutting/stonemason_00.ogg' => 'data/sound/stonecutting/stonemason.ogg'
=== modified file 'data/sound/wl-sound-docu.csv'
--- data/sound/wl-sound-docu.csv	2017-02-09 13:11:36 +0000
+++ data/sound/wl-sound-docu.csv	2019-04-28 09:46:14 +0000
@@ -1,53 +1,54 @@
 Widelands Sound Documentation (toptopple’s sounds added since BZR 8019),,,,,,,,,,
+There are some empty sounds to reduce the probability value of playing them below 1. You can recognize them by the file size of 3.6kB.,,,,,,,,,,
 ,,,,,,,,,,
 File Name,Format,Location,Usage,Author,License,reworked,Original File Name,Source,Orig. Format,BZR
 ,,,,,,,,,,
+beerbubble_00.ogg,11025 – 16,sound/empire,empire.brewery,Julian Evans,CC-0,yes,338107__mentalsanityoff__beer-fermenter-gurgling-liquid-bubbles-glug.wav,http://www.freesound.org/people/MentalSanityOff/sounds/338107/,48000 – 24,8022
 beerbubble_01.ogg,11025 – 16,sound/empire,empire.brewery,Julian Evans,CC-0,yes,338107__mentalsanityoff__beer-fermenter-gurgling-liquid-bubbles-glug.wav,http://www.freesound.org/people/MentalSanityOff/sounds/338107/,48000 – 24,8022
-beerbubble_02.ogg,11025 – 16,sound/empire,empire.brewery,Julian Evans,CC-0,yes,338107__mentalsanityoff__beer-fermenter-gurgling-liquid-bubbles-glug.wav,http://www.freesound.org/people/MentalSanityOff/sounds/338107/,48000 – 24,8022
+winebubble_00.ogg,22050 – 16,sound/empire,empire.winery,Michael Hinze,CC-0,yes,275578__hinzebeat__big-bubbles-on-water.wav,http://www.freesound.org/people/hinzebeat/sounds/275578/,44100 – 16,8022
 winebubble_01.ogg,22050 – 16,sound/empire,empire.winery,Michael Hinze,CC-0,yes,275578__hinzebeat__big-bubbles-on-water.wav,http://www.freesound.org/people/hinzebeat/sounds/275578/,44100 – 16,8022
-winebubble_02.ogg,22050 – 16,sound/empire,empire.winery,Michael Hinze,CC-0,yes,275578__hinzebeat__big-bubbles-on-water.wav,http://www.freesound.org/people/hinzebeat/sounds/275578/,44100 – 16,8022
-fizzle_01.ogg,11025 – 16,sound/metal,empire.smelting_works,luffy,CC-3,yes,17299__luffy__luffy-fire3alternate.wav,http://www.freesound.org/people/luffy/sounds/17299/,44100 – 16,8022
-ironping_01.ogg,22050 – 16,sound/metal,empire.smelting_works,timgormly,CC-3,yes,170964__timgormly__metal-ping1.aiff,http://www.freesound.org/people/timgormly/sounds/170964/,44100 – 16,8022
-goldping_01.ogg,22050 – 16,sound/metal,empire.smelting_works,timgormly,CC-3,yes,170964__timgormly__metal-ping1.aiff,http://www.freesound.org/people/timgormly/sounds/170964/,44100 – 16,8022
-furnace_01.ogg,11025 – 16,sound/metal,barbarian.smelting_works,UNKNOWN,,yes,Fire-8.wav,UNKNOWN,22050,8022
-blackwood_01.ogg,11025 – 16,sound/barbarians,barbarian.wood_hardener,UNKNOWN,,,Creek-1.wav,UNKNOWN,11025-32,8029
-mortar_01.ogg,11025 – 16,sound/barbarians,barbarian.limekiln,qubodup,CC-0,yes,184383__qubodup__gathering-stone-resources.flac,http://www.freesound.org/people/qubodup/sounds/184383/,48000 – 16,8029
-stonegrind_01.ogg,22050 – 16,sound/barbarians,barbarian.limekiln,timgormly,CC-3,yes,232102__thalamus-lab__stone-grind.wav,http://www.freesound.org/people/Thalamus_Lab/sounds/232102/,44100 – 32,8029
-tavern_01.ogg,11025 – 16,sound/barbarians/taverns,,UNKNOWN,,,Dishes-21.wav,UNKNOWN,11025,8029
-tavern_02.ogg,16000,sound/barbarians/taverns,,UNKNOWN,,,Dishes-1.wav,UNKNOWN,22050,8029
-inn_01.ogg,22050 – 16,sound/barbarians/taverns,barbarian.inn,Eelke Dekker,CC-3,yes,192099__eelke__preparing-dishes.wav,http://www.freesound.org/people/Eelke/sounds/192099/,44100 – 32,8145
-inn_02.ogg,22050 – 16,sound/barbarians/taverns,barbarian.inn,Hannebu,CC-0,yes,194806__hannebu__frying.wav,http://www.freesound.org/people/Hannebu/sounds/194806/,48000 – 24,8145
-biginn_01.ogg,22050 – 16,sound/barbarians/taverns,barbarian.biginn,Eelke Dekker,CC-3,yes,192099__eelke__preparing-dishes.wav,http://www.freesound.org/people/Eelke/sounds/192099/,44100 – 32,8145
-biginn_02.ogg,11025 – 16,sound/barbarians/taverns,barbarian.biginn,Mike Koenig,CC-3,yes,Glass Cookie Jar-SoundBible.com-2105585386.wav,http://soundbible.com/314-Glass-Cookie-Jar.html,32000 – 32,8145
-meal_01.ogg,,sound/empire/taverns,empire.biginn,DUPLICATE to inn_01.ogg,,,,,,8145
-meal_02.ogg,22050 – 16,sound/empire/taverns,empire.biginn,UNKNOWN,,,Bottle-2.wav,UNKNOWN,22050 – 32,8145
-ration_01.ogg,,sound/empire/taverns,empire.inn,DUPLICATE to tavern_02.ogg,,,,,,8145
-ration_02.ogg,,sound/empire/taverns,empire.inn,DUPLICATE to tavern_01.ogg,,,,,,8145
-weaving_01.ogg,22050 – 32,sound/mill,"empire.weavingmill, atlanteans.weavingmill",Xavier Serra,CC-3,yes,320510__xserra__kerala-1.wav,http://www.freesound.org/people/xserra/sounds/320510/,44100 – 16,8251
-weaver_01.ogg,22050 – 32,sound/barbarians,barbarian.weavingmill,Yle Arkisto,CC-3,yes,368577__ylearkisto__kangaspuut-old-wooden-loom-from-1857-weaving-a-rag-rug.wav,http://www.freesound.org/people/YleArkisto/sounds/368577/,44100 – 24,8251
+fizzle.ogg,11025 – 16,sound/metal,empire.smelting_works,luffy,CC-3,yes,17299__luffy__luffy-fire3alternate.wav,http://www.freesound.org/people/luffy/sounds/17299/,44100 – 16,8022
+ironping.ogg,22050 – 16,sound/metal,empire.smelting_works,timgormly,CC-3,yes,170964__timgormly__metal-ping1.aiff,http://www.freesound.org/people/timgormly/sounds/170964/,44100 – 16,8022
+goldping.ogg,22050 – 16,sound/metal,empire.smelting_works,timgormly,CC-3,yes,170964__timgormly__metal-ping1.aiff,http://www.freesound.org/people/timgormly/sounds/170964/,44100 – 16,8022
+furnace.ogg,11025 – 16,sound/metal,barbarian.smelting_works,UNKNOWN,,yes,Fire-8.wav,UNKNOWN,22050,8022
+blackwood.ogg,11025 – 16,sound/barbarians,barbarian.wood_hardener,UNKNOWN,,,Creek-1.wav,UNKNOWN,11025-32,8029
+mortar.ogg,11025 – 16,sound/barbarians,barbarian.limekiln,qubodup,CC-0,yes,184383__qubodup__gathering-stone-resources.flac,http://www.freesound.org/people/qubodup/sounds/184383/,48000 – 16,8029
+stonegrind.ogg,22050 – 16,sound/barbarians,barbarian.limekiln,timgormly,CC-3,yes,232102__thalamus-lab__stone-grind.wav,http://www.freesound.org/people/Thalamus_Lab/sounds/232102/,44100 – 32,8029
+tavern_00.ogg,11025 – 16,sound/barbarians/taverns,,UNKNOWN,,,Dishes-21.wav,UNKNOWN,11025,8029
+tavern_01.ogg,16000,sound/barbarians/taverns,,UNKNOWN,,,Dishes-1.wav,UNKNOWN,22050,8029
+inn_00.ogg,22050 – 16,sound/barbarians/taverns,barbarian.inn,Eelke Dekker,CC-3,yes,192099__eelke__preparing-dishes.wav,http://www.freesound.org/people/Eelke/sounds/192099/,44100 – 32,8145
+inn_01.ogg,22050 – 16,sound/barbarians/taverns,barbarian.inn,Hannebu,CC-0,yes,194806__hannebu__frying.wav,http://www.freesound.org/people/Hannebu/sounds/194806/,48000 – 24,8145
+biginn_00.ogg,22050 – 16,sound/barbarians/taverns,barbarian.biginn,Eelke Dekker,CC-3,yes,192099__eelke__preparing-dishes.wav,http://www.freesound.org/people/Eelke/sounds/192099/,44100 – 32,8145
+biginn_01.ogg,11025 – 16,sound/barbarians/taverns,barbarian.biginn,Mike Koenig,CC-3,yes,Glass Cookie Jar-SoundBible.com-2105585386.wav,http://soundbible.com/314-Glass-Cookie-Jar.html,32000 – 32,8145
+meal_00.ogg,,sound/empire/taverns,empire.biginn,DUPLICATE to inn_01.ogg,,,,,,8145
+meal_01.ogg,22050 – 16,sound/empire/taverns,empire.biginn,UNKNOWN,,,Bottle-2.wav,UNKNOWN,22050 – 32,8145
+ration_00.ogg,,sound/empire/taverns,empire.inn,DUPLICATE to tavern_02.ogg,,,,,,8145
+ration_01.ogg,,sound/empire/taverns,empire.inn,DUPLICATE to tavern_01.ogg,,,,,,8145
+weaving.ogg,22050 – 32,sound/mill,"empire.weavingmill, atlanteans.weavingmill",Xavier Serra,CC-3,yes,320510__xserra__kerala-1.wav,http://www.freesound.org/people/xserra/sounds/320510/,44100 – 16,8251
+weaver.ogg,22050 – 32,sound/barbarians,barbarian.weavingmill,Yle Arkisto,CC-3,yes,368577__ylearkisto__kangaspuut-old-wooden-loom-from-1857-weaving-a-rag-rug.wav,http://www.freesound.org/people/YleArkisto/sounds/368577/,44100 – 24,8251
+stonecutter_00.ogg,22050 – 32,sound/atlanteans/cutting,atlanteans.stonecutter,Benboncan,CC-3,yes,71823__benboncan__pickaxe-striking-rock.wav,http://www.freesound.org/people/Benboncan/sounds/71823/,44100 – 16,8251
 stonecutter_01.ogg,22050 – 32,sound/atlanteans/cutting,atlanteans.stonecutter,Benboncan,CC-3,yes,71823__benboncan__pickaxe-striking-rock.wav,http://www.freesound.org/people/Benboncan/sounds/71823/,44100 – 16,8251
 stonecutter_02.ogg,22050 – 32,sound/atlanteans/cutting,atlanteans.stonecutter,Benboncan,CC-3,yes,71823__benboncan__pickaxe-striking-rock.wav,http://www.freesound.org/people/Benboncan/sounds/71823/,44100 – 16,8251
-stonecutter_03.ogg,22050 – 32,sound/atlanteans/cutting,atlanteans.stonecutter,Benboncan,CC-3,yes,71823__benboncan__pickaxe-striking-rock.wav,http://www.freesound.org/people/Benboncan/sounds/71823/,44100 – 16,8251
+benchsaw_00.ogg,22050 – 32,sound/atlanteans/saw,atlanteans.sawmill,mauxuam,CC-0,yes,216828__mauxuam__saw-of-avalon-2.wav,http://www.freesound.org/people/mauxuam/sounds/216828/,44100 – 16,8251
 benchsaw_01.ogg,22050 – 32,sound/atlanteans/saw,atlanteans.sawmill,mauxuam,CC-0,yes,216828__mauxuam__saw-of-avalon-2.wav,http://www.freesound.org/people/mauxuam/sounds/216828/,44100 – 16,8251
-benchsaw_02.ogg,22050 – 32,sound/atlanteans/saw,atlanteans.sawmill,mauxuam,CC-0,yes,216828__mauxuam__saw-of-avalon-2.wav,http://www.freesound.org/people/mauxuam/sounds/216828/,44100 – 16,8251
+sawing_00.ogg,22050 – 32,sound/atlanteans/saw,atlanteans.woodcutter,dobroide,CC-3,yes,102844__dobroide__20100802-sawing.wav,http://www.freesound.org/people/dobroide/sounds/102844/,44100 – 16,8251
 sawing_01.ogg,22050 – 32,sound/atlanteans/saw,atlanteans.woodcutter,dobroide,CC-3,yes,102844__dobroide__20100802-sawing.wav,http://www.freesound.org/people/dobroide/sounds/102844/,44100 – 16,8251
 sawing_02.ogg,22050 – 32,sound/atlanteans/saw,atlanteans.woodcutter,dobroide,CC-3,yes,102844__dobroide__20100802-sawing.wav,http://www.freesound.org/people/dobroide/sounds/102844/,44100 – 16,8251
-sawing_03.ogg,22050 – 32,sound/atlanteans/saw,atlanteans.woodcutter,dobroide,CC-3,yes,102844__dobroide__20100802-sawing.wav,http://www.freesound.org/people/dobroide/sounds/102844/,44100 – 16,8251
+goldspin_00.ogg,22050 – 32,sound/atlanteans,atlanteans.goldspinner,Mike Koenig,CC-3,yes,Metal Debris Falling-SoundBible.com-238218965.wav,http://soundbible.com/1099-Metal-Debris-Falling.html,44100 – 16,8251
 goldspin_01.ogg,22050 – 32,sound/atlanteans,atlanteans.goldspinner,Mike Koenig,CC-3,yes,Metal Debris Falling-SoundBible.com-238218965.wav,http://soundbible.com/1099-Metal-Debris-Falling.html,44100 – 16,8251
-goldspin_02.ogg,22050 – 32,sound/atlanteans,atlanteans.goldspinner,Mike Koenig,CC-3,yes,Metal Debris Falling-SoundBible.com-238218965.wav,http://soundbible.com/1099-Metal-Debris-Falling.html,44100 – 16,8251
-tree-falling_00.ogg,11025 – 16,sound/woodcutting,woodcutters,ecfike,CC-0,yes,139952__ecfike__a-tree-falling-down.wav,http://www.freesound.org/people/ecfike/sounds/139952/,44100 – 16,new
-tree-falling_01.ogg,11025 – 16,sound/woodcutting,woodcutters,Daniel Simion,CC-3,yes,Tree_Fall_Small-Daniel_Simion-1639156552.wav,http://soundbible.com/2039-Tree-Fall-Small.html,44100 – 16,new
+tree_falling_00.ogg,11025 – 16,sound/woodcutting,woodcutters,ecfike,CC-0,yes,139952__ecfike__a-tree-falling-down.wav,http://www.freesound.org/people/ecfike/sounds/139952/,44100 – 16,new
+tree_falling_01.ogg,11025 – 16,sound/woodcutting,woodcutters,Daniel Simion,CC-3,yes,Tree_Fall_Small-Daniel_Simion-1639156552.wav,http://soundbible.com/2039-Tree-Fall-Small.html,44100 – 16,new
 ,,,,,,,,,,
-boar_01.ogg,11025 – 16,data/sound/animals,,UNKNOWN,personal,yes,Pig-SoundBible.com-1026656068.wav,http://soundbible.com/736-Pig.html,11025,8019
-elk_01.ogg,16000,data/sound/animals,,fws.gov,PD,yes,Elk Bellowing In Forest-SoundBible.com-681308174.wav,http://soundbible.com/245-Elk-Bellowing-In-Forest.html,48000,8019
-elk_02.ogg,22050 – 16,data/sound/animals,,fws.gov,PD,yes,Elk Bellowing In Forest 2-SoundBible.com-860406835.wav,http://soundbible.com/246-Elk-Bellowing-In-Forest-2.html,48000,8029
+boar.ogg,11025 – 16,data/sound/animals,,UNKNOWN,personal,yes,Pig-SoundBible.com-1026656068.wav,http://soundbible.com/736-Pig.html,11025,8019
+elk_00.ogg,16000,data/sound/animals,,fws.gov,PD,yes,Elk Bellowing In Forest-SoundBible.com-681308174.wav,http://soundbible.com/245-Elk-Bellowing-In-Forest.html,48000,8019
+elk_01.ogg,22050 – 16,data/sound/animals,,fws.gov,PD,yes,Elk Bellowing In Forest 2-SoundBible.com-860406835.wav,http://soundbible.com/246-Elk-Bellowing-In-Forest-2.html,48000,8029
+stag_00.ogg,11025 – 16,data/sound/animals,,Juan Carlos,PD,yes,Red_stag_roar-Juan_Carlos_-2004708707.wav,http://soundbible.com/2073-Red-Stag-Roar.html,44100 – 16,8019
 stag_01.ogg,11025 – 16,data/sound/animals,,Juan Carlos,PD,yes,Red_stag_roar-Juan_Carlos_-2004708707.wav,http://soundbible.com/2073-Red-Stag-Roar.html,44100 – 16,8019
-stag_02.ogg,11025 – 16,data/sound/animals,,Juan Carlos,PD,yes,Red_stag_roar-Juan_Carlos_-2004708707.wav,http://soundbible.com/2073-Red-Stag-Roar.html,44100 – 16,8019
+coyote_00.ogg,11025 – 16,data/sound/animals,,UNKNOWN,PD,yes,Coyote Call-SoundBible.com-2012388009.wav,http://soundbible.com/977-Coyote-Call.html,44100 – 16,8019
 coyote_01.ogg,11025 – 16,data/sound/animals,,UNKNOWN,PD,yes,Coyote Call-SoundBible.com-2012388009.wav,http://soundbible.com/977-Coyote-Call.html,44100 – 16,8019
-coyote_02.ogg,11025 – 16,data/sound/animals,,UNKNOWN,PD,yes,Coyote Call-SoundBible.com-2012388009.wav,http://soundbible.com/977-Coyote-Call.html,44100 – 16,8019
-wolf_01.ogg,11025 – 16,data/sound/animals,,UNKNOWN,,,Howl-5.wav,UNKNOWN,11025,8019
-wolf_02.ogg,22050 – 16,data/sound/animals,,UNKNOWN,,,Howl-4.wav,UNKNOWN,22050,8019
-wolf_03.ogg,11025 – 16,data/sound/animals,,UNKNOWN,,,Howl-6.wav,UNKNOWN,11025,8019
-sheep_01.ogg,22050 – 16,data/sound/farm,,UNKNOWN,,,Sheep-3.wav,UNKNOWN,22050,8019
-sheep_02.ogg,22050 – 16,data/sound/farm,,UNKNOWN,,,Sheep-6.wav,UNKNOWN,22050,8019
-sheep_03.ogg,22050 – 16,data/sound/farm,,UNKNOWN,,,Sheep-2.wav,UNKNOWN,22050,8019
+wolf_00.ogg,11025 – 16,data/sound/animals,,UNKNOWN,,,Howl-5.wav,UNKNOWN,11025,8019
+wolf_01.ogg,22050 – 16,data/sound/animals,,UNKNOWN,,,Howl-4.wav,UNKNOWN,22050,8019
+wolf_02.ogg,11025 – 16,data/sound/animals,,UNKNOWN,,,Howl-6.wav,UNKNOWN,11025,8019
+sheep_00.ogg,22050 – 16,data/sound/farm,,UNKNOWN,,,Sheep-3.wav,UNKNOWN,22050,8019
+sheep_01.ogg,22050 – 16,data/sound/farm,,UNKNOWN,,,Sheep-6.wav,UNKNOWN,22050,8019
+sheep_02.ogg,22050 – 16,data/sound/farm,,UNKNOWN,,,Sheep-2.wav,UNKNOWN,22050,8019

=== removed file 'data/sound/woodcutting/tree-falling_10.ogg'
Binary files data/sound/woodcutting/tree-falling_10.ogg	2017-02-07 18:05:21 +0000 and data/sound/woodcutting/tree-falling_10.ogg	1970-01-01 00:00:00 +0000 differ
=== renamed file 'data/sound/woodcutting/tree-falling_00.ogg' => 'data/sound/woodcutting/tree_falling_00.ogg'
=== renamed file 'data/sound/woodcutting/tree-falling_01.ogg' => 'data/sound/woodcutting/tree_falling_01.ogg'
=== renamed file 'data/sound/woodcutting/woodcutting_00.ogg' => 'data/sound/woodcutting/woodcutting.ogg'
=== modified file 'data/tribes/atlanteans.lua'
--- data/tribes/atlanteans.lua	2018-07-29 13:49:09 +0000
+++ data/tribes/atlanteans.lua	2019-04-28 09:46:14 +0000
@@ -5,10 +5,7 @@
 -- ---------------------
 --
 -- This file contains all the units for a tribe.
-
-dirname = path.dirname(__file__)
-
--- RST
+--
 -- .. function:: new_tribe{table}
 --
 --    This function adds all units to a tribe.
@@ -47,31 +44,25 @@
 --    **ship**: The internal name of the tribe's ship.
 --
 --    **port**: The internal name of the tribe's port building. This unit needs to be defined in the ``buildings`` table too.
+
+image_dirname = path.dirname(__file__) .. "images/atlanteans/"
+
+animations = {}
+add_animation(animations, "frontier", image_dirname, "frontier", {3, 12})
+add_animation(animations, "flag", image_dirname, "flag", {15, 35}, 10)
+
 tribes:new_tribe {
    name = "atlanteans",
-
-   animations = {
-      -- Some blue fires would be fine, but just an idea
-      frontier = {
-         pictures = path.list_files(dirname .. "images/atlanteans/frontier_??.png"),
-         hotspot = { 3, 12 },
-      },
-      flag = {
-         -- Not just a plain color, maybe a cross or some stripes
-         pictures = path.list_files(dirname .. "images/atlanteans/flag_??.png"),
-         hotspot = { 15, 35 },
-         fps = 10
-      }
-   },
+   animations = animations,
 
    -- Image file paths for this tribe's road textures
    roads = {
       busy = {
-         "tribes/images/atlanteans/roadt_busy.png",
+         image_dirname .. "roadt_busy.png",
       },
       normal = {
-         "tribes/images/atlanteans/roadt_normal_00.png",
-         "tribes/images/atlanteans/roadt_normal_01.png",
+         image_dirname .. "roadt_normal_00.png",
+         image_dirname .. "roadt_normal_01.png",
       },
    },
 

=== modified file 'data/tribes/barbarians.lua'
--- data/tribes/barbarians.lua	2018-07-29 13:49:09 +0000
+++ data/tribes/barbarians.lua	2019-04-28 09:46:14 +0000
@@ -1,28 +1,21 @@
-dirname = path.dirname(__file__)
+image_dirname = path.dirname(__file__) .. "images/barbarians/"
+
+animations = {}
+add_animation(animations, "frontier", image_dirname, "frontier", {1, 19})
+add_animation(animations, "flag", image_dirname, "flag", {10, 38}, 5)
 
 tribes:new_tribe {
    name = "barbarians",
-
-   animations = {
-      frontier = {
-         pictures = path.list_files(dirname .. "images/barbarians/frontier_??.png"),
-         hotspot = { 1, 19 },
-      },
-      flag = {
-         pictures = path.list_files(dirname .. "images/barbarians/flag_??.png"),
-         hotspot = { 10, 38 },
-         fps = 5
-      }
-   },
+   animations = animations,
 
    -- Image file paths for this tribe's road textures
    roads = {
       busy = {
-         "tribes/images/barbarians/roadt_busy.png",
+         image_dirname .. "roadt_busy.png",
       },
       normal = {
-         "tribes/images/barbarians/roadt_normal_00.png",
-         "tribes/images/barbarians/roadt_normal_01.png",
+         image_dirname .. "roadt_normal_00.png",
+         image_dirname .. "roadt_normal_01.png",
       },
    },
 

=== modified file 'data/tribes/empire.lua'
--- data/tribes/empire.lua	2018-07-29 13:49:09 +0000
+++ data/tribes/empire.lua	2019-04-28 09:46:14 +0000
@@ -1,31 +1,22 @@
-dirname = path.dirname(__file__)
+image_dirname = path.dirname(__file__) .. "images/empire/"
+
+animations = {}
+add_animation(animations, "frontier", image_dirname, "frontier", {1, 19})
+add_animation(animations, "flag", image_dirname, "flag", {14, 38}, 10)
 
 tribes:new_tribe {
    name = "empire",
-
-   animations = {
-      -- No idea for the frontier. Maybe some javelins?
-      frontier = {
-         pictures = path.list_files(dirname .. "images/empire/frontier_??.png"),
-         hotspot = { 1, 19 },
-      },
-      -- Not just a plain color, maybe a cross or some stripes
-      flag = {
-         pictures = path.list_files(dirname .. "images/empire/flag_??.png"),
-         hotspot = { 14, 38 },
-         fps = 10
-      }
-   },
+   animations = animations,
 
    -- Image file paths for this tribe's road textures
    roads = {
       busy = {
-         "tribes/images/empire/roadt_busy.png",
+         image_dirname .. "roadt_busy.png",
       },
       normal = {
-         "tribes/images/empire/roadt_normal_00.png",
-         "tribes/images/empire/roadt_normal_01.png",
-         "tribes/images/empire/roadt_normal_02.png",
+         image_dirname .. "roadt_normal_00.png",
+         image_dirname .. "roadt_normal_01.png",
+         image_dirname .. "roadt_normal_02.png",
       },
    },
 

=== modified file 'data/tribes/frisians.lua'
--- data/tribes/frisians.lua	2019-02-28 11:03:51 +0000
+++ data/tribes/frisians.lua	2019-04-28 09:46:14 +0000
@@ -1,28 +1,21 @@
-dirname = path.dirname (__file__)
+image_dirname = path.dirname(__file__) .. "images/frisians/"
+
+animations = {}
+add_animation(animations, "frontier", image_dirname, "frontier", {9, 26})
+add_animation(animations, "flag", image_dirname, "flag", {10, 39}, 10)
 
 tribes:new_tribe {
    name = "frisians",
-
-   animations = {
-      frontier = {
-         pictures = path.list_files (dirname .. "images/frisians/frontier_??.png"),
-         hotspot = { 9, 26 },
-      },
-      flag = {
-         pictures = path.list_files (dirname .. "images/frisians/flag_??.png"),
-         hotspot = { 10, 39 },
-         fps = 10,
-      }
-   },
+   animations = animations,
 
    -- Image file paths for this tribe's road textures
    roads = {
       busy = {
-         "tribes/images/frisians/roadt_busy.png",
+         image_dirname .. "roadt_busy.png",
       },
       normal = {
-         "tribes/images/frisians/roadt_normal_00.png",
-         "tribes/images/frisians/roadt_normal_01.png",
+         image_dirname .. "roadt_normal_00.png",
+         image_dirname .. "roadt_normal_01.png",
       },
    },
 

=== modified file 'data/tribes/immovables/berry_bushes/blueberry/init.lua'
--- data/tribes/immovables/berry_bushes/blueberry/init.lua	2019-03-02 13:56:42 +0000
+++ data/tribes/immovables/berry_bushes/blueberry/init.lua	2019-04-28 09:46:14 +0000
@@ -10,7 +10,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "tiny/idle", { 6, 7 })
+add_animation(animations, "idle", dirname .. "tiny", "idle", { 6, 7 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -31,7 +31,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "small/idle", { 12, 13 })
+add_animation(animations, "idle", dirname .. "small", "idle", { 12, 13 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -52,7 +52,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "medium/idle", { 15, 16 })
+add_animation(animations, "idle", dirname .. "medium", "idle", { 15, 16 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -73,7 +73,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "ripe/idle", { 15, 16 })
+add_animation(animations, "idle", dirname .. "ripe", "idle", { 15, 16 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",

=== modified file 'data/tribes/immovables/berry_bushes/currant_black/init.lua'
--- data/tribes/immovables/berry_bushes/currant_black/init.lua	2019-03-02 13:56:42 +0000
+++ data/tribes/immovables/berry_bushes/currant_black/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "tiny/idle", { 4, 10 })
+add_animation(animations, "idle", dirname .. "tiny", "idle", { 4, 10 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -29,7 +29,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "small/idle", { 8, 20 })
+add_animation(animations, "idle", dirname .. "small", "idle", { 8, 20 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -50,7 +50,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "medium/idle", { 13, 33 })
+add_animation(animations, "idle", dirname .. "medium", "idle", { 13, 33 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -71,7 +71,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "ripe/idle", { 13, 33 })
+add_animation(animations, "idle", dirname .. "ripe", "idle", { 13, 33 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",

=== modified file 'data/tribes/immovables/berry_bushes/currant_red/init.lua'
--- data/tribes/immovables/berry_bushes/currant_red/init.lua	2019-03-02 13:56:42 +0000
+++ data/tribes/immovables/berry_bushes/currant_red/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "tiny/idle", { 4, 10 })
+add_animation(animations, "idle", dirname .. "tiny", "idle", { 4, 10 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -29,7 +29,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "small/idle", { 8, 20 })
+add_animation(animations, "idle", dirname .. "small", "idle", { 8, 20 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -50,7 +50,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "medium/idle", { 13, 33 })
+add_animation(animations, "idle", dirname .. "medium", "idle", { 13, 33 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -71,7 +71,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "ripe/idle", { 13, 33 })
+add_animation(animations, "idle", dirname .. "ripe", "idle", { 13, 33 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",

=== modified file 'data/tribes/immovables/berry_bushes/desert_hackberry/init.lua'
--- data/tribes/immovables/berry_bushes/desert_hackberry/init.lua	2019-03-02 13:56:42 +0000
+++ data/tribes/immovables/berry_bushes/desert_hackberry/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "tiny/idle", { 10, 9 })
+add_animation(animations, "idle", dirname .. "tiny", "idle", { 10, 9 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -29,7 +29,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "small/idle", { 19, 21 })
+add_animation(animations, "idle", dirname .. "small", "idle", { 19, 21 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -50,7 +50,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "medium/idle", { 21, 27 })
+add_animation(animations, "idle", dirname .. "medium", "idle", { 21, 27 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -71,7 +71,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "ripe/idle", { 21, 27 })
+add_animation(animations, "idle", dirname .. "ripe", "idle", { 21, 27 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",

=== modified file 'data/tribes/immovables/berry_bushes/juniper/init.lua'
--- data/tribes/immovables/berry_bushes/juniper/init.lua	2019-03-02 13:56:42 +0000
+++ data/tribes/immovables/berry_bushes/juniper/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "tiny/idle", { 3, 15 })
+add_animation(animations, "idle", dirname .. "tiny", "idle", { 3, 15 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -29,7 +29,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "small/idle", { 6, 30 })
+add_animation(animations, "idle", dirname .. "small", "idle", { 6, 30 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -50,7 +50,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "medium/idle", { 10, 47 })
+add_animation(animations, "idle", dirname .. "medium", "idle", { 10, 47 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -71,7 +71,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "ripe/idle", { 11, 49 })
+add_animation(animations, "idle", dirname .. "ripe", "idle", { 11, 49 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",

=== modified file 'data/tribes/immovables/berry_bushes/raspberry/init.lua'
--- data/tribes/immovables/berry_bushes/raspberry/init.lua	2019-03-02 13:56:42 +0000
+++ data/tribes/immovables/berry_bushes/raspberry/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "tiny/idle", { 4, 7 })
+add_animation(animations, "idle", dirname .. "tiny", "idle", { 4, 7 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -29,7 +29,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "small/idle", { 16, 31 })
+add_animation(animations, "idle", dirname .. "small", "idle", { 16, 31 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -50,7 +50,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "medium/idle", { 17, 34 })
+add_animation(animations, "idle", dirname .. "medium", "idle", { 17, 34 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -71,7 +71,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "ripe/idle", { 17, 34 })
+add_animation(animations, "idle", dirname .. "ripe", "idle", { 17, 34 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",

=== modified file 'data/tribes/immovables/berry_bushes/sea_buckthorn/init.lua'
--- data/tribes/immovables/berry_bushes/sea_buckthorn/init.lua	2019-03-02 13:56:42 +0000
+++ data/tribes/immovables/berry_bushes/sea_buckthorn/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "tiny/idle", { 9, 19 })
+add_animation(animations, "idle", dirname .. "tiny", "idle", { 9, 19 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -29,7 +29,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "small/idle", { 14, 32 })
+add_animation(animations, "idle", dirname .. "small", "idle", { 14, 32 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -50,7 +50,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "medium/idle", { 17, 40 })
+add_animation(animations, "idle", dirname .. "medium", "idle", { 17, 40 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -71,7 +71,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "ripe/idle", { 17, 40 })
+add_animation(animations, "idle", dirname .. "ripe", "idle", { 17, 40 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",

=== modified file 'data/tribes/immovables/berry_bushes/strawberry/init.lua'
--- data/tribes/immovables/berry_bushes/strawberry/init.lua	2019-03-02 13:56:42 +0000
+++ data/tribes/immovables/berry_bushes/strawberry/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "tiny/idle", { 4, 4 })
+add_animation(animations, "idle", dirname .. "tiny", "idle", { 4, 4 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -29,7 +29,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "small/idle", { 12, 9 })
+add_animation(animations, "idle", dirname .. "small", "idle", { 12, 9 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -50,7 +50,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "medium/idle", { 21, 15 })
+add_animation(animations, "idle", dirname .. "medium", "idle", { 21, 15 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",
@@ -71,7 +71,7 @@
 }
 
 animations = {}
-add_animation(animations, "idle", dirname, "ripe/idle", { 21, 15 })
+add_animation(animations, "idle", dirname .. "ripe", "idle", { 21, 15 })
 
 tribes:new_immovable_type {
    msgctxt = "immovable",

=== modified file 'data/tribes/ships/atlanteans/init.lua'
--- data/tribes/ships/atlanteans/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/ships/atlanteans/init.lua	2019-04-28 09:46:14 +0000
@@ -24,7 +24,7 @@
       fps = 7
    }
 }
-add_walking_animations(animations, "sail", dirname, "sail", {89, 86}, 10)
+add_directional_animation(animations, "sail", dirname, "sail", {89, 86}, 10)
 
 
 -- RST

=== modified file 'data/tribes/ships/barbarians/init.lua'
--- data/tribes/ships/barbarians/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/ships/barbarians/init.lua	2019-04-28 09:46:14 +0000
@@ -7,7 +7,7 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "sail", dirname, "sail", {115, 76}, 10)
+add_directional_animation(animations, "sail", dirname, "sail", {115, 76}, 10)
 
 
 tribes:new_ship_type {

=== modified file 'data/tribes/ships/empire/init.lua'
--- data/tribes/ships/empire/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/ships/empire/init.lua	2019-04-28 09:46:14 +0000
@@ -7,7 +7,7 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "sail", dirname, "sail", {115, 100}, 10)
+add_directional_animation(animations, "sail", dirname, "sail", {115, 100}, 10)
 
 
 tribes:new_ship_type {

=== modified file 'data/tribes/ships/frisians/init.lua'
--- data/tribes/ships/frisians/init.lua	2018-02-08 17:18:30 +0000
+++ data/tribes/ships/frisians/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
       fps = 7
    }
 }
-add_walking_animations (animations, "sail", dirname, "sail", {146, 153}, 10)
+add_directional_animation(animations, "sail", dirname, "sail", {146, 153}, 10)
 
 tribes:new_ship_type {
    name = "frisians_ship",

=== modified file 'data/tribes/workers/atlanteans/armorsmith/init.lua'
--- data/tribes/workers/atlanteans/armorsmith/init.lua	2017-08-30 16:46:00 +0000
+++ data/tribes/workers/atlanteans/armorsmith/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       hotspot = { 10, 21 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 23}, 10)
 
 -- RST
 -- .. function:: new_worker_type{table}

=== modified file 'data/tribes/workers/atlanteans/baker/init.lua'
--- data/tribes/workers/atlanteans/baker/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/baker/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 5, 23 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {7, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {9, 25}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {7, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {9, 25}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/blackroot_farmer/init.lua'
--- data/tribes/workers/atlanteans/blackroot_farmer/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/atlanteans/blackroot_farmer/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {13, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {13, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {13, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {13, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/builder/init.lua'
--- data/tribes/workers/atlanteans/builder/init.lua	2019-03-17 08:30:43 +0000
+++ data/tribes/workers/atlanteans/builder/init.lua	2019-04-28 09:46:14 +0000
@@ -16,8 +16,8 @@
       fps=10,
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {8, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {8, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/carrier/init.lua'
--- data/tribes/workers/atlanteans/carrier/init.lua	2018-11-30 10:36:42 +0000
+++ data/tribes/workers/atlanteans/carrier/init.lua	2019-04-28 09:46:14 +0000
@@ -15,15 +15,10 @@
 
 dirname = path.dirname(__file__)
 
-animations = {
-   idle = {
-      pictures = path.list_files(dirname .. "idle_??.png"),
-      hotspot = { 13, 24 },
-      fps=10,
-   }
-}
-add_walking_animations(animations, "walk", dirname, "walk", {8, 25}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 25}, 10)
+animations = {}
+add_animation(animations, "idle", dirname, "idle", {13, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 25}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 25}, 10)
 
 -- RST
 -- .. function:: new_carrier_type{table}

=== modified file 'data/tribes/workers/atlanteans/charcoal_burner/init.lua'
--- data/tribes/workers/atlanteans/charcoal_burner/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/charcoal_burner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 22 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/farmer/init.lua'
--- data/tribes/workers/atlanteans/farmer/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/atlanteans/farmer/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 5
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {18, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {18, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {18, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {18, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/fishbreeder/init.lua'
--- data/tribes/workers/atlanteans/fishbreeder/init.lua	2017-11-18 17:49:18 +0000
+++ data/tribes/workers/atlanteans/fishbreeder/init.lua	2019-04-28 09:46:14 +0000
@@ -11,7 +11,7 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {11, 23}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 20)
 
 tribes:new_worker_type {
    msgctxt = "atlanteans_worker",

=== modified file 'data/tribes/workers/atlanteans/fisher/init.lua'
--- data/tribes/workers/atlanteans/fisher/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/atlanteans/fisher/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 21}, 20)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 20}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 21}, 20)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 20}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/forester/init.lua'
--- data/tribes/workers/atlanteans/forester/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/atlanteans/forester/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 5
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {10, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {10, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/geologist/init.lua'
--- data/tribes/workers/atlanteans/geologist/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/atlanteans/geologist/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {11, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {11, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {11, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/horse/init.lua'
--- data/tribes/workers/atlanteans/horse/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/horse/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {19, 33}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {19, 33}, 10) -- TODO(GunChleoc): Make animation
+add_directional_animation(animations, "walk", dirname, "walk", {19, 33}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {19, 33}, 10) -- TODO(GunChleoc): Make animation
 
 
 tribes:new_carrier_type {

=== modified file 'data/tribes/workers/atlanteans/horsebreeder/init.lua'
--- data/tribes/workers/atlanteans/horsebreeder/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/horsebreeder/init.lua	2019-04-28 09:46:14 +0000
@@ -6,7 +6,7 @@
       hotspot = { 8, 23 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {35, 28}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {35, 28}, 10)
 
 tribes:new_worker_type {
    msgctxt = "atlanteans_worker",

=== modified file 'data/tribes/workers/atlanteans/hunter/init.lua'
--- data/tribes/workers/atlanteans/hunter/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/atlanteans/hunter/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {14, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {13, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {14, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {13, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/miller/init.lua'
--- data/tribes/workers/atlanteans/miller/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/miller/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 22 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/miner/init.lua'
--- data/tribes/workers/atlanteans/miner/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/miner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 3, 23 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {10, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/recruit/init.lua'
--- data/tribes/workers/atlanteans/recruit/init.lua	2017-05-25 20:30:41 +0000
+++ data/tribes/workers/atlanteans/recruit/init.lua	2019-04-28 09:46:14 +0000
@@ -7,7 +7,7 @@
       fps = 5
    },
 }
-add_walking_animations(animations, "walk", dirname, "walk", {20, 30}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {20, 30}, 10)
 
 tribes:new_worker_type {
    msgctxt = "atlanteans_worker",

=== modified file 'data/tribes/workers/atlanteans/sawyer/init.lua'
--- data/tribes/workers/atlanteans/sawyer/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/sawyer/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 5, 31 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {16, 31}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {16, 31}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {16, 31}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {16, 31}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/scout/init.lua'
--- data/tribes/workers/atlanteans/scout/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/atlanteans/scout/init.lua	2019-04-28 09:46:14 +0000
@@ -6,7 +6,7 @@
       hotspot = { 4, 22 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 25}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 25}, 10)
 
 tribes:new_worker_type {
    msgctxt = "atlanteans_worker",

=== modified file 'data/tribes/workers/atlanteans/shipwright/init.lua'
--- data/tribes/workers/atlanteans/shipwright/init.lua	2019-03-17 08:30:43 +0000
+++ data/tribes/workers/atlanteans/shipwright/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {12, 28}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {12, 28}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {12, 28}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {12, 28}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/smelter/init.lua'
--- data/tribes/workers/atlanteans/smelter/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/smelter/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 10, 22 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {12, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {12, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {12, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {12, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/smoker/init.lua'
--- data/tribes/workers/atlanteans/smoker/init.lua	2018-08-29 11:31:58 +0000
+++ data/tribes/workers/atlanteans/smoker/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 17, 22 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {20, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {20, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {20, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {20, 24}, 10)
 
 tribes:new_worker_type {
    msgctxt = "atlanteans_worker",

=== modified file 'data/tribes/workers/atlanteans/soldier/init.lua'
--- data/tribes/workers/atlanteans/soldier/init.lua	2017-12-08 08:13:00 +0000
+++ data/tribes/workers/atlanteans/soldier/init.lua	2019-04-28 09:46:14 +0000
@@ -71,7 +71,7 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {20, 34}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {20, 34}, 10)
 
 -- RST
 -- .. function:: new_soldier_type{table}

=== modified file 'data/tribes/workers/atlanteans/spiderbreeder/init.lua'
--- data/tribes/workers/atlanteans/spiderbreeder/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/spiderbreeder/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 8, 22 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {10, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/stonecutter/init.lua'
--- data/tribes/workers/atlanteans/stonecutter/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/atlanteans/stonecutter/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 21}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {10, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 21}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/toolsmith/init.lua'
--- data/tribes/workers/atlanteans/toolsmith/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/toolsmith/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 10, 21 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/trainer/init.lua'
--- data/tribes/workers/atlanteans/trainer/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/trainer/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 11, 21 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {14, 21}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {14, 21}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {14, 21}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {14, 21}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/weaponsmith/init.lua'
--- data/tribes/workers/atlanteans/weaponsmith/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/weaponsmith/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 10, 21 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/weaver/init.lua'
--- data/tribes/workers/atlanteans/weaver/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/atlanteans/weaver/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 2, 22 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {6, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {9, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {6, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {9, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/atlanteans/woodcutter/init.lua'
--- data/tribes/workers/atlanteans/woodcutter/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/atlanteans/woodcutter/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {16, 31}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {13, 29}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {16, 31}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {13, 29}, 10)
 
 
 tribes:new_worker_type {
@@ -35,7 +35,7 @@
          "walk=object",
          "playsound=sound/atlanteans/saw/sawing 230",
          "animate=sawing 10000",
-         "playsound=sound/woodcutting/tree-falling 130",
+         "playsound=sound/woodcutting/tree_falling 130",
          "callobject=fall",
          "animate=idle 2000",
          "createware=log",

=== modified file 'data/tribes/workers/barbarians/baker/init.lua'
--- data/tribes/workers/barbarians/baker/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/baker/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 5, 23 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {7, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {9, 25}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {7, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {9, 25}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/blacksmith/init.lua'
--- data/tribes/workers/barbarians/blacksmith/init.lua	2017-12-07 08:33:46 +0000
+++ data/tribes/workers/barbarians/blacksmith/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 6, 28 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {11, 24}, 15)
-add_walking_animations(animations, "walkload", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walk", {11, 24}, 15)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/blacksmith_master/init.lua'
--- data/tribes/workers/barbarians/blacksmith_master/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/blacksmith_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 3, 22 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {6, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {9, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {6, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {9, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/brewer/init.lua'
--- data/tribes/workers/barbarians/brewer/init.lua	2017-12-07 08:33:46 +0000
+++ data/tribes/workers/barbarians/brewer/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 7, 22 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {12, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {11, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {12, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {11, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/brewer_master/init.lua'
--- data/tribes/workers/barbarians/brewer_master/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/brewer_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 8, 26 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {15, 26}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {11, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {15, 26}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {11, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/builder/init.lua'
--- data/tribes/workers/barbarians/builder/init.lua	2019-04-24 06:32:02 +0000
+++ data/tribes/workers/barbarians/builder/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
    path = "sound/hammering/hammering",
    priority = 64
 }
-add_walking_animations(animations, "walk", dirname, "walk", {7, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {7, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {7, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {7, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/carrier/init.lua'
--- data/tribes/workers/barbarians/carrier/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/carrier/init.lua	2019-04-28 09:46:14 +0000
@@ -1,14 +1,9 @@
 dirname = path.dirname(__file__)
 
-animations = {
-   idle = {
-      pictures = path.list_files(dirname .. "idle_??.png"),
-      hotspot = { 14, 21 },
-      fps = 5
-   }
-}
-add_walking_animations(animations, "walk", dirname, "walk", {9, 19}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {7, 22}, 10)
+animations = {}
+add_animation(animations, "idle", dirname, "idle", {14, 21}, 5)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 19}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {7, 22}, 10)
 
 
 tribes:new_carrier_type {

=== modified file 'data/tribes/workers/barbarians/cattlebreeder/init.lua'
--- data/tribes/workers/barbarians/cattlebreeder/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/cattlebreeder/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 3, 21 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {42, 30}, 20)
-add_walking_animations(animations, "walkload", dirname, "walk", {42, 30}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {42, 30}, 20)
+add_directional_animation(animations, "walkload", dirname, "walk", {42, 30}, 20)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/charcoal_burner/init.lua'
--- data/tribes/workers/barbarians/charcoal_burner/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/charcoal_burner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 6, 22 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {9, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {9, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/farmer/init.lua'
--- data/tribes/workers/barbarians/farmer/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/barbarians/farmer/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 5
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {18, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {16, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {18, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {16, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/fisher/init.lua'
--- data/tribes/workers/barbarians/fisher/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/barbarians/fisher/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 38}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {10, 38}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 38}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {10, 38}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/gamekeeper/init.lua'
--- data/tribes/workers/barbarians/gamekeeper/init.lua	2017-11-18 21:01:55 +0000
+++ data/tribes/workers/barbarians/gamekeeper/init.lua	2019-04-28 09:46:14 +0000
@@ -16,8 +16,8 @@
       fps = 5
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {15, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {15, 22})
+add_directional_animation(animations, "walk", dirname, "walk", {15, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {15, 22})
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/gardener/init.lua'
--- data/tribes/workers/barbarians/gardener/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/barbarians/gardener/init.lua	2019-04-28 09:46:14 +0000
@@ -16,8 +16,8 @@
       fps = 5
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {7, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {7, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/geologist/init.lua'
--- data/tribes/workers/barbarians/geologist/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/barbarians/geologist/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 21}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {9, 21}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 21}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {9, 21}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/helmsmith/init.lua'
--- data/tribes/workers/barbarians/helmsmith/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/helmsmith/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 21 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 21}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {7, 21}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 21}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {7, 21}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/hunter/init.lua'
--- data/tribes/workers/barbarians/hunter/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/barbarians/hunter/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {6, 26}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {6, 26}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {6, 26}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {6, 26}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/innkeeper/init.lua'
--- data/tribes/workers/barbarians/innkeeper/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/innkeeper/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 9, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {10, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/lime_burner/init.lua'
--- data/tribes/workers/barbarians/lime_burner/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/lime_burner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 23 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {7, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 27}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {7, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 27}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/lumberjack/init.lua'
--- data/tribes/workers/barbarians/lumberjack/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/barbarians/lumberjack/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {10, 21}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 21}, 10)
 
 
 tribes:new_worker_type {
@@ -36,8 +36,7 @@
          "walk=object",
          "playsound=sound/woodcutting/woodcutting 255",
          "animate=hacking 10000",
-         -- "playsound=sound/spoken timber 192",
-         "playsound=sound/woodcutting/tree-falling 130",
+         "playsound=sound/woodcutting/tree_falling 130",
          "callobject=fall",
          "animate=idle 2000",
          "createware=log",

=== modified file 'data/tribes/workers/barbarians/miner/init.lua'
--- data/tribes/workers/barbarians/miner/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/miner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 3, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 25}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {6, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 25}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {6, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/miner_chief/init.lua'
--- data/tribes/workers/barbarians/miner_chief/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/miner_chief/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 3, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 25}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {6, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 25}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {6, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/miner_master/init.lua'
--- data/tribes/workers/barbarians/miner_master/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/miner_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 2, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 25}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {6, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 25}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {6, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/ox/init.lua'
--- data/tribes/workers/barbarians/ox/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/ox/init.lua	2019-04-28 09:46:14 +0000
@@ -8,8 +8,8 @@
    }
 }
 -- TODO(GunChleoc): Make real oxen animations
-add_walking_animations(animations, "walk", dirname, "walk", {21, 31}, 20)
-add_walking_animations(animations, "walkload", dirname, "walk", {21, 31}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {21, 31}, 20)
+add_directional_animation(animations, "walkload", dirname, "walk", {21, 31}, 10)
 
 
 tribes:new_carrier_type {

=== modified file 'data/tribes/workers/barbarians/ranger/init.lua'
--- data/tribes/workers/barbarians/ranger/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/barbarians/ranger/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 5
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {11, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {11, 23})
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {11, 23})
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/recruit/init.lua'
--- data/tribes/workers/barbarians/recruit/init.lua	2018-04-12 07:50:05 +0000
+++ data/tribes/workers/barbarians/recruit/init.lua	2019-04-28 09:46:14 +0000
@@ -2,7 +2,7 @@
 
 animations = {}
 add_animation(animations, "idle", dirname, "idle", {16, 30}, 5)
-add_walking_animations(animations, "walk", dirname, "walk", {16, 30}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {16, 30}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/scout/init.lua'
--- data/tribes/workers/barbarians/scout/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/barbarians/scout/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 23 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 25}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {9, 25}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 25}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {9, 25}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/shipwright/init.lua'
--- data/tribes/workers/barbarians/shipwright/init.lua	2019-04-24 06:32:02 +0000
+++ data/tribes/workers/barbarians/shipwright/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
    path = "sound/hammering/hammering",
    priority = 64
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {11, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {11, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/smelter/init.lua'
--- data/tribes/workers/barbarians/smelter/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/smelter/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 7, 21 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {18, 25}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 27}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {18, 25}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 27}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/soldier/init.lua'
--- data/tribes/workers/barbarians/soldier/init.lua	2018-01-26 16:49:24 +0000
+++ data/tribes/workers/barbarians/soldier/init.lua	2019-04-28 09:46:14 +0000
@@ -57,7 +57,7 @@
       fps = 20
    },
 }
-add_walking_animations(animations, "walk", dirname, "walk", {16, 31}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {16, 31}, 10)
 
 
 tribes:new_soldier_type {

=== modified file 'data/tribes/workers/barbarians/stonemason/init.lua'
--- data/tribes/workers/barbarians/stonemason/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/barbarians/stonemason/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {7, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {7, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/barbarians/trainer/init.lua'
--- data/tribes/workers/barbarians/trainer/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/trainer/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 23 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {8, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {8, 23}, 10)
 
 tribes:new_worker_type {
    msgctxt = "barbarians_worker",

=== modified file 'data/tribes/workers/barbarians/weaver/init.lua'
--- data/tribes/workers/barbarians/weaver/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/barbarians/weaver/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 5, 22 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {7, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {11, 28}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {7, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {11, 28}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/armorsmith/init.lua'
--- data/tribes/workers/empire/armorsmith/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/armorsmith/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 8, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/baker/init.lua'
--- data/tribes/workers/empire/baker/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/baker/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 5, 26 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {14, 27}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {14, 27}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {14, 27}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {14, 27}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/brewer/init.lua'
--- data/tribes/workers/empire/brewer/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/brewer/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 8, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {14, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {10, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {14, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/builder/init.lua'
--- data/tribes/workers/empire/builder/init.lua	2019-03-17 08:30:43 +0000
+++ data/tribes/workers/empire/builder/init.lua	2019-04-28 09:46:14 +0000
@@ -16,8 +16,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {11, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {11, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {11, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/carpenter/init.lua'
--- data/tribes/workers/empire/carpenter/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/carpenter/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 7, 29 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {11, 30}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {11, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 30}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {11, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/carrier/init.lua'
--- data/tribes/workers/empire/carrier/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/carrier/init.lua	2019-04-28 09:46:14 +0000
@@ -1,14 +1,9 @@
 dirname = path.dirname(__file__)
 
-animations = {
-   idle = {
-      pictures = path.list_files(dirname .. "idle_??.png"),
-      hotspot = { 7, 22 },
-      fps = 10
-   }
-}
-add_walking_animations(animations, "walk", dirname, "walk", {7, 20}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 22}, 10)
+animations = {}
+add_animation(animations, "idle", dirname, "idle", {7, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {7, 20}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 22}, 10)
 
 
 tribes:new_carrier_type {

=== modified file 'data/tribes/workers/empire/charcoal_burner/init.lua'
--- data/tribes/workers/empire/charcoal_burner/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/charcoal_burner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 11, 23 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {21, 28}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {17, 27}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {21, 28}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {17, 27}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/donkey/init.lua'
--- data/tribes/workers/empire/donkey/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/donkey/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {14, 25}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {14, 25}, 10) -- TODO(GunChleoc): Make animation
+add_directional_animation(animations, "walk", dirname, "walk", {14, 25}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {14, 25}, 10) -- TODO(GunChleoc): Make animation
 
 
 tribes:new_carrier_type {

=== modified file 'data/tribes/workers/empire/donkeybreeder/init.lua'
--- data/tribes/workers/empire/donkeybreeder/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/donkeybreeder/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 19, 23 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {28, 26}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {28, 26}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {28, 26}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {28, 26}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/farmer/init.lua'
--- data/tribes/workers/empire/farmer/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/empire/farmer/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 5
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {18, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {18, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {18, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {18, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/fisher/init.lua'
--- data/tribes/workers/empire/fisher/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/empire/fisher/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 10,
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 38}, 20)
-add_walking_animations(animations, "walkload", dirname, "walk", {10, 38}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 38}, 20)
+add_directional_animation(animations, "walkload", dirname, "walk", {10, 38}, 20)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/forester/init.lua'
--- data/tribes/workers/empire/forester/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/empire/forester/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 5
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {10, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {10, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/geologist/init.lua'
--- data/tribes/workers/empire/geologist/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/empire/geologist/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 21}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {9, 21}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 21}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {9, 21}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/hunter/init.lua'
--- data/tribes/workers/empire/hunter/init.lua	2017-11-18 21:08:26 +0000
+++ data/tribes/workers/empire/hunter/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 32}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {9, 32}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 32}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {9, 32}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/innkeeper/init.lua'
--- data/tribes/workers/empire/innkeeper/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/innkeeper/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 26 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {6, 26}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {6, 26}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {6, 26}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {6, 26}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/lumberjack/init.lua'
--- data/tribes/workers/empire/lumberjack/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/empire/lumberjack/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {9, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {9, 22}, 10)
 
 
 tribes:new_worker_type {
@@ -36,8 +36,7 @@
          "walk=object",
          "playsound=sound/woodcutting/fast_woodcutting 250",
          "animate=hacking 10000",
-         --  "playsound=sound/spoken/timber 156",
-         "playsound=sound/woodcutting/tree-falling 130",
+         "playsound=sound/woodcutting/tree_falling 130",
          "callobject=fall",
          "animate=idle 2000",
          "createware=log",

=== modified file 'data/tribes/workers/empire/miller/init.lua'
--- data/tribes/workers/empire/miller/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/miller/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 5, 23 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/miner/init.lua'
--- data/tribes/workers/empire/miner/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/miner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 3, 23 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {7, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {7, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/miner_master/init.lua'
--- data/tribes/workers/empire/miner_master/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/miner_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 7, 22 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {11, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {10, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/pigbreeder/init.lua'
--- data/tribes/workers/empire/pigbreeder/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/pigbreeder/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 16, 29 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {27, 29}, 20)
-add_walking_animations(animations, "walkload", dirname, "walk", {27, 29}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {27, 29}, 20)
+add_directional_animation(animations, "walkload", dirname, "walk", {27, 29}, 20)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/recruit/init.lua'
--- data/tribes/workers/empire/recruit/init.lua	2017-05-25 21:24:54 +0000
+++ data/tribes/workers/empire/recruit/init.lua	2019-04-28 09:46:14 +0000
@@ -7,7 +7,7 @@
       fps = 5
    },
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 30}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 30}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/scout/init.lua'
--- data/tribes/workers/empire/scout/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/empire/scout/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 22 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {9, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {9, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/shepherd/init.lua'
--- data/tribes/workers/empire/shepherd/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/shepherd/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 16, 29 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {26, 30}, 20)
-add_walking_animations(animations, "walkload", dirname, "walk", {26, 30}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {26, 30}, 20)
+add_directional_animation(animations, "walkload", dirname, "walk", {26, 30}, 20)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/shipwright/init.lua'
--- data/tribes/workers/empire/shipwright/init.lua	2019-03-17 08:30:43 +0000
+++ data/tribes/workers/empire/shipwright/init.lua	2019-04-28 09:46:14 +0000
@@ -15,8 +15,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {11, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {9, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {9, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/smelter/init.lua'
--- data/tribes/workers/empire/smelter/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/smelter/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 23 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {18, 25}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 22}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {18, 25}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 22}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/soldier/init.lua'
--- data/tribes/workers/empire/soldier/init.lua	2018-01-26 16:49:24 +0000
+++ data/tribes/workers/empire/soldier/init.lua	2019-04-28 09:46:14 +0000
@@ -57,7 +57,7 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {10, 36}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 36}, 10)
 
 
 tribes:new_soldier_type {

=== modified file 'data/tribes/workers/empire/stonemason/init.lua'
--- data/tribes/workers/empire/stonemason/init.lua	2019-03-17 07:20:58 +0000
+++ data/tribes/workers/empire/stonemason/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 22}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 25}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 22}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 25}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/toolsmith/init.lua'
--- data/tribes/workers/empire/toolsmith/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/toolsmith/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 8, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/trainer/init.lua'
--- data/tribes/workers/empire/trainer/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/trainer/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 6, 23 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {9, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {9, 23}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {9, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {9, 23}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/vinefarmer/init.lua'
--- data/tribes/workers/empire/vinefarmer/init.lua	2018-02-28 09:38:13 +0000
+++ data/tribes/workers/empire/vinefarmer/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 10
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 23}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/vintner/init.lua'
--- data/tribes/workers/empire/vintner/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/vintner/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
       hotspot = { 12, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {12, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walk", {12, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {12, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walk", {12, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/weaponsmith/init.lua'
--- data/tribes/workers/empire/weaponsmith/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/weaponsmith/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 8, 24 }
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {8, 24}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {8, 24}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {8, 24}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {8, 24}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/empire/weaver/init.lua'
--- data/tribes/workers/empire/weaver/init.lua	2017-02-12 09:10:57 +0000
+++ data/tribes/workers/empire/weaver/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = { 4, 24 },
    }
 }
-add_walking_animations(animations, "walk", dirname, "walk", {6, 26}, 10)
-add_walking_animations(animations, "walkload", dirname, "walkload", {6, 26}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {6, 26}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {6, 26}, 10)
 
 
 tribes:new_worker_type {

=== modified file 'data/tribes/workers/frisians/baker/init.lua'
--- data/tribes/workers/frisians/baker/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/baker/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/baker_master/init.lua'
--- data/tribes/workers/frisians/baker_master/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/baker_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/beekeeper/init.lua'
--- data/tribes/workers/frisians/beekeeper/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/beekeeper/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 50
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/berry_farmer/init.lua'
--- data/tribes/workers/frisians/berry_farmer/init.lua	2018-03-25 18:28:00 +0000
+++ data/tribes/workers/frisians/berry_farmer/init.lua	2019-04-28 09:46:14 +0000
@@ -21,7 +21,7 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/blacksmith/init.lua'
--- data/tribes/workers/frisians/blacksmith/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/blacksmith/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/blacksmith_master/init.lua'
--- data/tribes/workers/frisians/blacksmith_master/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/blacksmith_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/brewer/init.lua'
--- data/tribes/workers/frisians/brewer/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/brewer/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/brewer_master/init.lua'
--- data/tribes/workers/frisians/brewer_master/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/brewer_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/brickmaker/init.lua'
--- data/tribes/workers/frisians/brickmaker/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/brickmaker/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    },
 }
-add_walking_animations (animations, "walk", dirname, "walk", {13, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 23}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {13, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 23}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/builder/init.lua'
--- data/tribes/workers/frisians/builder/init.lua	2019-03-17 08:30:43 +0000
+++ data/tribes/workers/frisians/builder/init.lua	2019-04-28 09:46:14 +0000
@@ -16,8 +16,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 24}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 24}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/carrier/init.lua'
--- data/tribes/workers/frisians/carrier/init.lua	2018-02-06 11:17:48 +0000
+++ data/tribes/workers/frisians/carrier/init.lua	2019-04-28 09:46:14 +0000
@@ -1,14 +1,9 @@
 dirname = path.dirname (__file__)
 
-animations = {
-   idle = {
-      pictures = path.list_files (dirname .. "idle_???.png"),
-      hotspot = {17, 18},
-      fps = 10
-   },
-}
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+animations = {}
+add_animation(animations, "idle", dirname, "idle", {17, 18}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_carrier_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/charcoal_burner/init.lua'
--- data/tribes/workers/frisians/charcoal_burner/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/charcoal_burner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/claydigger/init.lua'
--- data/tribes/workers/frisians/claydigger/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/claydigger/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 20
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/farmer/init.lua'
--- data/tribes/workers/frisians/farmer/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/farmer/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {16, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {16, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/fisher/init.lua'
--- data/tribes/workers/frisians/fisher/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/fisher/init.lua	2019-04-28 09:46:14 +0000
@@ -16,8 +16,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {13, 25}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {13, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {13, 25}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {13, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/forester/init.lua'
--- data/tribes/workers/frisians/forester/init.lua	2018-03-25 18:28:00 +0000
+++ data/tribes/workers/frisians/forester/init.lua	2019-04-28 09:46:14 +0000
@@ -21,7 +21,7 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/fruit_collector/init.lua'
--- data/tribes/workers/frisians/fruit_collector/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/fruit_collector/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/geologist/init.lua'
--- data/tribes/workers/frisians/geologist/init.lua	2018-03-25 18:28:00 +0000
+++ data/tribes/workers/frisians/geologist/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 23}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/hunter/init.lua'
--- data/tribes/workers/frisians/hunter/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/hunter/init.lua	2019-04-28 09:46:14 +0000
@@ -7,8 +7,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {11, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {11, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/landlady/init.lua'
--- data/tribes/workers/frisians/landlady/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/landlady/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {9, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/miner/init.lua'
--- data/tribes/workers/frisians/miner/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/miner/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 24},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/miner_master/init.lua'
--- data/tribes/workers/frisians/miner_master/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/miner_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 24},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/reed_farmer/init.lua'
--- data/tribes/workers/frisians/reed_farmer/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/reed_farmer/init.lua	2019-04-28 09:46:14 +0000
@@ -21,8 +21,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/reindeer/init.lua'
--- data/tribes/workers/frisians/reindeer/init.lua	2018-02-06 11:17:48 +0000
+++ data/tribes/workers/frisians/reindeer/init.lua	2019-04-28 09:46:14 +0000
@@ -8,8 +8,8 @@
    }
 }
 
-add_walking_animations (animations, "walk", dirname, "walk", {21, 43}, 20)
-add_walking_animations (animations, "walkload", dirname, "walk", {21, 43}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {21, 43}, 20)
+add_directional_animation(animations, "walkload", dirname, "walk", {21, 43}, 20)
 
 tribes:new_carrier_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/reindeer_breeder/init.lua'
--- data/tribes/workers/frisians/reindeer_breeder/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/reindeer_breeder/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 10)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 10)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 10)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 10)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/scout/init.lua'
--- data/tribes/workers/frisians/scout/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/scout/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {12, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {12, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/seamstress/init.lua'
--- data/tribes/workers/frisians/seamstress/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/seamstress/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {9, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/seamstress_master/init.lua'
--- data/tribes/workers/frisians/seamstress_master/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/seamstress_master/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {21, 25},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/shipwright/init.lua'
--- data/tribes/workers/frisians/shipwright/init.lua	2019-03-17 08:30:43 +0000
+++ data/tribes/workers/frisians/shipwright/init.lua	2019-04-28 09:46:14 +0000
@@ -15,8 +15,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/smelter/init.lua'
--- data/tribes/workers/frisians/smelter/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/smelter/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {13, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {13, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/smoker/init.lua'
--- data/tribes/workers/frisians/smoker/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/smoker/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walk", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walk", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/soldier/init.lua'
--- data/tribes/workers/frisians/soldier/init.lua	2018-09-23 20:08:36 +0000
+++ data/tribes/workers/frisians/soldier/init.lua	2019-04-28 09:46:14 +0000
@@ -67,7 +67,7 @@
       fps = 10
    },
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 25}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 25}, 15)
 
 tribes:new_soldier_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/stonemason/init.lua'
--- data/tribes/workers/frisians/stonemason/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/stonemason/init.lua	2019-04-28 09:46:14 +0000
@@ -11,8 +11,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {11, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/trainer/init.lua'
--- data/tribes/workers/frisians/trainer/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/trainer/init.lua	2019-04-28 09:46:14 +0000
@@ -6,8 +6,8 @@
       hotspot = {8, 23},
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {10, 24}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {10, 25}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {10, 24}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {10, 25}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",

=== modified file 'data/tribes/workers/frisians/woodcutter/init.lua'
--- data/tribes/workers/frisians/woodcutter/init.lua	2018-11-30 10:27:21 +0000
+++ data/tribes/workers/frisians/woodcutter/init.lua	2019-04-28 09:46:14 +0000
@@ -12,8 +12,8 @@
       fps = 10
    }
 }
-add_walking_animations (animations, "walk", dirname, "walk", {16, 23}, 15)
-add_walking_animations (animations, "walkload", dirname, "walkload", {12, 26}, 15)
+add_directional_animation(animations, "walk", dirname, "walk", {16, 23}, 15)
+add_directional_animation(animations, "walkload", dirname, "walkload", {12, 26}, 15)
 
 tribes:new_worker_type {
    msgctxt = "frisians_worker",
@@ -33,7 +33,9 @@
       harvest = {
          "findobject=attrib:tree radius:10",
          "walk=object",
+         "playsound=sound/woodcutting/woodcutting 255",
          "animate=hacking 10000",
+         "playsound=sound/woodcutting/tree_falling 130",
          "callobject=fall",
          "animate=idle 2000",
          "createware=log",

=== modified file 'data/world/critters/badger/init.lua'
--- data/world/critters/badger/init.lua	2017-09-03 09:39:39 +0000
+++ data/world/critters/badger/init.lua	2019-04-28 09:46:14 +0000
@@ -19,7 +19,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {13, 15}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {13, 15}, 20)
 
 -- RST
 -- .. function:: new_critter_type{table}

=== modified file 'data/world/critters/brownbear/init.lua'
--- data/world/critters/brownbear/init.lua	2017-02-12 09:10:57 +0000
+++ data/world/critters/brownbear/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {24, 24}, 4)
+add_directional_animation(animations, "walk", dirname, "walk", {24, 24}, 4)
 
 world:new_critter_type{
    name = "brownbear",

=== modified file 'data/world/critters/bunny/init.lua'
--- data/world/critters/bunny/init.lua	2017-02-12 09:10:57 +0000
+++ data/world/critters/bunny/init.lua	2019-04-28 09:46:14 +0000
@@ -7,7 +7,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {5, 9}, 4)
+add_directional_animation(animations, "walk", dirname, "walk", {5, 9}, 4)
 
 world:new_critter_type{
    name = "bunny",

=== modified file 'data/world/critters/chamois/init.lua'
--- data/world/critters/chamois/init.lua	2017-02-12 09:10:57 +0000
+++ data/world/critters/chamois/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {11, 20}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 20}, 20)
 
 world:new_critter_type{
    name = "chamois",

=== modified file 'data/world/critters/deer/init.lua'
--- data/world/critters/deer/init.lua	2017-02-12 09:10:57 +0000
+++ data/world/critters/deer/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {15, 25}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {15, 25}, 20)
 
 world:new_critter_type{
    name = "deer",

=== modified file 'data/world/critters/duck/init.lua'
--- data/world/critters/duck/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/critters/duck/init.lua	2019-04-28 09:46:14 +0000
@@ -11,7 +11,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {5, 10})
+add_directional_animation(animations, "walk", dirname, "walk", {5, 10})
 
 world:new_critter_type{
    name = "duck",

=== modified file 'data/world/critters/elk/init.lua'
--- data/world/critters/elk/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/critters/elk/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {21, 34}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {21, 34}, 20)
 
 world:new_critter_type{
    name = "elk",

=== modified file 'data/world/critters/fox/init.lua'
--- data/world/critters/fox/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/critters/fox/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {11, 14}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 14}, 20)
 
 world:new_critter_type{
    name = "fox",

=== modified file 'data/world/critters/lynx/init.lua'
--- data/world/critters/lynx/init.lua	2017-02-12 09:10:57 +0000
+++ data/world/critters/lynx/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {11, 21}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {11, 21}, 20)
 
 
 world:new_critter_type{

=== modified file 'data/world/critters/marten/init.lua'
--- data/world/critters/marten/init.lua	2017-02-12 09:10:57 +0000
+++ data/world/critters/marten/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {15, 14}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {15, 14}, 20)
 
 world:new_critter_type{
    name = "marten",

=== modified file 'data/world/critters/reindeer/init.lua'
--- data/world/critters/reindeer/init.lua	2017-02-12 09:10:57 +0000
+++ data/world/critters/reindeer/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {25, 30}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {25, 30}, 20)
 
 
 world:new_critter_type{

=== modified file 'data/world/critters/sheep/init.lua'
--- data/world/critters/sheep/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/critters/sheep/init.lua	2019-04-28 09:46:14 +0000
@@ -11,7 +11,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {15, 25}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {15, 25}, 20)
 
 world:new_critter_type{
    name = "sheep",

=== modified file 'data/world/critters/stag/init.lua'
--- data/world/critters/stag/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/critters/stag/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {25, 30}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {25, 30}, 20)
 
 world:new_critter_type{
    name = "stag",

=== modified file 'data/world/critters/wildboar/init.lua'
--- data/world/critters/wildboar/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/critters/wildboar/init.lua	2019-04-28 09:46:14 +0000
@@ -11,7 +11,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {20, 22}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {20, 22}, 20)
 
 world:new_critter_type{
    name = "wildboar",

=== modified file 'data/world/critters/wisent/init.lua'
--- data/world/critters/wisent/init.lua	2017-02-12 09:10:57 +0000
+++ data/world/critters/wisent/init.lua	2019-04-28 09:46:14 +0000
@@ -8,7 +8,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {24, 32}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {24, 32}, 20)
 
 world:new_critter_type{
    name = "wisent",

=== modified file 'data/world/critters/wolf/init.lua'
--- data/world/critters/wolf/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/critters/wolf/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
    },
 }
 
-add_walking_animations(animations, "walk", dirname, "walk", {19, 19}, 20)
+add_directional_animation(animations, "walk", dirname, "walk", {19, 19}, 20)
 
 world:new_critter_type{
    name = "wolf",

=== modified file 'data/world/immovables/grass1/init.lua'
--- data/world/immovables/grass1/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/immovables/grass1/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
          pictures = path.list_files(dirname .. "idle.png"),
          hotspot = { 10, 20 },
          sound_effect = {
-            path = "sound/animals/frog1",
+            path = "sound/animals/frog",
          },
       },
    }

=== modified file 'data/world/immovables/grass2/init.lua'
--- data/world/immovables/grass2/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/immovables/grass2/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
          pictures = path.list_files(dirname .. "idle.png"),
          hotspot = { 10, 16 },
          sound_effect = {
-            path = "sound/animals/frog1",
+            path = "sound/animals/frog",
          },
       },
    }

=== modified file 'data/world/immovables/grass3/init.lua'
--- data/world/immovables/grass3/init.lua	2019-03-17 08:30:43 +0000
+++ data/world/immovables/grass3/init.lua	2019-04-28 09:46:14 +0000
@@ -12,7 +12,7 @@
          pictures = path.list_files(dirname .. "idle.png"),
          hotspot = { 10, 11 },
          sound_effect = {
-            path = "sound/animals/frog1",
+            path = "sound/animals/frog",
          },
       },
    }

=== modified file 'doc/sphinx/source/animations.rst'
--- doc/sphinx/source/animations.rst	2019-04-24 06:32:02 +0000
+++ doc/sphinx/source/animations.rst	2019-04-28 09:46:14 +0000
@@ -19,7 +19,8 @@
 
    animations = {
       idle = {
-         files = path.list_files(path.dirname(__file__) .. "idle_??.png"),
+         directory = path.dirname(__file__),
+         basename = "idle",
          hotspot = { 5, 7 },
          fps = 4,
          sound_effect = {
@@ -27,7 +28,14 @@
             priority = 128
          },
       },
-      working = ...
+      walk = {
+         directory = path.dirname(__file__),
+         basename = "walk",
+         hotspot = { 5, 7 },
+         fps = 4,
+         directional = true
+      },
+      ...
    }
 
 Let's have a detailed look at the ``idle`` animation:
@@ -35,11 +43,23 @@
 **idle**
    *Mandatory*. This is the name of the animation. The animation can then be referenced by this name e.g. if you want to trigger it in a production program.
 
-**files**
-   *Mandatory*. A template for the image names. Our example will pick up any image from ``idle_00.png`` through ``idle_99.png`` in the specified directory path -- the current path in our example. These images can optionally have corresponding player color mask images called ``idle_00_pc.png`` through ``idle_99_pc.png``. Make sure to include leading 0's in the file names and to have consistent length -- we support 1, 2 and 3 digit numbers in an animation.
+**directory**
+   *Mandatory*. The directory where the animation image files are located.
+
+**basename**
+   *Mandatory*. The filename prefix for the image files. Our example will pick up any image from ``idle_00.png`` through ``idle_99.png`` in the specified directory path -- the current path in our example. These images can optionally have corresponding player color mask images called ``idle_00_pc.png`` through ``idle_99_pc.png``. Make sure to include leading 0's in the file names and to have consistent length -- we support 1, 2 and 3 digit numbers in an animation.
+   If your animation contains only one file, you can also call it ``idle.png`` (and ``idle_pc.png`` for the player color mask) without ``_`` or any numbers in the file name.
+
+   We support *mipmaps* for animations. They allow us to provide the same image in different resolutions for optimum rendering quality.
+   For using mipmaps, simply name your files accordingly, and the engine will pick them up. e.g. ``idle_0.5_00.png`` will be rendered at scale ``0.5``, and ``idle_1_00.png`` will be rendered at the neutral scale ``1``.
+   The scale of ``1`` is mandatory, and other supported scales are ``0.5``, ``2`` and ``4``.
 
 **pictures**
-   *DEPRECATED*. The same as ``files``.
+   *DEPRECATED*. This is older code that is slowly being phased out - do not use this parameter.
+   A table with full directory and file names.
+
+**directional**
+   *Optional*. If this is ``true``, indicates to the engine that this is a directional animation. In our example, the engine will create a set of 6 animations called ``"walk_ne"``, ``"walk_e"``, ``"walk_se"``, ``"walk_sw"``, ``"walk_w"``, and ``"walk_nw"``. See :ref:`animations_directional` below.
 
 **hotspot**
    *Mandatory*. Hotspots define a place on a graphic image through its *x* and *y* coordinates that can be used as a handle or reference point to provide control over positioning the image on the map. For example, hotspots help carriers stay on the road, and control the positioning of the wares they carry. Increase ``x`` to shift the animation to the left and ``y`` to shift it upwards.
@@ -54,56 +74,7 @@
    * **128-254:** Probability between ``0.0`` and ``1.0``, many instances can be playing at any time
    * **255:** Always play
 
-
-Mipmaps
--------
-
-We support mipmaps for animations. They allow us to provide the same image in different
-resolutions for optimum rendering quality. Let's look at an example with a mipmap ``idle`` animation and a normal ``build`` animation:
-
-.. code-block:: lua
-
-   animations = {
-      idle = {
-         mipmap = {
-            {
-               scale = 0.5,
-               files = path.list_files(dirname .. "idle_0.5_??.png"),
-            },
-            {
-               scale = 1,
-               files = path.list_files(dirname .. "idle_1_??.png"),
-            },
-            {
-               scale = 2,
-               files = path.list_files(dirname .. "idle_2_??.png"),
-            },
-            {
-               scale = 4,
-               files = path.list_files(dirname .. "idle_4_??.png"),
-            }
-         },
-         hotspot = { 5, 7 },
-         fps = 4,
-         sound_effect = {
-            directory = "sound/foo",
-            name = "bar",
-         },
-      },
-      build = {
-         files = path.list_files(dirname .. "build_??.png"),
-         hotspot = { 5, 7 },
-      }
-   },
-
-The scale of ``1`` is mandatory, and other supported scales are ``0.5``, ``2``
-and ``4``.
-The base table should no longer contain the ``files`` entry
-when you're using a mipmap.
-Each mimap entry must define the ``files`` and the ``scale``.
-See also :ref:`animations_converting_formats`.
-
-
+.. _animations_directional:
 Directional Animations
 ----------------------
 
@@ -139,10 +110,10 @@
    add_animation(animations, "idle", dirname, "idle", {16, 30}, 5)
 
    -- Add animations for the 6 directions with hotspot = {16, 30} and fps = 10
-   add_walking_animations(animations, "walk", dirname, "walk", {16, 30}, 10)
+   add_directional_animation(animations, "walk", dirname, "walk", {16, 30}, 10)
 
    -- Add a "walkload" animation. The animation hasn't been created yet in this example, so we reuse the files for the "walk" animation.
-   add_walking_animations(animations, "walkload", dirname, "walk", {16, 30}, 10)
+   add_directional_animation(animations, "walkload", dirname, "walk", {16, 30}, 10)
 
 
    tribes:new_worker_type {
@@ -188,7 +159,7 @@
   MipmapMaker accepts high-resolution images as input files (they should be at least 4 times the in-game size)
   and creates correctly named mipmap images for all supported scales for each animation, e.g.:
 
-  java MipmapMaker ~/widelands/data/tribes/workers/fancytribe/diligentworker walk_se 2 true true true 4.0
+  ``java MipmapMaker ~/widelands/data/tribes/workers/fancytribe/diligentworker walk_se 2 true true true 4.0``
 
   MipmapMaker is documented in ``widelands-media/graphics/tools/Graphics Tools (Java)/Readme``.
 

=== modified file 'src/graphic/animation.cc'
--- src/graphic/animation.cc	2019-04-24 20:48:37 +0000
+++ src/graphic/animation.cc	2019-04-28 09:46:14 +0000
@@ -31,13 +31,13 @@
 #include "base/i18n.h"
 #include "base/log.h"
 #include "base/macros.h"
-#include "base/wexception.h"
 #include "graphic/diranimations.h"
 #include "graphic/graphic.h"
 #include "graphic/image.h"
 #include "graphic/image_cache.h"
 #include "graphic/playercolor.h"
 #include "graphic/texture.h"
+#include "io/filesystem/filesystem.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "logic/game_data_error.h"
 #include "scripting/lua_table.h"
@@ -56,25 +56,36 @@
 class NonPackedAnimation : public Animation {
 public:
 	struct MipMapEntry {
-		explicit MipMapEntry(float scale, const LuaTable& table);
+		explicit MipMapEntry(std::vector<std::string> files);
+
+		// Loads the graphics if they are not yet loaded.
+		void ensure_graphics_are_loaded() const;
+
+		// Load the needed graphics from disk.
+		void load_graphics();
+
+		void blit(uint32_t idx, const Rectf& source_rect, const Rectf& destination_rect, const RGBColor* clr, Surface* target) const;
 
 		// Whether this image set has player color masks provided
 		bool has_playercolor_masks;
 
 		// Image files on disk
 		std::vector<std::string> image_files;
+
+		// Loaded images for each frame
+		std::vector<const Image*> frames;
+
+	private:
 		// Player color mask files on disk
 		std::vector<std::string> playercolor_mask_image_files;
 
-		// Loaded images for each frame
-		std::vector<const Image*> frames;
 		// Loaded player color mask images for each frame
 		std::vector<const Image*> playercolor_mask_frames;
 	};
 
 	~NonPackedAnimation() override {
 	}
-	explicit NonPackedAnimation(const LuaTable& table);
+	explicit NonPackedAnimation(const LuaTable& table, const std::string& basename);
 
 	// Implements Animation.
 	float height() const override;
@@ -91,8 +102,8 @@
 	                  const Rectf& source_rect,
 	                  const Rectf& destination_rect,
 	                  const RGBColor* clr,
-	                  Surface* target,
-	                  float scale) const override;
+	                  Surface* target, float scale) const override;
+	void load_default_scale() const override;
 
 private:
 	float find_best_scale(float scale) const;
@@ -101,12 +112,6 @@
 	// What if the game runs very slowly or very quickly?
 	void trigger_sound(uint32_t framenumber, const Widelands::Coords& coords) const override;
 
-	// Loads the graphics if they are not yet loaded.
-	void ensure_graphics_are_loaded() const;
-
-	// Load the needed graphics from disk.
-	void load_graphics();
-
 	uint32_t current_frame(uint32_t time) const;
 
 	uint32_t frametime_;
@@ -127,22 +132,17 @@
 	bool play_once_;
 };
 
-NonPackedAnimation::MipMapEntry::MipMapEntry(float scale, const LuaTable& table)
-   : has_playercolor_masks(false) {
-	if (scale <= 0.0f) {
-		throw wexception(
-		   "Animation scales must be positive numbers. Found %.2f", static_cast<double>(scale));
-	}
-
-	// TODO(GunChleoc): We want to rename these from "pictures" to "files", because we'll have
-	// spritesheets etc. in the future, and this naming will be clearer. We don't want to convert
-	// them in bulk right now though - it will take care of itself as we convert to mipmaps.
-	image_files = (table.has_key("files") ? table.get_table("files") : table.get_table("pictures"))
-	                 ->array_entries<std::string>();
-
+/*
+==============================================================================
+
+NonPackedAnimation::MipMapEntry IMPLEMENTATION
+
+==============================================================================
+*/
+
+NonPackedAnimation::MipMapEntry::MipMapEntry(std::vector<std::string> files) : has_playercolor_masks(false), image_files(files) {
 	if (image_files.empty()) {
-		throw wexception("Animation without image files. For a scale of 1.0, the template should "
-		                 "look similar to this:"
+		throw Widelands::GameDataError("Animation without image files. For a scale of 1.0, the template should look similar to this:"
 		                 " 'directory/idle_1_??.png' for 'directory/idle_1_00.png' etc.");
 	}
 
@@ -152,16 +152,82 @@
 			has_playercolor_masks = true;
 			playercolor_mask_image_files.push_back(image_file);
 		} else if (has_playercolor_masks) {
-			throw wexception("Animation is missing player color file: %s", image_file.c_str());
+			throw Widelands::GameDataError("Animation is missing player color file: %s", image_file.c_str());
 		}
 	}
 
 	assert(!image_files.empty());
-	assert(playercolor_mask_image_files.size() == image_files.size() ||
-	       playercolor_mask_image_files.empty());
-}
-
-NonPackedAnimation::NonPackedAnimation(const LuaTable& table)
+	assert(playercolor_mask_image_files.size() == image_files.size() || playercolor_mask_image_files.empty());
+}
+
+// Loads the graphics if they are not yet loaded.
+void NonPackedAnimation::MipMapEntry::ensure_graphics_are_loaded() const {
+	if (frames.empty()) {
+		const_cast<MipMapEntry*>(this)->load_graphics();
+	}
+}
+
+// Load the needed graphics from disk.
+void NonPackedAnimation::MipMapEntry::load_graphics() {
+	if (image_files.empty()) {
+		throw Widelands::GameDataError("animation without image files.");
+	}
+	if (playercolor_mask_image_files.size() && playercolor_mask_image_files.size() != image_files.size()) {
+		throw Widelands::GameDataError("animation has %" PRIuS " frames but playercolor mask has %" PRIuS " frames. First image is %s",
+							  image_files.size(), playercolor_mask_image_files.size(), image_files.front().c_str());
+	}
+
+	for (const std::string& filename : image_files) {
+		const Image* image = g_gr->images().get(filename);
+		if (frames.size() &&
+			 (frames.front()->width() != image->width() || frames.front()->height() != image->height())) {
+			throw Widelands::GameDataError("wrong size: (%u, %u) for file %s, should be (%u, %u) like the first frame",
+								  image->width(), image->height(), filename.c_str(), frames.front()->width(),
+								  frames.front()->height());
+		}
+		frames.push_back(image);
+	}
+
+	for (const std::string& filename : playercolor_mask_image_files) {
+		// TODO(unknown): Do not load playercolor mask as opengl texture or use it as
+		//     opengl texture.
+		const Image* pc_image = g_gr->images().get(filename);
+		if (frames.front()->width() != pc_image->width() || frames.front()->height() != pc_image->height()) {
+			throw Widelands::GameDataError("playercolor mask %s has wrong size: (%u, %u), should "
+								  "be (%u, %u) like the animation frame",
+								  filename.c_str(), pc_image->width(), pc_image->height(), frames.front()->width(),
+								  frames.front()->height());
+		}
+		playercolor_mask_frames.push_back(pc_image);
+	}
+}
+
+void NonPackedAnimation::MipMapEntry::blit(uint32_t idx,
+										   const Rectf& source_rect,
+										   const Rectf& destination_rect,
+										   const RGBColor* clr,
+										   Surface* target) const {
+	assert(!frames.empty());
+	assert(target);
+	assert(idx < frames.size());
+
+	if (!has_playercolor_masks || clr == nullptr) {
+		target->blit(destination_rect, *frames.at(idx), source_rect, 1., BlendMode::UseAlpha);
+	} else {
+		target->blit_blended(
+		   destination_rect, *frames.at(idx), *playercolor_mask_frames.at(idx), source_rect, *clr);
+	}
+}
+
+/*
+==============================================================================
+
+NonPackedAnimation IMPLEMENTATION
+
+==============================================================================
+*/
+
+NonPackedAnimation::NonPackedAnimation(const LuaTable& table, const std::string& basename)
    : frametime_(FRAME_LENGTH),
      hotspot_(table.get_vector<std::string, int>("hotspot")),
      sound_effect_(kNoSoundEffect),
@@ -190,36 +256,47 @@
 			play_once_ = table.get_bool("play_once");
 		}
 
-		if (table.has_key("mipmap")) {
-			std::unique_ptr<LuaTable> mipmaps_table = table.get_table("mipmap");
-			for (const int key : mipmaps_table->keys<int>()) {
-				std::unique_ptr<LuaTable> current_scale_table = mipmaps_table->get_table(key);
-				const float current_scale = current_scale_table->get_double("scale");
-				if (kSupportedScales.count(current_scale) != 1) {
-					std::string supported_scales = "";
-					for (const float supported_scale : kSupportedScales) {
-						supported_scales =
-						   (boost::format("%s %.1f") % supported_scales % supported_scale).str();
-					}
-					throw wexception(
-					   "Animation has unsupported scale '%.2f' in mipmap - supported scales are:%s",
-					   static_cast<double>(current_scale), supported_scales.c_str());
-				}
-				mipmaps_.insert(std::make_pair(
-				   current_scale,
-				   std::unique_ptr<MipMapEntry>(new MipMapEntry(current_scale, *current_scale_table))));
-			}
+		// Get image files
+		if (table.has_key("pictures")) {
+			// TODO(GunChleoc): Old code - remove this option once conversion has been completed
+			mipmaps_.insert(std::make_pair(
+								1.0f,
+								std::unique_ptr<MipMapEntry>(new MipMapEntry(table.get_table("pictures")->array_entries<std::string>()))));
 		} else {
-			mipmaps_.insert(
-			   std::make_pair(1.0f, std::unique_ptr<MipMapEntry>(new MipMapEntry(1.0f, table))));
+			if (basename.empty() || !table.has_key("directory")) {
+				throw Widelands::GameDataError("Animation did not define both a basename and a directory for its image files");
+			}
+			const std::string directory = table.get_string("directory");
+
+			// List files for the given scale, and if we have any, add a mipmap entry for them.
+			auto add_scale = [this, basename, directory](float scale_as_float, const std::string& scale_as_string) {
+				std::vector<std::string> filenames = g_fs->get_sequential_files(directory, basename + scale_as_string, "png");
+				if (!filenames.empty()) {
+					mipmaps_.insert(std::make_pair(scale_as_float, std::unique_ptr<MipMapEntry>(new MipMapEntry(filenames))));
+				}
+			};
+			add_scale(0.5f, "_0.5");
+			add_scale(1.0f, "_1");
+			add_scale(2.0f, "_2");
+			add_scale(4.0f, "_4");
+
+			if (mipmaps_.count(1.0f) == 0) {
+				// There might be only 1 scale
+				add_scale(1.0f, "");
+				if (mipmaps_.count(1.0f) == 0) {
+					// No files found at all
+					throw Widelands::GameDataError(
+						"Animation in directory '%s' with basename '%s' has no images for mandatory scale '1' in mipmap - supported scales are: 0.5, 1, 2, 4", directory.c_str(), basename.c_str());
+				}
+			}
 		}
 
-		// Frames
+		// Frames and FPS
 		nr_frames_ = mipmaps_.begin()->second->image_files.size();
 		if (table.has_key("fps")) {
 			if (nr_frames_ == 1) {
-				throw wexception("Animation with one picture %s must not have 'fps'",
-				                 mipmaps_.begin()->second->image_files[0].c_str());
+				throw Widelands::GameDataError(
+					"Animation with one picture %s must not have 'fps'", mipmaps_.begin()->second->image_files.front().c_str());
 			}
 			frametime_ = 1000 / get_positive_int(table, "fps");
 		}
@@ -228,22 +305,22 @@
 		const bool should_have_playercolor = mipmaps_.begin()->second->has_playercolor_masks;
 		for (const auto& mipmap : mipmaps_) {
 			if (mipmap.second->image_files.size() != nr_frames_) {
-				throw wexception(
-				   "Mismatched number of images for different scales in animation table: %" PRIuS
-				   " vs. %u at scale %.2f",
-				   mipmap.second->image_files.size(), nr_frames_, static_cast<double>(mipmap.first));
+				throw Widelands::GameDataError("Mismatched number of images for different scales in animation table: %" PRIuS " vs. %u at scale %.2f",
+									  mipmap.second->image_files.size(),
+									  nr_frames_,
+									  mipmap.first);
 			}
 			if (mipmap.second->has_playercolor_masks != should_have_playercolor) {
-				throw wexception(
-				   "Mismatched existence of player colors in animation table for scales %.2f and %.2f",
-				   static_cast<double>(mipmaps_.begin()->first), static_cast<double>(mipmap.first));
+				throw Widelands::GameDataError("Mismatched existence of player colors in animation table for scales %.2f and %.2f",
+									  mipmaps_.begin()->first,
+									  mipmap.first);
 			}
 		}
 		if (mipmaps_.count(1.0f) != 1) {
-			throw wexception("All animations must provide images for the neutral scale (1.0)");
+			throw Widelands::GameDataError("All animations must provide images for the neutral scale (1.0)");
 		}
 	} catch (const LuaError& e) {
-		throw wexception("Error in animation table: %s", e.what());
+		throw Widelands::GameDataError("Error in animation table: %s", e.what());
 	}
 }
 
@@ -260,59 +337,10 @@
 	return result;
 }
 
-void NonPackedAnimation::ensure_graphics_are_loaded() const {
-	if (mipmaps_.begin()->second->frames.empty()) {
-		const_cast<NonPackedAnimation*>(this)->load_graphics();
-	}
-}
-
-void NonPackedAnimation::load_graphics() {
-	for (const auto& entry : mipmaps_) {
-		MipMapEntry* mipmap = entry.second.get();
-
-		if (mipmap->image_files.empty()) {
-			throw wexception("animation without image files at promised scale %.2f.",
-			                 static_cast<double>(entry.first));
-		}
-		if (mipmap->playercolor_mask_image_files.size() &&
-		    mipmap->playercolor_mask_image_files.size() != mipmap->image_files.size()) {
-			throw wexception("animation has %" PRIuS " frames but playercolor mask has %" PRIuS
-			                 " frames for scale %.2f",
-			                 mipmap->image_files.size(), mipmap->playercolor_mask_image_files.size(),
-			                 static_cast<double>(entry.first));
-		}
-
-		for (const std::string& filename : mipmap->image_files) {
-			const Image* image = g_gr->images().get(filename);
-			if (mipmap->frames.size() && (mipmap->frames[0]->width() != image->width() ||
-			                              mipmap->frames[0]->height() != image->height())) {
-				throw wexception("wrong size: (%u, %u), should be (%u, %u) like the first frame",
-				                 image->width(), image->height(), mipmap->frames[0]->width(),
-				                 mipmap->frames[0]->height());
-			}
-			mipmap->frames.push_back(image);
-		}
-
-		for (const std::string& filename : mipmap->playercolor_mask_image_files) {
-			// TODO(unknown): Do not load playercolor mask as opengl texture or use it as
-			//     opengl texture.
-			const Image* pc_image = g_gr->images().get(filename);
-			if (mipmap->frames[0]->width() != pc_image->width() ||
-			    mipmap->frames[0]->height() != pc_image->height()) {
-				// TODO(unknown): see bug #1324642
-				throw wexception("playercolor mask has wrong size: (%u, %u), should "
-				                 "be (%u, %u) like the animation frame",
-				                 pc_image->width(), pc_image->height(), mipmap->frames[0]->width(),
-				                 mipmap->frames[0]->height());
-			}
-			mipmap->playercolor_mask_frames.push_back(pc_image);
-		}
-	}
-}
-
 float NonPackedAnimation::height() const {
-	ensure_graphics_are_loaded();
-	return mipmaps_.at(1.0f)->frames.at(0)->height();
+	const MipMapEntry& mipmap = *mipmaps_.at(1.0f);
+	mipmap.ensure_graphics_are_loaded();
+	return mipmap.frames.front()->height();
 }
 
 uint16_t NonPackedAnimation::nr_frames() const {
@@ -327,8 +355,8 @@
 	const MipMapEntry& mipmap = *mipmaps_.at(1.0f);
 	std::vector<std::string> images = mipmap.image_files;
 	assert(!images.empty());
-	const Image* image = (mipmap.has_playercolor_masks && clr) ? playercolor_image(*clr, images[0]) :
-	                                                             g_gr->images().get(images[0]);
+	const Image* image = (mipmap.has_playercolor_masks && clr) ? playercolor_image(*clr, images.front()) :
+	                                            g_gr->images().get(images.front());
 
 	const int w = image->width();
 	const int h = image->height();
@@ -366,8 +394,9 @@
 }
 
 Rectf NonPackedAnimation::source_rectangle(const int percent_from_bottom, float scale) const {
-	ensure_graphics_are_loaded();
-	const Image* first_frame = mipmaps_.at(find_best_scale(scale))->frames.at(0);
+	const MipMapEntry& mipmap = *mipmaps_.at(find_best_scale(scale));
+	mipmap.ensure_graphics_are_loaded();
+	const Image* first_frame = mipmap.frames.front();
 	const float h = percent_from_bottom * first_frame->height() / 100;
 	// Using floor for pixel perfect positioning
 	return Rectf(0.f, std::floor(first_frame->height() - h), first_frame->width(), h);
@@ -376,7 +405,6 @@
 Rectf NonPackedAnimation::destination_rectangle(const Vector2f& position,
                                                 const Rectf& source_rect,
                                                 const float scale) const {
-	ensure_graphics_are_loaded();
 	const float best_scale = find_best_scale(scale);
 	return Rectf(position.x - (hotspot_.x - source_rect.x / best_scale) * scale,
 	             position.y - (hotspot_.y - source_rect.y / best_scale) * scale,
@@ -388,23 +416,15 @@
                               const Rectf& source_rect,
                               const Rectf& destination_rect,
                               const RGBColor* clr,
-                              Surface* target,
-                              float scale) const {
-	ensure_graphics_are_loaded();
-	assert(target);
-	const uint32_t idx = current_frame(time);
-	assert(idx < nr_frames());
-
-	const MipMapEntry& mipmap = *mipmaps_.at(find_best_scale(scale));
-	if (!mipmap.has_playercolor_masks || clr == nullptr) {
-		target->blit(destination_rect, *mipmap.frames.at(idx), source_rect, 1., BlendMode::UseAlpha);
-	} else {
-		target->blit_blended(destination_rect, *mipmap.frames.at(idx),
-		                     *mipmap.playercolor_mask_frames.at(idx), source_rect, *clr);
-	}
+                              Surface* target, float scale) const {
+	mipmaps_.at(find_best_scale(scale))->blit(current_frame(time), source_rect, destination_rect, clr, target);
 	trigger_sound(time, coords);
 }
 
+void NonPackedAnimation::load_default_scale() const {
+	mipmaps_.at(1.0f)->ensure_graphics_are_loaded();
+}
+
 }  // namespace
 
 /*
@@ -432,15 +452,14 @@
 
 ==============================================================================
 */
-
-uint32_t AnimationManager::load(const LuaTable& table) {
-	animations_.push_back(std::unique_ptr<Animation>(new NonPackedAnimation(table)));
+uint32_t AnimationManager::load(const LuaTable& table, const std::string& basename) {
+	animations_.push_back(std::unique_ptr<Animation>(new NonPackedAnimation(table, basename)));
 	return animations_.size();
 }
 
 const Animation& AnimationManager::get_animation(uint32_t id) const {
 	if (!id || id > animations_.size())
-		throw wexception("Requested unknown animation with id: %i", id);
+		throw Widelands::GameDataError("Requested unknown animation with id: %i", id);
 
 	return *animations_[id - 1];
 }

=== modified file 'src/graphic/animation.h'
--- src/graphic/animation.h	2019-04-24 20:48:37 +0000
+++ src/graphic/animation.h	2019-04-28 09:46:14 +0000
@@ -96,8 +96,10 @@
 	                  const Rectf& source_rect,
 	                  const Rectf& destination_rect,
 	                  const RGBColor* clr,
-	                  Surface* target,
-	                  float scale) const = 0;
+	                  Surface* target, float scale) const = 0;
+
+	/// Load animation images into memory for default scale.
+	virtual void load_default_scale() const = 0;
 
 protected:
 	/// Play the sound effect associated with this animation at the given time.
@@ -117,11 +119,13 @@
 	/**
 	 * Loads an animation, graphics sound and everything from a Lua table.
 	 *
+	 * The 'basename' is the filename prefix for loading the images, e.g. "idle" or "walk_ne".
+	 *
 	 * The Lua table must contain a table 'pictures' with image paths and a 'hotspot' table.
 	 *
 	 * Optional parameters in the Lua table are 'fps' and 'sound_effect'.
 	 */
-	uint32_t load(const LuaTable& table);
+	uint32_t load(const LuaTable& table, const std::string& basename);
 
 	/// Returns the animation with the given ID or throws an exception if it is
 	/// unknown.

=== modified file 'src/helper.h'
--- src/helper.h	2019-02-23 11:00:49 +0000
+++ src/helper.h	2019-04-28 09:46:14 +0000
@@ -41,17 +41,4 @@
 /// lines.
 std::vector<std::string> split_string(const std::string&, char const* separators);
 
-// A functional container filtering (by copying the values). Returns a new
-// ContainerType that  contains all values where 'test' returned true.
-template <typename ContainerType, class UnaryPredicate>
-ContainerType filter(const ContainerType& container, UnaryPredicate test) {
-	ContainerType filtered;
-	for (const auto& entry : container) {
-		if (!test(entry)) {
-			continue;
-		}
-		filtered.insert(entry);
-	}
-	return filtered;
-}
 #endif  // end of include guard: WL_HELPER_H

=== modified file 'src/io/filesystem/disk_filesystem.cc'
--- src/io/filesystem/disk_filesystem.cc	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/disk_filesystem.cc	2019-04-28 09:46:14 +0000
@@ -76,7 +76,7 @@
 	return true;
 }
 
-std::set<std::string> RealFSImpl::list_directory(const std::string& path) {
+FilenameSet RealFSImpl::list_directory(const std::string& path) const {
 #ifdef _WIN32
 	std::string buf;
 	struct _finddata_t c_file;
@@ -152,7 +152,7 @@
  * \e can't exist then)
  */
 // TODO(unknown): Can this be rewritten to just using exceptions? Should it?
-bool RealFSImpl::file_exists(const std::string& path) {
+bool RealFSImpl::file_exists(const std::string& path) const {
 	return FileSystemPath(canonicalize_name(path)).exists_;
 }
 

=== modified file 'src/io/filesystem/disk_filesystem.h'
--- src/io/filesystem/disk_filesystem.h	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/disk_filesystem.h	2019-04-28 09:46:14 +0000
@@ -30,10 +30,10 @@
 public:
 	explicit RealFSImpl(const std::string& Directory);
 
-	std::set<std::string> list_directory(const std::string& path) override;
+	FilenameSet list_directory(const std::string& path) const override;
 
 	bool is_writable() const override;
-	bool file_exists(const std::string& path) override;
+	bool file_exists(const std::string& path) const override;
 	bool is_directory(const std::string& path) override;
 	void ensure_directory_exists(const std::string& fs_dirname) override;
 	void make_directory(const std::string& fs_dirname) override;

=== modified file 'src/io/filesystem/filesystem.cc'
--- src/io/filesystem/filesystem.cc	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/filesystem.cc	2019-04-28 09:46:14 +0000
@@ -34,7 +34,9 @@
 
 // We have to add Boost to this block to make codecheck happy
 #include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
 #ifdef _WIN32
 #include <direct.h>
 #include <io.h>
@@ -81,6 +83,54 @@
 const std::vector<std::string> illegal_filename_characters{
    "<", ">", ":", "\"", "|", "?", "*", "/", "\\",
 };
+
+/// A class that makes iteration over filename_?.* templates easy. It is much faster than using regex.
+class NumberGlob {
+public:
+	explicit NumberGlob(const std::string& file_template);
+
+	/// If there is a next filename, puts it in 's' and returns true.
+	bool next(std::string* s);
+
+private:
+	std::string template_;
+	std::string format_;
+	std::string to_replace_;
+	uint32_t current_;
+	uint32_t max_;
+
+	DISALLOW_COPY_AND_ASSIGN(NumberGlob);
+};
+
+/**
+ * Implementation for NumberGlob.
+ */
+NumberGlob::NumberGlob(const std::string& file_template) : template_(file_template), current_(0) {
+	int nchars = count(file_template.begin(), file_template.end(), '?');
+	format_ = "%0" + boost::lexical_cast<std::string>(nchars) + "i";
+
+	max_ = 1;
+	for (int i = 0; i < nchars; ++i) {
+		max_ *= 10;
+		to_replace_ += "?";
+	}
+	max_ -= 1;
+}
+
+bool NumberGlob::next(std::string* s) {
+	if (current_ > max_) {
+		return false;
+	}
+
+	if (max_) {
+		*s = boost::replace_last_copy(
+		   template_, to_replace_, (boost::format(format_) % current_).str());
+	} else {
+		*s = template_;
+	}
+	++current_;
+	return true;
+}
 }  // namespace
 
 /**
@@ -261,6 +311,37 @@
 	return homedir;
 }
 
+// Returning a vector rather than a set because animations need the indices
+std::vector<std::string> FileSystem::get_sequential_files(const std::string& directory, const std::string& basename, const std::string& extension) const {
+	std::vector<std::string> result;
+
+	auto get_files = [this, directory, basename, extension](const std::string& number_template) {
+		std::vector<std::string> files;
+		const std::string filename_template = directory + file_separator() + basename + number_template + "." + extension;
+
+		NumberGlob glob(filename_template);
+		std::string filename;
+		while (glob.next(&filename)) {
+			if (!file_exists(filename)) {
+				break;
+			}
+			files.push_back(filename);
+		}
+		return files;
+	};
+	result = get_files("");
+	if (result.empty()) {
+		result = get_files("_?");
+	}
+	if (result.empty()) {
+		result = get_files("_??");
+	}
+	if (result.empty()) {
+		result = get_files("_???");
+	}
+	return result;
+}
+
 /**
  * Split a string into components separated by a certain character.
  *

=== modified file 'src/io/filesystem/filesystem.h'
--- src/io/filesystem/filesystem.h	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/filesystem.h	2019-04-28 09:46:14 +0000
@@ -36,6 +36,7 @@
 class StreamRead;
 class StreamWrite;
 
+
 /**
  * FileSystem is an abstract base class representing certain filesystem
  * operations.
@@ -50,11 +51,11 @@
 	}
 
 	// Returns all files and directories (full path) in the given directory 'directory'.
-	virtual std::set<std::string> list_directory(const std::string& directory) = 0;
+	virtual FilenameSet list_directory(const std::string& directory) const = 0;
 
 	virtual bool is_writable() const = 0;
 	virtual bool is_directory(const std::string& path) = 0;
-	virtual bool file_exists(const std::string& path) = 0;
+	virtual bool file_exists(const std::string& path) const = 0;
 
 	virtual void* load(const std::string& fname, size_t& length) = 0;
 
@@ -132,6 +133,24 @@
 	static std::string filename_without_ext(const char* n);
 	static std::string get_homedir();
 
+
+	/// Return the files in the given 'directory' that match the condition in 'test', i.e. 'test' returned 'true' for their filenames.
+	template <class UnaryPredicate>
+	FilenameSet filter_directory(const std::string& directory, UnaryPredicate test) const {
+		FilenameSet result = list_directory(directory);
+		for (auto it = result.begin(); it != result.end();) {
+			if (!test(*it)) {
+				it = result.erase(it);
+			} else {
+				++it;
+			}
+		}
+		return result;
+	}
+
+	/// Returns all files in the given 'directory' that match 'basename[_\d{1,3}].extension'
+	std::vector<std::string> get_sequential_files(const std::string& directory, const std::string& basename, const std::string& extension) const;
+
 	virtual unsigned long long disk_space() = 0;
 
 protected:

=== modified file 'src/io/filesystem/layered_filesystem.cc'
--- src/io/filesystem/layered_filesystem.cc	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/layered_filesystem.cc	2019-04-28 09:46:14 +0000
@@ -59,7 +59,7 @@
  *
  * Returns the number of files found.
  */
-std::set<std::string> LayeredFileSystem::list_directory(const std::string& path) {
+FilenameSet LayeredFileSystem::list_directory(const std::string& path) const {
 	std::set<std::string> results;
 	FilenameSet files;
 	// Check home system first
@@ -81,7 +81,7 @@
 /**
  * Returns true if the file can be found in at least one of the sub-filesystems
  */
-bool LayeredFileSystem::file_exists(const std::string& path) {
+bool LayeredFileSystem::file_exists(const std::string& path) const {
 	if (home_ && home_->file_exists(path))
 		return true;
 	for (auto it = filesystems_.rbegin(); it != filesystems_.rend(); ++it)

=== modified file 'src/io/filesystem/layered_filesystem.h'
--- src/io/filesystem/layered_filesystem.h	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/layered_filesystem.h	2019-04-28 09:46:14 +0000
@@ -56,10 +56,10 @@
 	// files). Take ownership of the given filesystem.
 	void set_home_file_system(FileSystem*);
 
-	std::set<std::string> list_directory(const std::string& path) override;
+	FilenameSet list_directory(const std::string& path) const override;
 
 	bool is_writable() const override;
-	bool file_exists(const std::string& path) override;
+	bool file_exists(const std::string& path) const override;
 	bool is_directory(const std::string& path) override;
 	void ensure_directory_exists(const std::string& fs_dirname) override;
 	void make_directory(const std::string& fs_dirname) override;

=== modified file 'src/io/filesystem/zip_filesystem.cc'
--- src/io/filesystem/zip_filesystem.cc	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/zip_filesystem.cc	2019-04-28 09:46:14 +0000
@@ -154,7 +154,7 @@
  * pathname) in the results. There doesn't seem to be an even remotely
  * cross-platform way of doing this
  */
-std::set<std::string> ZipFilesystem::list_directory(const std::string& path_in) {
+FilenameSet ZipFilesystem::list_directory(const std::string& path_in) const {
 	assert(path_in.size());  //  prevent invalid read below
 
 	std::string path = basedir_in_zip_file_;
@@ -197,7 +197,7 @@
  * Returns true if the given file exists, and false if it doesn't.
  * Also returns false if the pathname is invalid
  */
-bool ZipFilesystem::file_exists(const std::string& path) {
+bool ZipFilesystem::file_exists(const std::string& path) const {
 	try {
 		unzGoToFirstFile(zip_file_->read_handle());
 	} catch (...) {

=== modified file 'src/io/filesystem/zip_filesystem.h'
--- src/io/filesystem/zip_filesystem.h	2019-02-23 11:00:49 +0000
+++ src/io/filesystem/zip_filesystem.h	2019-04-28 09:46:14 +0000
@@ -38,10 +38,10 @@
 
 	bool is_writable() const override;
 
-	std::set<std::string> list_directory(const std::string& path) override;
+	FilenameSet list_directory(const std::string& path) const override;
 
 	bool is_directory(const std::string& path) override;
-	bool file_exists(const std::string& path) override;
+	bool file_exists(const std::string& path) const override;
 
 	void* load(const std::string& fname, size_t& length) override;
 

=== modified file 'src/logic/map_objects/map_object.cc'
--- src/logic/map_objects/map_object.cc	2019-03-03 08:31:25 +0000
+++ src/logic/map_objects/map_object.cc	2019-04-28 09:46:14 +0000
@@ -43,6 +43,10 @@
 #include "map_io/map_object_loader.h"
 #include "map_io/map_object_saver.h"
 
+namespace {
+char const* const animation_direction_names[6] = {"_ne", "_e", "_se", "_sw", "_w", "_nw"};
+} // namespace
+
 namespace Widelands {
 
 CmdDestroyMapObject::CmdDestroyMapObject(uint32_t const t, MapObject& o)
@@ -238,10 +242,7 @@
                     init_descname,
                     table.has_key("helptext_script") ? table.get_string("helptext_script") : "") {
 	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)));
-		}
+		add_animations(*table.get_table("animations"));
 		if (!is_animation_known("idle")) {
 			throw GameDataError(
 			   "Map object %s has animations but no idle animation", init_name.c_str());
@@ -269,20 +270,39 @@
 }
 
 /**
- * Add this animation for this map object under this name
+ * Add all animations for this map object
  */
-void MapObjectDescr::add_animation(const std::string& animname, uint32_t const anim) {
-	if (is_animation_known(animname)) {
-		throw GameDataError("Tried to add already existing animation \"%s\"", animname.c_str());
-	} else {
-		anims_.insert(std::pair<std::string, uint32_t>(animname, anim));
+void MapObjectDescr::add_animations(const LuaTable& table) {
+	for (const std::string& animname : table.keys<std::string>()) {
+		try {
+			std::unique_ptr<LuaTable> anim = table.get_table(animname);
+			// TODO(GunChleoc): Require basename after conversion has been completed
+			const std::string basename = anim->has_key<std::string>("basename") ? anim->get_string("basename") : "";
+			const bool is_directional = anim->has_key<std::string>("directional") ? anim->get_bool("directional") : false;
+			if (is_directional) {
+				for (int dir = 1; dir <= 6; ++dir) {
+					const std::string directional_animname = animname + animation_direction_names[dir - 1];
+					if (is_animation_known(directional_animname)) {
+						throw GameDataError("Tried to add already existing directional animation '%s\'", directional_animname.c_str());
+					}
+					const std::string directional_basename = basename + animation_direction_names[dir - 1];
+					anims_.insert(std::pair<std::string, uint32_t>(directional_animname, g_gr->animations().load(*anim, directional_basename)));
+				}
+			} else {
+				if (is_animation_known(animname)) {
+					throw GameDataError("Tried to add already existing animation '%s'", animname.c_str());
+				}
+				anims_.insert(std::pair<std::string, uint32_t>(animname, g_gr->animations().load(*anim, basename)));
+			}
+		} catch (const std::exception& e) {
+			throw GameDataError("Error loading animation for map object '%s': %s", name().c_str(), e.what());
+		}
 	}
 }
 
-void MapObjectDescr::add_directional_animation(DirAnimations* anims, const std::string& prefix) {
-	static char const* const dirstrings[6] = {"ne", "e", "se", "sw", "w", "nw"};
+void MapObjectDescr::assign_directional_animation(DirAnimations* anims, const std::string& basename) {
 	for (int32_t dir = 1; dir <= 6; ++dir) {
-		const std::string anim_name = prefix + std::string("_") + dirstrings[dir - 1];
+		const std::string anim_name = basename + animation_direction_names[dir - 1];
 		try {
 			anims->set_animation(dir, get_animation(anim_name));
 		} catch (const GameDataError& e) {
@@ -316,6 +336,12 @@
 	NEVER_HERE();
 }
 
+void MapObjectDescr::load_graphics() const {
+	for (const auto& temp_anim : anims_) {
+		g_gr->animations().get_animation(temp_anim.second).load_default_scale();
+	}
+}
+
 const Image* MapObjectDescr::representative_image(const RGBColor* player_color) const {
 	if (is_animation_known("idle")) {
 		return g_gr->animations().get_representative_image(get_animation("idle"), player_color);
@@ -633,8 +659,12 @@
  * configured.
  *
  * Derived functions must call ancestor's function in the appropriate place.
+ *
+ * We also preload some animation graphics here to prevent jitter at game start.
  */
 void MapObject::Loader::load_finish() {
+	MapObject& mo = get<MapObject>();
+	mo.descr().load_graphics();
 }
 
 /**

=== modified file 'src/logic/map_objects/map_object.h'
--- src/logic/map_objects/map_object.h	2019-02-27 17:19:00 +0000
+++ src/logic/map_objects/map_object.h	2019-04-28 09:46:14 +0000
@@ -129,11 +129,9 @@
 	std::string get_animation_name(uint32_t) const;  ///< needed for save, debug
 
 	bool is_animation_known(const std::string& name) const;
-	void add_animation(const std::string& name, uint32_t anim);
 
-	/// Sets the directional animations in 'anims' with the animations
-	/// '&lt;prefix&gt;_(ne|e|se|sw|w|nw)'.
-	void add_directional_animation(DirAnimations* anims, const std::string& prefix);
+	/// Preload animation graphics at default scale
+	void load_graphics() const;
 
 	/// Returns the image for the first frame of the idle animation if the MapObject has animations,
 	/// nullptr otherwise
@@ -157,7 +155,13 @@
 	                    const std::set<uint32_t>& allowed_special);
 	void add_attribute(uint32_t attr);
 
+	/// Sets the directional animations in 'anims' with the animations
+	/// '&lt;basename&gt;_(ne|e|se|sw|w|nw)'.
+	void assign_directional_animation(DirAnimations* anims, const std::string& basename);
+
 private:
+	void add_animations(const LuaTable& table);
+
 	/// Throws an exception if the MapObjectDescr has no representative image
 	void check_representative_image();
 

=== modified file 'src/logic/map_objects/tribes/ship.cc'
--- src/logic/map_objects/tribes/ship.cc	2019-04-26 20:38:39 +0000
+++ src/logic/map_objects/tribes/ship.cc	2019-04-28 09:46:14 +0000
@@ -114,7 +114,7 @@
 	i18n::Textdomain td("tribes");
 
 	// Read the sailing animations
-	add_directional_animation(&sail_anims_, "sail");
+	assign_directional_animation(&sail_anims_, "sail");
 
 	capacity_ = table.has_key("capacity") ? table.get_int("capacity") : 20;
 }

=== modified file 'src/logic/map_objects/tribes/tribe_descr.cc'
--- src/logic/map_objects/tribes/tribe_descr.cc	2019-04-09 16:43:49 +0000
+++ src/logic/map_objects/tribes/tribe_descr.cc	2019-04-28 09:46:14 +0000
@@ -64,8 +64,12 @@
 		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"));
+		{
+			std::unique_ptr<LuaTable> animations_table = items_table->get_table("frontier");
+			frontier_animation_id_ = g_gr->animations().load(*animations_table, animations_table->get_string("basename"));
+			animations_table = items_table->get_table("flag");
+			flag_animation_id_ = g_gr->animations().load(*animations_table, animations_table->get_string("basename"));
+		}
 
 		items_table = table.get_table("roads");
 		const auto load_roads = [&items_table](

=== modified file 'src/logic/map_objects/tribes/worker_descr.cc'
--- src/logic/map_objects/tribes/worker_descr.cc	2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/tribes/worker_descr.cc	2019-04-28 09:46:14 +0000
@@ -93,13 +93,13 @@
 	}
 
 	// Read the walking animations
-	add_directional_animation(&walk_anims_, "walk");
+	assign_directional_animation(&walk_anims_, "walk");
 
 	// Many workers don't carry wares, so they have no walkload animation.
 	std::unique_ptr<LuaTable> anims(table.get_table("animations"));
 	anims->do_not_warn_about_unaccessed_keys();
-	if (anims->has_key("walkload_e")) {
-		add_directional_animation(&walkload_anims_, "walkload");
+	if (is_animation_known("walkload_e")) {
+		assign_directional_animation(&walkload_anims_, "walkload");
 	}
 
 	// Read programs

=== modified file 'src/logic/map_objects/world/critter.cc'
--- src/logic/map_objects/world/critter.cc	2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/world/critter.cc	2019-04-28 09:46:14 +0000
@@ -101,7 +101,7 @@
                            const World& world)
    : BobDescr(init_descname, MapObjectType::CRITTER, MapObjectDescr::OwnerType::kWorld, table),
      editor_category_(nullptr) {
-	add_directional_animation(&walk_anims_, "walk");
+	assign_directional_animation(&walk_anims_, "walk");
 
 	add_attributes(
 	   table.get_table("attributes")->array_entries<std::string>(), std::set<uint32_t>());

=== modified file 'src/map_io/map_scripting_packet.cc'
--- src/map_io/map_scripting_packet.cc	2019-02-23 11:00:49 +0000
+++ src/map_io/map_scripting_packet.cc	2019-04-28 09:46:14 +0000
@@ -24,7 +24,6 @@
 #include <boost/algorithm/string/predicate.hpp>
 
 #include "base/macros.h"
-#include "helper.h"
 #include "io/fileread.h"
 #include "io/filewrite.h"
 #include "logic/editor_game_base.h"
@@ -43,7 +42,7 @@
 void write_lua_dir(FileSystem& target_fs, FileSystem* map_fs, const std::string& path) {
 	assert(map_fs);
 	target_fs.ensure_directory_exists(path);
-	for (const std::string& script : filter(map_fs->list_directory(path), [](const std::string& fn) {
+	for (const std::string& script : map_fs->filter_directory(path, [](const std::string& fn) {
 		     return boost::ends_with(fn, ".lua");
 	     })) {
 		size_t length;

=== modified file 'src/scripting/lua_path.cc'
--- src/scripting/lua_path.cc	2019-02-23 11:00:49 +0000
+++ src/scripting/lua_path.cc	2019-04-28 09:46:14 +0000
@@ -30,6 +30,8 @@
 namespace {
 
 /// A class that makes iteration over filename_?.png templates easy.
+// TODO(GunChleoc): Code duplication with g_fs->get_sequential_files.
+// Get rid of this and list_files when conversion to spritemaps has been done.
 class NumberGlob {
 public:
 	explicit NumberGlob(const std::string& file_template);
@@ -132,10 +134,11 @@
 /* RST
 .. function:: list_files(filename_template)
 
-   Lists the full path for all files that fit the template pattern.
+   **DEPRECATED**. Lists the full path for all files that fit the template pattern.
    Use ? as placeholders for numbers, e.g. 'directory/idle\_??.png' will list
    'directory/idle_00.png', 'directory/idle_01.png' etc, and
    'directory/idle.png' will just list 'directory/idle.png'.
+   Lua Tables need lots of memory, so only use this when you have to.
 
    :type filename_template: class:`string`
    :arg filename_template: The filename template to use for the listing.
@@ -147,6 +150,7 @@
 
 	NumberGlob glob(filename_template);
 	std::string filename;
+
 	lua_newtable(L);
 	int idx = 1;
 
@@ -165,6 +169,7 @@
 .. function:: list_directory(filename)
 
    Returns all file names contained in the given directory.
+   Lua Tables need lots of memory, so only use this when you have to.
 
    :type filename: class:`string`
    :arg filename: The directory to read.

=== modified file 'src/sound/fxset.cc'
--- src/sound/fxset.cc	2019-04-24 06:01:37 +0000
+++ src/sound/fxset.cc	2019-04-28 09:46:14 +0000
@@ -36,25 +36,14 @@
  * \param random: Randomize the time last played a bit to prevent sound onslaught at game start
  */
 FXset::FXset(const std::string& path, uint32_t random) : last_used_(random % 2000) {
-	// Check directory
-	std::string directory = FileSystem::fs_dirname(path);
-	if (!g_fs->is_directory(directory)) {
-		throw Widelands::GameDataError(
-		   "SoundHandler: Can't load files from %s, not a directory!", directory.c_str());
-	}
-
-	// Find files
-	std::string base_filename = FileSystem::fs_filename(path.c_str());
-	boost::regex re(base_filename + "_\\d+\\.ogg");
-	paths_ = filter(g_fs->list_directory(directory), [&re](const std::string& fn) {
-		return boost::regex_match(FileSystem::fs_filename(fn.c_str()), re);
-	});
+	const std::string dirname = FileSystem::fs_dirname(path.c_str());
+	const std::string basename = FileSystem::fs_filename(path.c_str());
+	paths_ = g_fs->get_sequential_files(dirname, basename, "ogg");
 
 	// Ensure that we have at least 1 file
 	if (paths_.empty()) {
-		throw Widelands::GameDataError(
-		   "FXset: No files matching the pattern '%s_<numbers>.ogg' found in directory %s\n",
-		   base_filename.c_str(), directory.c_str());
+		throw Widelands::GameDataError("FXset: No files matching the pattern '%s_<numbers>.ogg' found in directory %s\n",
+							basename.c_str(), dirname.c_str());
 	}
 
 #ifndef NDEBUG
@@ -118,6 +107,7 @@
 		assert(m);
 		fxs_.push_back(m);
 	} else {
-		log("FXset: loading sound effect file \"%s\" failed: %s\n", path.c_str(), Mix_GetError());
+		log("FXset: loading sound effect file \"%s\" failed: %s\n",
+		    path.c_str(), Mix_GetError());
 	}
 }

=== modified file 'src/sound/fxset.h'
--- src/sound/fxset.h	2019-04-24 06:01:37 +0000
+++ src/sound/fxset.h	2019-04-28 09:46:14 +0000
@@ -20,7 +20,6 @@
 #ifndef WL_SOUND_FXSET_H
 #define WL_SOUND_FXSET_H
 
-#include <set>
 #include <string>
 #include <vector>
 
@@ -65,11 +64,10 @@
 	uint32_t last_used_;
 
 	/**
-	 * Filename paths for the physical sound files
-	 * This will be cleared when the effects have been loaded into memory by \ref get_fx on first
-	 * play.
-	 */
-	std::set<std::string> paths_;
+	* Filename paths for the physical sound files
+	* This will be cleared when the effects have been loaded into memory by \ref get_fx on first play.
+	*/
+	std::vector<std::string> paths_;
 
 	/// The collection of sound effects, to be loaded on demand
 	std::vector<Mix_Chunk*> fxs_;

=== modified file 'src/sound/songset.cc'
--- src/sound/songset.cc	2019-04-24 06:01:37 +0000
+++ src/sound/songset.cc	2019-04-28 09:46:14 +0000
@@ -33,11 +33,7 @@
 Songset::Songset(const std::string& dir, const std::string& basename)
    : m_(nullptr), rwops_(nullptr) {
 	assert(g_fs);
-	FilenameSet files = filter(g_fs->list_directory(dir), [&basename](const std::string& fn) {
-		const std::string only_filename = FileSystem::fs_filename(fn.c_str());
-		return boost::starts_with(only_filename, basename) && boost::ends_with(only_filename, ".ogg");
-	});
-
+	std::vector<std::string> files = g_fs->get_sequential_files(dir, basename, "ogg");
 	for (const std::string& filename : files) {
 		assert(!g_fs->is_directory(filename));
 		add_song(filename);

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2019-04-24 06:01:37 +0000
+++ src/wlapplication.cc	2019-04-28 09:46:14 +0000
@@ -56,7 +56,6 @@
 #include "graphic/font_handler.h"
 #include "graphic/text/font_set.h"
 #include "graphic/text_constants.h"
-#include "helper.h"
 #include "io/filesystem/disk_filesystem.h"
 #include "io/filesystem/filesystem_exceptions.h"
 #include "io/filesystem/layered_filesystem.h"
@@ -1497,7 +1496,7 @@
  */
 void WLApplication::cleanup_replays() {
 	for (const std::string& filename :
-	     filter(g_fs->list_directory(kReplayDir), [](const std::string& fn) {
+	     g_fs->filter_directory(kReplayDir, [](const std::string& fn) {
 		     return boost::ends_with(
 		        fn, (boost::format("%s%s") % kReplayExtension % kSyncstreamExtension).str());
 	     })) {
@@ -1518,7 +1517,7 @@
  */
 void WLApplication::cleanup_ai_files() {
 	for (const std::string& filename :
-	     filter(g_fs->list_directory(kAiDir), [](const std::string& fn) {
+	     g_fs->filter_directory(kAiDir, [](const std::string& fn) {
 		     return boost::ends_with(fn, kAiExtension) || boost::contains(fn, "ai_player");
 	     })) {
 		if (is_autogenerated_and_expired(filename, kAIFilesKeepAroundTime)) {
@@ -1538,7 +1537,7 @@
  */
 void WLApplication::cleanup_temp_files() {
 	for (const std::string& filename :
-	     filter(g_fs->list_directory(kTempFileDir),
+	     g_fs->filter_directory(kTempFileDir,
 	            [](const std::string& fn) { return boost::ends_with(fn, kTempFileExtension); })) {
 		if (is_autogenerated_and_expired(filename, kTempFilesKeepAroundTime)) {
 			log("Deleting old temp file: %s\n", filename.c_str());
@@ -1556,7 +1555,7 @@
  * Recursively delete temporary backup files in a given directory
  */
 void WLApplication::cleanup_temp_backups(std::string dir) {
-	for (const std::string& filename : filter(g_fs->list_directory(dir), [](const std::string& fn) {
+	for (const std::string& filename : g_fs->filter_directory(dir, [](const std::string& fn) {
 		     return boost::ends_with(fn, kTempBackupExtension);
 	     })) {
 		if (is_autogenerated_and_expired(filename, kTempBackupsKeepAroundTime)) {
@@ -1570,7 +1569,7 @@
 		}
 	}
 	// recursively delete in subdirs
-	for (const std::string& dirname : filter(g_fs->list_directory(dir), [](const std::string& fn) {
+	for (const std::string& dirname : g_fs->filter_directory(dir, [](const std::string& fn) {
 		     return g_fs->is_directory(fn) &&
 		            // avoid searching within savegames/maps/backups that were created
 		            // as directories instead of zipfiles

=== modified file 'src/wui/load_or_save_game.cc'
--- src/wui/load_or_save_game.cc	2019-04-18 16:50:35 +0000
+++ src/wui/load_or_save_game.cc	2019-04-28 09:46:14 +0000
@@ -363,16 +363,15 @@
 	table_.clear();
 
 	FilenameSet gamefiles;
-
 	if (filetype_ == FileType::kReplay) {
-		gamefiles = filter(g_fs->list_directory(kReplayDir), [](const std::string& fn) {
+		gamefiles = g_fs->filter_directory(kReplayDir, [](const std::string& fn) {
 			return boost::algorithm::ends_with(fn, kReplayExtension);
 		});
 		// Update description column title for replays
 		table_.set_column_tooltip(2, show_filenames_ ? _("Filename: Map name (start of replay)") :
 		                                               _("Map name (start of replay)"));
 	} else {
-		gamefiles = filter(g_fs->list_directory(kSaveDir), [](const std::string& fn) {
+		gamefiles = g_fs->filter_directory(kSaveDir, [](const std::string& fn) {
 			return boost::algorithm::ends_with(fn, kSavegameExtension);
 		});
 	}


Follow ups